Introduction
This page shows you how to use the PicketLink API to programatically work with SAML Assertions.
The examples above demonstrates the following scenarios:
-
How to parse a XML to a PicketLink AssertionType
-
How to sign SAML Assertions
-
How to validate SAML Assertions
The following API classes were used:
-
org.picketlink.identity.federation.saml.v2.assertion.AssertionType
-
org.picketlink.identity.federation.core.saml.v2.util.AssertionUtil
-
org.picketlink.identity.federation.core.parsers.saml.SAMLParser
-
org.picketlink.identity.federation.core.saml.v2.writers.SAMLAssertionWriter
-
org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature
-
org.picketlink.identity.federation.core.impl.KeyStoreKeyManager
Please, check the javadoc for more informations about these classes.
Parsing SAML Assertions
The PicketLink API provides the org.picketlink.identity.federation.saml.v2.assertion.AssertionType class to encapsulate the informations parsed from a SAML Assertion.
Let's suppose we have the following SAML Assertion:
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="ID_75291c31-93f7-4f7f-8422-aacdb07466ee" IssueInstant="2012-05-25T10:40:58.912-03:00" Version="2.0">
<saml:Issuer>http: //192.168.1.1:8080/idp-sig/</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">user</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData InResponseTo="ID_326a389f-6a8a-4712-b71d-77aa9c36795c" NotBefore="2012-05-25T10:40:58.894-03:00" NotOnOrAfter="2012-05-25T10:41:00.912-03:00" Recipient="http://192.168.1.4:8080/fake-sp" />
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2012-05-25T10:40:57.912-03:00" NotOnOrAfter="2012-05-25T10:41:00.912-03:00" />
<saml:AuthnStatement AuthnInstant="2012-05-25T10:40:58.981-03:00">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="Role">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">test-role1</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="Role">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">test-role2</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="Role">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">test-role3</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
The code to parse this XML is:
/**
* <p>
* Parses a SAML Assertion XML representation and convert it to a {@link AssertionType} instance.
* </p>
*
* @throws Exception
*/
@Test
public void testParseAssertion() throws Exception {
// get a InputStream from the source XML file
InputStream samlAssertionInputStream = getSAMLAssertion();
SAMLParser samlParser = new SAMLParser();
Object parsedObject = samlParser.parse(samlAssertionInputStream);
Assert.assertNotNull(parsedObject);
Assert.assertTrue(parsedObject.getClass().equals(AssertionType.class));
// cast the parsed object to the expected type, in this case AssertionType
AssertionType assertionType = (AssertionType) parsedObject;
// checks if the Assertion has expired.
Assert.assertTrue(AssertionUtil.hasExpired(assertionType));
// let's write the parsed assertion to the sysout
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SAMLAssertionWriter writer = new SAMLAssertionWriter(StaxUtil.getXMLStreamWriter(baos));
writer.write(assertionType);
System.out.println(new String(baos.toByteArray()));
}
Signing a SAML Assertion
The PicketLink API provides the org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature to help during signature generation/validation for SAML Assertions.
/**
* <p>
* Signs a SAML Assertion.
* </p>
*
* @throws Exception
*/
@Test
public void testSignAssertion() throws Exception {
InputStream samlAssertionInputStream = getSAMLAssertion();
// convert the InputStream to a DOM Document
Document document = DocumentUtil.getDocument(samlAssertionInputStream);
SAML2Signature samlSignature = new SAML2Signature();
// get the key store manager instance.
KeyStoreKeyManager keyStoreKeyManager = getKeyStoreManager();
samlSignature.signSAMLDocument(document, keyStoreKeyManager.getSigningKeyPair());
// let's print the signed assertion to the sysout
System.out.println(DocumentUtil.asString(document));
}
As you can see, we need to create a instance of org.picketlink.identity.federation.core.impl.KeyStoreKeyManager from where the certificates will be retrieved from. The code bellow shows you how to create it:
/**
* <p>
* Creates a {@link KeyStoreKeyManager} instance.
* </p>
*
* @throws Exception
*/
private KeyStoreKeyManager getKeyStoreManager()
throws TrustKeyConfigurationException, TrustKeyProcessingException {
KeyStoreKeyManager keyStoreKeyManager = new KeyStoreKeyManager();
ArrayList<AuthPropertyType> authProperties = new ArrayList<AuthPropertyType>();
authProperties.add(createAuthProperty(KeyStoreKeyManager.KEYSTORE_URL, Thread.currentThread().getContextClassLoader().getResource("./keystore/jbid_test_keystore.jks").getFile()));
authProperties.add(createAuthProperty(KeyStoreKeyManager.KEYSTORE_PASS, "store123"));
authProperties.add(createAuthProperty(KeyStoreKeyManager.SIGNING_KEY_ALIAS, "servercert"));
authProperties.add(createAuthProperty(KeyStoreKeyManager.SIGNING_KEY_PASS, "test123"));
keyStoreKeyManager.setAuthProperties(authProperties);
return keyStoreKeyManager;
}
public AuthPropertyType createAuthProperty(String key, String value) {
AuthPropertyType authProperty = new AuthPropertyType();
authProperty.setKey(key);
authProperty.setValue(value);
return authProperty;
}
Validating a Signed SAML Assertion
The code to validate signatures is almost the same for signing. You still need a KeyStoreKeyManager instance.
/**
* <p>
* Validates a SAML Assertion.
* </p>
*
* @throws Exception
*/
@Test
public void testValidateSignatureAssertion() throws Exception {
InputStream samlAssertionInputStream = getSAMLSignedAssertion();
KeyStoreKeyManager keyStoreKeyManager = getKeyStoreManager();
Document signedDocument = DocumentUtil.getDocument(samlAssertionInputStream);
boolean isValidSignature = AssertionUtil.isSignatureValid(signedDocument.getDocumentElement(), keyStoreKeyManager.getSigningKeyPair().getPublic());
Assert.assertTrue(isValidSignature);
}