Page tree

The OpenSAML 2 software has reached its End of Life and is no longer supported. This documentation is available for historical purposes only.

Skip to end of metadata
Go to start of metadata

Please note that this is just a way of using OpenSAML API not THE way. This example does not utilise Trust support given by OpenSAML. It is based on unit test code shipped with OpenSAML distribution and help from the OpenSAML community including the Authors.

Please refer to it as sample code rather than recommendation

Following is a sample use of OpenSAML APIs in a SAML SP use case, where trust is already been established outside the context of SAML
and incoming requests are using inline key reference.

Sample configuration identified with "service" below makes use of a IoC framework like Spring to make the OpenSAML implementation available to it's client.
Example setup below uses a proprietary IoC configuration

 <properties>
  <property name="saml2.parser.maxPoolSize" value="?"/>
  <property name="saml2.parser.createBuildersAtPoolLimit" value="true"/>
  <property name="saml2.parser.namespaceAware" value="true"/>
  <property name="saml2.replay.cache.minutes" value="?"/>
  <property name="saml2.clock.skew.seconds" value="?"/>
 </properties>

 <service id="saml2.parser.pool" interface="org.opensaml.xml.parse.ParserPool" type="org.opensaml.xml.parse.BasicParserPool">
  <init-method name="setMaxPoolSize">
            <param name="maxPoolSize" value="[saml2.parser.maxPoolSize]" type="int"/>
        </init-method>
  <init-method name="setCreateBuildersAtPoolLimit">
            <param name="createBuildersAtPoolLimit" value="[saml2.parser.createBuildersAtPoolLimit]" type="boolean"/>
        </init-method>
  <init-method name="setNamespaceAware">
            <param name="namespaceAware" value="[saml2.parser.namespaceAware]" type="boolean"/>
        </init-method>
 </service>

 <service id="saml2.message.decoder" interface="org.opensaml.common.binding.decoding.SAMLMessageDecoder" type="org.opensaml.saml2.binding.decoding.HTTPPostDecoder">
  <constructor>
   <param name="pool" value="saml2.parser.pool" type="service"/>
  </constructor>
 </service>

 <service id="saml2.signature.validator" type="org.opensaml.security.SAMLSignatureProfileValidator"/>

 <service id="opensaml2.bootstrap" type="org.opensaml.DefaultBootstrap" deployModel="init">
  <static-init-method name="bootstrap"/>
 </service>

 <service id="saml_2.0_sp" interface="com.company.sso.security.saml.SAMLProcessorSP" type="com.company.sso.security.saml.opensaml.OpenSAMLProcessorSP_2_0">
  <depends service-ref="opensaml2.bootstrap"/>
  <constructor>
   <param name="decoder" value="saml2.message.decoder" type="service"/>
   <param name="validator" value="saml2.signature.validator" type="service"/>
   <param name="replay.minutes" value="[saml2.replay.cache.minutes]" type="int"/>
   <param name="clock.skew" value="[saml2.clock.skew.seconds]" type="int"/>
  </constructor>
 </service>

// contructor for service saml_2.0_sp above
OpenSAMLProcessorSP_2_0(SAMLMessageDecoder decoder, SAMLSignatureProfileValidator validator, int replayMinutes,int clockSkewSeconds)
  
 // global var
 samlMessageDecoder = decoder;
 // global var
 signatureProfileValidator = validator;
  
 StorageService<String, ReplayCache.ReplayCacheEntry> storageEngine = new MapBasedStorageService<String, ReplayCache.ReplayCacheEntry>();
 ReplayCache replayCache = new ReplayCache(storageEngine, 60 * 1000 * replayMinutes);
 // global var
 rule = new MessageReplayRule(replayCache);
 //global var 
 this.clockSkewSeconds = clockSkewSeconds;
// end contructor

Steps involved in processing a given incoming SAML 2.0 request

// get the decrypter (it's hardcoded to use Inline key resolver
BasicCredential credential = new BasicCredential();
credential.setPrivateKey(@get the private key to be used for this request possibly configured based on where the request is coming from@);
Decrypter decrypter = new Decrypter(null, new StaticKeyInfoCredentialResolver(credential), new InlineEncryptedKeyResolver());

// get the SignatureValidator
BasicCredential credential = new BasicCredential();
credential.setPublicKey(@get the public key to be used for this request possibly configured based on where the request is coming from@);
SignatureValidator signatureValidator = new SignatureValidator(credential);

// get the message context
MessageContext messageContext = new BasicSAMLMessageContext();
messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(new SAML2HttpRequestWrapper(@http request@)));
samlMessageDecoder.decode(messageContext);

// validate message context based on rules
rule.evaluate(messageContext);

// get the SAML Response
Response samlResponse = (Response)messageContext.getInboundMessage();
if (!StatusCode.SUCCESS_URI.equals(samlResponse.getStatus().getStatusCode().getValue())) @something wrong@

// retrieve first assertion
List<Assertion> assertions = samlResponse.getAssertions();
Assertion assertion = assertions.get(0);

// or retrieve first encrypted assertion and decrypt it to get the assertion
List<EncryptedAssertion> encAssertions = samlResponse.getEncryptedAssertions();
EncryptedAssertion encAssertion = encAssertions.get(0);
Assertion assertion = decrypter.decrypt(encAssertion);
Configuration.getMarshallerFactory().getMarshaller(assertion).marshall(assertion);

// get the assertion signature
signature = assertion.getSignature();

// validate and verify signature
signatureProfileValidator.validate(signature);
signatureValidator.validate(signature);

// get subject (code below only processes first Subject confirmation)
Subject subject = assertion.getSubject();
List<SubjectConfirmation> subjectConfirmations = subject.getSubjectConfirmations();
SubjectConfirmation subjectConfirmation = subjectConfirmations.get(0);
SubjectConfirmationData subjectConfirmationData = subjectConfirmation.getSubjectConfirmationData();
@verify the validity of time using clock skew, subjectConfirmationData.getNotBefore() and subjectConfirmationData.getNotOnOrAfter()@
NameID nameId = subject.getNameID();

// get attributes(code below only processes first statement)
List<AttributeStatement> statements = assertion.getAttributeStatements();
AttributeStatement statement = statements.get(0);
List<Attribute> attributes = statement.getAttributes();

// validate conditions
Conditions conditions = assertion.getConditions();
@verify the validity of time using clock skew, conditions.getNotBefore() and conditions.getNotOnOrAfter()@

  • No labels