keycloak-memoizeit

Changes

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java 250(+0 -250)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlKeycloakRule.java 183(+0 -183)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlPicketlinkSPTest.java 539(+0 -539)

testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java 95(+0 -95)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/ecp/testsamlecp.json 67(+0 -67)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/sp-metadata.xml 55(+0 -55)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/sp-metadata-email-nameid.xml 55(+0 -55)

testsuite/integration-deprecated/src/test/resources/keycloak-saml/testsaml.json 535(+0 -535)

Details

diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EcpSP.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EcpSP.java
new file mode 100644
index 0000000..4160014
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EcpSP.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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.
+ */
+
+package org.keycloak.testsuite.adapter.page;
+
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+
+import java.net.URL;
+
+/**
+ * @author mhajas
+ */
+public class EcpSP extends SAMLServlet {
+    public static final String DEPLOYMENT_NAME = "ecp-sp";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
index 1459cf4..80868cf 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
@@ -17,6 +17,13 @@
 
 package org.keycloak.testsuite.adapter.servlet;
 
+import org.jboss.resteasy.util.Base64;
+import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.dom.saml.v2.protocol.StatusCodeType;
+import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
+import org.keycloak.saml.common.constants.JBossSAMLConstants;
+import org.keycloak.saml.common.util.DocumentUtil;
+import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
 import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
@@ -69,26 +76,42 @@ import org.keycloak.testsuite.util.SamlClientBuilder;
 import org.openqa.selenium.By;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
 import org.xml.sax.SAXException;
 
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Form;
 import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.NewCookie;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriBuilderException;
 import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.soap.SOAPHeaderElement;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 import javax.xml.validation.Validator;
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
 import java.net.URI;
 import java.net.URL;
 import java.security.KeyPair;
@@ -102,6 +125,8 @@ import javax.xml.xpath.XPathExpression;
 import javax.xml.xpath.XPathFactory;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
+
+import static javax.ws.rs.core.Response.Status.OK;
 import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.*;
 import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
@@ -209,6 +234,9 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
     @Page
     protected SalesPostAutodetectServlet salesPostAutodetectServletPage;
 
+    @Page
+    protected EcpSP ecpSPPage;
+
     public static final String FORBIDDEN_TEXT = "HTTP status code: 403";
     public static final String WEBSPHERE_FORBIDDEN_TEXT = "Error reported: 403";
 
@@ -342,6 +370,11 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
         return samlServletDeployment(SalesPostAutodetectServlet.DEPLOYMENT_NAME, "sales-post-autodetect/WEB-INF/web.xml", SendUsernameServlet.class);
     }
 
+    @Deployment(name = EcpSP.DEPLOYMENT_NAME)
+    protected static WebArchive ecpSp() {
+        return samlServletDeployment(EcpSP.DEPLOYMENT_NAME, SendUsernameServlet.class);
+    }
+
     @Override
     public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
         testRealms.add(loadRealm("/adapter-test/keycloak-saml/testsaml.json"));
@@ -1299,6 +1332,166 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
         client.close();
     }
 
+    @Test
+    public void testSuccessfulEcpFlow() throws Exception {
+        Response authnRequestResponse = ClientBuilder.newClient().target(ecpSPPage.toString()).request()
+                .header("Accept", "text/html; application/vnd.paos+xml")
+                .header("PAOS", "ver='urn:liberty:paos:2003-08' ;'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp'")
+                .get();
+
+        SOAPMessage authnRequestMessage = MessageFactory.newInstance().createMessage(null, new ByteArrayInputStream(authnRequestResponse.readEntity(byte[].class)));
+
+        //printDocument(authnRequestMessage.getSOAPPart().getContent(), System.out);
+
+        Iterator<SOAPHeaderElement> it = authnRequestMessage.getSOAPHeader().<SOAPHeaderElement>getChildElements(new QName("urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp", "Request"));
+        SOAPHeaderElement ecpRequestHeader = it.next();
+        NodeList idpList = ecpRequestHeader.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:protocol", "IDPList");
+
+        assertThat("No IDPList returned from Service Provider", idpList.getLength(), is(1));
+
+        NodeList idpEntries = idpList.item(0).getChildNodes();
+
+        assertThat("No IDPEntry returned from Service Provider", idpEntries.getLength(), is(1));
+
+        String singleSignOnService = null;
+
+        for (int i = 0; i < idpEntries.getLength(); i++) {
+            Node item = idpEntries.item(i);
+            NamedNodeMap attributes = item.getAttributes();
+            Node location = attributes.getNamedItem("Loc");
+
+            singleSignOnService = location.getNodeValue();
+        }
+
+        assertThat("Could not obtain SSO Service URL", singleSignOnService, notNullValue());
+
+        Document authenticationRequest = authnRequestMessage.getSOAPBody().getFirstChild().getOwnerDocument();
+        String username = "pedroigor";
+        String password = "password";
+        String pair = username + ":" + password;
+        String authHeader = "Basic " + Base64.encodeBytes(pair.getBytes());
+
+        Response authenticationResponse = ClientBuilder.newClient().target(singleSignOnService).request()
+                .header(HttpHeaders.AUTHORIZATION, authHeader)
+                .post(Entity.entity(DocumentUtil.asString(authenticationRequest), "text/xml"));
+
+        assertThat(authenticationResponse.getStatus(), is(OK.getStatusCode()));
+
+        SOAPMessage responseMessage  = MessageFactory.newInstance().createMessage(null, new ByteArrayInputStream(authenticationResponse.readEntity(byte[].class)));
+
+        //printDocument(responseMessage.getSOAPPart().getContent(), System.out);
+
+        SOAPHeader responseMessageHeaders = responseMessage.getSOAPHeader();
+
+        NodeList ecpResponse = responseMessageHeaders.getElementsByTagNameNS(JBossSAMLURIConstants.ECP_PROFILE.get(), JBossSAMLConstants.RESPONSE__ECP.get());
+
+        assertThat("No ECP Response", ecpResponse.getLength(), is(1));
+
+        Node samlResponse = responseMessage.getSOAPBody().getFirstChild();
+
+        assertThat(samlResponse, notNullValue());
+
+        ResponseType responseType = (ResponseType) SAMLParser.getInstance().parse(samlResponse);
+        StatusCodeType statusCode = responseType.getStatus().getStatusCode();
+
+        assertThat(statusCode.getValue().toString(), is(JBossSAMLURIConstants.STATUS_SUCCESS.get()));
+        assertThat(responseType.getDestination(), is(ecpSPPage.toString() + "/"));
+        assertThat(responseType.getSignature(), notNullValue());
+        assertThat(responseType.getAssertions().size(), is(1));
+
+        SOAPMessage samlResponseRequest = MessageFactory.newInstance().createMessage();
+
+        samlResponseRequest.getSOAPBody().addDocument(responseMessage.getSOAPBody().extractContentAsDocument());
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+        samlResponseRequest.writeTo(os);
+
+        Response serviceProviderFinalResponse = ClientBuilder.newClient().target(responseType.getDestination()).request()
+                .post(Entity.entity(os.toByteArray(), "application/vnd.paos+xml"));
+
+        Map<String, NewCookie> cookies = serviceProviderFinalResponse.getCookies();
+
+        Invocation.Builder resourceRequest = ClientBuilder.newClient().target(responseType.getDestination()).request();
+
+        for (NewCookie cookie : cookies.values()) {
+            resourceRequest.cookie(cookie);
+        }
+
+        Response resourceResponse = resourceRequest.get();
+        assertThat(resourceResponse.readEntity(String.class), containsString("pedroigor"));
+    }
+
+    @Test
+    public void testInvalidCredentialsEcpFlow() throws Exception {
+        Response authnRequestResponse = ClientBuilder.newClient().target(ecpSPPage.toString()).request()
+                .header("Accept", "text/html; application/vnd.paos+xml")
+                .header("PAOS", "ver='urn:liberty:paos:2003-08' ;'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp'")
+                .get();
+
+        SOAPMessage authnRequestMessage = MessageFactory.newInstance().createMessage(null, new ByteArrayInputStream(authnRequestResponse.readEntity(byte[].class)));
+        Iterator<SOAPHeaderElement> it = authnRequestMessage.getSOAPHeader().<SOAPHeaderElement>getChildElements(new QName("urn:liberty:paos:2003-08", "Request"));
+
+        it.next();
+
+        it = authnRequestMessage.getSOAPHeader().<SOAPHeaderElement>getChildElements(new QName("urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp", "Request"));
+        SOAPHeaderElement ecpRequestHeader = it.next();
+        NodeList idpList = ecpRequestHeader.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:protocol", "IDPList");
+
+        assertThat("No IDPList returned from Service Provider", idpList.getLength(), is(1));
+
+        NodeList idpEntries = idpList.item(0).getChildNodes();
+
+        assertThat("No IDPEntry returned from Service Provider", idpEntries.getLength(), is(1));
+
+        String singleSignOnService = null;
+
+        for (int i = 0; i < idpEntries.getLength(); i++) {
+            Node item = idpEntries.item(i);
+            NamedNodeMap attributes = item.getAttributes();
+            Node location = attributes.getNamedItem("Loc");
+
+            singleSignOnService = location.getNodeValue();
+        }
+
+        assertThat("Could not obtain SSO Service URL", singleSignOnService, notNullValue());
+
+        Document authenticationRequest = authnRequestMessage.getSOAPBody().getFirstChild().getOwnerDocument();
+        String username = "pedroigor";
+        String password = "baspassword";
+        String pair = username + ":" + password;
+        String authHeader = "Basic " + Base64.encodeBytes(pair.getBytes());
+
+        Response authenticationResponse = ClientBuilder.newClient().target(singleSignOnService).request()
+                .header(HttpHeaders.AUTHORIZATION, authHeader)
+                .post(Entity.entity(DocumentUtil.asString(authenticationRequest), "application/soap+xml"));
+
+        assertThat(authenticationResponse.getStatus(), is(OK.getStatusCode()));
+
+        SOAPMessage responseMessage  = MessageFactory.newInstance().createMessage(null, new ByteArrayInputStream(authenticationResponse.readEntity(byte[].class)));
+        Node samlResponse = responseMessage.getSOAPBody().getFirstChild();
+
+        assertThat(samlResponse, notNullValue());
+
+        StatusResponseType responseType = (StatusResponseType) SAMLParser.getInstance().parse(samlResponse);
+        StatusCodeType statusCode = responseType.getStatus().getStatusCode();
+
+        assertThat(statusCode.getStatusCode().getValue().toString(), is(not(JBossSAMLURIConstants.STATUS_SUCCESS.get())));
+    }
+
+    public static void printDocument(Source doc, OutputStream out) throws IOException, TransformerException {
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer transformer = tf.newTransformer();
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+        transformer.transform(doc,
+                new StreamResult(new OutputStreamWriter(out, "UTF-8")));
+    }
+
     private URI getAuthServerSamlEndpoint(String realm) throws IllegalArgumentException, UriBuilderException {
         return RealmsResource
                 .protocolUrl(UriBuilder.fromUri(getAuthServerRoot()))
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json
index 9c12795..8dca692 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json
@@ -85,6 +85,19 @@
             "groups": [
                 "/top/level2"
             ]
+        },
+        {
+            "username" : "pedroigor",
+            "enabled": true,
+            "email" : "psilva@redhat.com",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "attributes" : {
+                "phone": "617"
+            },
+            "realmRoles": ["manager", "user"]
         }
     ],
     "clients": [
@@ -614,6 +627,27 @@
                 "saml.authnstatement": "true",
                 "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
             }
+        },
+        {
+            "clientId": "http://localhost:8081/ecp-sp/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8080/ecp-sp",
+            "redirectUris": [
+                "http://localhost:8080/ecp-sp/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8080/ecp-sp/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8080/ecp-sp/",
+                "saml_single_logout_service_url_post": "http://localhost:8080/ecp-sp/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8080/ecp-sp/",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
         }
     ],
     "groups" : [