All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.rahas.impl.SAML2TokenIssuer Maven / Gradle / Ivy

The newest version!
/*
 * 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.OMElement;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.context.MessageContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.rahas.*;
import org.apache.rahas.impl.util.*;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.util.XmlSchemaDateFormat;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.signature.XMLSignature;
import org.joda.time.DateTime;
import org.opensaml.Configuration;
import org.opensaml.common.SAMLException;
import org.opensaml.common.SAMLObjectBuilder;
import org.opensaml.saml2.core.*;
import org.opensaml.xml.XMLObjectBuilderFactory;
import org.opensaml.xml.io.*;
import org.opensaml.xml.schema.XSString;
import org.opensaml.xml.schema.impl.XSStringBuilder;
import org.opensaml.xml.signature.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.security.PrivateKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * WS-Trust based SAML2 token issuer. This issuer will generate request security token responses with SAML2
 * assertions.
 */
public class SAML2TokenIssuer implements TokenIssuer {

    private String configParamName;

    private OMElement configElement;

    private String configFile;

    protected List signatureList = new ArrayList();

    private boolean isSymmetricKeyBasedHoK = false;

    private SAMLTokenIssuerConfig tokenIssuerConfiguration;

    private static Log log = LogFactory.getLog(SAML2TokenIssuer.class);

    /**
     * This is the main method which issues SAML2 assertions as security token responses. This method will
     * read issuer configuration and in message context properties (Basically request security token properties)
     * and will create a security token response with SAML2 assertion. The attributes are retrieved from a callback
     * class.
     * @param data A populated RahasData instance
     * @return A SOAP message with security token response (as per ws-trust spec) with a SAML2 assertion.
     * @throws TrustException If an error occurred while creating the response.
     */
    public SOAPEnvelope issue(RahasData data) throws TrustException {
        MessageContext inMsgCtx = data.getInMessageContext();

        this.tokenIssuerConfiguration = CommonUtil.getTokenIssuerConfiguration(this.configElement,
                this.configFile, inMsgCtx.getParameter(this.configParamName));

        if (tokenIssuerConfiguration == null) {

            if (log.isDebugEnabled()) {
                String parameterName;
                if (this.configElement != null) {
                    parameterName = "OMElement - " + this.configElement.toString();
                } else if (this.configFile != null) {
                    parameterName = "File - " + this.configFile;
                } else if (this.configParamName != null) {
                    parameterName = "With message context parameter name - " + this.configParamName;
                } else {
                    parameterName = "No method to build configurations";
                }

                log.debug("Unable to build token configurations, " + parameterName);
            }

            throw new TrustException("configurationIsNull");
        }

        SOAPEnvelope env = TrustUtil.createSOAPEnvelope(inMsgCtx
                .getEnvelope().getNamespace().getNamespaceURI());

        Crypto crypto = tokenIssuerConfiguration.getIssuerCrypto(inMsgCtx
                .getAxisService().getClassLoader());

        // Get the document
        Document doc = ((Element) env).getOwnerDocument();

        // Get the key size and create a new byte array of that size
        int keySize = data.getKeySize();
        keySize = (keySize == -1) ? tokenIssuerConfiguration.getKeySize() : keySize;

        data.setKeySize(keySize);

        // Build the assertion
        Assertion assertion = buildAssertion(doc, crypto, data);

        // Sign the assertion
        Assertion signedAssertion = signAssertion(doc, assertion, crypto);

        return createRequestSecurityTokenResponse(data, signedAssertion, env);

    }

    /**
     * This method prepares the final response. This method will create a request security token response as
     * specified in WS-Trust specification. The equivalent XML would take following format,
     * 
  <wst:RequestSecurityTokenResponse xmlns:wst="...">
     *       <wst:TokenType>...</wst:TokenType>
     *       <wst:RequestedSecurityToken>...</wst:RequestedSecurityToken>
     *       ...
     *       <wsp:AppliesTo xmlns:wsp="...">...</wsp:AppliesTo>
     *       <wst:RequestedAttachedReference>
     *       ...
     *       </wst:RequestedAttachedReference>
     *       <wst:RequestedUnattachedReference>
     *       ...
     *       </wst:RequestedUnattachedReference>
     *       <wst:RequestedProofToken>...</wst:RequestedProofToken>
     *       <wst:Entropy>
     *       <wst:BinarySecret>...</wst:BinarySecret>
     *       </wst:Entropy>
     *       <wst:Lifetime>...</wst:Lifetime>
     *   </wst:RequestSecurityTokenResponse>
* * Thus the RequestedSecurityToken will have SAML2 assertion passed. * @param rahasData The configuration data which comes with RST * @param assertion OpenSAM representation of SAML2 assertion. * @param soapEnvelope SOAP message envelope * @return SOAPEnvelope which includes RequestSecurityTokenResponse * @throws TrustException If an error occurred while creating RequestSecurityTokenResponse. */ protected SOAPEnvelope createRequestSecurityTokenResponse(RahasData rahasData, Assertion assertion, SOAPEnvelope soapEnvelope) throws TrustException { OMElement requestSecurityTokenResponse; int wstVersion = rahasData.getVersion(); if (RahasConstants.VERSION_05_02 == wstVersion) { requestSecurityTokenResponse = TrustUtil.createRequestSecurityTokenResponseElement( wstVersion, soapEnvelope.getBody()); } else { OMElement requestSecurityTokenResponseCollectionElement = TrustUtil .createRequestSecurityTokenResponseCollectionElement( wstVersion, soapEnvelope.getBody()); requestSecurityTokenResponse = TrustUtil.createRequestSecurityTokenResponseElement( wstVersion, requestSecurityTokenResponseCollectionElement); } TrustUtil.createTokenTypeElement(wstVersion, requestSecurityTokenResponse).setText( RahasConstants.TOK_TYPE_SAML_20); if (rahasData.getKeyType().endsWith(RahasConstants.KEY_TYPE_SYMM_KEY)) { TrustUtil.createKeySizeElement(wstVersion, requestSecurityTokenResponse, rahasData.getKeySize()); } if (tokenIssuerConfiguration.isAddRequestedAttachedRef()) { TrustUtil.createRequestedAttachedRef(wstVersion, requestSecurityTokenResponse, "#" + assertion.getID(), RahasConstants.TOK_TYPE_SAML_20); } if (tokenIssuerConfiguration.isAddRequestedUnattachedRef()) { TrustUtil.createRequestedUnattachedRef(wstVersion, requestSecurityTokenResponse, assertion.getID(), RahasConstants.TOK_TYPE_SAML_20); } if (rahasData.getAppliesToAddress() != null) { TrustUtil.createAppliesToElement(requestSecurityTokenResponse, rahasData .getAppliesToAddress(), rahasData.getAddressingNs()); } // Use GMT time in milliseconds DateFormat xmlSchemaDateFormat = new XmlSchemaDateFormat(); // Add the Lifetime element TrustUtil.createLifetimeElement(wstVersion, requestSecurityTokenResponse, xmlSchemaDateFormat .format(rahasData.getAssertionCreatedDate()), xmlSchemaDateFormat.format(rahasData.getAssertionExpiringDate())); // Create the RequestedSecurityToken element and add the SAML token // to it OMElement requestedSecurityTokenElement = TrustUtil .createRequestedSecurityTokenElement(wstVersion, requestSecurityTokenResponse); Element assertionElement = assertion.getDOM(); requestedSecurityTokenElement.addChild((OMNode)assertionElement); // Store the token Token assertionToken = new Token(assertion.getID(), (OMElement) assertionElement, rahasData.getAssertionCreatedDate(), rahasData.getAssertionExpiringDate()); // At this point we definitely have the secret // Otherwise it should fail with an exception earlier assertionToken.setSecret(rahasData.getEphmeralKey()); TrustUtil.getTokenStore(rahasData.getInMessageContext()).add(assertionToken); if (rahasData.getKeyType().endsWith(RahasConstants.KEY_TYPE_SYMM_KEY) && tokenIssuerConfiguration.getKeyComputation() != SAMLTokenIssuerConfig.KeyComputation.KEY_COMP_USE_REQ_ENT) { Document doc = ((Element) soapEnvelope).getOwnerDocument(); // Add the RequestedProofToken TokenIssuerUtil.handleRequestedProofToken(rahasData, wstVersion, tokenIssuerConfiguration, requestSecurityTokenResponse, assertionToken, doc); } return soapEnvelope; } /** * This methods builds the SAML2 assertion. The equivalent XML would look as follows, *
<saml:Assertion
     *      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
     *      xmlns:xs="http://www.w3.org/2001/XMLSchema"
     *      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     *      ID="b07b804c-7c29-ea16-7300-4f3d6f7928ac"
     *      Version="2.0"
     *      IssueInstant="2004-12-05T09:22:05Z">
     *      <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
     *      <ds:Signature
     *        xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
     *      <saml:Subject>
     *        <saml:NameID
     *          Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
     *          3f7b3dcf-1674-4ecd-92c8-1544f346baf8
     *        </saml:NameID>
     *        <saml:SubjectConfirmation
     *          Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
     *          <saml:SubjectConfirmationData
     *            InResponseTo="aaf23196-1773-2113-474a-fe114412ab72"
     *            Recipient="https://sp.example.com/SAML2/SSO/POST"
     *            NotOnOrAfter="2004-12-05T09:27:05Z"/>
     *        </saml:SubjectConfirmation>
     *      </saml:Subject>
     *      <saml:Conditions
     *        NotBefore="2004-12-05T09:17:05Z"
     *        NotOnOrAfter="2004-12-05T09:27:05Z">
     *        <saml:AudienceRestriction>
     *          <saml:Audience>https://sp.example.com/SAML2</saml:Audience>
     *        </saml:AudienceRestriction>
     *      </saml:Conditions>
     *      <saml:AuthnStatement
     *        AuthnInstant="2004-12-05T09:22:00Z"
     *        SessionIndex="b07b804c-7c29-ea16-7300-4f3d6f7928ac">
     *        <saml:AuthnContext>
     *          <saml:AuthnContextClassRef>
     *            urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
     *         </saml:AuthnContextClassRef>
     *        </saml:AuthnContext>
     *      </saml:AuthnStatement>
     *      <saml:AttributeStatement>
     *        <saml:Attribute
     *          xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
     *          x500:Encoding="LDAP"
     *          NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
     *          Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1"
     *          FriendlyName="eduPersonAffiliation">
     *          <saml:AttributeValue
     *            xsi:type="xs:string">member</saml:AttributeValue>
     *          <saml:AttributeValue
     *            xsi:type="xs:string">staff</saml:AttributeValue>
     *        </saml:Attribute>
     *      </saml:AttributeStatement>
     *    </saml:Assertion>
* * Reference - en.wikipedia.org/wiki/SAML_2.0#SAML_2.0_Assertions * @param doc The Document which comprises SAML 2 assertion. * @param crypto Crypto properties. * @param data The RST data and other configuration information. * @return OpenSAML representation of an Assertion. * @throws TrustException If an error occurred while creating the Assertion. */ protected Assertion buildAssertion(Document doc, Crypto crypto, RahasData data) throws TrustException { //Build the assertion Assertion assertion = SAML2Utils.createAssertion(); Issuer issuer = SAML2Utils.createIssuer(this.tokenIssuerConfiguration.getIssuerName()); assertion.setIssuer(issuer); // Validity period DateTime creationDate = new DateTime(); DateTime expirationDate = new DateTime(creationDate.getMillis() + tokenIssuerConfiguration.getTtl()); data.setAssertionCreatedDate(creationDate.toDate()); data.setAssertionExpiringDate(expirationDate.toDate()); // Set the issued time. assertion.setIssueInstant(creationDate); // These variables are used to build the trust assertion Conditions conditions = SAML2Utils.createConditions(creationDate, expirationDate); assertion.setConditions(conditions); // Create the subject Subject subject; if (!data.getKeyType().endsWith(RahasConstants.KEY_TYPE_BEARER)) { subject = createSubjectWithHolderOfKeySubjectConfirmation(doc, crypto, creationDate, expirationDate, data); } else { subject = createSubjectWithBearerSubjectConfirmation(data); } // Set the subject assertion.setSubject(subject); // If a SymmetricKey is used build an attr stmt, if a public key is build an authn stmt. if (isSymmetricKeyBasedHoK) { AttributeStatement attrStmt = createAttributeStatement(data); assertion.getAttributeStatements().add(attrStmt); } else { AuthnStatement authStmt = createAuthenticationStatement(data); assertion.getAuthnStatements().add(authStmt); if (data.getClaimDialect() != null && data.getClaimElem() != null) { assertion.getAttributeStatements().add(createAttributeStatement(data)); } } return assertion; } /** * This method will create a SAML 2 subject based on Holder of Key confirmation method. * The relevant XML would look as follows, *
  <saml2:Subject>
     *       <saml2:NameID>
     *           ...
     *       </saml2:NameID>
     *       <saml2:SubjectConfirmation
     *               Method="urn:oasis:names:tc:SAML:2.0:cm:holder-of-key">
     *           <saml2:SubjectConfirmationData
     *                   xsi:type="saml2:KeyInfoConfirmationDataType">
     *               <ds:KeyInfo>
     *                   <ds:KeyValue>...</ds:KeyValue>
     *               </ds:KeyInfo>
     *           </saml2:SubjectConfirmationData>
     *       </saml2:SubjectConfirmation>
     *   </saml2:Subject>
* * KeyInfo can be created based on public key or symmetric key. That is decided by looking at * the RahasData.getKeyType. TODO make sure this implementation is correct. * Theoretically we should be able to have many subject confirmation methods in a SAML2 subject. * TODO - Do we need to support that ? * @param doc The original XML document which we need to include the assertion. * @param crypto The relevant crypto properties * @param creationTime The time that assertion was created. * @param expirationTime The expiring time * @param data The configuration data relevant request. * @return OpenSAML representation of the SAML2 object. * @throws TrustException If an error occurred while creating the subject. */ protected Subject createSubjectWithHolderOfKeySubjectConfirmation(Document doc, Crypto crypto, DateTime creationTime, DateTime expirationTime, RahasData data) throws TrustException { // Create the subject Subject subject = (Subject)CommonUtil.buildXMLObject(Subject.DEFAULT_ELEMENT_NAME); // Set the subject name identifier if (data.getPrincipal() != null) { setSubjectNamedIdentifierData(subject, data.getPrincipal().getName(), NameID.EMAIL); } // Create KeyInfo KeyInfo keyInfo = createKeyInfo(doc, crypto, data); //Build the Subject Confirmation SubjectConfirmation subjectConfirmation = (SubjectConfirmation)CommonUtil.buildXMLObject(SubjectConfirmation.DEFAULT_ELEMENT_NAME); //Set the subject Confirmation method subjectConfirmation.setMethod("urn:oasis:names:tc:SAML:2.0:cm:holder-of-key"); //Build the subject confirmation data element KeyInfoConfirmationDataType scData = createKeyInfoConfirmationDataType(); //Set the keyInfo element scData.getKeyInfos().add(keyInfo); // Set the validity period scData.setNotBefore(creationTime); scData.setNotOnOrAfter(expirationTime); //Set the subject confirmation data subjectConfirmation.setSubjectConfirmationData(scData); //set the subject confirmation subject.getSubjectConfirmations().add(subjectConfirmation); log.debug("SAML2.0 subject is constructed successfully."); return subject; } private KeyInfoConfirmationDataType createKeyInfoConfirmationDataType() { XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); @SuppressWarnings({"unchecked"}) SAMLObjectBuilder keyInfoSubjectConfirmationDataBuilder = (SAMLObjectBuilder) builderFactory.getBuilder (KeyInfoConfirmationDataType.TYPE_NAME); //Build the subject confirmation data element return keyInfoSubjectConfirmationDataBuilder. buildObject(SubjectConfirmationData.DEFAULT_ELEMENT_NAME, KeyInfoConfirmationDataType.TYPE_NAME); } /** * This method creates a subject element with the bearer subject confirmation method. *
   <saml:Subject>
     *       <saml:NameIdentifier
     *                   NameQualifier="www.example.com"
     *                   Format="urn:oasis:names:tc:SAML:1.1:nameid-
     *           format:X509SubjectName">
     *           uid=joe,ou=people,ou=saml-demo,o=baltimore.com
     *       </saml:NameIdentifier>
     *       <saml:SubjectConfirmation>
     *           <saml:ConfirmationMethod>
     *               urn:oasis:names:tc:SAML:1.0:cm:bearer
     *           </saml:ConfirmationMethod>
     *       </saml:SubjectConfirmation>
     *   </saml:Subject>
* @param data RahasData element * @return SAML 2.0 Subject element with Bearer subject confirmation * @throws org.apache.rahas.TrustException if an error occurred while creating the subject. */ protected Subject createSubjectWithBearerSubjectConfirmation(RahasData data) throws TrustException { // Create the subject Subject subject = (Subject)CommonUtil.buildXMLObject(Subject.DEFAULT_ELEMENT_NAME); //Create NameID and attach it to the subject setSubjectNamedIdentifierData(subject, data.getPrincipal().getName(), NameID.EMAIL); //Build the Subject Confirmation SubjectConfirmation subjectConfirmation = (SubjectConfirmation)CommonUtil.buildXMLObject(SubjectConfirmation.DEFAULT_ELEMENT_NAME); //Set the subject Confirmation method subjectConfirmation.setMethod("urn:oasis:names:tc:SAML:2.0:cm:bearer"); subject.getSubjectConfirmations().add(subjectConfirmation); return subject; } /** * This method signs the given assertion with issuer's private key. * @param document The original RST document. * @param assertion Assertion to be signed. * @param crypto The cryptographic properties. * @return The signed assertion. * @throws TrustException If an error occurred while signing the assertion. */ protected Assertion signAssertion(Document document, Assertion assertion, Crypto crypto) throws TrustException { // Create a SignKeyHolder to hold the crypto objects that are used to sign the assertion SignKeyHolder signKeyHolder = createSignKeyHolder(crypto); // Build the signature object and set the credentials. Signature signature = (Signature) CommonUtil.buildXMLObject(Signature.DEFAULT_ELEMENT_NAME); signature.setSigningCredential(signKeyHolder); signature.setSignatureAlgorithm(signKeyHolder.getSignatureAlgorithm()); signature.setCanonicalizationAlgorithm(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); //Build the KeyInfo element and set the certificate try { KeyInfo keyInfo = (KeyInfo) CommonUtil.buildXMLObject(KeyInfo.DEFAULT_ELEMENT_NAME); X509Data x509Data = (X509Data) CommonUtil.buildXMLObject(X509Data.DEFAULT_ELEMENT_NAME); org.opensaml.xml.signature.X509Certificate cert = (org.opensaml.xml.signature.X509Certificate) CommonUtil.buildXMLObject (org.opensaml.xml.signature.X509Certificate.DEFAULT_ELEMENT_NAME); String value = org.apache.xml.security.utils.Base64.encode(signKeyHolder.getEntityCertificate().getEncoded()); cert.setValue(value); x509Data.getX509Certificates().add(cert); keyInfo.getX509Datas().add(x509Data); signature.setKeyInfo(keyInfo); assertion.setSignature(signature); signatureList.add(signature); //Marshall and Sign MarshallerFactory marshallerFactory = org.opensaml.xml.Configuration.getMarshallerFactory(); Marshaller marshaller = marshallerFactory.getMarshaller(assertion); marshaller.marshall(assertion, document); Signer.signObjects(signatureList); } catch (CertificateEncodingException e) { throw new TrustException("Error in setting the signature", e); } catch (SignatureException e) { throw new TrustException("errorSigningAssertion", e); } catch (MarshallingException e) { throw new TrustException("errorMarshallingAssertion", e); } log.debug("SAML2.0 assertion is marshalled and signed.."); return assertion; } /** * This method is used to create SignKeyHolder instances that contains the credentials required for signing the * assertion * @param crypto The crypto properties associated with the issuer. * @return SignKeyHolder object. * @throws TrustException If an error occurred while creating SignKeyHolder object. */ private SignKeyHolder createSignKeyHolder(Crypto crypto) throws TrustException { SignKeyHolder signKeyHolder = new SignKeyHolder(); try { X509Certificate[] issuerCerts = CommonUtil.getCertificatesByAlias(crypto, this.tokenIssuerConfiguration.getIssuerKeyAlias()); String sigAlgo = XMLSignature.ALGO_ID_SIGNATURE_RSA; String pubKeyAlgo = issuerCerts[0].getPublicKey().getAlgorithm(); if (pubKeyAlgo.equalsIgnoreCase("DSA")) { sigAlgo = XMLSignature.ALGO_ID_SIGNATURE_DSA; } java.security.Key issuerPK = crypto.getPrivateKey( this.tokenIssuerConfiguration.getIssuerKeyAlias(), this.tokenIssuerConfiguration.getIssuerKeyPassword()); signKeyHolder.setIssuerCerts(issuerCerts); signKeyHolder.setIssuerPK((PrivateKey) issuerPK); signKeyHolder.setSignatureAlgorithm(sigAlgo); } catch (Exception e) { throw new TrustException("Error creating issuer signature"); } log.debug("SignKeyHolder object is created with the credentials.."); return signKeyHolder; } /** * This method creates an AttributeStatement. The relevant XML would look like as follows, *
  <saml:AttributeStatement>
     *    <saml:Attribute
     *      xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
     *      x500:Encoding="LDAP"
     *      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
     *      Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1"
     *      FriendlyName="eduPersonAffiliation">
     *      <saml:AttributeValue
     *        xsi:type="xs:string">member</saml:AttributeValue>
     *      <saml:AttributeValue
     *        xsi:type="xs:string">staff</saml:AttributeValue>
     *    </saml:Attribute>
     *  </saml:AttributeStatement>
* Reference - http://en.wikipedia.org/wiki/SAML_2.0#SAML_2.0_Assertions * @param data The RahasData which carry information about RST. * @return An AttributeStatement with filled attributes retrieved by calling callback class. * @throws TrustException If an error occurred while creating the AttributeStatement. */ protected AttributeStatement createAttributeStatement(RahasData data) throws TrustException { AttributeStatement attributeStatement = (AttributeStatement) CommonUtil.buildXMLObject(AttributeStatement.DEFAULT_ELEMENT_NAME); Attribute[] attributes; SAMLCallbackHandler handler = CommonUtil.getSAMLCallbackHandler(this.tokenIssuerConfiguration, data); SAMLAttributeCallback cb = new SAMLAttributeCallback(data); if (handler != null) { try { handler.handle(cb); } catch (SAMLException e) { throw new TrustException( "errorCallingSAMLCallback", e); } attributes = cb.getSAML2Attributes(); } else { //else add the attribute with a default value log.debug("No callback registered to get attributes ... Using default attributes"); // TODO do we need to remove this ? Attribute attribute = (Attribute) CommonUtil.buildXMLObject(Attribute.DEFAULT_ELEMENT_NAME); attribute.setName("Name"); attribute.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"); XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); XSStringBuilder attributeValueBuilder = (XSStringBuilder) builderFactory .getBuilder(XSString.TYPE_NAME); XSString stringValue = attributeValueBuilder.buildObject( AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME); stringValue.setValue("Colombo/Rahas"); attribute.getAttributeValues().add(stringValue); attributes = new Attribute[1]; attributes[0] = attribute; } //add attributes to the attribute statement attributeStatement.getAttributes().addAll(Arrays.asList(attributes)); log.debug("SAML2.0 attribute statement is constructed successfully."); return attributeStatement; } /** * This method creates an authentication statement. The equivalent XML would look as follows, *
  <saml:AuthnStatement
     *    AuthnInstant="2004-12-05T09:22:00Z"
     *    SessionIndex="b07b804c-7c29-ea16-7300-4f3d6f7928ac">
     *    <saml:AuthnContext>
     *      <saml:AuthnContextClassRef>
     *        urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
     *     </saml:AuthnContextClassRef>
     *    </saml:AuthnContext>
     *  </saml:AuthnStatement>
* @param data The RahasData which carry information about RST. * @return OpenSAML representation of an AuthnStatement class. * @throws TrustException If an error occurred while creating the authentication statement. */ protected AuthnStatement createAuthenticationStatement(RahasData data) throws TrustException { MessageContext inMsgCtx = data.getInMessageContext(); //build the auth stmt AuthnStatement authenticationStatement = (AuthnStatement)CommonUtil.buildXMLObject(AuthnStatement.DEFAULT_ELEMENT_NAME); // set the authn instance // TODO do we need to use the same time as specified in the conditions ? authenticationStatement.setAuthnInstant(new DateTime()); // Create authentication context AuthnContext authContext = (AuthnContext)CommonUtil.buildXMLObject(AuthnContext.DEFAULT_ELEMENT_NAME); // Create authentication context class reference AuthnContextClassRef authCtxClassRef = (AuthnContextClassRef)CommonUtil.buildXMLObject(AuthnContextClassRef.DEFAULT_ELEMENT_NAME); //if username/password based authn if (inMsgCtx.getProperty(RahasConstants.USERNAME) != null) { authCtxClassRef.setAuthnContextClassRef(AuthnContext.PASSWORD_AUTHN_CTX); } else if (inMsgCtx.getProperty(RahasConstants.X509_CERT) != null) { //if X.509 cert based authn authCtxClassRef.setAuthnContextClassRef(AuthnContext.X509_AUTHN_CTX); } authContext.setAuthnContextClassRef(authCtxClassRef); authenticationStatement.setAuthnContext(authContext); log.debug("SAML2.0 authentication statement is constructed successfully."); return authenticationStatement; } /** * This method will set the subject principal details to the given subject. * @param subject The subject. * @param subjectNameId Subject name id, to identify the principal * @param format Format of the subjectNameId, i.e. email, x509subject etc ... * @throws TrustException If an error occurred while building NameID. */ protected static void setSubjectNamedIdentifierData(Subject subject, String subjectNameId, String format) throws TrustException { //Create NameID and attach it to the subject NameID nameID = SAML2Utils.createNamedIdentifier(subjectNameId, format); subject.setNameID(nameID); } /** * This method creates the KeyInfo relevant for the assertion. The KeyInfo could be created in 2 ways. * 1. Using symmetric key - KeyInfo is created using a symmetric key * 2. Using a public key - KeyInfo created using a public key * The methodology is decided by looking at RahasData.getKeyType() method. * @param doc The document which we are processing. * @param crypto Includes crypto properties relevant to issuer. * @param data Includes metadata about the RST. * @return OpenSAML representation of KeyInfo. * @throws TrustException If an error occurred while creating the KeyInfo object. */ protected KeyInfo createKeyInfo(Document doc, Crypto crypto, RahasData data) throws TrustException { KeyInfo keyInfo; // If it is a Symmetric Key if (data.getKeyType().endsWith(RahasConstants.KEY_TYPE_SYMM_KEY)) { isSymmetricKeyBasedHoK = true; X509Certificate serviceCert = null; try { // Get AppliesTo to figure out which service to issue the token // for serviceCert = this.tokenIssuerConfiguration.getServiceCert(crypto, data.getAppliesToAddress()); keyInfo = CommonUtil.getSymmetricKeyBasedKeyInfo(doc, data, serviceCert, data.getKeySize(), crypto, tokenIssuerConfiguration.getKeyComputation()); } catch (Exception e) { if (serviceCert != null) { throw new TrustException( "errorInBuildingTheEncryptedKeyForPrincipal", new String[]{serviceCert.getSubjectDN().getName()}, e); } else { throw new TrustException( "errorInBuildingTheEncryptedKeyForPrincipal", new String[]{"UnknownSubjectDN"}, e); } } } else if (data.getKeyType().endsWith(RahasConstants.KEY_TYPE_PUBLIC_KEY)) { // If it is a public Key try { // Create the ds:KeyValue element with the ds:X509Data X509Certificate clientCert = data.getClientCert(); if (clientCert == null) { // TODO are we always looking up by alias ? Dont we need to lookup by any other attribute ? clientCert = CommonUtil.getCertificateByAlias(crypto, data.getPrincipal().getName()); } keyInfo = CommonUtil.getCertificateBasedKeyInfo(clientCert); } catch (Exception e) { throw new TrustException("samlAssertionCreationError", e); } } else { log.error("Unidentified key type " + data.getKeyType()); throw new TrustException( "unidentifiedKeyType", new String[]{data.getKeyType()}); } return keyInfo; } public String getResponseAction(RahasData data) throws TrustException { return null; } public void setConfigurationFile(String configFile) { this.configFile = configFile; } public void setConfigurationElement(OMElement configElement) { this.configElement = configElement; } public void setConfigurationParamName(String configParamName) { this.configParamName = configParamName; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy