Package org.picketlink.test.identity.federation.bindings.authenticators

Source Code of org.picketlink.test.identity.federation.bindings.authenticators.IDPWebBrowserSSOTestCase

/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.picketlink.test.identity.federation.bindings.authenticators;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;

import org.junit.Before;
import org.junit.Test;
import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request;
import org.picketlink.identity.federation.api.saml.v2.response.SAML2Response;
import org.picketlink.identity.federation.bindings.tomcat.idp.IDPWebBrowserSSOValve;
import org.picketlink.identity.federation.core.config.IDPType;
import org.picketlink.identity.federation.core.exceptions.ConfigurationException;
import org.picketlink.identity.federation.core.exceptions.ParsingException;
import org.picketlink.identity.federation.core.exceptions.ProcessingException;
import org.picketlink.identity.federation.core.saml.v2.common.IDGenerator;
import org.picketlink.identity.federation.core.saml.v2.constants.JBossSAMLURIConstants;
import org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil;
import org.picketlink.identity.federation.core.util.TransformerUtil;
import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType.ASTChoiceType;
import org.picketlink.identity.federation.saml.v2.assertion.AudienceRestrictionType;
import org.picketlink.identity.federation.saml.v2.assertion.ConditionAbstractType;
import org.picketlink.identity.federation.saml.v2.assertion.ConditionsType;
import org.picketlink.identity.federation.saml.v2.assertion.StatementAbstractType;
import org.picketlink.identity.federation.saml.v2.protocol.AuthnRequestType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
import org.picketlink.identity.federation.web.constants.GeneralConstants;
import org.picketlink.identity.federation.web.core.IdentityParticipantStack;
import org.picketlink.identity.federation.web.util.PostBindingUtil;
import org.picketlink.identity.federation.web.util.RedirectBindingSignatureUtil;
import org.picketlink.identity.federation.web.util.RedirectBindingUtil;
import org.picketlink.test.identity.federation.bindings.authenticators.idp.TestIdentityParticipantStack;
import org.picketlink.test.identity.federation.bindings.mock.MockCatalinaRequest;
import org.picketlink.test.identity.federation.bindings.mock.MockCatalinaResponse;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
* <p>
* Test class for the IDP authenticator {@link IDPWebBrowserSSOValve}.
* </p>
* <p>
* This tests simulates a scenario with the following characteristics: <br/>
* <ul>
* <li>Identity Provider is deployed in a host with this address: <code>IDENTITY_PROVIDER_HOST_ADDRESS</code>. The URL is
* <code>IDENTITY_PROVIDER_URL</code></li>
* <li>Service Provider is deployed in a host with this address: <code>SERVICE_PROVIDER_HOST_ADDRESS</code>. The URL is
* <code>SERVICE_PROVIDER_URL</code></li>
* </ul>
* </p>
*
* </p>
*
* @author <a href="mailto:psilva@redhat.com">Pedro Silva</a>
*
*/
public class IDPWebBrowserSSOTestCase {

    private static final String CERTIFICATE_ALIAS = "servercert";

    private static final Logger logger = Logger.getLogger(IDPWebBrowserSSOTestCase.class.getName());

    private static final String IDENTITY_PROVIDER_HOST_ADDRESS = "192.168.1.1";
    private static final String SERVICE_PROVIDER_HOST_ADDRESS = "192.168.1.4";
    private static final String IDENTITY_PROVIDER_URL = "http://" + IDENTITY_PROVIDER_HOST_ADDRESS + ":8080/idp-sig/";
    private static final String SERVICE_PROVIDER_URL = "http://" + SERVICE_PROVIDER_HOST_ADDRESS + ":8080/fake-sp";

    private IDPWebBrowserSSOValve identityProvider;

    @Before
    public void onSetup() {
        TestIdentityParticipantStack.reset();
    }
   
    /**
     * <p>
     * Tests the configuration of a custom {@link IdentityParticipantStack}.
     * </p>
     */
    @Test
    public void testRoleGeneratorConfiguration() {
        logger.info("testRoleGeneratorConfiguration");

        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(SERVICE_PROVIDER_HOST_ADDRESS, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        sendAuthenticationRequest(request, response, SERVICE_PROVIDER_URL, true);

        ResponseType responseType = getResponseTypeAndCheckSignature(response, null);

        assertNotNull(responseType);
        assertEquals(1, responseType.getAssertions().size());
       
        AssertionType assertion = responseType.getAssertions().get(0).getAssertion();
       
        assertEquals(assertion.getIssuer().getValue(), IDENTITY_PROVIDER_URL);
       
        List<String> expectedRoles = new ArrayList<String>();
       
        expectedRoles.add("test-role1");
        expectedRoles.add("test-role2");
        expectedRoles.add("test-role3");
       
        Set<StatementAbstractType> statements = assertion.getStatements();
       
        for (StatementAbstractType statementType : statements) {
            if (statementType instanceof AttributeStatementType) {
                AttributeStatementType attributeType = (AttributeStatementType) statementType;
                List<ASTChoiceType> attributes = attributeType.getAttributes();
               
                for (ASTChoiceType astChoiceType : attributes) {
                    if (astChoiceType.getAttribute().getName().equals("Role")) {
                        expectedRoles.remove(astChoiceType.getAttribute().getAttributeValue().get(0));
                    }
                }
            }
        }
       
        assertTrue(expectedRoles.isEmpty());
       
        // The response should redirect back to the caller SP
        assertTrue("Expected a redirect to the SP.", response.redirectString.contains(SERVICE_PROVIDER_URL));
    }
   
    /**
     * <p>
     * Tests the configuration of a custom {@link IdentityParticipantStack}.
     * </p>
     */
    @Test
    public void testIdentityParticipantStackConfiguration() {
        logger.info("testIdentityParticipantStackConfiguration");

        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(SERVICE_PROVIDER_HOST_ADDRESS, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        sendAuthenticationRequest(request, response, SERVICE_PROVIDER_URL, true);

        IdentityParticipantStack testIdentityParticipantStack = TestIdentityParticipantStack.getDelegate();

        assertEquals("Unexpected total created sessions.", 1, testIdentityParticipantStack.totalSessions());

        ResponseType responseType = getResponseTypeAndCheckSignature(response, null);

        assertNotNull(responseType);
        assertEquals(1, responseType.getAssertions().size());
        assertEquals(responseType.getAssertions().get(0).getAssertion().getIssuer().getValue(), IDENTITY_PROVIDER_URL);

        // The response should redirect back to the caller SP
        assertTrue("Expected a redirect to the SP.", response.redirectString.contains(SERVICE_PROVIDER_URL));

        String currentSessionID = request.getSession().getId();

        // asserts if there is a participant for the current session ID
        assertEquals(1, testIdentityParticipantStack.getParticipants(currentSessionID));

        // asserts if the last participant in the stack is the last caller SP
        assertEquals(SERVICE_PROVIDER_URL, testIdentityParticipantStack.peek(currentSessionID));
    }

    /**
     * <p>
     * Tests the StrictPostBinding configuration.
     * </p>
     *
     * @throws ProcessingException
     * @throws ParsingException
     * @throws ConfigurationException
     */
    @Test
    public void testStrictPostBindingConfiguration() throws ConfigurationException, ParsingException, ProcessingException {
        logger.info("testStrictPostBindingConfiguration");

        ((IDPType) getAuthenticator().getConfiguration().getIdpOrSP()).setStrictPostBinding(true);

        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(SERVICE_PROVIDER_HOST_ADDRESS, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
       
        response.setOutputStream(bos);

        sendAuthenticationRequest(request, response, SERVICE_PROVIDER_URL, true);

        ResponseType responseType = getResponseTypeAndCheckSignature(response, bos);

        assertNotNull(responseType);
        assertEquals(1, responseType.getAssertions().size());
        AssertionType assertion = responseType.getAssertions().get(0).getAssertion();
        assertEquals(assertion.getIssuer().getValue(), IDENTITY_PROVIDER_URL);
       
        ConditionsType conditions = assertion.getConditions();
        assertNotNull(conditions);
        List<ConditionAbstractType> conditionList = conditions.getConditions();
        assertEquals(1, conditionList.size());
        AudienceRestrictionType audience = (AudienceRestrictionType) conditionList.get(0);
        assertEquals(SERVICE_PROVIDER_URL, audience.getAudience().get(0).toString());
    }

    /**
     * <p>
     * Tests if the IDP respond with an ResponseType with a <code>JBossSAMLURIConstants.STATUS_AUTHNFAILED.get()</code> status
     * code. This test sends a request without any signature information. Because the IDP is configured with signatures an error
     * response is expected.
     * </p>
     */
    @Test
    public void testInvalidRequestWithoutSignature() {
        logger.info("testInvalidRequestWithoutSignature");

        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(SERVICE_PROVIDER_HOST_ADDRESS, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        sendAuthenticationRequest(request, response, SERVICE_PROVIDER_URL, false);

        ResponseType responseType = getResponseTypeAndCheckSignature(response, null);

        assertNotNull(responseType);
        assertEquals(JBossSAMLURIConstants.STATUS_AUTHNFAILED.get(), responseType.getStatus().getStatusCode().getValue()
                .toString());

        // The response should redirect back to the caller SP
        assertTrue("Expected a redirect to the SP.", response.redirectString.contains(SERVICE_PROVIDER_URL));
    }

    /**
     * <p>
     * Tests if the IDP respond with an ResponseType with a <code>JBossSAMLURIConstants.STATUS_AUTHNFAILED.get()</code> status
     * code. This test sends a {@link AuthnRequestType} with a invalid issuer. The issuer is not in the IDP ValidatingAlias
     * list.
     * </p>
     */
    @Test
    public void testRequestFromInvalidValidatingAlias() {
        logger.info("testRequestFromInvalidValidatingAlias");
        String notTrustedDomain = "123.123.123.123";
        String notTrustedDomainForIssuer = "145.145.145.145";
        String notTrustedServiceProviderURL = SERVICE_PROVIDER_URL.replace(SERVICE_PROVIDER_HOST_ADDRESS, notTrustedDomain);
        String notTrustedIssuerURL = SERVICE_PROVIDER_URL.replace(SERVICE_PROVIDER_HOST_ADDRESS, notTrustedDomainForIssuer);

        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(notTrustedDomain, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        // We will use different URL for assertionConsumerServiceURL and for issuerURL to ensure that error response
        // will be redirected to assertionConsumerServiceURL
        sendAuthenticationRequest(request, response, notTrustedIssuerURL, notTrustedServiceProviderURL, true);

        ResponseType responseType = getResponseTypeAndCheckSignature(response, null);

        assertNotNull(responseType);
        assertEquals(JBossSAMLURIConstants.STATUS_AUTHNFAILED.get(), responseType.getStatus().getStatusCode().getValue()
                .toString());

        // The response should redirect back to the caller SP
        assertTrue("Expected a redirect to the SP.", response.redirectString.contains(notTrustedServiceProviderURL));
    }

    /**
     * <p>
     * Tests if the IDP respond with an ResponseType with a <code>JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get()</code>
     * status code. This test sends a {@link AuthnRequestType} with a invalid issuer. The issuer is not in the IDP trusted
     * domain list.
     * </p>
     */
    @Test
    public void testRequestFromUntrustedDOmain() {
        logger.info("testRequestFromUntrustedDOmain");
        String notTrustedDomain = "192.168.1.5";
        String notTrustedServiceProviderURL = SERVICE_PROVIDER_URL.replace(SERVICE_PROVIDER_HOST_ADDRESS, notTrustedDomain);

        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(notTrustedDomain, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        sendAuthenticationRequest(request, response, notTrustedServiceProviderURL, true);

        ResponseType responseType = getResponseTypeAndCheckSignature(response, null);

        assertNotNull(responseType);
        assertEquals(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get(), responseType.getStatus().getStatusCode().getValue()
                .toString());

        // The response should redirect back to the caller SP
        assertTrue("Expected a redirect to the SP.", response.redirectString.contains(notTrustedServiceProviderURL));
    }

    /**
     * <p>
     * Tests if the IDP respond with a valid {@link AssertionType} given a valid {@link AuthnRequestType}.
     * </p>
     *
     * @throws Exception
     */
    @Test
    public void testSimpleAuthenticationRequest() throws Exception {
        logger.info("testSimpleAuthenticationRequest");
        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(SERVICE_PROVIDER_HOST_ADDRESS, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        sendAuthenticationRequest(request, response, SERVICE_PROVIDER_URL, true);

        ResponseType responseType = getResponseTypeAndCheckSignature(response, null);

        assertNotNull(responseType);
        assertEquals(1, responseType.getAssertions().size());
        assertEquals(responseType.getAssertions().get(0).getAssertion().getIssuer().getValue(), IDENTITY_PROVIDER_URL);

        // The response should redirect back to the caller SP
        assertTrue("Expected a redirect to the SP.", response.redirectString.contains(SERVICE_PROVIDER_URL));
    }

    /**
     * <p>
     * Tests if the IDP respond with a valid {@link AssertionType} given a valid {@link AuthnRequestType}. This test disables
     * signature support on the IDP and try to get an assertion without signatures.
     * </p>
     *
     * @throws Exception
     */
    @Test
    public void testSimpleAuthenticationRequestWithoutSignature() throws Exception {
        logger.info("testSimpleAuthenticationRequest");

        getAuthenticator().getConfiguration().getIdpOrSP().setSupportsSignature(false);

        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(SERVICE_PROVIDER_HOST_ADDRESS, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        sendAuthenticationRequest(request, response, SERVICE_PROVIDER_URL, false);

        ResponseType responseType = getResponseType(response, null);

        assertNotNull(responseType);
        assertEquals(1, responseType.getAssertions().size());
        assertEquals(responseType.getAssertions().get(0).getAssertion().getIssuer().getValue(), IDENTITY_PROVIDER_URL);

        // The response should redirect back to the caller SP
        assertTrue("Expected a redirect to the SP.", response.redirectString.contains(SERVICE_PROVIDER_URL));
    }

    /**
     * <p>
     * Tests if the the assertion issued by the IDP has the expected time conditions. This test asserts if the
     * PicketLinkSTS.TokenTimeout attribute is being considered when creating the assertion conditions.
     * </p>
     *
     * @throws Exception
     */
    @Test
    public void testAssertionTokenTimeoutAndClockSkew() throws Exception {
        logger.info("testAssertionTokenTimeoutAndClockSkew");
        MockCatalinaRequest request = AuthenticatorTestUtils.createRequest(SERVICE_PROVIDER_HOST_ADDRESS, true);
        MockCatalinaResponse response = new MockCatalinaResponse();

        sendAuthenticationRequest(request, response, SERVICE_PROVIDER_URL, true);

        ResponseType responseType = getResponseTypeAndCheckSignature(response, null);

        assertNotNull(responseType);
        assertEquals(1, responseType.getAssertions().size());

        AssertionType issuedAssertion = responseType.getAssertions().get(0).getAssertion();

        assertEquals(issuedAssertion.getIssuer().getValue(), IDENTITY_PROVIDER_URL);

        // The response should redirect back to the caller SP
        assertTrue("Expected a redirect to the SP.", response.redirectString.contains(SERVICE_PROVIDER_URL));

        ConditionsType conditions = issuedAssertion.getConditions();

        assertEquals("The assertion timeout is invalid.", 3000, conditions.getNotOnOrAfter().toGregorianCalendar()
                .getTimeInMillis()
                - conditions.getNotBefore().toGregorianCalendar().getTimeInMillis());
    }

    /**
     * <p>
     * Extracts the {@link ResponseType} from the http response. This methos allows to extract the {@link ResponseType} from a
     * {@link StringWriter} or direct from the response.redirectString. If using HTTP Redirect Binding you should pass null. to
     * the writer param.
     * </p>
     *
     * @param response
     * @param bos if not null, try to get the {@link ResponseType} from the this writer. Otherwise try to get from
     *        the response querystring.
     * @return
     */
    private ResponseType getResponseType(MockCatalinaResponse response, ByteArrayOutputStream bos) {
        ResponseType responseType = null;

        try {
            SAML2Response samlResponse = new SAML2Response();

            if (bos == null) {
                MockCatalinaRequest requestTmp = new MockCatalinaRequest();

                AuthenticatorTestUtils.populateParametersWithQueryString(response.redirectString, requestTmp);

                responseType = (ResponseType) samlResponse.getSAML2ObjectFromStream(RedirectBindingUtil
                        .base64DeflateDecode(requestTmp.getParameter(GeneralConstants.SAML_RESPONSE_KEY)));
            } else {
                Document postBindingForm = DocumentUtil.getDocument(bos.toString());

                logger.info("POST Binding response from the IDP:");
                logger.info(prettyPrintDocument(postBindingForm).toString());

                NodeList nodes = postBindingForm.getElementsByTagName("INPUT");
                Element inputElement = (Element) nodes.item(0);
                String idpResponse = inputElement.getAttributeNode("VALUE").getValue();

                responseType = (ResponseType) samlResponse.getSAML2ObjectFromStream(PostBindingUtil
                        .base64DecodeAsStream(idpResponse));
            }

            Document convert = samlResponse.convert(responseType);

            logger.info("ResponseType returned from the IDP:");
            System.out.println(prettyPrintDocument(convert));
        } catch (Exception e) {
            e.printStackTrace();
            fail("Error getting the ResponseType.");
        }

        return responseType;
    }

    private ResponseType getResponseTypeAndCheckSignature(MockCatalinaResponse response, ByteArrayOutputStream bos) {
        ResponseType responseType = getResponseType(response, bos);

        try {
            if (bos == null) {
                assertTrue(RedirectBindingSignatureUtil.validateSignature(response.redirectString, getAuthenticator()
                        .getKeyManager().getPublicKey(CERTIFICATE_ALIAS), RedirectBindingSignatureUtil
                        .getSignatureValueFromSignedURL(response.redirectString)));
            } else {
                assertTrue("No Signature element found.", responseType.getSignature() != null);
            }
        } catch (Exception e) {
            e.printStackTrace();
            fail("Error checking response signature.");
        }

        return responseType;
    }

    // We use same URL for assertionConsumerServiceURL and for issuer in this case
    private void sendAuthenticationRequest(MockCatalinaRequest request, MockCatalinaResponse response, String issuer,
                                           boolean signToken) {
       sendAuthenticationRequest(request, response, issuer, issuer, signToken);
    }

    /**
     * <p>
     * Sends an authentication request ({@link AuthnRequestType}) to the IDP.
     * </p>
     *
     * @param request
     * @param response
     * @param issuer
     * @param assertionConsumerURL
     * @param signToken
     */
    private void sendAuthenticationRequest(MockCatalinaRequest request, MockCatalinaResponse response, String issuer,
            String assertionConsumerURL, boolean signToken) {
        try {
            SAML2Request samlRequest = new SAML2Request();

            AuthnRequestType authnRequestType = samlRequest.createAuthnRequestType(IDGenerator.create("ID_"),
                  assertionConsumerURL, getAuthenticator().getConfiguration().getIdpOrSP().getIdentityURL(), issuer);

            Document authnRequestDocument = samlRequest.convert(authnRequestType);

            logger.info("AuthRequestType:" + prettyPrintDocument(authnRequestDocument).toString());

            if (signToken) {
                request.setQueryString(RedirectBindingSignatureUtil.getSAMLRequestURLWithSignature(authnRequestType, null,
                        getAuthenticator().getKeyManager().getSigningKey()));
                AuthenticatorTestUtils.populateParametersWithQueryString(request.getQueryString(), request);
            } else {
                String deflateBase64URLEncode = RedirectBindingUtil.deflateBase64Encode(DocumentUtil.asString(
                        authnRequestDocument).getBytes("UTF-8"));
                request.setQueryString("SAMLRequest=" + deflateBase64URLEncode);
                request.setParameter("SAMLRequest", deflateBase64URLEncode);
            }

            getAuthenticator().invoke(request, response);
        } catch (Exception e) {
            e.printStackTrace();
            fail("Error sending AuthnRequestType.");
        }
    }

    /**
     * <p>
     * Creates and returns a instance of {@link IDPWebBrowserSSOValve}.
     * </p>
     *
     * @return
     */
    private IDPWebBrowserSSOValve getAuthenticator() {
        if (this.identityProvider == null) {
            this.identityProvider = AuthenticatorTestUtils.createIdentityProvider("saml2/redirect/idp-sig");
        }

        return this.identityProvider;
    }

    private StringWriter prettyPrintDocument(Document authnRequestDocument) {
        StringWriter writer = new StringWriter();

        try {
            Transformer transformer = TransformerUtil.getTransformer();

            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

            transformer.transform(DocumentUtil.getXMLSource(authnRequestDocument), new StreamResult(writer));
        } catch (Exception e) {
            e.printStackTrace();
            fail("Error printing the document.");
        } finally {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return writer;
    }

}
TOP

Related Classes of org.picketlink.test.identity.federation.bindings.authenticators.IDPWebBrowserSSOTestCase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.