com.qut.middleware.saml2.SAML2Test.java Source code

Java tutorial

Introduction

Here is the source code for com.qut.middleware.saml2.SAML2Test.java

Source

/* 
 * Copyright 2006, Queensland University of Technology
 * Licensed under the Apache License, Version 2.0 (the "License"); 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 "AS IS" 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.
 * 
 * Author: Bradley Beddoes
 * Creation Date:  23/10/2006
 * 
 * Purpose: Provides real world functionality tests for critical aspects of the integrated marshaller and unmarshaller package
 */

package com.qut.middleware.saml2;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;

import javax.xml.datatype.XMLGregorianCalendar;

import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
import org.w3._2000._09.xmldsig_.Signature;

import com.qut.middleware.saml2.handler.Marshaller;
import com.qut.middleware.saml2.handler.Unmarshaller;
import com.qut.middleware.saml2.handler.impl.MarshallerImpl;
import com.qut.middleware.saml2.handler.impl.UnmarshallerImpl;
import com.qut.middleware.saml2.schemas.assertion.Assertion;
import com.qut.middleware.saml2.schemas.assertion.AudienceRestriction;
import com.qut.middleware.saml2.schemas.assertion.AuthnContext;
import com.qut.middleware.saml2.schemas.assertion.AuthnStatement;
import com.qut.middleware.saml2.schemas.assertion.Conditions;
import com.qut.middleware.saml2.schemas.assertion.NameIDType;
import com.qut.middleware.saml2.schemas.assertion.Subject;
import com.qut.middleware.saml2.schemas.assertion.SubjectLocality;
import com.qut.middleware.saml2.schemas.protocol.AuthnRequest;
import com.qut.middleware.saml2.schemas.protocol.Response;
import com.qut.middleware.saml2.schemas.protocol.Status;
import com.qut.middleware.saml2.schemas.protocol.StatusCode;
import com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;

@SuppressWarnings(value = { "unqualified-field-access", "nls", "boxing" })
public class SAML2Test {
    private String path;
    private SAML2TestKeyResolver keyResolver;

    public SAML2Test() throws Exception {
        this.path = "tests" + File.separator + "testdata" + File.separator;

        System.setProperty("file.encoding", "UTF-16");

        System.getProperties().list(System.out);

        this.keyResolver = new SAML2TestKeyResolver();
    }

    class SAML2TestKeyResolver implements LocalKeyResolver {
        Certificate cert = null;
        PublicKey pubKey = null;
        PrivateKey privKey = null;
        String keyAlias = null;

        public SAML2TestKeyResolver() throws Exception {
            keyAlias = "myrsakey";
            KeyStore ks = KeyStore.getInstance("PKCS12");
            FileInputStream fis = new FileInputStream(SAML2Test.this.path + "tests.ks");
            char[] passwd = { 't', 'e', 's', 't', 'p', 'a', 's', 's' };
            ks.load(fis, passwd);

            privKey = (PrivateKey) ks.getKey(keyAlias, passwd);
            cert = ks.getCertificate(keyAlias);
            pubKey = cert.getPublicKey();
        }

        public Certificate getLocalCertificate() {
            // TODO Auto-generated method stub
            return null;
        }

        public String getLocalKeyAlias() {
            // TODO Auto-generated method stub
            return null;
        }

        public PrivateKey getLocalPrivateKey() {

            return privKey;
        }

        public PublicKey getLocalPublicKey() {
            return pubKey;
        }
    }

    private AuthnRequest generateAuthnRequest() {
        AudienceRestriction audienceRestriction = new AudienceRestriction();
        Conditions conditions = new Conditions();
        NameIDType nameID = new NameIDType();
        Subject subject = new Subject();
        Signature signature = new Signature();
        AuthnRequest authnRequest = new AuthnRequest();

        /* GMT timezone */
        SimpleTimeZone gmt = new SimpleTimeZone(0, "UTC");

        /* GregorianCalendar with the GMT time zone */
        GregorianCalendar calendar = new GregorianCalendar(gmt);
        XMLGregorianCalendar xmlCalander = new XMLGregorianCalendarImpl(calendar);

        audienceRestriction.getAudiences().add("spep-n1.qut.edu.au");
        audienceRestriction.getAudiences().add("spep-n2.qut.edu.au");
        conditions.getConditionsAndOneTimeUsesAndAudienceRestrictions().add(audienceRestriction);

        nameID.setValue("beddoes@qut.com");
        nameID.setFormat("urn:oasis:names:tc:SAML:2.0:something");

        subject.setNameID(nameID);

        authnRequest.setSignature(signature);
        authnRequest.setSubject(subject);
        authnRequest.setConditions(conditions);

        authnRequest.setForceAuthn(false);
        authnRequest.setAssertionConsumerServiceURL("http://spep-n1.qut.edu.au/sso/aa");
        authnRequest.setAttributeConsumingServiceIndex(0);
        authnRequest.setProviderName("spep-n1-itscandy-you-like-it");
        authnRequest.setID("abe567de6-122wert67");
        authnRequest.setVersion("2.0");
        authnRequest.setIssueInstant(xmlCalander);

        return authnRequest;
    }

    private XMLGregorianCalendar generateXMLCalendar(int offset) {
        SimpleTimeZone gmt;
        GregorianCalendar calendar;
        XMLGregorianCalendar xmlCalendar;

        /* GMT timezone TODO: I am sure this isn't correct need to ensure we set GMT */
        // GMT or UTC ??
        gmt = new SimpleTimeZone(0, "UTC");
        calendar = new GregorianCalendar(gmt);
        calendar.add(Calendar.MILLISECOND, offset);
        xmlCalendar = new XMLGregorianCalendarImpl(calendar);

        return xmlCalendar;
    }

    private Response generateResponse() {
        AuthnStatement authnStatement;
        SubjectLocality subjectLocality;
        AuthnContext authnContext;
        Subject subject;
        NameIDType issuer;
        NameIDType nameID;
        Signature signature;
        Assertion assertion;
        Assertion assertion2;
        Status status;
        StatusCode statusCode;
        Response response;

        /* Generate subject locality */
        subjectLocality = new SubjectLocality();
        subjectLocality.setDNSName("esoe.test.code");

        /*
         * Generate AuthnContext, SAML spec requires previous session to be set if user not directly authenticated
         * during this transaction TODO: This needs to be GMT
         */
        authnContext = new AuthnContext();
        authnContext.setAuthnContextClassRef(AuthenticationContextConstants.previousSession);

        /* Generate successful authentication response for consumption by SPEP */
        authnStatement = new AuthnStatement();
        authnStatement.setAuthnInstant(generateXMLCalendar(0));
        authnStatement.setSessionIndex("1");
        authnStatement.setSessionNotOnOrAfter(generateXMLCalendar(200)); /*
                                                                         * Add our allowed time skew to the current
                                                                         * time
                                                                         */

        authnStatement.setSubjectLocality(subjectLocality);
        authnStatement.setAuthnContext(authnContext);

        /* Generate Issuer to attach to assertion and response */
        issuer = new NameIDType();
        issuer.setValue("esoetestcode");

        /* Generate placeholder <Signature/> block for SAML2lib-j in assertion and response */
        signature = new Signature();

        /* Generate subject to attach to assertion */
        subject = new Subject();
        nameID = new NameIDType();

        nameID.setValue("_12345");
        subject.setNameID(nameID);

        /* Generate the assertions */
        assertion = new Assertion();
        assertion.setVersion(VersionConstants.saml20);
        assertion.setID("_12345-ass");
        assertion.setIssueInstant(generateXMLCalendar(0));

        assertion.setIssuer(issuer);
        assertion.setSignature(signature);
        assertion.setSubject(subject);
        assertion.getAuthnStatementsAndAuthzDecisionStatementsAndAttributeStatements().add(authnStatement);

        assertion2 = new Assertion();
        assertion2.setVersion(VersionConstants.saml20);
        assertion2.setID("_12345-ass2");
        assertion2.setIssueInstant(generateXMLCalendar(0));

        assertion2.setIssuer(issuer);
        assertion2.setSignature(signature);
        assertion2.setSubject(subject);
        assertion2.getAuthnStatementsAndAuthzDecisionStatementsAndAttributeStatements().add(authnStatement);

        /* Generate successful status, only top level code supplied */
        statusCode = new StatusCode();
        statusCode.setValue(StatusCodeConstants.success);
        status = new Status();
        status.setStatusCode(statusCode);

        /* Generate our response */
        response = new Response();
        response.setID("_12345-res");
        response.setInResponseTo("_0987");
        response.setVersion(VersionConstants.saml20);
        response.setIssueInstant(generateXMLCalendar(0));
        response.setDestination("http://esoe.test.code");
        response.setConsent(ConsentIdentifierConstants.prior);

        response.setIssuer(issuer);
        response.setSignature(new Signature());
        response.setStatus(status);
        response.getEncryptedAssertionsAndAssertions().add(assertion);
        response.getEncryptedAssertionsAndAssertions().add(assertion2);

        return response;
    }

    /*
     * Tests to ensure that a generated xml document can be signed, base64 encoded and base 64 decoded without
     * corruption (mimicks SAML browser post sso profile requirements)
     * 
     * If this test is failing and your on windows it will be because of the hebrew - be sure to carefully read http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html
     * its most likely you have only the european version of the JVM installed
     */
    @Test
    public void testSAML2lib1() throws Exception {
        Marshaller<AuthnRequest> marshaller;
        Unmarshaller<AuthnRequest> unmarshaller;
        String[] schemas = new String[] { "saml-schema-protocol-2.0.xsd", "saml-schema-assertion-2.0.xsd" };

        /* Supplied private/public key will be in RSA format */
        marshaller = new MarshallerImpl<AuthnRequest>(AuthnRequest.class.getPackage().getName(), schemas,
                keyResolver);
        unmarshaller = new UnmarshallerImpl<AuthnRequest>(AuthnRequest.class.getPackage().getName(), schemas);

        AuthnRequest authnRequest = generateAuthnRequest();
        String schema = "saml-schema-protocol-2.0.xsd";

        byte[] doc = marshaller.marshallSigned(authnRequest);

        assertNotNull("Supplied XML document should not be null", doc);

        byte[] base64 = Base64.encodeBase64(doc);
        byte[] debase64 = Base64.decodeBase64(base64);

        AuthnRequest authnRequestDecoded = unmarshaller.unMarshallSigned(keyResolver.getLocalPublicKey(), debase64); //$NON-NLS-1$

        assertEquals("Expected Signature ID not supplied", "abe567de6-122wert67", authnRequestDecoded.getID());
    }

    /*
     * Tests to ensure that a generated xml document can successfully have multiple embedded signatures, both as parents
     * and siblings Ensure we don't get any exceptions when this is called
     */
    @Test
    public void testSAML2lib2() throws Exception {
        Marshaller<Response> marshaller;
        Unmarshaller<Response> unmarshaller;

        String[] schemas = new String[] { "saml-schema-protocol-2.0.xsd", "saml-schema-assertion-2.0.xsd" };

        /* Supplied private/public key will be in RSA format */
        marshaller = new MarshallerImpl<Response>(AuthnRequest.class.getPackage().getName(), schemas, keyResolver);
        unmarshaller = new UnmarshallerImpl<Response>(Response.class.getPackage().getName(), schemas);

        Response authnResponse = generateResponse();
        String schema = "saml-schema-protocol-2.0.xsd";

        byte[] doc = marshaller.marshallSigned(authnResponse);

        assertNotNull("Supplied XML document should not be null", doc);

        Response authnResponseDecoded = unmarshaller.unMarshallSigned(keyResolver.getLocalPublicKey(), doc); //$NON-NLS-1$
    }
}