keycloak-aplcache
Changes
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadAssertionSalesPostSig.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeServlet.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java 6(+3 -3)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MissingAssertionSig.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPost2Servlet.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostAssertionAndResponseSig.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java 4(+2 -2)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java 24(+24 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SamlSPFacade.java 69(+69 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java 91(+89 -2)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java 69(+44 -25)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakDependenciesResolver.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SAMLFilterDependency.java 87(+0 -87)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java 88(+85 -3)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java 16(+16 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java 11(+5 -6)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java 21(+19 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java 406(+357 -49)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/bad-assertion-sales-post-sig/WEB-INF/keycloak-saml.xml 62(+62 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/bad-assertion-sales-post-sig/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee/WEB-INF/keycloak-saml.xml 42(+42 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee/WEB-INF/web.xml 54(+54 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/input-portal/WEB-INF/keycloak-saml.xml 41(+41 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/input-portal/WEB-INF/web.xml 54(+54 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml 60(+60 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post2/WEB-INF/keycloak-saml.xml 41(+41 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml 60(+60 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json 95(+95 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml 4(+4 -0)
Details
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadAssertionSalesPostSig.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadAssertionSalesPostSig.java
new file mode 100644
index 0000000..8d10b22
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadAssertionSalesPostSig.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 BadAssertionSalesPostSig extends SAMLServlet {
+ public static final String DEPLOYMENT_NAME = "bad-assertion-sales-post-sig";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeServlet.java
new file mode 100644
index 0000000..c8a0d66
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeServlet.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 EmployeeServlet extends SAMLServlet {
+ public static final String DEPLOYMENT_NAME = "employee";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java
index 6e66e2c..7edc5c5 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java
@@ -17,18 +17,18 @@
package org.keycloak.testsuite.adapter.page;
-import java.net.URL;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.test.api.ArquillianResource;
-import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
+import java.net.URL;
+
/**
*
* @author tkyjovsk
*/
-public class InputPortal extends AbstractPageWithInjectedUrl {
+public class InputPortal extends SAMLServlet {
public static final String DEPLOYMENT_NAME = "input-portal";
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MissingAssertionSig.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MissingAssertionSig.java
new file mode 100644
index 0000000..78ff38c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MissingAssertionSig.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 MissingAssertionSig extends SAMLServlet {
+ public static final String DEPLOYMENT_NAME = "missing-assertion-sig";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPost2Servlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPost2Servlet.java
new file mode 100644
index 0000000..d821d86
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPost2Servlet.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 SalesPost2Servlet extends SAMLServlet {
+ public static final String DEPLOYMENT_NAME = "sales-post2";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostAssertionAndResponseSig.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostAssertionAndResponseSig.java
new file mode 100644
index 0000000..a4522b4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostAssertionAndResponseSig.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 SalesPostAssertionAndResponseSig extends SAMLServlet {
+ public static final String DEPLOYMENT_NAME = "sales-post-assertion-and-response-sig";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java
index fe856dc..cc4a419 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SAMLServlet.java
@@ -40,8 +40,8 @@ public abstract class SAMLServlet extends AbstractPageWithInjectedUrl {
}
}
- public void checkRolesEndPoint() {
- driver.navigate().to(getUriBuilder().build().toASCIIString() + "/checkRoles");
+ public void checkRolesEndPoint(boolean value) {
+ driver.navigate().to(getUriBuilder().build().toASCIIString() + "/" + (value ? "" : "un") + "checkRoles");
pause(300);
}
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java
index a2038bf..5fb04e9 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java
@@ -17,6 +17,8 @@
package org.keycloak.testsuite.adapter.servlet;
+import org.junit.Assert;
+
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
@@ -31,6 +33,8 @@ import java.io.PrintWriter;
@WebServlet("/input-portal")
public class InputServlet extends HttpServlet {
+ private static final String FORM_URLENCODED = "application/x-www-form-urlencoded";
+
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String appBase;
@@ -41,6 +45,16 @@ public class InputServlet extends HttpServlet {
}
String actionUrl = appBase + "/input-portal/secured/post";
+ if (req.getRequestURI().endsWith("insecure")) {
+ if (System.getProperty("insecure.user.principal.unsupported") == null) Assert.assertNotNull(req.getUserPrincipal());
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ pw.printf("<html><head><title>Input Servlet</title></head><body>%s\n", "Insecure Page");
+ if (req.getUserPrincipal() != null) pw.printf("UserPrincipal: " + req.getUserPrincipal().getName());
+ pw.print("</body></html>");
+ pw.flush();
+ return;
+ }
resp.setContentType("text/html");
PrintWriter pw = resp.getWriter();
@@ -56,6 +70,16 @@ public class InputServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ if (!FORM_URLENCODED.equals(req.getContentType())) {
+ resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ PrintWriter pw = resp.getWriter();
+ resp.setContentType("text/plain");
+ pw.printf("Expecting content type " + FORM_URLENCODED +
+ ", received " + req.getContentType() + " instead");
+ pw.flush();
+ return;
+ }
+
resp.setContentType("text/plain");
PrintWriter pw = resp.getWriter();
pw.printf("parameter="+req.getParameter("parameter"));
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SamlSPFacade.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SamlSPFacade.java
new file mode 100755
index 0000000..21f07b3
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SamlSPFacade.java
@@ -0,0 +1,69 @@
+/*
+ * 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.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+* @version $Revision: 1 $
+*/
+public class SamlSPFacade extends HttpServlet {
+ public static String samlResponse;
+ public static String RELAY_STATE = "http://test.com/foo/bar";
+ public static String sentRelayState;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ handler(req, resp);
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ handler(req, resp);
+ }
+
+ private void handler(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ System.out.println("In SamlSPFacade Servlet handler()");
+ if (req.getParameterMap().isEmpty()) {
+ System.out.println("ParameterMap is empty, redirecting to keycloak server ");
+ resp.setStatus(302);
+ // Redirect
+ // UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVLRTsIwFP2Vpe%2BjG4wxG0YyWYxL0BBAH3wx3XYnTbp29nYof%2B8YEvEBNOlD03vOveec2ynyWjYsae1WreC9BbTOZy0Vsr4Qk9YopjkKZIrXgMwWbJ08LNhw4LHGaKsLLcmRch3MEcFYoRVxktN1rhW2NZg1mJ0o4Gm1iMnW2oZRKnXB5VajZZEX%2BRTqRuo9ACVO2mkUih%2F4l9C8s0MNcFkjLaHW9KSUHlwR506bAnrPMam4RCBOlsYkS1%2BD3MvLcDJxAx9KN4jCkXszrG5cP%2BCVH4y8IM8PYFx2dsQOfuiILWQKLVc2JkPPH7te6HrRxh%2BzUdidwSSIXoiz%2FBZyK1Qp1Nv1yPIjCNn9ZrN0V1AKA4UlzjMY7N13IDKbHjyxXoA5291%2FtzH7I%2FApPet%2FHNawx65hli61FMXeSaTUH%2FMubtvlYU0LfcA1t5cl%2BAO%2FfxGlW%2FVQ1ipsoBCVgJLQ2XHo7385%2BwI%3D");
+ UriBuilder builder = UriBuilder.fromUri("http://localhost:8180/auth/realms/demo/protocol/saml?SAMLRequest=jZJdS8MwFIbvBf9DyX2XNG62hnUwHeLAj7JNL7yRmJ65QJrUnNSPf29WHQp%2BIOQiJM%2FJed%2F3ZIyyMa2YdmFjF%2FDYAYbkpTEWRX9Rks5b4SRqFFY2gCIosZxenAs%2BYKL1LjjlDHkv%2BRuWiOCDdpYk0932xFnsGvBL8E9awfXivCSbEFpBqXFKmo3DIApeMApNa9wrACXJLGrUVm7rf6KzSMtoh3qQpkFaQ%2BPoTinduiLJqfMKes8lWUuDQJL5rCTz2d2wLmCkgKc5Z4fpMOf3qSyO8pTXxUHOjphibBRhrKId%2FQSf5YgdzC0GaUNJOMtGKTtI2eGKcxFXlg%2BK0fCWJNWHkGNta20f%2Fo7s%2Fh1CcbZaVWl1tVyR5AY89s4jQCb7e%2BOtI9G3918m999ZTL4HyIrsM%2B4x%2FfL%2Brl0rLuOT81nljFavydQY93wS4w4xj%2BA76ANuZPhdRDbI%2BhNdp%2BseFZ3FFpRea6gJ3Tai33%2Fm5A0%3D");
+ builder.queryParam("RelayState", RELAY_STATE);
+ resp.setHeader("Location", builder.build().toString());
+ return;
+ }
+
+ System.out.println("Response was received");
+ samlResponse = req.getParameter("SAMLResponse");
+ sentRelayState = req.getParameter("RelayState");
+
+ PrintWriter pw = resp.getWriter();
+ pw.println("Relay state: " + sentRelayState);
+ pw.println("SAML response: " + samlResponse);
+ pw.flush();
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java
index 58feae3..6e70f15 100755
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java
@@ -19,6 +19,10 @@ package org.keycloak.testsuite.adapter.servlet;
import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.adapters.saml.SamlAuthenticationError;
+import org.keycloak.adapters.saml.SamlPrincipal;
+import org.keycloak.adapters.spi.AuthenticationError;
+import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -28,6 +32,9 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -38,6 +45,9 @@ import java.security.Principal;
public class SendUsernameServlet {
private static boolean checkRoles = false;
+ private static SamlAuthenticationError authError;
+ private static Principal sentPrincipal;
+ private static List<String> checkRolesList = Collections.singletonList("manager");
@Context
private HttpServletRequest httpServletRequest;
@@ -62,7 +72,15 @@ public class SendUsernameServlet {
throw new RuntimeException("User: " + httpServletRequest.getUserPrincipal() + " do not have required role");
}
- return Response.ok(getOutput(), MediaType.TEXT_PLAIN).build();
+ return Response.ok(getOutput(), MediaType.TEXT_HTML_TYPE).build();
+ }
+
+ @GET
+ @Path("getAttributes")
+ public Response getSentPrincipal() throws IOException {
+ System.out.println("In SendUsername Servlet getSentPrincipal()");
+
+ return Response.ok(getAttributes(), MediaType.TEXT_HTML_TYPE).build();
}
@GET
@@ -79,6 +97,23 @@ public class SendUsernameServlet {
return doPost(checkRolesFlag);
}
+ @POST
+ @Path("error.html")
+ public Response errorPagePost() {
+ authError = (SamlAuthenticationError) httpServletRequest.getAttribute(AuthenticationError.class.getName());
+ Integer statusCode = (Integer) httpServletRequest.getAttribute("javax.servlet.error.status_code");
+ System.out.println("In SendUsername Servlet errorPage() status code: " + statusCode);
+
+ return Response.ok(getErrorOutput(statusCode), MediaType.TEXT_HTML_TYPE).build();
+ }
+
+ @GET
+ @Path("error.html")
+ public Response errorPageGet() {
+ return errorPagePost();
+ }
+
+
@GET
@Path("checkRoles")
public String checkRolesEndPoint() {
@@ -87,8 +122,35 @@ public class SendUsernameServlet {
return "Roles will be checked";
}
+ @GET
+ @Path("uncheckRoles")
+ public String uncheckRolesEndPoint() {
+ checkRoles = false;
+ System.out.println("Setting checkRoles to false");
+ checkRolesList = Collections.singletonList("manager");
+ return "Roles will not be checked";
+ }
+
+ @GET
+ @Path("setCheckRoles")
+ public String setCheckRoles(@QueryParam("roles") String roles) {
+ checkRolesList = Arrays.asList(roles.split(","));
+ checkRoles = true;
+ System.out.println("Setting checkRolesList to " + checkRolesList.toString());
+ return "These roles will be checked: " + checkRolesList.toString();
+ }
+
+
private boolean checkRoles() {
- return httpServletRequest.isUserInRole("manager");
+ for (String role : checkRolesList) {
+ System.out.println("In checkRoles() checking role " + role + " for user " + httpServletRequest.getUserPrincipal().getName());
+ if (!httpServletRequest.isUserInRole(role)) {
+ System.out.println("User is not in role " + role);
+ return false;
+ }
+ }
+
+ return true;
}
private String getOutput() {
@@ -102,6 +164,31 @@ public class SendUsernameServlet {
return output + "null";
}
+ sentPrincipal = principal;
+
return output + principal.getName();
}
+
+ private String getErrorOutput(Integer statusCode) {
+ String output = "<html><head><title>Error Page</title></head><body><h1>There was an error</h1>";
+ if (statusCode != null)
+ output += "<br/>HTTP status code: " + statusCode;
+ if (authError != null)
+ output += "<br/>Error info: " + authError.toString();
+ return output + "</body></html>";
+ }
+
+ private String getAttributes() {
+ SamlPrincipal principal = (SamlPrincipal) sentPrincipal;
+ String output = "attribute email: " + principal.getAttribute(X500SAMLProfileConstants.EMAIL.get());
+ output += "<br /> topAttribute: " + principal.getAttribute("topAttribute");
+ output += "<br /> level2Attribute: " + principal.getAttribute("level2Attribute");
+ output += "<br /> group: " + principal.getAttributes("group").toString();
+ output += "<br /> friendlyAttribute email: " + principal.getFriendlyAttribute("email");
+ output += "<br /> phone: " + principal.getAttribute("phone");
+ output += "<br /> friendlyAttribute phone: " + principal.getFriendlyAttribute("phone");
+ output += "<br /> hardcoded-attribute: " + principal.getAttribute("hardcoded-attribute");
+
+ return output;
+ }
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
index 68d7183..9cd7625 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
@@ -17,7 +17,6 @@
package org.keycloak.testsuite.arquillian;
-import org.apache.commons.io.IOUtils;
import org.apache.tools.ant.DirectoryScanner;
import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
import org.jboss.arquillian.test.spi.TestClass;
@@ -31,6 +30,7 @@ import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
import org.keycloak.testsuite.util.IOUtil;
import org.keycloak.util.JsonSerialization;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import javax.xml.transform.TransformerException;
import java.io.File;
@@ -112,6 +112,12 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
log.error("Can't transform document to String");
throw new RuntimeException(e);
}
+
+ // For running SAML tests it is necessary to have few dependencies on app-server side.
+ // Few of them are not in adapter zip so we need to add them manually here
+ log.info("Adding SAMLFilter dependencies to " + archive.getName());
+ ((WebArchive) archive).addAsLibraries(KeycloakDependenciesResolver.resolveDependencies("org.keycloak:keycloak-saml-servlet-filter-adapter:" + System.getProperty("project.version")));
+
} else { // OIDC adapter config
try {
AdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
@@ -156,45 +162,58 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
protected void modifyWebXml(Archive<?> archive, TestClass testClass) {
try {
- String webXmlContent = IOUtils.toString(
+ Document webXmlDoc = loadXML(
archive.get(WEBXML_PATH).getAsset().openStream());
if (isTomcatAppServer(testClass.getJavaClass())) {
- webXmlContent = webXmlContent.replace("<auth-method>KEYCLOAK</auth-method>", "<auth-method>BASIC</auth-method>");
+ modifyDocElementValue(webXmlDoc, "auth-method", "KEYCLOAK", "BASIC");
}
if (testClass.getJavaClass().isAnnotationPresent(UseServletFilter.class)) {
//We need to add filter declaration to web.xml
log.info("Adding filter to " + testClass.getAnnotation(UseServletFilter.class).filterClass() + " with mapping " + testClass.getAnnotation(UseServletFilter.class).filterPattern() + " for " + archive.getName());
- String filter = "\n<filter>\n" +
- "<filter-name>" + testClass.getAnnotation(UseServletFilter.class).filterName() + "</filter-name>\n" +
- "<filter-class>" + testClass.getAnnotation(UseServletFilter.class).filterClass() + "</filter-class>\n" +
- "</filter>\n" +
- "\n<filter-mapping>\n" +
- "<filter-name>" + testClass.getAnnotation(UseServletFilter.class).filterName() + "</filter-name>\n" +
- "<url-pattern>" + testClass.getAnnotation(UseServletFilter.class).filterPattern() + "</url-pattern>\n";
- if (!testClass.getAnnotation(UseServletFilter.class).dispatcherType().isEmpty()) {
- filter += "<dispatcher>" + testClass.getAnnotation(UseServletFilter.class).dispatcherType() + "</dispatcher>\n";
- }
- filter += "</filter-mapping>\n";
- webXmlContent = webXmlContent.replace("</module-name>", "</module-name> " + filter);
+ Element filter = webXmlDoc.createElement("filter");
+ Element filterName = webXmlDoc.createElement("filter-name");
+ Element filterClass = webXmlDoc.createElement("filter-class");
- //Also we need to add all dependencies within war lib directory, because filter needs to work without installed adapter
- log.info("Adding SAMLFilter dependencies to " + archive.getName());
- ((WebArchive) archive).addAsLibraries(new SAMLFilterDependency().getDependencies());
+ filterName.setTextContent(testClass.getAnnotation(UseServletFilter.class).filterName());
+ filterClass.setTextContent(testClass.getAnnotation(UseServletFilter.class).filterClass());
+ filter.appendChild(filterName);
+ filter.appendChild(filterClass);
+ appendChildInDocument(webXmlDoc, "web-app", filter);
+
+ Element filterMapping = webXmlDoc.createElement("filter-mapping");
- //finally we need to remove all keycloak related configuration from web.xml
- int start = webXmlContent.indexOf("<security-constraint>");
- int end = webXmlContent.indexOf("</security-role>") + "</security-role>".length();
+ Element urlPattern = webXmlDoc.createElement("url-pattern");
- webXmlContent = webXmlContent.substring(0, start) + webXmlContent.substring(end);
+ filterName = webXmlDoc.createElement("filter-name");
+
+ filterName.setTextContent(testClass.getAnnotation(UseServletFilter.class).filterName());
+ urlPattern.setTextContent(getElementTextContent(webXmlDoc, "web-app/security-constraint/web-resource-collection/url-pattern"));
+
+ filterMapping.appendChild(filterName);
+ filterMapping.appendChild(urlPattern);
+
+ if (!testClass.getAnnotation(UseServletFilter.class).dispatcherType().isEmpty()) {
+ Element dispatcher = webXmlDoc.createElement("dispatcher");
+ dispatcher.setTextContent(testClass.getAnnotation(UseServletFilter.class).dispatcherType());
+ filterMapping.appendChild(dispatcher);
+ }
+ appendChildInDocument(webXmlDoc, "web-app", filterMapping);
+
+ //finally we need to remove all keycloak related configuration from web.xml
+ removeElementFromDoc(webXmlDoc, "web-app", "security-constraint");
+ removeElementFromDoc(webXmlDoc, "web-app", "login-config");
+ removeElementFromDoc(webXmlDoc, "web-app", "security-role");
}
- archive.add(new StringAsset((webXmlContent)), WEBXML_PATH);
- } catch (IOException ex) {
- throw new RuntimeException("Cannot load web.xml from archive.");
+
+ archive.add(new StringAsset((documentToString(webXmlDoc))), WEBXML_PATH);
+ } catch (TransformerException e) {
+ log.error("Can't transform document to String");
+ throw new RuntimeException(e);
}
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakDependenciesResolver.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakDependenciesResolver.java
new file mode 100644
index 0000000..2f62c2b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakDependenciesResolver.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.arquillian;
+
+import org.jboss.logging.Logger;
+import org.jboss.shrinkwrap.resolver.api.maven.Maven;
+import org.jboss.shrinkwrap.resolver.api.maven.PomEquippedResolveStage;
+import org.jboss.shrinkwrap.resolver.api.maven.ScopeType;
+import org.jboss.shrinkwrap.resolver.api.maven.coordinate.MavenDependencies;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author mhajas
+ */
+public class KeycloakDependenciesResolver {
+
+ private static Map<String, File[]> dependencies = new HashMap<>();
+
+ protected static final Logger log = org.jboss.logging.Logger.getLogger(KeycloakDependenciesResolver.class);
+
+ public static File[] resolveDependencies(String canonicalForm) {
+ if (dependencies.containsKey(canonicalForm)) {
+ return dependencies.get(canonicalForm);
+ }
+
+ log.info("Resolving " + canonicalForm + "'s dependencies");
+ PomEquippedResolveStage resolver = Maven.configureResolverViaPlugin();
+
+ File[] files = resolver.addDependency(MavenDependencies.createDependency(canonicalForm, ScopeType.COMPILE, false))
+ .resolve().withTransitivity().asFile();
+
+ dependencies.put(canonicalForm, files);
+
+ log.info("Resolving dependencies is finished with " + files.length + " files");
+
+ return dependencies.get(canonicalForm);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
index d872914..89084d4 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
@@ -16,9 +16,11 @@
*/
package org.keycloak.testsuite.util;
+import org.jboss.logging.Logger;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.util.JsonSerialization;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@@ -33,7 +35,6 @@ import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.concurrent.TimeUnit;
-import org.jboss.logging.Logger;
/**
*
@@ -93,18 +94,99 @@ public class IOUtil {
public static void modifyDocElementAttribute(Document doc, String tagName, String attributeName, String regex, String replacement) {
NodeList nodes = doc.getElementsByTagName(tagName);
if (nodes.getLength() != 1) {
- System.out.println("Not able to find element: " + tagName);
+ log.warn("Not able or ambiguous to find element: " + tagName);
return;
}
Node node = nodes.item(0).getAttributes().getNamedItem(attributeName);
if (node == null) {
- System.out.println("Not able to find attribute " + attributeName + " within element: " + tagName);
+ log.warn("Not able to find attribute " + attributeName + " within element: " + tagName);
+ return;
+ }
+ node.setTextContent(node.getTextContent().replace(regex, replacement));
+ }
+
+ public static void modifyDocElementValue(Document doc, String tagName, String regex, String replacement) {
+ NodeList nodes = doc.getElementsByTagName(tagName);
+ if (nodes.getLength() != 1) {
+ log.warn("Not able or ambiguous to find element: " + tagName);
+ return;
+ }
+
+ Node node = nodes.item(0);
+ if (node == null) {
+ log.warn("Not able to find element: " + tagName);
return;
}
+
node.setTextContent(node.getTextContent().replace(regex, replacement));
}
+ public static void removeElementFromDoc(Document doc, String parentTag, String removeNode) {
+ NodeList nodes = doc.getElementsByTagName(parentTag);
+ if (nodes.getLength() != 1) {
+ log.warn("Not able or ambiguous to find element: " + parentTag);
+ return;
+ }
+
+ Element parentElement = (Element) nodes.item(0);
+ if (parentElement == null) {
+ log.warn("Not able to find element: " + parentTag);
+ return;
+ }
+
+ NodeList removeNodes = parentElement.getElementsByTagName(removeNode);
+ if (removeNodes.getLength() != 1) {
+ log.warn("Not able or ambiguous to find element: " + removeNode + " within node " + parentTag);
+ return;
+ }
+
+ Element removeElement = (Element) removeNodes.item(0);
+ if (removeElement == null) {
+ log.warn("Not able to find element: " + removeNode + " within node " + parentTag);
+ return;
+ }
+
+ parentElement.removeChild(removeElement);
+ }
+
+ public static String getElementTextContent(Document doc, String path) {
+ String[] pathSegments = path.split("/");
+
+ Element currentElement = (Element) doc.getElementsByTagName(pathSegments[0]).item(0);
+ if (currentElement == null) {
+ log.warn("Not able to find element: " + pathSegments[0] + " in document");
+ return null;
+ }
+
+ for (int i = 1; i < pathSegments.length; i++) {
+ currentElement = (Element) currentElement.getElementsByTagName(pathSegments[i]).item(0);
+
+ if (currentElement == null) {
+ log.warn("Not able to find element: " + pathSegments[i] + " in " + pathSegments[i - 1]);
+ return null;
+ }
+ }
+
+ return currentElement.getTextContent();
+ }
+
+ public static void appendChildInDocument(Document doc, String parentTag, Element node) {
+ NodeList nodes = doc.getElementsByTagName(parentTag);
+ if (nodes.getLength() != 1) {
+ log.warn("Not able or ambiguous to find element: " + parentTag);
+ return;
+ }
+
+ Element parentElement = (Element) nodes.item(0);
+ if (parentElement == null) {
+ log.warn("Not able to find element: " + parentTag);
+ return;
+ }
+
+ parentElement.appendChild(node);
+ }
+
public static void execCommand(String command, File dir) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec(command, null, dir);
if (process.waitFor(10, TimeUnit.SECONDS)) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
index 0ef7215..63821b3 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
@@ -31,6 +31,7 @@ import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
*
@@ -63,10 +64,12 @@ public abstract class AbstractAdapterTest extends AbstractAuthTest {
modifyClientUrls(tr, appServerContextRootPage.toString(), "");
modifyClientWebOrigins(tr, "8080", System.getProperty("auth.server.http.port", null));
modifySamlMasterURLs(tr, "/", "http://localhost:" + System.getProperty("auth.server.http.port", null) + "/");
+ modifySAMLClientsAttributes(tr, "8080", System.getProperty("auth.server.http.port", "8180"));
} else {
modifyClientRedirectUris(tr, "^(/.*/\\*)", appServerContextRootPage.toString() + "$1");
modifyClientUrls(tr, "^(/.*)", appServerContextRootPage.toString() + "$1");
modifySamlMasterURLs(tr, "8080", System.getProperty("auth.server.http.port", null));
+ modifySAMLClientsAttributes(tr, "8080", System.getProperty("app.server.http.port", "8280"));
}
if ("true".equals(System.getProperty("auth.server.ssl.required"))) {
tr.setSslRequired("all");
@@ -125,6 +128,19 @@ public abstract class AbstractAdapterTest extends AbstractAuthTest {
}
}
+ protected void modifySAMLClientsAttributes(RealmRepresentation realm, String regex, String replacement) {
+ if (realm.getClients() != null) {
+ for (ClientRepresentation client : realm.getClients()) {
+ if (client.getProtocol() != null && client.getProtocol().equals("saml")) {
+ log.info("Modifying attributes of SAML client: " + client.getClientId());
+ for (Map.Entry<String, String> entry : client.getAttributes().entrySet()) {
+ client.getAttributes().put(entry.getKey(), entry.getValue().replaceAll(regex, replacement));
+ }
+ }
+ }
+ }
+ }
+
protected void modifySamlMasterURLs(RealmRepresentation realm, String regex, String replacement) {
if (realm.getClients() != null) {
for (ClientRepresentation client : realm.getClients()) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
index badf51c..127c863 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
@@ -25,12 +25,11 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
+import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.URL;
import java.util.List;
-import javax.ws.rs.core.UriBuilder;
-
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
@@ -66,15 +65,15 @@ public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest {
}
protected static WebArchive samlServletDeployment(String name, Class... servletClasses) {
- return samlServletDeployment(name, "keycloak-saml.xml", servletClasses);
+ return samlServletDeployment(name, "web.xml", servletClasses);
}
- protected static WebArchive samlServletDeployment(String name, String adapterConfig ,Class... servletClasses) {
+ protected static WebArchive samlServletDeployment(String name, String webXMLPath, Class... servletClasses) {
String baseSAMLPath = "/adapter-test/keycloak-saml/";
String webInfPath = baseSAMLPath + name + "/WEB-INF/";
- URL keycloakSAMLConfig = AbstractServletsAdapterTest.class.getResource(webInfPath + adapterConfig);
- URL webXML = AbstractServletsAdapterTest.class.getResource(baseSAMLPath + "web.xml");
+ URL keycloakSAMLConfig = AbstractServletsAdapterTest.class.getResource(webInfPath + "keycloak-saml.xml");
+ URL webXML = AbstractServletsAdapterTest.class.getResource(baseSAMLPath + webXMLPath);
WebArchive deployment = ShrinkWrap.create(WebArchive.class, name + ".war")
.addClasses(servletClasses)
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
index 0df65a4..268285a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
@@ -2,6 +2,8 @@ package org.keycloak.testsuite.adapter.servlet;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
/**
@@ -25,11 +27,12 @@ public abstract class AbstractSAMLFilterServletAdapterTest extends AbstractSAMLS
salesPostSigEmailServletPage.checkRoles(true);
salesPostSigPersistentServletPage.checkRoles(true);
salesPostSigTransientServletPage.checkRoles(true);
- employee2ServletPage.navigateTo();
+ salesPostAssertionAndResponseSigPage.checkRoles(true);
//using endpoint instead of query param because we are not able to put query param to IDP initiated login
+ employee2ServletPage.navigateTo();
testRealmLoginPage.form().login(bburkeUser);
- employee2ServletPage.checkRolesEndPoint();
+ employee2ServletPage.checkRolesEndPoint(true);
employee2ServletPage.logout();
forbiddenIfNotAuthenticated = false;
@@ -51,4 +54,18 @@ public abstract class AbstractSAMLFilterServletAdapterTest extends AbstractSAMLS
salesPostSigPersistentServletPage.checkRoles(false);
salesPostSigTransientServletPage.checkRoles(false);
}
+
+ @Test
+ @Override
+ @Ignore
+ public void testSavedPostRequest() {
+
+ }
+
+ @Test
+ @Override
+ @Ignore
+ public void testErrorHandling() {
+
+ }
}
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 ddc23b7..2973caa 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
@@ -20,11 +20,19 @@ package org.keycloak.testsuite.adapter.servlet;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ProtocolMappersResource;
+import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
+import org.keycloak.protocol.saml.mappers.RoleListMapper;
import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.saml.BaseSAML2BindingBuilder;
+import org.keycloak.saml.SAML2ErrorResponseBuilder;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
import org.keycloak.testsuite.adapter.page.*;
import org.keycloak.testsuite.admin.ApiUtil;
@@ -35,8 +43,15 @@ import org.keycloak.testsuite.util.IOUtil;
import org.openqa.selenium.By;
import org.w3c.dom.Document;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Form;
import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -71,6 +86,9 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
protected SalesPostServlet salesPostServletPage;
@Page
+ private SalesPost2Servlet salesPost2ServletPage;
+
+ @Page
protected SalesPostEncServlet salesPostEncServletPage;
@Page
@@ -93,6 +111,26 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
protected boolean forbiddenIfNotAuthenticated = true;
+ @Page
+ protected SalesPostAssertionAndResponseSig salesPostAssertionAndResponseSigPage;
+
+ @Page
+ protected BadAssertionSalesPostSig badAssertionSalesPostSigPage;
+
+ @Page
+ protected MissingAssertionSig missingAssertionSigPage;
+
+ @Page
+ protected EmployeeServlet employeeServletPage;
+
+ @Page
+ private InputPortal inputPortalPage;
+
+ @Page
+ private SAMLIDPInitiatedLogin samlidpInitiatedLoginPage;
+
+ public static final String FORBIDDEN_TEXT = "HTTP status code: 403";
+
@Deployment(name = BadClientSalesPostSigServlet.DEPLOYMENT_NAME)
protected static WebArchive badClientSalesPostSig() {
return samlServletDeployment(BadClientSalesPostSigServlet.DEPLOYMENT_NAME, SendUsernameServlet.class);
@@ -158,6 +196,36 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
return samlServletDeployment(SalesPostSigTransientServlet.DEPLOYMENT_NAME, SendUsernameServlet.class);
}
+ @Deployment(name = InputPortal.DEPLOYMENT_NAME)
+ protected static WebArchive inputPortal() {
+ return samlServletDeployment(InputPortal.DEPLOYMENT_NAME, "input-portal/WEB-INF/web.xml" , InputServlet.class);
+ }
+
+ @Deployment(name = SalesPost2Servlet.DEPLOYMENT_NAME)
+ protected static WebArchive salesPost2() {
+ return samlServletDeployment(SalesPost2Servlet.DEPLOYMENT_NAME, SendUsernameServlet.class);
+ }
+
+ @Deployment(name = SalesPostAssertionAndResponseSig.DEPLOYMENT_NAME)
+ protected static WebArchive salesPostAssertionAndResponseSig() {
+ return samlServletDeployment(SalesPostAssertionAndResponseSig.DEPLOYMENT_NAME, SendUsernameServlet.class);
+ }
+
+ @Deployment(name = BadAssertionSalesPostSig.DEPLOYMENT_NAME)
+ protected static WebArchive badAssertionSalesPostSig() {
+ return samlServletDeployment(BadAssertionSalesPostSig.DEPLOYMENT_NAME, SendUsernameServlet.class);
+ }
+
+ @Deployment(name = MissingAssertionSig.DEPLOYMENT_NAME)
+ protected static WebArchive missingAssertionSig() {
+ return samlServletDeployment(MissingAssertionSig.DEPLOYMENT_NAME, SendUsernameServlet.class);
+ }
+
+ @Deployment(name = EmployeeServlet.DEPLOYMENT_NAME)
+ protected static WebArchive employeeServlet() {
+ return samlServletDeployment(EmployeeServlet.DEPLOYMENT_NAME, "employee/WEB-INF/web.xml", SamlSPFacade.class);
+ }
+
@Override
public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
testRealms.add(loadRealm("/adapter-test/keycloak-saml/testsaml.json"));
@@ -171,38 +239,54 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
testRealmSAMLPostLoginPage.setAuthRealm(SAMLSERVLETDEMO);
}
- private void assertForbidden(AbstractPage page) {
+ private void assertForbidden(AbstractPage page, String expectedNotContains) {
page.navigateTo();
- waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
- assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("Status 403"));
+ waitUntilElement(By.xpath("//body")).text().not().contains(expectedNotContains);
+ assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
}
- private void assertSuccessfullyLoggedIn(AbstractPage page) {
+ private void assertSuccessfullyLoggedIn(AbstractPage page, String expectedText) {
page.navigateTo();
- waitUntilElement(By.xpath("//body")).text().contains("principal=bburke");
+ waitUntilElement(By.xpath("//body")).text().contains(expectedText);
}
- private void assertForbiddenLogin(AbstractPage page, String username, String password, Login loginPage) {
+ private void assertForbiddenLogin(AbstractPage page, String username, String password, Login loginPage, String expectedNotContains) {
page.navigateTo();
assertCurrentUrlStartsWith(loginPage);
loginPage.form().login(username, password);
- waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
+ waitUntilElement(By.xpath("//body")).text().not().contains(expectedNotContains);
//Different 403 status page on EAP and Wildfly
- assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("Status 403"));
+ assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
}
- private void assertSuccessfulLogin(AbstractPage page, UserRepresentation user, Login loginPage) {
+ private void assertSuccessfulLogin(AbstractPage page, UserRepresentation user, Login loginPage, String expectedString) {
page.navigateTo();
assertCurrentUrlStartsWith(loginPage);
loginPage.form().login(user);
- waitUntilElement(By.xpath("//body")).text().contains("principal=bburke");
+ waitUntilElement(By.xpath("//body")).text().contains(expectedString);
}
private void testSuccessfulAndUnauthorizedLogin(SAMLServlet page, Login loginPage) {
- assertSuccessfulLogin(page, bburkeUser, loginPage);
+ testSuccessfulAndUnauthorizedLogin(page, loginPage, "principal=bburke");
+ }
+
+ private void testSuccessfulAndUnauthorizedLogin(SAMLServlet page, Login loginPage, String expectedText) {
+ testSuccessfulAndUnauthorizedLogin(page, loginPage, expectedText, "principal=");
+ }
+
+ private void testSuccessfulAndUnauthorizedLogin(SAMLServlet page, Login loginPage, String expectedText, String expectedNotContains) {
+ assertSuccessfulLogin(page, bburkeUser, loginPage, expectedText);
page.logout();
- assertForbiddenLogin(page, "unauthorized", "password", loginPage);
+ checkLoggedOut(page, loginPage);
+ assertForbiddenLogin(page, "unauthorized", "password", loginPage, expectedNotContains);
page.logout();
+ checkLoggedOut(page, loginPage);
+ }
+
+ private void checkLoggedOut(AbstractPage page, Login loginPage) {
+ page.navigateTo();
+ waitUntilElement(By.xpath("//body")).is().present();
+ assertCurrentUrlStartsWith(loginPage);
}
@Test
@@ -221,38 +305,35 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
@Test
public void unauthorizedSSOTest() {
- assertForbiddenLogin(salesPostServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage);
- assertForbidden(employee2ServletPage);
- assertForbidden(employeeSigFrontServletPage);
- assertForbidden(salesPostSigPersistentServletPage);
+ assertForbiddenLogin(salesPostServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage, "principal=");
+ assertForbidden(employee2ServletPage, "principal=");
+ assertForbidden(employeeSigFrontServletPage, "principal=");
+ assertForbidden(salesPostSigPersistentServletPage, "principal=");
salesPostServletPage.logout();
+ checkLoggedOut(salesPostServletPage, testRealmSAMLPostLoginPage);
}
@Test
public void singleLoginAndLogoutSAMLTest() {
- assertSuccessfulLogin(salesPostServletPage, bburkeUser, testRealmSAMLPostLoginPage);
- assertSuccessfullyLoggedIn(salesPostSigServletPage);
- assertSuccessfullyLoggedIn(employee2ServletPage);
- assertSuccessfullyLoggedIn(salesPostEncServletPage);
+ assertSuccessfulLogin(salesPostServletPage, bburkeUser, testRealmSAMLPostLoginPage, "principal=bburke");
+ assertSuccessfullyLoggedIn(salesPostSigServletPage, "principal=bburke");
+ assertSuccessfullyLoggedIn(employee2ServletPage, "principal=bburke");
+ assertSuccessfullyLoggedIn(salesPostEncServletPage, "principal=bburke");
employeeSigFrontServletPage.logout();
- employeeSigFrontServletPage.navigateTo();
- assertCurrentUrlStartsWith(testRealmSAMLRedirectLoginPage);
-
- employeeSigServletPage.navigateTo();
- assertCurrentUrlStartsWith(testRealmSAMLRedirectLoginPage);
+ checkLoggedOut(employeeSigFrontServletPage, testRealmSAMLRedirectLoginPage);
+ checkLoggedOut(employeeSigServletPage, testRealmSAMLRedirectLoginPage);
salesPostPassiveServletPage.navigateTo();
if (forbiddenIfNotAuthenticated) {
waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
- assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().equals(""));
+ assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
} else {
waitUntilElement(By.xpath("//body")).text().contains("principal=null");
}
- salesPostSigEmailServletPage.navigateTo();
- assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ checkLoggedOut(salesPostSigEmailServletPage, testRealmSAMLPostLoginPage);
}
@Test
@@ -268,7 +349,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
//Different 403 status page on EAP and Wildfly
- assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("Status 403"));
+ assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
}
@Test
@@ -328,14 +409,14 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
if (forbiddenIfNotAuthenticated) {
waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
//Different 403 status page on EAP and Wildfly
- assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().equals(""));
+ assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
} else {
waitUntilElement(By.xpath("//body")).text().contains("principal=null");
}
- assertSuccessfulLogin(salesPostServletPage, bburkeUser, testRealmSAMLPostLoginPage);
+ assertSuccessfulLogin(salesPostServletPage, bburkeUser, testRealmSAMLPostLoginPage, "principal=bburke");
- assertSuccessfullyLoggedIn(salesPostPassiveServletPage);
+ assertSuccessfullyLoggedIn(salesPostPassiveServletPage, "principal=bburke");
salesPostPassiveServletPage.logout();
salesPostPassiveServletPage.navigateTo();
@@ -343,12 +424,13 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
if (forbiddenIfNotAuthenticated) {
waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
//Different 403 status page on EAP and Wildfly
- assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().equals(""));
+ assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
} else {
waitUntilElement(By.xpath("//body")).text().contains("principal=null");
}
- assertForbiddenLogin(salesPostServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage);
- assertForbidden(salesPostPassiveServletPage);
+
+ assertForbiddenLogin(salesPostServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage, "principal=");
+ assertForbidden(salesPostPassiveServletPage, "principal=");
salesPostPassiveServletPage.logout();
}
@@ -360,7 +442,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
@Test
public void salesPostSigEmailTest() {
- testSuccessfulAndUnauthorizedLogin(salesPostSigEmailServletPage, testRealmSAMLPostLoginPage);
+ testSuccessfulAndUnauthorizedLogin(salesPostSigEmailServletPage, testRealmSAMLPostLoginPage, "principal=bburke@redhat.com");
}
@Test
@@ -371,9 +453,11 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
waitUntilElement(By.xpath("//body")).text().contains("principal=G-");
salesPostSigPersistentServletPage.logout();
+ checkLoggedOut(salesPostSigPersistentServletPage, testRealmSAMLPostLoginPage);
- assertForbiddenLogin(salesPostSigPersistentServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage);
+ assertForbiddenLogin(salesPostSigPersistentServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage, "principal=");
salesPostSigPersistentServletPage.logout();
+ checkLoggedOut(salesPostSigPersistentServletPage, testRealmSAMLPostLoginPage);
}
@Test
@@ -384,36 +468,260 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
waitUntilElement(By.xpath("//body")).text().contains("principal=G-");
salesPostSigTransientServletPage.logout();
+ checkLoggedOut(salesPostSigTransientServletPage, testRealmSAMLPostLoginPage);
- assertForbiddenLogin(salesPostSigTransientServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage);
+ assertForbiddenLogin(salesPostSigTransientServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage, "principal=");
salesPostSigTransientServletPage.logout();
+ checkLoggedOut(salesPostSigTransientServletPage, testRealmSAMLPostLoginPage);
}
@Test
public void idpInitiatedLogin() {
- samlidpInitiatedLogin.setAuthRealm(SAMLSERVLETDEMO);
- samlidpInitiatedLogin.setUrlName("employee2");
- samlidpInitiatedLogin.navigateTo();
- samlidpInitiatedLogin.form().login(bburkeUser);
+ samlidpInitiatedLoginPage.setAuthRealm(SAMLSERVLETDEMO);
+ samlidpInitiatedLoginPage.setUrlName("employee2");
+ samlidpInitiatedLoginPage.navigateTo();
+ samlidpInitiatedLoginPage.form().login(bburkeUser);
waitUntilElement(By.xpath("//body")).text().contains("principal=bburke");
- assertSuccessfullyLoggedIn(salesPostSigServletPage);
+ assertSuccessfullyLoggedIn(salesPostSigServletPage, "principal=bburke");
employee2ServletPage.logout();
+ checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
}
@Test
public void idpInitiatedUnauthorizedLoginTest() {
- samlidpInitiatedLogin.setAuthRealm(SAMLSERVLETDEMO);
- samlidpInitiatedLogin.setUrlName("employee2");
- samlidpInitiatedLogin.navigateTo();
- samlidpInitiatedLogin.form().login("unauthorized", "password");
+ samlidpInitiatedLoginPage.setAuthRealm(SAMLSERVLETDEMO);
+ samlidpInitiatedLoginPage.setUrlName("employee2");
+ samlidpInitiatedLoginPage.navigateTo();
+ samlidpInitiatedLoginPage.form().login("unauthorized", "password");
waitUntilElement(By.xpath("//body")).text().not().contains("bburke");
- assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("Status 403"));
+ assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT));
+
+ assertForbidden(employee2ServletPage, "principal=");
+ employee2ServletPage.logout();
+ checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
+ }
+
+ @Test
+ public void testSavedPostRequest() {
+ inputPortalPage.navigateTo();
+ assertCurrentUrlStartsWith(inputPortalPage);
+ inputPortalPage.execute("hello");
+
+ assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ Assert.assertEquals(driver.getCurrentUrl(), inputPortalPage + "/secured/post");
+ waitUntilElement(By.xpath("//body")).text().contains("parameter=hello");
+
+ // test that user principal and KeycloakSecurityContext available
+ driver.navigate().to(inputPortalPage + "/insecure");
+ waitUntilElement(By.xpath("//body")).text().contains("Insecure Page");
+
+ if (System.getProperty("insecure.user.principal.unsupported") == null) waitUntilElement(By.xpath("//body")).text().contains("UserPrincipal");
+
+ // test logout
+
+ inputPortalPage.logout();
+
+ // test unsecured POST KEYCLOAK-901
- assertForbidden(employee2ServletPage);
+ Client client = ClientBuilder.newClient();
+ Form form = new Form();
+ form.param("parameter", "hello");
+ String text = client.target(inputPortalPage + "/unsecured").request().post(Entity.form(form), String.class);
+ Assert.assertTrue(text.contains("parameter=hello"));
+ client.close();
+ }
+
+ @Test
+ public void testPostSimpleLoginLogoutIdpInitiatedRedirectTo() {
+ samlidpInitiatedLoginPage.setAuthRealm(SAMLSERVLETDEMO);
+ samlidpInitiatedLoginPage.setUrlName("sales-post2");
+ samlidpInitiatedLoginPage.navigateTo();
+
+ samlidpInitiatedLoginPage.form().login(bburkeUser);
+ assertCurrentUrlStartsWith(salesPost2ServletPage);
+ assertTrue(driver.getCurrentUrl().endsWith("/foo"));
+ waitUntilElement(By.xpath("//body")).text().contains("principal=bburke");
+ salesPost2ServletPage.logout();
+ checkLoggedOut(salesPost2ServletPage, testRealmSAMLPostLoginPage);
+ }
+
+ @Test
+ public void salesPostAssertionAndResponseSigTest() {
+ testSuccessfulAndUnauthorizedLogin(salesPostAssertionAndResponseSigPage, testRealmSAMLPostLoginPage);
+ }
+
+ @Test
+ public void testPostBadAssertionSignature() {
+ badAssertionSalesPostSigPage.navigateTo();
+ assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ testRealmSAMLPostLoginPage.form().login("bburke", "password");
+
+ waitUntilElement(By.xpath("//body")).text().contains("Error info: SamlAuthenticationError [reason=INVALID_SIGNATURE, status=null]");
+ assertEquals(driver.getCurrentUrl(), badAssertionSalesPostSigPage + "/saml");
+ }
+
+ @Test
+ public void testMissingAssertionSignature() {
+ missingAssertionSigPage.navigateTo();
+ assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ testRealmSAMLPostLoginPage.form().login("bburke", "password");
+
+ waitUntilElement(By.xpath("//body")).text().contains("Error info: SamlAuthenticationError [reason=INVALID_SIGNATURE, status=null]");
+ assertEquals(driver.getCurrentUrl(), missingAssertionSigPage + "/saml");
+ }
+
+ @Test
+ public void testErrorHandling() throws Exception {
+ Client client = ClientBuilder.newClient();
+ // make sure
+ Response response = client.target(employeeSigServletPage.toString()).request().get();
+ response.close();
+ SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
+ .destination(employeeSigServletPage.toString() + "/saml")
+ .issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
+ .status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
+ BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder()
+ .relayState(null);
+ Document document = builder.buildDocument();
+ URI uri = binding.redirectBinding(document).generateURI(employeeSigServletPage.toString() + "/saml", false);
+ response = client.target(uri).request().get();
+ String errorPage = response.readEntity(String.class);
+ response.close();
+ Assert.assertTrue(errorPage.contains("Error info: SamlAuthenticationError [reason=ERROR_STATUS"));
+ Assert.assertFalse(errorPage.contains("status=null"));
+ client.close();
+ }
+
+ @Test
+ public void testRelayStateEncoding() throws Exception {
+ // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
+ // at the relay state
+ employeeServletPage.navigateTo();
+ assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ testRealmSAMLPostLoginPage.form().login("bburke", "password");
+ assertCurrentUrlStartsWith(employeeServletPage);
+ waitUntilElement(By.xpath("//body")).text().contains("Relay state: " + SamlSPFacade.RELAY_STATE);
+ waitUntilElement(By.xpath("//body")).text().not().contains("SAML response: null");
+ }
+
+ @Test
+ public void testAttributes() throws Exception {
+ ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "http://localhost:8081/employee2/");
+ ProtocolMappersResource protocolMappersResource = clientResource.getProtocolMappers();
+
+ Map<String, String> config = new LinkedHashMap<>();
+ config.put("attribute.nameformat", "Basic");
+ config.put("user.attribute", "topAttribute");
+ config.put("attribute.name", "topAttribute");
+ createProtocolMapper(protocolMappersResource, "topAttribute", "saml", "saml-user-attribute-mapper", config);
+
+ config = new LinkedHashMap<>();
+ config.put("attribute.nameformat", "Basic");
+ config.put("user.attribute", "level2Attribute");
+ config.put("attribute.name", "level2Attribute");
+ createProtocolMapper(protocolMappersResource, "level2Attribute", "saml", "saml-user-attribute-mapper", config);
+
+ config = new LinkedHashMap<>();
+ config.put("attribute.nameformat", "Basic");
+ config.put("single", "true");
+ config.put("attribute.name", "group");
+ createProtocolMapper(protocolMappersResource, "groups", "saml", "saml-group-membership-mapper", config);
+
+ setRolesToCheck("manager,user");
+
+ employee2ServletPage.navigateTo();
+ assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ testRealmSAMLPostLoginPage.form().login("level2GroupUser", "password");
+
+ driver.navigate().to(employee2ServletPage.toString() + "/getAttributes");
+ waitUntilElement(By.xpath("//body")).text().contains("topAttribute: true");
+ waitUntilElement(By.xpath("//body")).text().contains("level2Attribute: true");
+ waitUntilElement(By.xpath("//body")).text().contains("attribute email: level2@redhat.com");
+ waitUntilElement(By.xpath("//body")).text().not().contains("group: []");
+ waitUntilElement(By.xpath("//body")).text().not().contains("group: null");
+ waitUntilElement(By.xpath("//body")).text().contains("group: [level2]");
+
+ employee2ServletPage.logout();
+ checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
+
+ setRolesToCheck("manager,employee,user");
+
+ employee2ServletPage.navigateTo();
+ assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ testRealmSAMLPostLoginPage.form().login(bburkeUser);
+
+ driver.navigate().to(employee2ServletPage.toString() + "/getAttributes");
+ waitUntilElement(By.xpath("//body")).text().contains("attribute email: bburke@redhat.com");
+ waitUntilElement(By.xpath("//body")).text().contains("friendlyAttribute email: bburke@redhat.com");
+ waitUntilElement(By.xpath("//body")).text().contains("phone: 617");
+ waitUntilElement(By.xpath("//body")).text().contains("friendlyAttribute phone: null");
+
+ employee2ServletPage.logout();
+ checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
+
+ config = new LinkedHashMap<>();
+ config.put("attribute.value", "hard");
+ config.put("attribute.nameformat", "Basic");
+ config.put("attribute.name", "hardcoded-attribute");
+ createProtocolMapper(protocolMappersResource, "hardcoded-attribute", "saml", "saml-hardcode-attribute-mapper", config);
+
+ config = new LinkedHashMap<>();
+ config.put("role", "hardcoded-role");
+ createProtocolMapper(protocolMappersResource, "hardcoded-role", "saml", "saml-hardcode-role-mapper", config);
+
+ config = new LinkedHashMap<>();
+ config.put("new.role.name", "pee-on");
+ config.put("role", "http://localhost:8081/employee/.employee");
+ createProtocolMapper(protocolMappersResource, "renamed-employee-role", "saml", "saml-role-name-mapper", config);
+
+ for (ProtocolMapperRepresentation mapper : clientResource.toRepresentation().getProtocolMappers()) {
+ if (mapper.getName().equals("role-list")) {
+ protocolMappersResource.delete(mapper.getId());
+
+ mapper.setId(null);
+ mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
+ mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
+ protocolMappersResource.createMapper(mapper);
+ }
+ }
+
+ setRolesToCheck("pee-on,el-jefe,manager,hardcoded-role");
+
+ config = new LinkedHashMap<>();
+ config.put("new.role.name", "el-jefe");
+ config.put("role", "user");
+ createProtocolMapper(protocolMappersResource, "renamed-role", "saml", "saml-role-name-mapper", config);
+
+ employee2ServletPage.navigateTo();
+ assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ testRealmSAMLPostLoginPage.form().login(bburkeUser);
+
+ driver.navigate().to(employee2ServletPage.toString() + "/getAttributes");
+ waitUntilElement(By.xpath("//body")).text().contains("hardcoded-attribute: hard");
+ employee2ServletPage.checkRolesEndPoint(false);
+ employee2ServletPage.logout();
+ checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
+ }
+
+ private void createProtocolMapper(ProtocolMappersResource resource, String name, String protocol, String protocolMapper, Map<String, String> config) {
+ ProtocolMapperRepresentation representation = new ProtocolMapperRepresentation();
+ representation.setName(name);
+ representation.setProtocol(protocol);
+ representation.setProtocolMapper(protocolMapper);
+ representation.setConfig(config);
+ resource.createMapper(representation);
+ }
+
+ private void setRolesToCheck(String roles) {
+ employee2ServletPage.navigateTo();
+ assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
+ testRealmSAMLPostLoginPage.form().login(bburkeUser);
+ driver.navigate().to(employee2ServletPage.toString() + "/setCheckRoles?roles=" + roles);
employee2ServletPage.logout();
}
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/bad-assertion-sales-post-sig/WEB-INF/keycloak-saml.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/bad-assertion-sales-post-sig/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..2ea7ff7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/bad-assertion-sales-post-sig/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+ ~ 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.
+ -->
+
+<keycloak-saml-adapter>
+ <SP entityID="http://localhost:8081/bad-assertion-sales-post-sig/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+ <Keys>
+ <Key signing="true" >
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <PrivateKey alias="http://localhost:8081/bad-realm-sales-post-sig/" password="test123"/>
+ <Certificate alias="http://localhost:8081/bad-realm-sales-post-sig/"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ <PrincipalNameMapping policy="FROM_NAME_ID"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp">
+ <SingleSignOnService signRequest="true"
+ validateAssertionSignature="true"
+ requestBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+
+ <SingleLogoutService
+ validateRequestSignature="true"
+ validateResponseSignature="true"
+ signRequest="true"
+ signResponse="true"
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+ <Keys>
+ <Key signing="true">
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <Certificate alias="demo"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ </IDP>
+ </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/bad-assertion-sales-post-sig/WEB-INF/keystore.jks b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/bad-assertion-sales-post-sig/WEB-INF/keystore.jks
new file mode 100755
index 0000000..215384c
Binary files /dev/null and b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/bad-assertion-sales-post-sig/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee/WEB-INF/keycloak-saml.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..96f0b86
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,42 @@
+<!--
+ ~ 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.
+ -->
+
+<keycloak-saml-adapter>
+ <SP entityID="http://localhost:8081/employee/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+ <PrincipalNameMapping policy="FROM_NAME_ID"/>
+ <RoleIdentifiers>
+ <Attribute name="memberOf"/>
+ <Attribute name="Role"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp">
+ <SingleSignOnService requestBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+
+ <SingleLogoutService
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+ </IDP>
+ </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee/WEB-INF/web.xml
new file mode 100644
index 0000000..0199588
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/employee/WEB-INF/web.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>%CONTEXT_PATH%</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.SamlSPFacade</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>manager</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK-SAML</auth-method>
+ <realm-name>demo</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>manager</role-name>
+ </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/input-portal/WEB-INF/keycloak-saml.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/input-portal/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..e1cd76a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/input-portal/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,41 @@
+<!--
+ ~ 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.
+ -->
+
+<keycloak-saml-adapter>
+ <SP entityID="http://localhost:8081/input-portal/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+ <PrincipalNameMapping policy="FROM_NAME_ID"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp">
+ <SingleSignOnService requestBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+
+ <SingleLogoutService
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+ </IDP>
+ </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/input-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/input-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..865dc8a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/input-portal/WEB-INF/web.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>%CONTEXT_PATH%</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/secured/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>manager</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK-SAML</auth-method>
+ <realm-name>demo</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>manager</role-name>
+ </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..936fb21
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,60 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2016 Red Hat, Inc., and individual 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.
+ -->
+
+<keycloak-saml-adapter>
+ <SP entityID="http://localhost:8081/missing-assertion-sig/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+ <Keys>
+ <Key signing="true" >
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+ <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ <PrincipalNameMapping policy="FROM_NAME_ID"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp"
+ signaturesRequired="true">
+ <SingleSignOnService requestBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ validateAssertionSignature="true"
+ validateResponseSignature="false"
+ />
+
+ <SingleLogoutService
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+ <Keys>
+ <Key signing="true">
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <Certificate alias="demo"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ </IDP>
+ </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks
new file mode 100755
index 0000000..144830b
Binary files /dev/null and b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post2/WEB-INF/keycloak-saml.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post2/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..eae5b14
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post2/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,41 @@
+<!--
+ ~ 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.
+ -->
+
+<keycloak-saml-adapter>
+ <SP entityID="http://localhost:8081/sales-post2/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+ <PrincipalNameMapping policy="FROM_NAME_ID"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp">
+ <SingleSignOnService requestBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+
+ <SingleLogoutService
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+ </IDP>
+ </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..94c3f4d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,60 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2016 Red Hat, Inc., and individual 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.
+ -->
+
+<keycloak-saml-adapter>
+ <SP entityID="http://localhost:8081/sales-post-assertion-and-response-sig/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+ <Keys>
+ <Key signing="true" >
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+ <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ <PrincipalNameMapping policy="FROM_NAME_ID"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp"
+ signaturesRequired="true">
+ <SingleSignOnService requestBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ validateAssertionSignature="true"
+ validateResponseSignature="true"
+ />
+
+ <SingleLogoutService
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/demo/protocol/saml"
+ />
+ <Keys>
+ <Key signing="true">
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <Certificate alias="demo"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ </IDP>
+ </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks
new file mode 100755
index 0000000..144830b
Binary files /dev/null and b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks differ
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 5a1d2c6..0e25d89 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
@@ -68,6 +68,101 @@
],
"clients": [
{
+ "clientId": "http://localhost:8081/missing-assertion-sig/",
+ "enabled": true,
+ "protocol": "saml",
+ "fullScopeAllowed": true,
+ "baseUrl": "http://localhost:8080/missing-assertion-sig",
+ "redirectUris": [
+ "http://localhost:8080/missing-assertion-sig/*"
+ ],
+ "attributes": {
+ "saml_assertion_consumer_url_post": "http://localhost:8080/missing-assertion-sig/saml",
+ "saml_assertion_consumer_url_redirect": "http://localhost:8080/missing-assertion-sig/saml",
+ "saml_single_logout_service_url_post": "http://localhost:8080/missing-assertion-sig/saml",
+ "saml_single_logout_service_url_redirect": "http://localhost:8080/missing-assertion-sig/saml",
+ "saml.server.signature": "true",
+ "saml.assertion.signature": "false",
+ "saml.signature.algorithm": "RSA_SHA256",
+ "saml.client.signature": "true",
+ "saml.authnstatement": "true",
+ "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+ }
+ },
+ {
+ "clientId": "http://localhost:8081/bad-assertion-sales-post-sig/",
+ "enabled": true,
+ "protocol": "saml",
+ "fullScopeAllowed": true,
+ "baseUrl": "http://localhost:8080/bad-assertion-sales-post-sig/",
+ "adminUrl": "http://localhost:8080/bad-assertion-sales-post-sig/saml",
+ "redirectUris": [
+ "http://localhost:8080/bad-assertion-sales-post-sig/*"
+ ],
+ "attributes": {
+ "saml.assertion.signature": "true",
+ "saml.client.signature": "true",
+ "saml.authnstatement": "true",
+ "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+ }
+ },
+ {
+ "clientId": "http://localhost:8081/input-portal/",
+ "enabled": true,
+ "fullScopeAllowed": true,
+ "protocol": "saml",
+ "baseUrl": "http://localhost:8080/input-portal",
+ "redirectUris": [
+ "http://localhost:8080/input-portal/*"
+ ],
+ "attributes": {
+ "saml.authnstatement": "true",
+ "saml_assertion_consumer_url_post": "http://localhost:8080/input-portal/saml",
+ "saml_assertion_consumer_url_redirect": "http://localhost:8080/input-portal/saml",
+ "saml_single_logout_service_url_post": "http://localhost:8080/input-portal/saml",
+ "saml_single_logout_service_url_redirect": "http://localhost:8080/input-portal/saml"
+ }
+ },
+ {
+ "clientId": "http://localhost:8081/sales-post-assertion-and-response-sig/",
+ "enabled": true,
+ "protocol": "saml",
+ "fullScopeAllowed": true,
+ "baseUrl": "http://localhost:8080/sales-post-assertion-and-response-sig",
+ "redirectUris": [
+ "http://localhost:8080/sales-post-assertion-and-response-sig/*"
+ ],
+ "attributes": {
+ "saml_assertion_consumer_url_post": "http://localhost:8080/sales-post-assertion-and-response-sig/saml",
+ "saml_assertion_consumer_url_redirect": "http://localhost:8080/sales-post-assertion-and-response-sig/saml",
+ "saml_single_logout_service_url_post": "http://localhost:8080/sales-post-assertion-and-response-sig/saml",
+ "saml_single_logout_service_url_redirect": "http://localhost:8080/sales-post-assertion-and-response-sig/saml",
+ "saml.server.signature": "true",
+ "saml.assertion.signature": "true",
+ "saml.signature.algorithm": "RSA_SHA256",
+ "saml.client.signature": "true",
+ "saml.authnstatement": "true",
+ "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+ }
+ },
+ {
+ "clientId": "http://localhost:8081/sales-post2/",
+ "enabled": true,
+ "fullScopeAllowed": true,
+ "protocol": "saml",
+ "baseUrl": "http://localhost:8080/sales-post2",
+ "redirectUris": [
+ "http://localhost:8080/sales-post2/*"
+ ],
+ "attributes": {
+ "saml.authnstatement": "true",
+ "saml_assertion_consumer_url_post": "http://localhost:8080/sales-post2/saml",
+ "saml_single_logout_service_url_post": "http://localhost:8080/sales-post2/saml",
+ "saml_idp_initiated_sso_url_name": "sales-post2",
+ "saml_idp_initiated_sso_relay_state": "redirectTo=/foo"
+ }
+ },
+ {
"clientId": "http://localhost:8081/sales-post/",
"enabled": true,
"fullScopeAllowed": true,
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml
index 4207f91..aa2c4b7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml
@@ -28,6 +28,10 @@
<url-pattern>/*</url-pattern>
</servlet-mapping>
+ <error-page>
+ <location>/error.html</location>
+ </error-page>
+
<security-constraint>
<web-resource-collection>
<web-resource-name>Application</web-resource-name>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLFilterAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLFilterAdapterTest.java
index 627e5f3..1dcf846 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLFilterAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLFilterAdapterTest.java
@@ -8,5 +8,5 @@ import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
* @author mhajas
*/
@AppServerContainer("app-server-eap6")
-public class EAPSAMLFilterAdapterTest extends AbstractSAMLFilterServletAdapterTest {
+public class EAP6SAMLFilterAdapterTest extends AbstractSAMLFilterServletAdapterTest {
}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/pom.xml
index 9c49390..15fc1c4 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/pom.xml
@@ -172,6 +172,18 @@
</systemPropertyVariables>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.jboss.shrinkwrap.resolver</groupId>
+ <artifactId>shrinkwrap-resolver-maven-plugin</artifactId>
+ <version>${version.shrinkwrap.resolvers}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>propagate-execution-context</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
</profile>
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index 6c25059..de3d65f 100755
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -780,6 +780,10 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-saml-adapter-api-public</artifactId>
+ </dependency>
<!--UNDERTOW-->