org.wso2.carbon.identity.authenticator.saml2.sso.util.Util.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.identity.authenticator.saml2.sso.util.Util.java

Source

/*
 * Copyright (c) 2005, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.carbon.identity.authenticator.saml2.sso.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xerces.impl.Constants;
import org.apache.xerces.util.SecurityManager;
import org.opensaml.Configuration;
import org.opensaml.DefaultBootstrap;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.io.UnmarshallingException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.core.util.KeyStoreManager;
import org.wso2.carbon.identity.authenticator.saml2.sso.SAML2SSOAuthenticatorException;
import org.wso2.carbon.identity.authenticator.saml2.sso.internal.SAML2SSOAuthBEDataHolder;
import org.wso2.carbon.user.core.service.RealmService;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.X509Certificate;

public class Util {
    private Util() {

    }

    private static final String SECURITY_MANAGER_PROPERTY = Constants.XERCES_PROPERTY_PREFIX
            + Constants.SECURITY_MANAGER_PROPERTY;
    private static final int ENTITY_EXPANSION_LIMIT = 0;
    private static boolean bootStrapped = false;
    private static Log log = LogFactory.getLog(Util.class);

    /**
     * Constructing the XMLObject Object from a String
     *
     * @param authReqStr
     * @return Corresponding XMLObject which is a SAML2 object
     * @throws org.wso2.carbon.identity.authenticator.saml2.sso.SAML2SSOAuthenticatorException
     */
    public static XMLObject unmarshall(String authReqStr) throws SAML2SSOAuthenticatorException {

        XMLObject response;
        try {
            doBootstrap();
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            documentBuilderFactory.setNamespaceAware(true);

            documentBuilderFactory.setExpandEntityReferences(false);
            documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
            SecurityManager securityManager = new SecurityManager();
            securityManager.setEntityExpansionLimit(ENTITY_EXPANSION_LIMIT);
            documentBuilderFactory.setAttribute(SECURITY_MANAGER_PROPERTY, securityManager);

            DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
            docBuilder.setEntityResolver(new CarbonEntityResolver());
            Document document = docBuilder.parse(new ByteArrayInputStream(authReqStr.trim().getBytes()));
            Element element = document.getDocumentElement();
            UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
            Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(element);
            response = unmarshaller.unmarshall(element);
            // Check for duplicate samlp:Response
            NodeList list = response.getDOM().getElementsByTagNameNS(SAMLConstants.SAML20P_NS, "Response");
            if (list.getLength() > 0) {
                log.error("Invalid schema for the SAML2 reponse");
                throw new SAML2SSOAuthenticatorException("Error occured while processing saml2 response");
            }
            return response;
        } catch (ParserConfigurationException e) {
            log.error("Error occured while processing saml2 response");
            throw new SAML2SSOAuthenticatorException("Error occured while processing saml2 response", e);
        } catch (SAXException e) {
            log.error("Error occured while processing saml2 response");
            throw new SAML2SSOAuthenticatorException("Error occured while processing saml2 response", e);
        } catch (IOException e) {
            log.error("Error occured while processing saml2 response");
            throw new SAML2SSOAuthenticatorException("Error occured while processing saml2 response", e);
        } catch (UnmarshallingException e) {
            log.error("Error occured while processing saml2 response");
            throw new SAML2SSOAuthenticatorException("Error occured while processing saml2 response", e);
        }

    }

    /**
     * This method is used to initialize the OpenSAML2 library. It calls the bootstrap method, if it
     * is not initialized yet.
     */
    public static void doBootstrap() {

        if (!bootStrapped) {
            try {
                DefaultBootstrap.bootstrap();
                bootStrapped = true;
            } catch (ConfigurationException e) {
                log.error("Error in bootstrapping the OpenSAML2 library", e);
            }
        }
    }

    /**
     * Get the X509CredentialImpl object for a particular tenant
     *
     * @param domainName domain name
     * @return X509CredentialImpl object containing the public certificate of that tenant
     * @throws org.wso2.carbon.identity.authenticator.saml2.sso.SAML2SSOAuthenticatorException Error when creating X509CredentialImpl object
     */
    public static X509CredentialImpl getX509CredentialImplForTenant(String domainName)
            throws SAML2SSOAuthenticatorException {

        int tenantID = MultitenantConstants.SUPER_TENANT_ID;
        RealmService realmService = SAML2SSOAuthBEDataHolder.getInstance().getRealmService();

        // get the tenantID
        if (!domainName.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
            try {
                tenantID = realmService.getTenantManager().getTenantId(domainName);
            } catch (org.wso2.carbon.user.api.UserStoreException e) {
                String errorMsg = "Error getting the TenantID for the domain name";
                log.error(errorMsg, e);
                throw new SAML2SSOAuthenticatorException(errorMsg, e);
            }
        }

        KeyStoreManager keyStoreManager = null;
        // get an instance of the corresponding Key Store Manager instance
        keyStoreManager = KeyStoreManager.getInstance(tenantID);

        X509CredentialImpl credentialImpl = null;
        try {
            if (tenantID != MultitenantConstants.SUPER_TENANT_ID) {
                // for non zero tenants, load private key from their generated key store

                KeyStore keystore = keyStoreManager.getKeyStore(generateKSNameFromDomainName(domainName));
                java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) keystore
                        .getCertificate(domainName);
                credentialImpl = new X509CredentialImpl(cert);
            } else { // for tenant zero, load the cert corresponding to given alias in authenticators.xml
                String alias = SAML2SSOAuthBEDataHolder.getInstance().getIdPCertAlias();
                java.security.cert.X509Certificate cert = null;
                if (alias != null) {
                    cert = (X509Certificate) keyStoreManager.getPrimaryKeyStore().getCertificate(alias);
                    if (cert == null) {
                        String errorMsg = "Cannot find a certificate with the alias " + alias
                                + " in the default key store. Please check the 'KeyAlias' property in"
                                + " the SSO configuration of the authenticators.xml";
                        log.error(errorMsg);
                        throw new SAML2SSOAuthenticatorException(errorMsg);
                    }
                } else { // if the idpCertAlias is not given, use the default certificate.
                    cert = keyStoreManager.getDefaultPrimaryCertificate();
                }
                credentialImpl = new X509CredentialImpl(cert);
            }
        } catch (Exception e) {
            String errorMsg = "Error instantiating an X509CredentialImpl object for the public cert.";
            log.error(errorMsg, e);
            throw new SAML2SSOAuthenticatorException(errorMsg, e);
        }
        return credentialImpl;
    }

    /**
     * Generate the key store name from the domain name
     *
     * @param tenantDomain tenant domain name
     * @return key store file name
     */
    private static String generateKSNameFromDomainName(String tenantDomain) {
        String ksName = tenantDomain.trim().replace(".", "-");
        return (ksName + ".jks");
    }

}