org.apache.rahas.impl.SAMLTokenIssuerConfig.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.rahas.impl.SAMLTokenIssuerConfig.java

Source

/*
 * Copyright 2004,2005 The Apache Software Foundation.
 *
 * Licensed 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.apache.rahas.impl;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.description.Parameter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.rahas.TrustException;
import org.apache.rahas.impl.util.SAMLCallbackHandler;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;

import javax.xml.namespace.QName;
import java.io.FileInputStream;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

/**
 * Configuration manager for the <code>SAMLTokenIssuer</code>
 *
 * @see SAMLTokenIssuer
 */
public class SAMLTokenIssuerConfig extends AbstractIssuerConfig {

    Log log = LogFactory.getLog(SAMLTokenIssuerConfig.class);

    /**
     * The QName of the configuration element of the SAMLTokenIssuer
     */
    public final static QName SAML_ISSUER_CONFIG = new QName("saml-issuer-config");

    /**
     * Element name to include the alias of the private key to sign the response or
     * the issued token
     */
    private final static QName ISSUER_KEY_ALIAS = new QName("issuerKeyAlias");

    /**
    * Element name to include the password of the private key to sign the response or the issued
    * token
    */
    private final static QName ISSUER_KEY_PASSWD = new QName("issuerKeyPassword");

    /**
     * Element name of the attribute call-back handler
     */
    private final static QName ATTR_CALLBACK_HANDLER_NAME = new QName("attrCallbackHandlerName");

    /**
     * Element to specify the lifetime of the SAMLToken
     * Dafaults to 300000 milliseconds (5 mins)
     */
    private final static QName TTL = new QName("timeToLive");

    /**
     * Element to list the trusted services
     */
    private final static QName TRUSTED_SERVICES = new QName("trusted-services");

    private final static QName KEY_SIZE = new QName("keySize");

    private final static QName SERVICE = new QName("service");
    private final static QName ALIAS = new QName("alias");

    public final static QName USE_SAML_ATTRIBUTE_STATEMENT = new QName("useSAMLAttributeStatement");

    public final static QName ISSUER_NAME = new QName("issuerName");

    public final static QName SAML_CALLBACK_CLASS = new QName("dataCallbackHandlerClass");

    protected String issuerKeyAlias;
    protected String issuerKeyPassword;
    protected String issuerName;
    protected Map trustedServices = new HashMap();
    protected String trustStorePropFile;
    protected SAMLCallbackHandler callbackHandler;
    protected String callbackHandlerName;
    protected OMElement persisterElement = null;
    protected String persisterClassName = null;
    protected Map<String, String> persisterPropertyMap = null;
    protected boolean tokenStoreDisabled = false;

    /**
     * Create a new configuration with issuer name and crypto information
     * @param issuerName Name of the issuer
     * @param cryptoProviderClassName WSS4J Crypto impl class name
     * @param cryptoProps Configuration properties of crypto impl
     */
    public SAMLTokenIssuerConfig(String issuerName, String cryptoProviderClassName, Properties cryptoProps) {
        this.issuerName = issuerName;
        this.setCryptoProperties(cryptoProviderClassName, cryptoProps);
    }

    /**
     * Create a SAMLTokenIssuer configuration with a config file picked from the
     * given location.
     * @param configFilePath Path to the config file
     * @throws TrustException
     */
    public SAMLTokenIssuerConfig(String configFilePath) throws TrustException {
        FileInputStream fis;
        StAXOMBuilder builder;
        try {
            fis = new FileInputStream(configFilePath);
            builder = new StAXOMBuilder(fis);
        } catch (Exception e) {
            throw new TrustException("errorLoadingConfigFile", new String[] { configFilePath });
        }
        this.load(builder.getDocumentElement());
    }

    /**
     * Create a  SAMLTokenIssuer configuration using the give config element
     * @param elem Configuration element as an <code>OMElement</code>
     * @throws TrustException
     */
    public SAMLTokenIssuerConfig(OMElement elem) throws TrustException {
        this.load(elem);
    }

    private void load(OMElement elem) throws TrustException {
        OMElement proofKeyElem = elem.getFirstChildWithName(PROOF_KEY_TYPE);
        if (proofKeyElem != null) {
            this.proofKeyType = proofKeyElem.getText().trim();
        }

        OMElement callbackNameElem = elem.getFirstChildWithName(ATTR_CALLBACK_HANDLER_NAME);
        if (callbackNameElem != null) {
            this.callbackHandlerName = callbackNameElem.getText().trim();
        }

        //The alias of the private key
        OMElement userElem = elem.getFirstChildWithName(ISSUER_KEY_ALIAS);
        if (userElem != null) {
            this.issuerKeyAlias = userElem.getText().trim();
        }

        if (this.issuerKeyAlias == null || "".equals(this.issuerKeyAlias)) {
            throw new TrustException("samlIssuerKeyAliasMissing");
        }

        OMElement issuerKeyPasswdElem = elem.getFirstChildWithName(ISSUER_KEY_PASSWD);
        if (issuerKeyPasswdElem != null) {
            this.issuerKeyPassword = issuerKeyPasswdElem.getText().trim();
        }

        if (this.issuerKeyPassword == null || "".equals(this.issuerKeyPassword)) {
            throw new TrustException("samlIssuerKeyPasswdMissing");
        }

        OMElement issuerNameElem = elem.getFirstChildWithName(ISSUER_NAME);
        if (issuerNameElem != null) {
            this.issuerName = issuerNameElem.getText().trim();
        }

        if (this.issuerName == null || "".equals(this.issuerName)) {
            throw new TrustException("samlIssuerNameMissing");
        }

        this.cryptoPropertiesElement = elem.getFirstChildWithName(CRYPTO_PROPERTIES);
        if (this.cryptoPropertiesElement != null) {
            if ((this.cryptoElement = this.cryptoPropertiesElement.getFirstChildWithName(CRYPTO)) == null) {
                // no children. Hence, prop file should have been defined
                this.cryptoPropertiesFile = this.cryptoPropertiesElement.getText().trim();
            }
            // else Props should be defined as children of a crypto element
        }

        OMElement keyCompElem = elem.getFirstChildWithName(KeyComputation.KEY_COMPUTATION);
        if (keyCompElem != null && keyCompElem.getText() != null && !"".equals(keyCompElem.getText())) {
            this.keyComputation = Integer.parseInt(keyCompElem.getText());
        }

        //time to live
        OMElement ttlElem = elem.getFirstChildWithName(TTL);
        if (ttlElem != null) {
            try {
                this.ttl = Long.parseLong(ttlElem.getText().trim());
            } catch (NumberFormatException e) {
                throw new TrustException("invlidTTL");
            }
        }

        OMElement keySizeElem = elem.getFirstChildWithName(KEY_SIZE);
        if (keySizeElem != null) {
            try {
                this.keySize = Integer.parseInt(keySizeElem.getText().trim());
            } catch (NumberFormatException e) {
                throw new TrustException("invalidKeysize");
            }
        }

        this.addRequestedAttachedRef = elem.getFirstChildWithName(ADD_REQUESTED_ATTACHED_REF) != null;
        this.addRequestedUnattachedRef = elem.getFirstChildWithName(ADD_REQUESTED_UNATTACHED_REF) != null;

        //Process trusted services
        OMElement trustedServices = elem.getFirstChildWithName(TRUSTED_SERVICES);

        /*
        * If there are trusted services add them to a list
        * Only trusts myself to issue tokens to :
        * In this case the STS is embedded in the service as well and
        * the issued token can only be used with that particular service
        * since the response secret is encrypted by the service's public key
        */
        if (trustedServices != null) {
            //Now process the trusted services
            Iterator servicesIter = trustedServices.getChildrenWithName(SERVICE);
            while (servicesIter.hasNext()) {
                OMElement service = (OMElement) servicesIter.next();
                OMAttribute aliasAttr = service.getAttribute(ALIAS);
                if (aliasAttr == null) {
                    //The certificate alias is a must
                    throw new TrustException("aliasMissingForService", new String[] { service.getText().trim() });
                }
                if (this.trustedServices == null) {
                    this.trustedServices = new HashMap();
                }

                //Add the trusted service and the alias to the map of services
                this.trustedServices.put(service.getText().trim(), aliasAttr.getAttributeValue());
            }

            //There maybe no trusted services as well, Therefore do not 
            //throw an exception when there are no trusted in the list at the 
            //moment
        }

        OMElement attrElemet = elem.getFirstChildWithName(SAML_CALLBACK_CLASS);
        if (attrElemet != null) {
            try {
                String value = attrElemet.getText();
                Class handlerClass = Class.forName(value);
                this.callbackHandler = (SAMLCallbackHandler) handlerClass.newInstance();
            } catch (ClassNotFoundException e) {
                log.error("Error loading class", e);
                throw new TrustException("Error loading class", e);
            } catch (InstantiationException e) {
                log.error("Error instantiating class", e);
                throw new TrustException("Error instantiating class", e);
            } catch (IllegalAccessException e) {
                log.error("Illegal Access", e);
                throw new TrustException("Illegal Access", e);
            }
        }

        //read & set if token storage is disabled
        OMElement storageDisabledElement = elem.getFirstChildWithName(TOKEN_STORE_DISABLED_QN);
        if (storageDisabledElement != null) {
            tokenStoreDisabled = Boolean.parseBoolean(storageDisabledElement.getText());
        }

        //read token persister configuration
        persisterElement = elem.getFirstChildWithName(TOKEN_PERSISTER_QN);
        //read persister configuration only if they are set
        if (persisterElement != null) {
            persisterClassName = persisterElement.getAttributeValue(ATTR_CLASS_QN);
            persisterPropertyMap = readPropertyMap(persisterElement);
        }

    }

    /**
     * Util method to extract property names and values to a property map
     * @param propertySetElement
     * @return property map
     */
    private Map<String, String> readPropertyMap(OMElement propertySetElement) {
        Map<String, String> propMap = new HashMap<String, String>();
        Iterator<?> ite = propertySetElement.getChildrenWithName(LOCAL_PROPERTY_QN);
        while (ite.hasNext()) {
            OMElement propertyElement = (OMElement) ite.next();
            String propertyName = propertyElement.getAttributeValue(ATTR_PROP_NAME_QN);
            String propertyValue = propertyElement.getText();
            propMap.put(propertyName, propertyValue);
        }
        return propMap;
    }

    /**
     * Generate an Axis2 parameter for this configuration
     * @return An Axis2 Parameter instance with configuration information
     */
    public Parameter getParameter() {
        Parameter param = new Parameter();

        OMFactory fac = OMAbstractFactory.getOMFactory();

        OMElement paramElem = fac.createOMElement("Parameter", null);
        paramElem.addAttribute("name", SAML_ISSUER_CONFIG.getLocalPart(), null);

        OMElement configElem = fac.createOMElement(SAML_ISSUER_CONFIG, paramElem);

        OMElement issuerNameElem = fac.createOMElement(ISSUER_NAME, configElem);
        issuerNameElem.setText(this.issuerName);

        OMElement issuerKeyAliasElem = fac.createOMElement(ISSUER_KEY_ALIAS, configElem);
        issuerKeyAliasElem.setText(this.issuerKeyAlias);

        OMElement issuerKeyPasswd = fac.createOMElement(ISSUER_KEY_PASSWD, configElem);
        issuerKeyPasswd.setText(this.issuerKeyPassword);

        OMElement callbackHandlerName = fac.createOMElement(ATTR_CALLBACK_HANDLER_NAME, configElem);
        callbackHandlerName.setText(this.callbackHandlerName);

        OMElement timeToLive = fac.createOMElement(TTL, configElem);
        timeToLive.setText(String.valueOf(this.ttl));

        configElem.addChild(this.cryptoPropertiesElement);

        OMElement keySizeElem = fac.createOMElement(KEY_SIZE, configElem);
        keySizeElem.setText(Integer.toString(this.keySize));

        if (this.addRequestedAttachedRef) {
            fac.createOMElement(ADD_REQUESTED_ATTACHED_REF, configElem);
        }
        if (this.addRequestedUnattachedRef) {
            fac.createOMElement(ADD_REQUESTED_UNATTACHED_REF, configElem);
        }

        OMElement keyCompElem = fac.createOMElement(KeyComputation.KEY_COMPUTATION, configElem);
        keyCompElem.setText(Integer.toString(this.keyComputation));

        OMElement proofKeyTypeElem = fac.createOMElement(PROOF_KEY_TYPE, configElem);
        proofKeyTypeElem.setText(this.proofKeyType);

        OMElement trustedServicesElem = fac.createOMElement(TRUSTED_SERVICES, configElem);
        for (Iterator iterator = this.trustedServices.keySet().iterator(); iterator.hasNext();) {
            String service = (String) iterator.next();
            OMElement serviceElem = fac.createOMElement(SERVICE, trustedServicesElem);
            serviceElem.setText(service);
            serviceElem.addAttribute("alias", (String) this.trustedServices.get(service), null);

        }

        //set storage disable parameter
        OMElement storageDisabledElement = fac.createOMElement(TOKEN_STORE_DISABLED_QN, configElem);
        storageDisabledElement.setText(Boolean.toString(tokenStoreDisabled));

        //set the persister element if configured
        if (persisterClassName != null) {
            OMElement persisterElement = fac.createOMElement(TOKEN_PERSISTER_QN, configElem);
            persisterElement.addAttribute(LOCAL_PROPERTY_CLASS, this.getPersisterClassName(), null);
            if (this.persisterPropertyMap != null && this.persisterPropertyMap.size() != 0) {
                for (Map.Entry<String, String> entry : persisterPropertyMap.entrySet()) {
                    OMElement propElement = fac.createOMElement(LOCAL_PROPERTY_QN, persisterElement);
                    propElement.addAttribute(ATTR_PROP_NAME, entry.getKey(), null);
                    propElement.setText(entry.getValue());
                }
            }
        }

        param.setName(SAML_ISSUER_CONFIG.getLocalPart());
        param.setParameterElement(paramElem);
        param.setValue(paramElem);
        param.setParameterType(Parameter.OM_PARAMETER);

        return param;
    }

    public void setIssuerKeyAlias(String issuerKeyAlias) {
        this.issuerKeyAlias = issuerKeyAlias;
    }

    public String getIssuerKeyAlias() {
        return issuerKeyAlias;
    }

    public void setIssuerKeyPassword(String issuerKeyPassword) {
        this.issuerKeyPassword = issuerKeyPassword;
    }

    public String getIssuerKeyPassword() {
        return issuerKeyPassword;
    }

    public void setIssuerName(String issuerName) {
        this.issuerName = issuerName;
    }

    public void setTrustedServices(Map trustedServices) {
        this.trustedServices = trustedServices;
    }

    public void setTrustStorePropFile(String trustStorePropFile) {
        this.trustStorePropFile = trustStorePropFile;
    }

    /**
     * Add a new trusted service endpoint address with its certificate
     * @param address Service endpoint address
     * @param alias certificate alias
     */
    public void addTrustedServiceEndpointAddress(String address, String alias) {
        this.trustedServices.put(address, alias);
    }

    /**
     * Set crypto information using WSS4J mechanisms
     * 
     * @param providerClassName
     *            Provider class - an implementation of
     *            org.apache.ws.security.components.crypto.Crypto
     * @param props Configuration properties
     */
    public void setCryptoProperties(String providerClassName, Properties props) {
        OMFactory fac = OMAbstractFactory.getOMFactory();
        this.cryptoPropertiesElement = fac.createOMElement(CRYPTO_PROPERTIES);
        OMElement cryptoElem = fac.createOMElement(CRYPTO, this.cryptoPropertiesElement);
        cryptoElem.addAttribute(PROVIDER.getLocalPart(), providerClassName, null);
        Enumeration keys = props.keys();
        while (keys.hasMoreElements()) {
            String prop = (String) keys.nextElement();
            String value = (String) props.get(prop);
            OMElement propElem = fac.createOMElement(PROPERTY, cryptoElem);
            propElem.setText(value);
            propElem.addAttribute("name", prop, null);
        }
    }

    /**
     * Return the list of trusted services as a <code>java.util.Map</code>.
     * The services addresses are the keys and cert aliases available under 
     * those keys. 
     * @return
     */
    public Map getTrustedServices() {
        return trustedServices;
    }

    @Deprecated
    public SAMLCallbackHandler getCallbackHander() {
        return callbackHandler;
    }

    @Deprecated
    public void setCallbackHander(SAMLCallbackHandler callbackHandler) {
        this.callbackHandler = callbackHandler;
    }

    public SAMLCallbackHandler getCallbackHandler() {
        return callbackHandler;
    }

    public void setCallbackHandler(SAMLCallbackHandler callbackHandler) {
        this.callbackHandler = callbackHandler;
    }

    public String getCallbackHandlerName() {
        return callbackHandlerName;
    }

    public void setCallbackHandlerName(String callbackHandlerName) {
        this.callbackHandlerName = callbackHandlerName;
    }

    /**
     * Uses the <code>wst:AppliesTo</code> to figure out the certificate to
     * encrypt the secret in the SAML token
     *
     * @param crypto
     * @param serviceAddress
     *            The address of the service
     * @return
     * @throws org.apache.ws.security.WSSecurityException
     */
    public X509Certificate getServiceCert(Crypto crypto, String serviceAddress) throws WSSecurityException {

        if (serviceAddress != null && !"".equals(serviceAddress)) {
            String alias = (String) this.trustedServices.get(serviceAddress);
            if (alias != null) {
                return crypto.getCertificates(alias)[0];
            } else {
                alias = (String) this.trustedServices.get("*");
                return crypto.getCertificates(alias)[0];
            }
        } else {
            String alias = (String) this.trustedServices.get("*");
            return crypto.getCertificates(alias)[0];
        }

    }

    public String getPersisterClassName() {
        return persisterClassName;
    }

    public void setPersisterClassName(String persisterClassName) {
        this.persisterClassName = persisterClassName;
    }

    public Map getPersisterPropertyMap() {
        return persisterPropertyMap;
    }

    public void setPersisterPropertyMap(Map persisterPropertyMap) {
        this.persisterPropertyMap = persisterPropertyMap;
    }

    public OMElement getPersisterElement() {
        return persisterElement;
    }

    public boolean isTokenStoreDisabled() {
        return tokenStoreDisabled;
    }

    public void setTokenStoreDisabled(boolean tokenStoreDisabled) {
        this.tokenStoreDisabled = tokenStoreDisabled;
    }

}