blob: 14deef7f029d48290be2816662f074d189f0046d [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../.resources/report.css" type="text/css"/><link rel="shortcut icon" href="../.resources/report.gif" type="image/gif"/><title>SAML2TokenIssuer.java</title><link rel="stylesheet" href="../.resources/prettify.css" type="text/css"/><script type="text/javascript" src="../.resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../.sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Coverage Report</a> &gt; <a href="index.source.html" class="el_package">org.apache.rahas.impl</a> &gt; <span class="el_source">SAML2TokenIssuer.java</span></div><h1>SAML2TokenIssuer.java</h1><pre class="source lang-java linenums">/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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.
*/
<span class="fc" id="L56">public class SAML2TokenIssuer implements TokenIssuer {</span>
private String configParamName;
private OMElement configElement;
private String configFile;
<span class="fc" id="L64"> protected List&lt;Signature&gt; signatureList = new ArrayList&lt;Signature&gt;();</span>
<span class="fc" id="L66"> private boolean isSymmetricKeyBasedHoK = false;</span>
private SAMLTokenIssuerConfig tokenIssuerConfiguration;
<span class="fc" id="L70"> private static Log log = LogFactory.getLog(SAML2TokenIssuer.class);</span>
/**
* 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 &lt;code&gt;RahasData&lt;/code&gt; 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 {
<span class="fc" id="L82"> MessageContext inMsgCtx = data.getInMessageContext();</span>
<span class="fc" id="L84"> this.tokenIssuerConfiguration = CommonUtil.getTokenIssuerConfiguration(this.configElement,</span>
this.configFile, inMsgCtx.getParameter(this.configParamName));
<span class="pc bpc" id="L87" title="1 of 2 branches missed."> if (tokenIssuerConfiguration == null) {</span>
<span class="nc bnc" id="L89" title="All 2 branches missed."> if (log.isDebugEnabled()) {</span>
String parameterName;
<span class="nc bnc" id="L91" title="All 2 branches missed."> if (this.configElement != null) {</span>
<span class="nc" id="L92"> parameterName = &quot;OMElement - &quot; + this.configElement.toString();</span>
<span class="nc bnc" id="L93" title="All 2 branches missed."> } else if (this.configFile != null) {</span>
<span class="nc" id="L94"> parameterName = &quot;File - &quot; + this.configFile;</span>
<span class="nc bnc" id="L95" title="All 2 branches missed."> } else if (this.configParamName != null) {</span>
<span class="nc" id="L96"> parameterName = &quot;With message context parameter name - &quot; + this.configParamName;</span>
} else {
<span class="nc" id="L98"> parameterName = &quot;No method to build configurations&quot;;</span>
}
<span class="nc" id="L101"> log.debug(&quot;Unable to build token configurations, &quot; + parameterName);</span>
}
<span class="nc" id="L104"> throw new TrustException(&quot;configurationIsNull&quot;);</span>
}
<span class="fc" id="L107"> SOAPEnvelope env = TrustUtil.createSOAPEnvelope(inMsgCtx</span>
.getEnvelope().getNamespace().getNamespaceURI());
<span class="fc" id="L110"> Crypto crypto = tokenIssuerConfiguration.getIssuerCrypto(inMsgCtx</span>
.getAxisService().getClassLoader());
// Get the document
<span class="fc" id="L114"> Document doc = ((Element) env).getOwnerDocument();</span>
// Get the key size and create a new byte array of that size
<span class="fc" id="L117"> int keySize = data.getKeySize();</span>
<span class="pc bpc" id="L118" title="1 of 2 branches missed."> keySize = (keySize == -1) ? tokenIssuerConfiguration.getKeySize() : keySize;</span>
<span class="fc" id="L120"> data.setKeySize(keySize);</span>
// Build the assertion
<span class="fc" id="L123"> Assertion assertion = buildAssertion(doc, crypto, data);</span>
// Sign the assertion
<span class="fc" id="L126"> Assertion signedAssertion = signAssertion(doc, assertion, crypto);</span>
<span class="fc" id="L128"> return createRequestSecurityTokenResponse(data, signedAssertion, env);</span>
}
/**
* 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,
* &lt;pre&gt; &amp;lt;wst:RequestSecurityTokenResponse xmlns:wst=&quot;...&quot;&amp;gt;
* &amp;lt;wst:TokenType&amp;gt;...&amp;lt;/wst:TokenType&amp;gt;
* &amp;lt;wst:RequestedSecurityToken&amp;gt;...&amp;lt;/wst:RequestedSecurityToken&amp;gt;
* ...
* &amp;lt;wsp:AppliesTo xmlns:wsp=&quot;...&quot;&amp;gt;...&amp;lt;/wsp:AppliesTo&amp;gt;
* &amp;lt;wst:RequestedAttachedReference&amp;gt;
* ...
* &amp;lt;/wst:RequestedAttachedReference&amp;gt;
* &amp;lt;wst:RequestedUnattachedReference&amp;gt;
* ...
* &amp;lt;/wst:RequestedUnattachedReference&amp;gt;
* &amp;lt;wst:RequestedProofToken&amp;gt;...&amp;lt;/wst:RequestedProofToken&amp;gt;
* &amp;lt;wst:Entropy&amp;gt;
* &amp;lt;wst:BinarySecret&amp;gt;...&amp;lt;/wst:BinarySecret&amp;gt;
* &amp;lt;/wst:Entropy&amp;gt;
* &amp;lt;wst:Lifetime&amp;gt;...&amp;lt;/wst:Lifetime&amp;gt;
* &amp;lt;/wst:RequestSecurityTokenResponse&amp;gt;&lt;/pre&gt;
*
* 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;
<span class="fc" id="L165"> int wstVersion = rahasData.getVersion();</span>
<span class="pc bpc" id="L166" title="1 of 2 branches missed."> if (RahasConstants.VERSION_05_02 == wstVersion) {</span>
<span class="fc" id="L167"> requestSecurityTokenResponse = TrustUtil.createRequestSecurityTokenResponseElement(</span>
wstVersion, soapEnvelope.getBody());
} else {
<span class="nc" id="L170"> OMElement requestSecurityTokenResponseCollectionElement = TrustUtil</span>
.createRequestSecurityTokenResponseCollectionElement(
wstVersion, soapEnvelope.getBody());
<span class="nc" id="L173"> requestSecurityTokenResponse = TrustUtil.createRequestSecurityTokenResponseElement(</span>
wstVersion, requestSecurityTokenResponseCollectionElement);
}
<span class="fc" id="L177"> TrustUtil.createTokenTypeElement(wstVersion, requestSecurityTokenResponse).setText(</span>
RahasConstants.TOK_TYPE_SAML_20);
<span class="fc bfc" id="L180" title="All 2 branches covered."> if (rahasData.getKeyType().endsWith(RahasConstants.KEY_TYPE_SYMM_KEY)) {</span>
<span class="fc" id="L181"> TrustUtil.createKeySizeElement(wstVersion, requestSecurityTokenResponse, rahasData.getKeySize());</span>
}
<span class="pc bpc" id="L184" title="1 of 2 branches missed."> if (tokenIssuerConfiguration.isAddRequestedAttachedRef()) {</span>
<span class="fc" id="L185"> TrustUtil.createRequestedAttachedRef(wstVersion, requestSecurityTokenResponse, &quot;#&quot;</span>
+ assertion.getID(), RahasConstants.TOK_TYPE_SAML_20);
}
<span class="pc bpc" id="L189" title="1 of 2 branches missed."> if (tokenIssuerConfiguration.isAddRequestedUnattachedRef()) {</span>
<span class="fc" id="L190"> TrustUtil.createRequestedUnattachedRef(wstVersion, requestSecurityTokenResponse,</span>
assertion.getID(), RahasConstants.TOK_TYPE_SAML_20);
}
<span class="fc bfc" id="L194" title="All 2 branches covered."> if (rahasData.getAppliesToAddress() != null) {</span>
<span class="fc" id="L195"> TrustUtil.createAppliesToElement(requestSecurityTokenResponse, rahasData</span>
.getAppliesToAddress(), rahasData.getAddressingNs());
}
// Use GMT time in milliseconds
<span class="fc" id="L200"> DateFormat xmlSchemaDateFormat = new XmlSchemaDateFormat();</span>
// Add the Lifetime element
<span class="fc" id="L203"> TrustUtil.createLifetimeElement(wstVersion, requestSecurityTokenResponse, xmlSchemaDateFormat</span>
.format(rahasData.getAssertionCreatedDate()),
xmlSchemaDateFormat.format(rahasData.getAssertionExpiringDate()));
// Create the RequestedSecurityToken element and add the SAML token
// to it
<span class="fc" id="L209"> OMElement requestedSecurityTokenElement = TrustUtil</span>
.createRequestedSecurityTokenElement(wstVersion, requestSecurityTokenResponse);
<span class="fc" id="L212"> Element assertionElement = assertion.getDOM();</span>
<span class="fc" id="L214"> requestedSecurityTokenElement.addChild((OMNode)assertionElement);</span>
// Store the token
<span class="fc" id="L217"> Token assertionToken = new Token(assertion.getID(),</span>
(OMElement) assertionElement, rahasData.getAssertionCreatedDate(),
rahasData.getAssertionExpiringDate());
// At this point we definitely have the secret
// Otherwise it should fail with an exception earlier
<span class="fc" id="L223"> assertionToken.setSecret(rahasData.getEphmeralKey());</span>
<span class="fc" id="L224"> TrustUtil.getTokenStore(rahasData.getInMessageContext()).add(assertionToken);</span>
<span class="pc bpc" id="L226" title="1 of 4 branches missed."> if (rahasData.getKeyType().endsWith(RahasConstants.KEY_TYPE_SYMM_KEY)</span>
&amp;&amp; tokenIssuerConfiguration.getKeyComputation()
!= SAMLTokenIssuerConfig.KeyComputation.KEY_COMP_USE_REQ_ENT) {
<span class="fc" id="L230"> Document doc = ((Element) soapEnvelope).getOwnerDocument();</span>
// Add the RequestedProofToken
<span class="fc" id="L233"> TokenIssuerUtil.handleRequestedProofToken(rahasData, wstVersion,</span>
tokenIssuerConfiguration,
requestSecurityTokenResponse, assertionToken, doc);
}
<span class="fc" id="L238"> return soapEnvelope;</span>
}
/**
* This methods builds the SAML2 assertion. The equivalent XML would look as follows,
* &lt;pre&gt;&amp;lt;saml:Assertion
* xmlns:saml=&quot;urn:oasis:names:tc:SAML:2.0:assertion&quot;
* xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;
* xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
* ID=&quot;b07b804c-7c29-ea16-7300-4f3d6f7928ac&quot;
* Version=&quot;2.0&quot;
* IssueInstant=&quot;2004-12-05T09:22:05Z&quot;&amp;gt;
* &amp;lt;saml:Issuer&amp;gt;https://idp.example.org/SAML2&amp;lt;/saml:Issuer&amp;gt;
* &amp;lt;ds:Signature
* xmlns:ds=&quot;http://www.w3.org/2000/09/xmldsig#&quot;&amp;gt;...&amp;lt;/ds:Signature&amp;gt;
* &amp;lt;saml:Subject&amp;gt;
* &amp;lt;saml:NameID
* Format=&quot;urn:oasis:names:tc:SAML:2.0:nameid-format:transient&quot;&amp;gt;
* 3f7b3dcf-1674-4ecd-92c8-1544f346baf8
* &amp;lt;/saml:NameID&amp;gt;
* &amp;lt;saml:SubjectConfirmation
* Method=&quot;urn:oasis:names:tc:SAML:2.0:cm:bearer&quot;&amp;gt;
* &amp;lt;saml:SubjectConfirmationData
* InResponseTo=&quot;aaf23196-1773-2113-474a-fe114412ab72&quot;
* Recipient=&quot;https://sp.example.com/SAML2/SSO/POST&quot;
* NotOnOrAfter=&quot;2004-12-05T09:27:05Z&quot;/&amp;gt;
* &amp;lt;/saml:SubjectConfirmation&amp;gt;
* &amp;lt;/saml:Subject&amp;gt;
* &amp;lt;saml:Conditions
* NotBefore=&quot;2004-12-05T09:17:05Z&quot;
* NotOnOrAfter=&quot;2004-12-05T09:27:05Z&quot;&amp;gt;
* &amp;lt;saml:AudienceRestriction&amp;gt;
* &amp;lt;saml:Audience&amp;gt;https://sp.example.com/SAML2&amp;lt;/saml:Audience&amp;gt;
* &amp;lt;/saml:AudienceRestriction&amp;gt;
* &amp;lt;/saml:Conditions&amp;gt;
* &amp;lt;saml:AuthnStatement
* AuthnInstant=&quot;2004-12-05T09:22:00Z&quot;
* SessionIndex=&quot;b07b804c-7c29-ea16-7300-4f3d6f7928ac&quot;&amp;gt;
* &amp;lt;saml:AuthnContext&amp;gt;
* &amp;lt;saml:AuthnContextClassRef&amp;gt;
* urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
* &amp;lt;/saml:AuthnContextClassRef&amp;gt;
* &amp;lt;/saml:AuthnContext&amp;gt;
* &amp;lt;/saml:AuthnStatement&amp;gt;
* &amp;lt;saml:AttributeStatement&amp;gt;
* &amp;lt;saml:Attribute
* xmlns:x500=&quot;urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500&quot;
* x500:Encoding=&quot;LDAP&quot;
* NameFormat=&quot;urn:oasis:names:tc:SAML:2.0:attrname-format:uri&quot;
* Name=&quot;urn:oid:1.3.6.1.4.1.5923.1.1.1.1&quot;
* FriendlyName=&quot;eduPersonAffiliation&quot;&amp;gt;
* &amp;lt;saml:AttributeValue
* xsi:type=&quot;xs:string&quot;&amp;gt;member&amp;lt;/saml:AttributeValue&amp;gt;
* &amp;lt;saml:AttributeValue
* xsi:type=&quot;xs:string&quot;&amp;gt;staff&amp;lt;/saml:AttributeValue&amp;gt;
* &amp;lt;/saml:Attribute&amp;gt;
* &amp;lt;/saml:AttributeStatement&amp;gt;
* &amp;lt;/saml:Assertion&amp;gt;&lt;/pre&gt;
*
* 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
<span class="fc" id="L307"> Assertion assertion = SAML2Utils.createAssertion();</span>
<span class="fc" id="L309"> Issuer issuer = SAML2Utils.createIssuer(this.tokenIssuerConfiguration.getIssuerName());</span>
<span class="fc" id="L310"> assertion.setIssuer(issuer);</span>
// Validity period
<span class="fc" id="L313"> DateTime creationDate = new DateTime();</span>
<span class="fc" id="L314"> DateTime expirationDate = new DateTime(creationDate.getMillis() + tokenIssuerConfiguration.getTtl());</span>
<span class="fc" id="L316"> data.setAssertionCreatedDate(creationDate.toDate());</span>
<span class="fc" id="L317"> data.setAssertionExpiringDate(expirationDate.toDate());</span>
// Set the issued time.
<span class="fc" id="L320"> assertion.setIssueInstant(creationDate);</span>
// These variables are used to build the trust assertion
<span class="fc" id="L323"> Conditions conditions = SAML2Utils.createConditions(creationDate, expirationDate);</span>
<span class="fc" id="L324"> assertion.setConditions(conditions);</span>
// Create the subject
Subject subject;
<span class="fc bfc" id="L329" title="All 2 branches covered."> if (!data.getKeyType().endsWith(RahasConstants.KEY_TYPE_BEARER)) {</span>
<span class="fc" id="L330"> subject = createSubjectWithHolderOfKeySubjectConfirmation(doc, crypto,</span>
creationDate, expirationDate, data);
} else {
<span class="fc" id="L333"> subject = createSubjectWithBearerSubjectConfirmation(data);</span>
}
// Set the subject
<span class="fc" id="L337"> assertion.setSubject(subject);</span>
// If a SymmetricKey is used build an attr stmt, if a public key is build an authn stmt.
<span class="fc bfc" id="L340" title="All 2 branches covered."> if (isSymmetricKeyBasedHoK) {</span>
<span class="fc" id="L341"> AttributeStatement attrStmt = createAttributeStatement(data);</span>
<span class="fc" id="L342"> assertion.getAttributeStatements().add(attrStmt);</span>
<span class="fc" id="L343"> } else {</span>
<span class="fc" id="L344"> AuthnStatement authStmt = createAuthenticationStatement(data);</span>
<span class="fc" id="L345"> assertion.getAuthnStatements().add(authStmt);</span>
<span class="pc bpc" id="L346" title="3 of 4 branches missed."> if (data.getClaimDialect() != null &amp;&amp; data.getClaimElem() != null) {</span>
<span class="nc" id="L347"> assertion.getAttributeStatements().add(createAttributeStatement(data));</span>
}
}
<span class="fc" id="L351"> return assertion;</span>
}
/**
* This method will create a SAML 2 subject based on Holder of Key confirmation method.
* The relevant XML would look as follows,
* &lt;pre&gt; &amp;lt;saml2:Subject&amp;gt;
* &amp;lt;saml2:NameID&amp;gt;
* ...
* &amp;lt;/saml2:NameID&amp;gt;
* &amp;lt;saml2:SubjectConfirmation
* Method=&quot;urn:oasis:names:tc:SAML:2.0:cm:holder-of-key&quot;&amp;gt;
* &amp;lt;saml2:SubjectConfirmationData
* xsi:type=&quot;saml2:KeyInfoConfirmationDataType&quot;&amp;gt;
* &amp;lt;ds:KeyInfo&amp;gt;
* &amp;lt;ds:KeyValue&amp;gt;...&amp;lt;/ds:KeyValue&amp;gt;
* &amp;lt;/ds:KeyInfo&amp;gt;
* &amp;lt;/saml2:SubjectConfirmationData&amp;gt;
* &amp;lt;/saml2:SubjectConfirmation&amp;gt;
* &amp;lt;/saml2:Subject&amp;gt;&lt;/pre&gt;
*
* 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
<span class="fc" id="L391"> Subject subject = (Subject)CommonUtil.buildXMLObject(Subject.DEFAULT_ELEMENT_NAME);</span>
// Set the subject name identifier
<span class="pc bpc" id="L394" title="1 of 2 branches missed."> if (data.getPrincipal() != null) {</span>
<span class="fc" id="L395"> setSubjectNamedIdentifierData(subject, data.getPrincipal().getName(), NameID.EMAIL);</span>
}
// Create KeyInfo
<span class="fc" id="L399"> KeyInfo keyInfo = createKeyInfo(doc, crypto, data);</span>
//Build the Subject Confirmation
<span class="fc" id="L402"> SubjectConfirmation subjectConfirmation</span>
= (SubjectConfirmation)CommonUtil.buildXMLObject(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
//Set the subject Confirmation method
<span class="fc" id="L406"> subjectConfirmation.setMethod(&quot;urn:oasis:names:tc:SAML:2.0:cm:holder-of-key&quot;);</span>
//Build the subject confirmation data element
<span class="fc" id="L409"> KeyInfoConfirmationDataType scData = createKeyInfoConfirmationDataType();</span>
//Set the keyInfo element
<span class="fc" id="L412"> scData.getKeyInfos().add(keyInfo);</span>
// Set the validity period
<span class="fc" id="L415"> scData.setNotBefore(creationTime);</span>
<span class="fc" id="L416"> scData.setNotOnOrAfter(expirationTime);</span>
//Set the subject confirmation data
<span class="fc" id="L419"> subjectConfirmation.setSubjectConfirmationData(scData);</span>
//set the subject confirmation
<span class="fc" id="L422"> subject.getSubjectConfirmations().add(subjectConfirmation);</span>
<span class="fc" id="L424"> log.debug(&quot;SAML2.0 subject is constructed successfully.&quot;);</span>
<span class="fc" id="L425"> return subject;</span>
}
private KeyInfoConfirmationDataType createKeyInfoConfirmationDataType() {
<span class="fc" id="L429"> XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();</span>
<span class="fc" id="L430"> @SuppressWarnings({&quot;unchecked&quot;}) SAMLObjectBuilder&lt;KeyInfoConfirmationDataType&gt; keyInfoSubjectConfirmationDataBuilder =</span>
(SAMLObjectBuilder&lt;KeyInfoConfirmationDataType&gt;) builderFactory.getBuilder
(KeyInfoConfirmationDataType.TYPE_NAME);
//Build the subject confirmation data element
<span class="fc" id="L435"> return keyInfoSubjectConfirmationDataBuilder.</span>
buildObject(SubjectConfirmationData.DEFAULT_ELEMENT_NAME, KeyInfoConfirmationDataType.TYPE_NAME);
}
/**
* This method creates a subject element with the bearer subject confirmation method.
* &lt;pre&gt; &amp;lt;saml:Subject&amp;gt;
* &amp;lt;saml:NameIdentifier
* NameQualifier=&quot;www.example.com&quot;
* Format=&quot;urn:oasis:names:tc:SAML:1.1:nameid-
* format:X509SubjectName&quot;&amp;gt;
* uid=joe,ou=people,ou=saml-demo,o=baltimore.com
* &amp;lt;/saml:NameIdentifier&amp;gt;
* &amp;lt;saml:SubjectConfirmation&amp;gt;
* &amp;lt;saml:ConfirmationMethod&amp;gt;
* urn:oasis:names:tc:SAML:1.0:cm:bearer
* &amp;lt;/saml:ConfirmationMethod&amp;gt;
* &amp;lt;/saml:SubjectConfirmation&amp;gt;
* &amp;lt;/saml:Subject&amp;gt;&lt;/pre&gt;
* @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
<span class="fc" id="L461"> Subject subject = (Subject)CommonUtil.buildXMLObject(Subject.DEFAULT_ELEMENT_NAME);</span>
//Create NameID and attach it to the subject
<span class="fc" id="L464"> setSubjectNamedIdentifierData(subject, data.getPrincipal().getName(), NameID.EMAIL);</span>
//Build the Subject Confirmation
<span class="fc" id="L467"> SubjectConfirmation subjectConfirmation</span>
= (SubjectConfirmation)CommonUtil.buildXMLObject(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
//Set the subject Confirmation method
<span class="fc" id="L471"> subjectConfirmation.setMethod(&quot;urn:oasis:names:tc:SAML:2.0:cm:bearer&quot;);</span>
<span class="fc" id="L473"> subject.getSubjectConfirmations().add(subjectConfirmation);</span>
<span class="fc" id="L474"> return subject;</span>
}
/**
* 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
<span class="fc" id="L489"> SignKeyHolder signKeyHolder = createSignKeyHolder(crypto);</span>
// Build the signature object and set the credentials.
<span class="fc" id="L492"> Signature signature = (Signature) CommonUtil.buildXMLObject(Signature.DEFAULT_ELEMENT_NAME);</span>
<span class="fc" id="L494"> signature.setSigningCredential(signKeyHolder);</span>
<span class="fc" id="L495"> signature.setSignatureAlgorithm(signKeyHolder.getSignatureAlgorithm());</span>
<span class="fc" id="L496"> signature.setCanonicalizationAlgorithm(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);</span>
//Build the KeyInfo element and set the certificate
try {
<span class="fc" id="L500"> KeyInfo keyInfo = (KeyInfo) CommonUtil.buildXMLObject(KeyInfo.DEFAULT_ELEMENT_NAME);</span>
<span class="fc" id="L501"> X509Data x509Data = (X509Data) CommonUtil.buildXMLObject(X509Data.DEFAULT_ELEMENT_NAME);</span>
<span class="fc" id="L502"> org.opensaml.xml.signature.X509Certificate cert</span>
= (org.opensaml.xml.signature.X509Certificate) CommonUtil.buildXMLObject
(org.opensaml.xml.signature.X509Certificate.DEFAULT_ELEMENT_NAME);
<span class="fc" id="L505"> String value</span>
= org.apache.xml.security.utils.Base64.encode(signKeyHolder.getEntityCertificate().getEncoded());
<span class="fc" id="L508"> cert.setValue(value);</span>
<span class="fc" id="L509"> x509Data.getX509Certificates().add(cert);</span>
<span class="fc" id="L510"> keyInfo.getX509Datas().add(x509Data);</span>
<span class="fc" id="L512"> signature.setKeyInfo(keyInfo);</span>
<span class="fc" id="L513"> assertion.setSignature(signature);</span>
<span class="fc" id="L515"> signatureList.add(signature);</span>
//Marshall and Sign
<span class="fc" id="L518"> MarshallerFactory marshallerFactory = org.opensaml.xml.Configuration.getMarshallerFactory();</span>
<span class="fc" id="L519"> Marshaller marshaller = marshallerFactory.getMarshaller(assertion);</span>
<span class="fc" id="L520"> marshaller.marshall(assertion, document);</span>
<span class="fc" id="L522"> Signer.signObjects(signatureList);</span>
<span class="nc" id="L524"> } catch (CertificateEncodingException e) {</span>
<span class="nc" id="L525"> throw new TrustException(&quot;Error in setting the signature&quot;, e);</span>
<span class="nc" id="L526"> } catch (SignatureException e) {</span>
<span class="nc" id="L527"> throw new TrustException(&quot;errorSigningAssertion&quot;, e);</span>
<span class="nc" id="L528"> } catch (MarshallingException e) {</span>
<span class="nc" id="L529"> throw new TrustException(&quot;errorMarshallingAssertion&quot;, e);</span>
<span class="fc" id="L530"> }</span>
<span class="fc" id="L532"> log.debug(&quot;SAML2.0 assertion is marshalled and signed..&quot;);</span>
<span class="fc" id="L534"> return assertion;</span>
}
/**
* 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 {
<span class="fc" id="L546"> SignKeyHolder signKeyHolder = new SignKeyHolder();</span>
try {
<span class="fc" id="L549"> X509Certificate[] issuerCerts = CommonUtil.getCertificatesByAlias(crypto,</span>
this.tokenIssuerConfiguration.getIssuerKeyAlias());
<span class="fc" id="L552"> String sigAlgo = XMLSignature.ALGO_ID_SIGNATURE_RSA;</span>
<span class="fc" id="L553"> String pubKeyAlgo = issuerCerts[0].getPublicKey().getAlgorithm();</span>
<span class="pc bpc" id="L554" title="1 of 2 branches missed."> if (pubKeyAlgo.equalsIgnoreCase(&quot;DSA&quot;)) {</span>
<span class="nc" id="L555"> sigAlgo = XMLSignature.ALGO_ID_SIGNATURE_DSA;</span>
}
<span class="fc" id="L558"> java.security.Key issuerPK = crypto.getPrivateKey(</span>
this.tokenIssuerConfiguration.getIssuerKeyAlias(),
this.tokenIssuerConfiguration.getIssuerKeyPassword());
<span class="fc" id="L562"> signKeyHolder.setIssuerCerts(issuerCerts);</span>
<span class="fc" id="L563"> signKeyHolder.setIssuerPK((PrivateKey) issuerPK);</span>
<span class="fc" id="L564"> signKeyHolder.setSignatureAlgorithm(sigAlgo);</span>
<span class="nc" id="L566"> } catch (Exception e) {</span>
<span class="nc" id="L567"> throw new TrustException(&quot;Error creating issuer signature&quot;);</span>
<span class="fc" id="L568"> }</span>
<span class="fc" id="L570"> log.debug(&quot;SignKeyHolder object is created with the credentials..&quot;);</span>
<span class="fc" id="L572"> return signKeyHolder;</span>
}
/**
* This method creates an AttributeStatement. The relevant XML would look like as follows,
* &lt;pre&gt; &amp;lt;saml:AttributeStatement&amp;gt;
* &amp;lt;saml:Attribute
* xmlns:x500=&quot;urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500&quot;
* x500:Encoding=&quot;LDAP&quot;
* NameFormat=&quot;urn:oasis:names:tc:SAML:2.0:attrname-format:uri&quot;
* Name=&quot;urn:oid:1.3.6.1.4.1.5923.1.1.1.1&quot;
* FriendlyName=&quot;eduPersonAffiliation&quot;&amp;gt;
* &amp;lt;saml:AttributeValue
* xsi:type=&quot;xs:string&quot;&amp;gt;member&amp;lt;/saml:AttributeValue&amp;gt;
* &amp;lt;saml:AttributeValue
* xsi:type=&quot;xs:string&quot;&amp;gt;staff&amp;lt;/saml:AttributeValue&amp;gt;
* &amp;lt;/saml:Attribute&amp;gt;
* &amp;lt;/saml:AttributeStatement&amp;gt;&lt;/pre&gt;
* 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 {
<span class="fc" id="L598"> AttributeStatement attributeStatement</span>
= (AttributeStatement) CommonUtil.buildXMLObject(AttributeStatement.DEFAULT_ELEMENT_NAME);
Attribute[] attributes;
<span class="fc" id="L603"> SAMLCallbackHandler handler = CommonUtil.getSAMLCallbackHandler(this.tokenIssuerConfiguration, data);</span>
<span class="fc" id="L605"> SAMLAttributeCallback cb = new SAMLAttributeCallback(data);</span>
<span class="pc bpc" id="L606" title="1 of 2 branches missed."> if (handler != null) {</span>
try {
<span class="nc" id="L608"> handler.handle(cb);</span>
<span class="nc" id="L609"> } catch (SAMLException e) {</span>
<span class="nc" id="L610"> throw new TrustException(</span>
&quot;errorCallingSAMLCallback&quot;,
e);
<span class="nc" id="L613"> }</span>
<span class="nc" id="L615"> attributes = cb.getSAML2Attributes();</span>
} else { //else add the attribute with a default value
<span class="fc" id="L618"> log.debug(&quot;No callback registered to get attributes ... Using default attributes&quot;);</span>
// TODO do we need to remove this ?
<span class="fc" id="L621"> Attribute attribute = (Attribute) CommonUtil.buildXMLObject(Attribute.DEFAULT_ELEMENT_NAME);</span>
<span class="fc" id="L622"> attribute.setName(&quot;Name&quot;);</span>
<span class="fc" id="L623"> attribute.setNameFormat(&quot;urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified&quot;);</span>
<span class="fc" id="L625"> XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();</span>
<span class="fc" id="L627"> XSStringBuilder attributeValueBuilder = (XSStringBuilder) builderFactory</span>
.getBuilder(XSString.TYPE_NAME);
<span class="fc" id="L630"> XSString stringValue = attributeValueBuilder.buildObject(</span>
AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
<span class="fc" id="L632"> stringValue.setValue(&quot;Colombo/Rahas&quot;);</span>
<span class="fc" id="L633"> attribute.getAttributeValues().add(stringValue);</span>
<span class="fc" id="L634"> attributes = new Attribute[1];</span>
<span class="fc" id="L635"> attributes[0] = attribute;</span>
}
//add attributes to the attribute statement
<span class="fc" id="L638"> attributeStatement.getAttributes().addAll(Arrays.asList(attributes));</span>
<span class="fc" id="L640"> log.debug(&quot;SAML2.0 attribute statement is constructed successfully.&quot;);</span>
<span class="fc" id="L642"> return attributeStatement;</span>
}
/**
* This method creates an authentication statement. The equivalent XML would look as follows,
* &lt;pre&gt; &amp;lt;saml:AuthnStatement
* AuthnInstant=&quot;2004-12-05T09:22:00Z&quot;
* SessionIndex=&quot;b07b804c-7c29-ea16-7300-4f3d6f7928ac&quot;&amp;gt;
* &amp;lt;saml:AuthnContext&amp;gt;
* &amp;lt;saml:AuthnContextClassRef&amp;gt;
* urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
* &amp;lt;/saml:AuthnContextClassRef&amp;gt;
* &amp;lt;/saml:AuthnContext&amp;gt;
* &amp;lt;/saml:AuthnStatement&amp;gt;&lt;/pre&gt;
* @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 {
<span class="fc" id="L662"> MessageContext inMsgCtx = data.getInMessageContext();</span>
//build the auth stmt
<span class="fc" id="L665"> AuthnStatement authenticationStatement</span>
= (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 ?
<span class="fc" id="L670"> authenticationStatement.setAuthnInstant(new DateTime());</span>
// Create authentication context
<span class="fc" id="L673"> AuthnContext authContext = (AuthnContext)CommonUtil.buildXMLObject(AuthnContext.DEFAULT_ELEMENT_NAME);</span>
// Create authentication context class reference
<span class="fc" id="L676"> AuthnContextClassRef authCtxClassRef</span>
= (AuthnContextClassRef)CommonUtil.buildXMLObject(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
//if username/password based authn
<span class="fc bfc" id="L680" title="All 2 branches covered."> if (inMsgCtx.getProperty(RahasConstants.USERNAME) != null) {</span>
<span class="fc" id="L681"> authCtxClassRef.setAuthnContextClassRef(AuthnContext.PASSWORD_AUTHN_CTX);</span>
<span class="pc bpc" id="L682" title="1 of 2 branches missed."> } else if (inMsgCtx.getProperty(RahasConstants.X509_CERT) != null) { //if X.509 cert based authn</span>
<span class="fc" id="L683"> authCtxClassRef.setAuthnContextClassRef(AuthnContext.X509_AUTHN_CTX);</span>
}
<span class="fc" id="L686"> authContext.setAuthnContextClassRef(authCtxClassRef);</span>
<span class="fc" id="L687"> authenticationStatement.setAuthnContext(authContext);</span>
<span class="fc" id="L689"> log.debug(&quot;SAML2.0 authentication statement is constructed successfully.&quot;);</span>
<span class="fc" id="L691"> return authenticationStatement;</span>
}
/**
* 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
<span class="fc" id="L705"> NameID nameID = SAML2Utils.createNamedIdentifier(subjectNameId, format);</span>
<span class="fc" id="L706"> subject.setNameID(nameID);</span>
<span class="fc" id="L707"> }</span>
/**
* 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
<span class="fc bfc" id="L726" title="All 2 branches covered."> if (data.getKeyType().endsWith(RahasConstants.KEY_TYPE_SYMM_KEY)) {</span>
<span class="fc" id="L728"> isSymmetricKeyBasedHoK = true;</span>
<span class="fc" id="L729"> X509Certificate serviceCert = null;</span>
try {
// Get AppliesTo to figure out which service to issue the token
// for
<span class="fc" id="L734"> serviceCert = this.tokenIssuerConfiguration.getServiceCert(crypto, data.getAppliesToAddress());</span>
<span class="fc" id="L736"> keyInfo = CommonUtil.getSymmetricKeyBasedKeyInfo(doc, data, serviceCert, data.getKeySize(), crypto,</span>
tokenIssuerConfiguration.getKeyComputation());
<span class="nc" id="L739"> } catch (Exception e) {</span>
<span class="nc bnc" id="L740" title="All 2 branches missed."> if (serviceCert != null) {</span>
<span class="nc" id="L741"> throw new TrustException(</span>
&quot;errorInBuildingTheEncryptedKeyForPrincipal&quot;,
new String[]{serviceCert.getSubjectDN().getName()},
e);
} else {
<span class="nc" id="L746"> throw new TrustException(</span>
&quot;errorInBuildingTheEncryptedKeyForPrincipal&quot;,
new String[]{&quot;UnknownSubjectDN&quot;},
e);
}
<span class="fc" id="L751"> }</span>
<span class="pc bpc" id="L753" title="1 of 2 branches missed."> } else if (data.getKeyType().endsWith(RahasConstants.KEY_TYPE_PUBLIC_KEY)) { // If it is a public Key</span>
try {
// Create the ds:KeyValue element with the ds:X509Data
<span class="fc" id="L757"> X509Certificate clientCert = data.getClientCert();</span>
<span class="pc bpc" id="L759" title="1 of 2 branches missed."> if (clientCert == null) {</span>
// TODO are we always looking up by alias ? Dont we need to lookup by any other attribute ?
<span class="nc" id="L761"> clientCert = CommonUtil.getCertificateByAlias(crypto, data.getPrincipal().getName());</span>
}
<span class="fc" id="L764"> keyInfo = CommonUtil.getCertificateBasedKeyInfo(clientCert);</span>
<span class="nc" id="L766"> } catch (Exception e) {</span>
<span class="nc" id="L767"> throw new TrustException(&quot;samlAssertionCreationError&quot;, e);</span>
<span class="fc" id="L768"> }</span>
} else {
<span class="nc" id="L770"> log.error(&quot;Unidentified key type &quot; + data.getKeyType());</span>
<span class="nc" id="L771"> throw new TrustException(</span>
&quot;unidentifiedKeyType&quot;,
new String[]{data.getKeyType()});
}
<span class="fc" id="L776"> return keyInfo;</span>
}
public String getResponseAction(RahasData data) throws TrustException {
<span class="fc" id="L781"> return null;</span>
}
public void setConfigurationFile(String configFile) {
<span class="fc" id="L785"> this.configFile = configFile;</span>
<span class="fc" id="L786"> }</span>
public void setConfigurationElement(OMElement configElement) {
<span class="fc" id="L789"> this.configElement = configElement;</span>
<span class="fc" id="L790"> }</span>
public void setConfigurationParamName(String configParamName) {
<span class="fc" id="L793"> this.configParamName = configParamName;</span>
<span class="fc" id="L794"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.eclemma.org/jacoco">JaCoCo</a> 0.7.5.201505241946</span></div></body></html>