Product SiteDocumentation Site

⁠14.9. PicketLink API

⁠14.9.1. Working with SAML Assertions

⁠14.9.1.1. 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

Important

Please, check the javadoc for more informations about these classes.

⁠14.9.1.2. 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()));
    }

⁠14.9.1.3. 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;
    }

⁠14.9.1.4. 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);
    }