Merge pull request #3146 from mhajas/KEYCLOAK-3161
KEYCLOAK-3161 Migrate SAML adapter tests
This commit is contained in:
commit
9ffd6548ce
34 changed files with 1479 additions and 182 deletions
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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"));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
||||
Element filter = webXmlDoc.createElement("filter");
|
||||
Element filterName = webXmlDoc.createElement("filter-name");
|
||||
Element filterClass = webXmlDoc.createElement("filter-class");
|
||||
|
||||
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");
|
||||
|
||||
|
||||
Element urlPattern = webXmlDoc.createElement("url-pattern");
|
||||
|
||||
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()) {
|
||||
filter += "<dispatcher>" + testClass.getAnnotation(UseServletFilter.class).dispatcherType() + "</dispatcher>\n";
|
||||
Element dispatcher = webXmlDoc.createElement("dispatcher");
|
||||
dispatcher.setTextContent(testClass.getAnnotation(UseServletFilter.class).dispatcherType());
|
||||
filterMapping.appendChild(dispatcher);
|
||||
}
|
||||
filter += "</filter-mapping>\n";
|
||||
|
||||
webXmlContent = webXmlContent.replace("</module-name>", "</module-name> " + filter);
|
||||
|
||||
//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());
|
||||
|
||||
appendChildInDocument(webXmlDoc, "web-app", filterMapping);
|
||||
|
||||
//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();
|
||||
|
||||
|
||||
webXmlContent = webXmlContent.substring(0, start) + webXmlContent.substring(end);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
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.PackagingType;
|
||||
import org.jboss.shrinkwrap.resolver.api.maven.ScopeType;
|
||||
import org.jboss.shrinkwrap.resolver.api.maven.coordinate.MavenDependency;
|
||||
import org.jboss.shrinkwrap.resolver.api.maven.coordinate.MavenDependencyExclusion;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author mhajas
|
||||
*/
|
||||
public class SAMLFilterDependency implements MavenDependency {
|
||||
|
||||
private static File[] files;
|
||||
|
||||
protected final Logger log = org.jboss.logging.Logger.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
public Set<MavenDependencyExclusion> getExclusions() {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScopeType getScope() {
|
||||
return ScopeType.COMPILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptional() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackagingType getPackaging() {
|
||||
return PackagingType.JAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackagingType getType() {
|
||||
return PackagingType.JAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return System.getProperty("project.version");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupId() {
|
||||
return "org.keycloak";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArtifactId() {
|
||||
return "keycloak-saml-servlet-filter-adapter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toCanonicalForm() {
|
||||
return getGroupId() + ":" + getArtifactId() + ":" + getVersion();
|
||||
}
|
||||
|
||||
private void resolve() {
|
||||
log.info("Resolving SAMLFilter dependencies");
|
||||
files = Maven.configureResolver().addDependency(this)
|
||||
.resolve().withTransitivity().asFile();
|
||||
log.info("Resolving dependencies is finished with " + files.length + " files");
|
||||
}
|
||||
|
||||
public File[] getDependencies() {
|
||||
if (files == null) {
|
||||
resolve();
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
|
@ -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)) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -70,6 +85,9 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
|
|||
@Page
|
||||
protected SalesPostServlet salesPostServletPage;
|
||||
|
||||
@Page
|
||||
private SalesPost2Servlet salesPost2ServletPage;
|
||||
|
||||
@Page
|
||||
protected SalesPostEncServlet salesPostEncServletPage;
|
||||
|
||||
|
@ -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);
|
||||
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
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
Binary file not shown.
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
Binary file not shown.
|
@ -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>
|
Binary file not shown.
|
@ -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>
|
|
@ -67,6 +67,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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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-->
|
||||
|
||||
|
|
Loading…
Reference in a new issue