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
Important
Please, check the javadoc for more informations about these classes.
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())); }
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; }
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); }