Package org.jboss.seam.security.externaltest.integration.client

Source Code of org.jboss.seam.security.externaltest.integration.client.IntegrationTest

package org.jboss.seam.security.externaltest.integration.client;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import junit.framework.Assert;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.solder.logging.Logger;
import org.jboss.shrinkwrap.api.Archive;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
@RunAsClient
public class IntegrationTest {
    private static final Logger log = Logger.getLogger(IntegrationTest.class);

    private HttpClient httpClient;

    private HttpUriRequest request;

    private ResponseType responseType;

    private String responseBody;

    private HttpResponse response;

    enum ResponseType {
        SAML_MESSAGE_REDIRECT_BOUND, SAML_MESSAGE_POST_BOUND, APPLICATION_MESSAGE, ERROR
    }

    @Deployment(order = 1, name = "sp")
    public static Archive<?> createSpArchive()
    {
     return ArchiveBuilder.getArchive("sp");
    }
   
    @Deployment(order = 2, name = "idp")
    public static Archive<?> createIdpArchive()
    {
     return ArchiveBuilder.getArchive("idp");
    }
   
    @Deployment(order = 3, name = "rp")
    public static Archive<?> createRpArchive()
    {
     return ArchiveBuilder.getArchive("rp");
    }
   
    @Deployment(order = 4, name = "op")
    public static Archive<?> createOpArchive()
    {
     return ArchiveBuilder.getArchive("op");
    }   

    // Seems broken in ARQ Alpha5
    //@Before
    public void init() {
        httpClient = new DefaultHttpClient();
        httpClient.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false);
    }

    @Test @OperateOnDeployment("sp")
    public void samlTest() {
        init();
        Map<String, String> params = new HashMap<String, String>();
        params.put("command", "loadMetaData");
        sendMessageToApplication("www.sp1.com", "sp", params);
        sendMessageToApplication("www.sp2.com", "sp", params);
        sendMessageToApplication("www.idp.com", "idp", params);

        // Login one user at each service provider application
        samlSignOn("www.sp1.com", "https://www.idp.com", "John Doe");
        samlSignOn("www.sp2.com", "https://www.idp.com", "Jane Doe");

        // Check that the IDP has two sessions (one for each user) and that each
        // SP has one
        checkNrOfSessions("www.idp.com", "idp", 2);
        checkNrOfSessions("www.sp1.com", "sp", 1);
        checkNrOfSessions("www.sp2.com", "sp", 1);

        // Do an IDP-initiated single logout of the user at SP1.
        params.clear();
        params.put("command", "singleLogout");
        sendMessageToApplication("www.idp.com", "idp", params);

        checkApplicationMessage("Single logout succeeded");

        checkNrOfSessions("www.idp.com", "idp", 1);
        checkNrOfSessions("www.sp1.com", "sp", 0);
        checkNrOfSessions("www.sp2.com", "sp", 1);

        // Do an SP-initiated single logout of the user at SP2.
        params.clear();
        params.put("command", "singleLogout");
        sendMessageToApplication("www.sp2.com", "sp", params);

        checkApplicationMessage("Single logout succeeded");

        // All sessions should be terminated by now.
        checkNrOfSessions("www.idp.com", "idp", 0);
        checkNrOfSessions("www.sp1.com", "sp", 0);
        checkNrOfSessions("www.sp2.com", "sp", 0);

        // All dialogues should be terminated by now.
        checkDialogueTermination("www.idp.com", "idp");
        checkDialogueTermination("www.sp1.com", "sp");
        checkDialogueTermination("www.sp2.com", "sp");
    }

    @Test @OperateOnDeployment("sp")
    public void openIdLoginWithOpIdentifierTest() {
        init();
        String opIdentifier = "http://localhost:8080/op/openid/OP/XrdsService";
        String userName = "john_doe";

        Map<String, String> params = new HashMap<String, String>();
        params.put("command", "login");
        params.put("identifier", opIdentifier);
        params.put("fetchEmail", "false");
        sendMessageToApplication("localhost", "rp", params);

        checkApplicationMessage("Please login.");

        params = new HashMap<String, String>();
        params.put("command", "authenticate");
        params.put("userName", userName);
        sendMessageToApplication("localhost", "op", params);

        checkApplicationMessage("Login succeeded (http://localhost:8080/op/users/" + userName + ")");

        // All dialogues should be terminated by now.
        checkDialogueTermination("www.op.com", "op");
        checkDialogueTermination("www.rp.com", "rp");
    }

    @Test @OperateOnDeployment("sp")
    public void openIdLoginWithClaimedIdentifierAndAttributeExchangeTest() {
        init();
        String userName = "jane_doe";
        String claimedId = "http://localhost:8080/op/users/" + userName;

        Map<String, String> params = new HashMap<String, String>();
        params.put("command", "login");
        params.put("identifier", claimedId);
        params.put("fetchEmail", "true");
        sendMessageToApplication("localhost", "rp", params);

        checkApplicationMessage("Please provide the password for " + userName + ".");

        params = new HashMap<String, String>();
        params.put("command", "authenticate");
        params.put("userName", userName);
        sendMessageToApplication("localhost", "op", params);

        checkApplicationMessage("Please provide your email.");

        params = new HashMap<String, String>();
        params.put("command", "setAttribute");
        String email = "jane_doe@op.com";
        params.put("email", email);
        sendMessageToApplication("localhost", "op", params);

        checkApplicationMessage("Login succeeded (" + claimedId + ", email " + email + ")");

        // All dialogues should be terminated by now.
        checkDialogueTermination("www.op.com", "op");
        checkDialogueTermination("www.rp.com", "rp");
    }

    private void checkNrOfSessions(String serverName, String spOrIdp, int expectedNumber) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("command", "getNrOfSessions");
        sendMessageToApplication(serverName, spOrIdp, params);
        checkApplicationMessage(Integer.toString(expectedNumber));
    }

    private void samlSignOn(String spHostName, String idpEntityId, String userName) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("command", "login");
        params.put("idpEntityId", idpEntityId);
        sendMessageToApplication(spHostName, "sp", params);

        checkApplicationMessage("Please login");

        params = new HashMap<String, String>();
        params.put("command", "authenticate");
        params.put("userName", userName);
        sendMessageToApplication("www.idp.com", "idp", params);

        checkApplicationMessage("Login succeeded (" + userName + ")");
    }

    private void sendMessageToApplication(String hostName, String contextRoot, Map<String, String> params) {
        List<NameValuePair> qParams = new ArrayList<NameValuePair>();
        for (Map.Entry<String, String> mapEntry : params.entrySet()) {
            qParams.add(new BasicNameValuePair(mapEntry.getKey(), mapEntry.getValue()));
        }
        URI uri;
        try {
            uri = URIUtils.createURI("http", "localhost", 8080, "/" + contextRoot + "/testservlet", URLEncodedUtils.format(qParams, "UTF-8"), null);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        request = new HttpGet(uri);
        if (!hostName.equals("localhost")) {
            request.getParams().setParameter(ClientPNames.VIRTUAL_HOST, new HttpHost(hostName, 8080));
        }

        executeHttpRequestAndRelay();
    }

    private void checkDialogueTermination(String serverName, String spOrIdp) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("command", "getNrOfDialogues");
        sendMessageToApplication(serverName, spOrIdp, params);
        checkApplicationMessage("0");
    }

    /**
     * Relays the SAML message from the SP to the IDP or vice versa. Results in
     * an HTTP request that is ready to be executed.
     */
    private void relaySamlMessage() {
        if (responseType == ResponseType.SAML_MESSAGE_POST_BOUND) {
            Matcher matcher = Pattern.compile("ACTION=\"(.*?)\"").matcher(responseBody);
            matcher.find();
            String uri = matcher.group(1);

            matcher = Pattern.compile("NAME=\"(.*?)\"").matcher(responseBody);
            matcher.find();
            String name = matcher.group(1);

            matcher = Pattern.compile("VALUE=\"(.*?)\"").matcher(responseBody);
            matcher.find();
            String value = matcher.group(1);

            String serverName = extractServerNameFromUri(uri);
            uri = uri.replace(serverName, "localhost");
            HttpPost httpPost = new HttpPost(uri);
            if (!serverName.equals("localhost")) {
                httpPost.getParams().setParameter(ClientPNames.VIRTUAL_HOST, new HttpHost(serverName, 8080));
            }
            List<NameValuePair> formparams = new ArrayList<NameValuePair>();
            formparams.add(new BasicNameValuePair(name, value));
            UrlEncodedFormEntity entity;
            try {
                entity = new UrlEncodedFormEntity(formparams, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
            httpPost.setEntity(entity);
            request = httpPost;
        } else if (responseType == ResponseType.SAML_MESSAGE_REDIRECT_BOUND) {
            String location = response.getFirstHeader("Location").getValue();
            log.info("Received redirect to " + location);
            String serverName = extractServerNameFromUri(location);
            HttpGet httpGet = new HttpGet(location.replace(serverName, "localhost"));
            httpGet.getParams().setParameter(ClientPNames.VIRTUAL_HOST, new HttpHost(serverName, 8080));
            request = httpGet;
        } else if (responseType == ResponseType.ERROR) {
            Assert.fail("Error response received by test client (status code " + response.getStatusLine().getStatusCode() + "): " + responseBody);
        } else {
            throw new RuntimeException("Cannot relay the non-SAML response type " + responseType + " (message: " + responseBody + ")");
        }
    }

    private ResponseType determineResponseType() {
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) {
            return ResponseType.SAML_MESSAGE_REDIRECT_BOUND;
        } else if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
            return ResponseType.ERROR;
        } else if (responseBody.contains("HTTP Post SamlBinding")) {
            return ResponseType.SAML_MESSAGE_POST_BOUND;
        } else {
            return ResponseType.APPLICATION_MESSAGE;
        }
    }

    private String extractServerNameFromUri(String string) {
        Matcher matcher = Pattern.compile("http://(.*?):").matcher(string);
        matcher.find();
        return matcher.group(1);
    }

    private void checkApplicationMessage(String expectedMessageBody) {
        if (responseType == ResponseType.ERROR) {
            Assert.fail("Error response received by test client (status code " + response.getStatusLine().getStatusCode() + "): " + responseBody);
        }
        Assert.assertEquals(ResponseType.APPLICATION_MESSAGE, responseType);
        Assert.assertEquals(expectedMessageBody, responseBody);
    }

    /**
     * Executes the current HTTP request and evaluates the response. If the
     * response is a SAML message that needs to be relayed, by the user agent
     * (which is mimicked by the current class), from the SP to the IDP or vice
     * versa, the relay is performed. This is repeated until a non-relay response
     * has been received.
     */
    private void executeHttpRequestAndRelay() {
        executeHttpRequest();
        while (responseType == ResponseType.SAML_MESSAGE_POST_BOUND || responseType == ResponseType.SAML_MESSAGE_REDIRECT_BOUND) {
            relaySamlMessage();
            executeHttpRequest();
        }
    }

    private void executeHttpRequest() {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            response = httpClient.execute(request);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                entity.writeTo(outputStream);
            }
            responseBody = outputStream.toString("UTF-8");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        responseType = determineResponseType();
    }
}
TOP

Related Classes of org.jboss.seam.security.externaltest.integration.client.IntegrationTest

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.