keycloak-memoizeit
Changes
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EcpSP.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java 193(+193 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/ecp-sp/WEB-INF/keycloak-saml.xml 6(+3 -3)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/ecp-sp/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json 34(+34 -0)
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)
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" : [