/* * 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 org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; 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.admin.client.resource.RoleScopeResource; import org.keycloak.common.util.KeyUtils; import org.keycloak.common.util.PemUtils; import org.keycloak.dom.saml.v2.protocol.AuthnRequestType; import org.keycloak.keys.Attributes; import org.keycloak.keys.KeyProvider; import org.keycloak.keys.ImportedRsaKeyProviderFactory; import org.keycloak.protocol.saml.SamlConfigAttributes; import org.keycloak.protocol.saml.SamlProtocol; import org.keycloak.representations.idm.ComponentRepresentation; 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.RoleRepresentation; 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.saml.common.util.XmlKeyInfoKeyNameTransformer; import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.services.resources.RealmsResource; import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest; import org.keycloak.testsuite.adapter.page.*; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.auth.page.login.Login; import org.keycloak.testsuite.auth.page.login.SAMLIDPInitiatedLogin; import org.keycloak.testsuite.page.AbstractPage; import org.keycloak.testsuite.util.*; import org.keycloak.testsuite.util.SamlClient.Binding; import org.openqa.selenium.By; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Form; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilderException; import javax.xml.XMLConstants; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URI; import java.net.URL; import java.security.KeyPair; import java.security.PublicKey; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD; import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient; import static org.keycloak.testsuite.admin.Users.setPasswordFor; import static org.keycloak.testsuite.auth.page.AuthRealm.SAMLSERVLETDEMO; import static org.keycloak.testsuite.util.IOUtil.loadRealm; import static org.keycloak.testsuite.util.IOUtil.loadXML; import static org.keycloak.testsuite.util.IOUtil.modifyDocElementAttribute; import static org.keycloak.testsuite.util.Matchers.bodyHC; import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC; import static org.keycloak.testsuite.util.SamlClient.Binding.POST; import static org.keycloak.testsuite.util.SamlClient.idpInitiatedLogin; import static org.keycloak.testsuite.util.SamlClient.login; import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; import static org.keycloak.testsuite.util.WaitUtils.*; /** * @author mhajas */ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAdapterTest { @Page protected BadClientSalesPostSigServlet badClientSalesPostSigServletPage; @Page protected BadRealmSalesPostSigServlet badRealmSalesPostSigServletPage; @Page protected EmployeeAcsServlet employeeAcsServletPage; @Page protected Employee2Servlet employee2ServletPage; @Page protected EmployeeSigServlet employeeSigServletPage; @Page protected EmployeeSigPostNoIdpKeyServlet employeeSigPostNoIdpKeyServletPage; @Page protected EmployeeSigRedirNoIdpKeyServlet employeeSigRedirNoIdpKeyServletPage; @Page protected EmployeeSigRedirOptNoIdpKeyServlet employeeSigRedirOptNoIdpKeyServletPage; @Page protected EmployeeSigFrontServlet employeeSigFrontServletPage; @Page protected SalesMetadataServlet salesMetadataServletPage; @Page protected SalesPostServlet salesPostServletPage; @Page private SalesPost2Servlet salesPost2ServletPage; @Page protected SalesPostEncServlet salesPostEncServletPage; @Page protected SalesPostPassiveServlet salesPostPassiveServletPage; @Page protected SalesPostSigServlet salesPostSigServletPage; @Page protected SalesPostSigEmailServlet salesPostSigEmailServletPage; @Page protected SalesPostSigPersistentServlet salesPostSigPersistentServletPage; @Page protected SalesPostSigTransientServlet salesPostSigTransientServletPage; @Page protected SAMLIDPInitiatedLogin samlidpInitiatedLogin; protected boolean forbiddenIfNotAuthenticated = true; @Page protected SalesPostAssertionAndResponseSig salesPostAssertionAndResponseSigPage; @Page protected BadAssertionSalesPostSig badAssertionSalesPostSigPage; @Page protected MissingAssertionSig missingAssertionSigPage; @Page protected EmployeeServlet employeeServletPage; @Page protected DifferentCookieNameServlet differentCookieNameServletPage; @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); } @Deployment(name = BadRealmSalesPostSigServlet.DEPLOYMENT_NAME) protected static WebArchive badRealmSalesPostSig() { return samlServletDeployment(BadRealmSalesPostSigServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = EmployeeAcsServlet.DEPLOYMENT_NAME) protected static WebArchive employeeAssertionConsumerServiceUrlSet() { return samlServletDeployment(EmployeeAcsServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = Employee2Servlet.DEPLOYMENT_NAME) protected static WebArchive employee2() { return samlServletDeployment(Employee2Servlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = EmployeeSigServlet.DEPLOYMENT_NAME) protected static WebArchive employeeSig() { return samlServletDeployment(EmployeeSigServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = EmployeeSigPostNoIdpKeyServlet.DEPLOYMENT_NAME) protected static WebArchive employeeSigPostNoIdpKeyServlet() { return samlServletDeployment(EmployeeSigPostNoIdpKeyServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = EmployeeSigRedirNoIdpKeyServlet.DEPLOYMENT_NAME) protected static WebArchive employeeSigRedirNoIdpKeyServlet() { return samlServletDeployment(EmployeeSigRedirNoIdpKeyServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = EmployeeSigRedirOptNoIdpKeyServlet.DEPLOYMENT_NAME) protected static WebArchive employeeSigRedirOptNoIdpKeyServlet() { return samlServletDeployment(EmployeeSigRedirOptNoIdpKeyServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = EmployeeSigFrontServlet.DEPLOYMENT_NAME) protected static WebArchive employeeSigFront() { return samlServletDeployment(EmployeeSigFrontServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = SalesMetadataServlet.DEPLOYMENT_NAME) protected static WebArchive salesMetadata() { return samlServletDeployment(SalesMetadataServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = SalesPostServlet.DEPLOYMENT_NAME) protected static WebArchive salesPost() { return samlServletDeployment(SalesPostServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = SalesPostEncServlet.DEPLOYMENT_NAME) protected static WebArchive salesPostEnc() { return samlServletDeployment(SalesPostEncServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = SalesPostPassiveServlet.DEPLOYMENT_NAME) protected static WebArchive salesPostPassive() { return samlServletDeployment(SalesPostPassiveServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = SalesPostSigServlet.DEPLOYMENT_NAME) protected static WebArchive salesPostSig() { return samlServletDeployment(SalesPostSigServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = SalesPostSigEmailServlet.DEPLOYMENT_NAME) protected static WebArchive salesPostSigEmail() { return samlServletDeployment(SalesPostSigEmailServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = SalesPostSigPersistentServlet.DEPLOYMENT_NAME) protected static WebArchive salesPostSigPersistent() { return samlServletDeployment(SalesPostSigPersistentServlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = SalesPostSigTransientServlet.DEPLOYMENT_NAME) protected static WebArchive salesPostSigTransient() { 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, ServletTestUtils.class); } @Deployment(name = SalesPost2Servlet.DEPLOYMENT_NAME) protected static WebArchive salesPost2() { return samlServletDeployment(SalesPost2Servlet.DEPLOYMENT_NAME, SendUsernameServlet.class); } @Deployment(name = DifferentCookieNameServlet.DEPLOYMENT_NAME) protected static WebArchive differentCokieName() { return samlServletDeployment(DifferentCookieNameServlet.DEPLOYMENT_NAME, "different-cookie-name/WEB-INF/web.xml", 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, ServletTestUtils.class); } @Override public void addAdapterTestRealms(List<RealmRepresentation> testRealms) { testRealms.add(loadRealm("/adapter-test/keycloak-saml/testsaml.json")); } @Override public void setDefaultPageUriParameters() { super.setDefaultPageUriParameters(); testRealmPage.setAuthRealm(SAMLSERVLETDEMO); testRealmSAMLRedirectLoginPage.setAuthRealm(SAMLSERVLETDEMO); testRealmSAMLPostLoginPage.setAuthRealm(SAMLSERVLETDEMO); } private void assertForbidden(AbstractPage page, String expectedNotContains) { page.navigateTo(); waitUntilElement(By.xpath("//body")).text().not().contains(expectedNotContains); assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT)); } private void assertSuccessfullyLoggedIn(AbstractPage page, String expectedText) { page.navigateTo(); waitUntilElement(By.xpath("//body")).text().contains(expectedText); } 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(expectedNotContains); //Different 403 status page on EAP and Wildfly assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT)); } 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(expectedString); } private void testSuccessfulAndUnauthorizedLogin(SAMLServlet page, Login 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(); checkLoggedOut(page, loginPage); assertForbiddenLogin(page, "unauthorized", "password", loginPage, expectedNotContains); page.logout(); checkLoggedOut(page, loginPage); } private void checkLoggedOut(AbstractPage page, Login loginPage) { page.navigateTo(); waitForPageToLoad(driver); assertCurrentUrlStartsWith(loginPage); } @Test public void disabledClientTest() { ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "http://localhost:8081/sales-post-sig/"); ClientRepresentation client = clientResource.toRepresentation(); client.setEnabled(false); clientResource.update(client); salesPostSigServletPage.navigateTo(); waitUntilElement(By.xpath("//body")).text().contains("Login requester not enabled"); client.setEnabled(true); clientResource.update(client); } @Test public void unauthorizedSSOTest() { 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, "principal=bburke"); assertSuccessfullyLoggedIn(salesPostSigServletPage, "principal=bburke"); assertSuccessfullyLoggedIn(employee2ServletPage, "principal=bburke"); assertSuccessfullyLoggedIn(salesPostEncServletPage, "principal=bburke"); employeeSigFrontServletPage.logout(); checkLoggedOut(employeeSigFrontServletPage, testRealmSAMLRedirectLoginPage); checkLoggedOut(employeeSigServletPage, testRealmSAMLRedirectLoginPage); salesPostPassiveServletPage.navigateTo(); if (forbiddenIfNotAuthenticated) { assertOnForbiddenPage(); } else { waitUntilElement(By.xpath("//body")).text().contains("principal=null"); } checkLoggedOut(salesPostSigEmailServletPage, testRealmSAMLPostLoginPage); } @Test public void badClientSalesPostSigTest() { badClientSalesPostSigServletPage.navigateTo(); waitUntilElement(By.xpath("//body")).text().contains("Invalid requester"); } @Test public void badRealmSalesPostSigTest() { badRealmSalesPostSigServletPage.navigateTo(); testRealmSAMLRedirectLoginPage.form().login(bburkeUser); waitUntilElement(By.xpath("//body")).text().not().contains("principal="); //Different 403 status page on EAP and Wildfly assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains(FORBIDDEN_TEXT)); } @Test public void employee2Test() { testSuccessfulAndUnauthorizedLogin(employee2ServletPage, testRealmSAMLPostLoginPage); } @Test public void employeeSigTest() { testSuccessfulAndUnauthorizedLogin(employeeSigServletPage, testRealmSAMLRedirectLoginPage); } @Test public void employeeAcsTest() { SAMLDocumentHolder samlResponse = new SamlClient(employeeAcsServletPage.buildUri()).getSamlResponse(Binding.POST, (client, context, strategy) -> { strategy.setRedirectable(false); return client.execute(new HttpGet(employeeAcsServletPage.buildUri()), context); }); assertThat(samlResponse.getSamlObject(), instanceOf(AuthnRequestType.class)); assertThat(((AuthnRequestType) samlResponse.getSamlObject()).getAssertionConsumerServiceURL(), notNullValue()); assertThat(((AuthnRequestType) samlResponse.getSamlObject()).getAssertionConsumerServiceURL().getPath(), is("/employee-acs/a/different/endpoint/for/saml")); assertSuccessfulLogin(employeeAcsServletPage, bburkeUser, testRealmSAMLPostLoginPage, "principal=bburke"); } private static final KeyPair NEW_KEY_PAIR = KeyUtils.generateRsaKeyPair(1024); private static final String NEW_KEY_PRIVATE_KEY_PEM = PemUtils.encodeKey(NEW_KEY_PAIR.getPrivate()); private PublicKey createKeys(String priority) throws Exception { PublicKey publicKey = NEW_KEY_PAIR.getPublic(); ComponentRepresentation rep = new ComponentRepresentation(); rep.setName("mycomponent"); rep.setParentId("demo"); rep.setProviderId(ImportedRsaKeyProviderFactory.ID); rep.setProviderType(KeyProvider.class.getName()); org.keycloak.common.util.MultivaluedHashMap config = new org.keycloak.common.util.MultivaluedHashMap(); config.addFirst("priority", priority); config.addFirst(Attributes.PRIVATE_KEY_KEY, NEW_KEY_PRIVATE_KEY_PEM); rep.setConfig(config); testRealmResource().components().add(rep); return publicKey; } private void dropKeys(String priority) { for (ComponentRepresentation c : testRealmResource().components().query("demo", KeyProvider.class.getName())) { if (c.getConfig().getFirst("priority").equals(priority)) { testRealmResource().components().component(c.getId()).remove(); return; } } throw new RuntimeException("Failed to find keys"); } private void testRotatedKeysPropagated(SAMLServlet servletPage, Login loginPage) throws Exception { boolean keyDropped = false; try { log.info("Creating new key"); createKeys("1000"); testSuccessfulAndUnauthorizedLogin(servletPage, loginPage); log.info("Dropping new key"); dropKeys("1000"); keyDropped = true; testSuccessfulAndUnauthorizedLogin(servletPage, loginPage); } finally { if (! keyDropped) { dropKeys("1000"); } } } @Test public void employeeSigPostNoIdpKeyTest() throws Exception { testRotatedKeysPropagated(employeeSigPostNoIdpKeyServletPage, testRealmSAMLPostLoginPage); } @Test public void employeeSigPostNoIdpKeyTestNoKeyNameInKeyInfo() throws Exception { RealmRepresentation r = testRealmResource().toRepresentation(); r.getAttributes().put(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER, XmlKeyInfoKeyNameTransformer.NONE.name()); testRotatedKeysPropagated(employeeSigPostNoIdpKeyServletPage, testRealmSAMLPostLoginPage); } @Test public void employeeSigPostNoIdpKeyTestCertSubjectAsKeyNameInKeyInfo() throws Exception { RealmRepresentation r = testRealmResource().toRepresentation(); r.getAttributes().put(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER, XmlKeyInfoKeyNameTransformer.CERT_SUBJECT.name()); testRotatedKeysPropagated(employeeSigPostNoIdpKeyServletPage, testRealmSAMLPostLoginPage); } @Test public void employeeSigPostNoIdpKeyTestKeyIdAsKeyNameInKeyInfo() throws Exception { RealmRepresentation r = testRealmResource().toRepresentation(); r.getAttributes().put(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER, XmlKeyInfoKeyNameTransformer.KEY_ID.name()); testRotatedKeysPropagated(employeeSigPostNoIdpKeyServletPage, testRealmSAMLPostLoginPage); } @Test public void employeeSigRedirNoIdpKeyTest() throws Exception { testRotatedKeysPropagated(employeeSigRedirNoIdpKeyServletPage, testRealmSAMLRedirectLoginPage); } @Test public void employeeSigRedirNoIdpKeyTestNoKeyNameInKeyInfo() throws Exception { RealmRepresentation r = testRealmResource().toRepresentation(); r.getAttributes().put(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER, XmlKeyInfoKeyNameTransformer.NONE.name()); testRotatedKeysPropagated(employeeSigRedirNoIdpKeyServletPage, testRealmSAMLRedirectLoginPage); } @Test public void employeeSigRedirNoIdpKeyTestCertSubjectAsKeyNameInKeyInfo() throws Exception { RealmRepresentation r = testRealmResource().toRepresentation(); r.getAttributes().put(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER, XmlKeyInfoKeyNameTransformer.CERT_SUBJECT.name()); testRotatedKeysPropagated(employeeSigRedirNoIdpKeyServletPage, testRealmSAMLRedirectLoginPage); } @Test public void employeeSigRedirNoIdpKeyTestKeyIdAsKeyNameInKeyInfo() throws Exception { RealmRepresentation r = testRealmResource().toRepresentation(); r.getAttributes().put(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER, XmlKeyInfoKeyNameTransformer.KEY_ID.name()); testRotatedKeysPropagated(employeeSigRedirNoIdpKeyServletPage, testRealmSAMLRedirectLoginPage); } @Test public void employeeSigRedirOptNoIdpKeyTest() throws Exception { testRotatedKeysPropagated(employeeSigRedirOptNoIdpKeyServletPage, testRealmSAMLRedirectLoginPage); } @Test public void employeeSigFrontTest() { testSuccessfulAndUnauthorizedLogin(employeeSigFrontServletPage, testRealmSAMLRedirectLoginPage); } @Test public void salesMetadataTest() throws Exception { Document doc = loadXML(AbstractSAMLServletsAdapterTest.class.getResourceAsStream("/adapter-test/keycloak-saml/sp-metadata.xml")); modifyDocElementAttribute(doc, "SingleLogoutService", "Location", "8080", System.getProperty("app.server.http.port", null)); modifyDocElementAttribute(doc, "AssertionConsumerService", "Location", "8080", System.getProperty("app.server.http.port", null)); ClientRepresentation clientRep = testRealmResource().convertClientDescription(IOUtil.documentToString(doc)); String appServerUrl; if (Boolean.parseBoolean(System.getProperty("app.server.ssl.required"))) { appServerUrl = "https://localhost:" + System.getProperty("app.server.https.port", "8543") + "/"; } else { appServerUrl = "http://localhost:" + System.getProperty("app.server.http.port", "8280") + "/"; } clientRep.setAdminUrl(appServerUrl + "sales-metadata/saml"); Response response = testRealmResource().clients().create(clientRep); assertEquals(201, response.getStatus()); response.close(); testSuccessfulAndUnauthorizedLogin(salesMetadataServletPage, testRealmSAMLPostLoginPage); } @Test public void salesPostTestCompositeRoleForUser() { UserRepresentation topGroupUser = createUserRepresentation("topGroupUser", "top@redhat.com", "", "", true); setPasswordFor(topGroupUser, PASSWORD); assertSuccessfulLogin(salesPostServletPage, topGroupUser, testRealmSAMLPostLoginPage, "principal=topgroupuser"); salesPostServletPage.logout(); checkLoggedOut(salesPostServletPage, testRealmSAMLPostLoginPage); } @Test public void salesPostTest() { testSuccessfulAndUnauthorizedLogin(salesPostServletPage, testRealmSAMLPostLoginPage); } @Test public void salesPostEncTest() { testSuccessfulAndUnauthorizedLogin(salesPostEncServletPage, testRealmSAMLPostLoginPage); } @Test public void salesPostPassiveTest() { salesPostPassiveServletPage.navigateTo(); if (forbiddenIfNotAuthenticated) { assertOnForbiddenPage(); } else { waitUntilElement(By.xpath("//body")).text().contains("principal=null"); } assertSuccessfulLogin(salesPostServletPage, bburkeUser, testRealmSAMLPostLoginPage, "principal=bburke"); assertSuccessfullyLoggedIn(salesPostPassiveServletPage, "principal=bburke"); salesPostPassiveServletPage.logout(); salesPostPassiveServletPage.navigateTo(); if (forbiddenIfNotAuthenticated) { assertOnForbiddenPage(); } else { waitUntilElement(By.xpath("//body")).text().contains("principal=null"); } assertForbiddenLogin(salesPostServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage, "principal="); assertForbidden(salesPostPassiveServletPage, "principal="); salesPostPassiveServletPage.logout(); } @Test public void salesPostSigTest() { testSuccessfulAndUnauthorizedLogin(salesPostSigServletPage, testRealmSAMLPostLoginPage); } @Test // https://issues.jboss.org/browse/KEYCLOAK-3971 public void salesPostSigTestUnicodeCharacters() { final String username = "ěščřžýáíRoàåéèíñòøöùüßÅÄÖÜ"; UserRepresentation user = UserBuilder .edit(createUserRepresentation(username, "xyz@redhat.com", "ěščřžýáí", "RoàåéèíñòøöùüßÅÄÖÜ", true)) .addPassword(PASSWORD) .build(); String userId = createUserAndResetPasswordWithAdminClient(testRealmResource(), user, PASSWORD); final RoleScopeResource realmRoleRes = testRealmResource().users().get(userId).roles().realmLevel(); List<RoleRepresentation> availableRoles = realmRoleRes.listAvailable(); realmRoleRes.add(availableRoles.stream().filter(r -> r.getName().equalsIgnoreCase("manager")).collect(Collectors.toList())); UserRepresentation storedUser = testRealmResource().users().get(userId).toRepresentation(); assertThat(storedUser, notNullValue()); assertThat("Database seems to be unable to store Unicode for username. Refer to KEYCLOAK-3439 and related issues.", storedUser.getUsername(), equalToIgnoringCase(username)); assertSuccessfulLogin(salesPostSigServletPage, user, testRealmSAMLPostLoginPage, "principal=" + storedUser.getUsername()); salesPostSigServletPage.logout(); checkLoggedOut(salesPostSigServletPage, testRealmSAMLPostLoginPage); } @Test // https://issues.jboss.org/browse/KEYCLOAK-3971 public void employeeSigTestUnicodeCharacters() { final String username = "ěščřžýáíRoàåéèíñòøöùüßÅÄÖÜ"; UserRepresentation user = UserBuilder .edit(createUserRepresentation(username, "xyz@redhat.com", "ěščřžýáí", "RoàåéèíñòøöùüßÅÄÖÜ", true)) .addPassword(PASSWORD) .build(); String userId = createUserAndResetPasswordWithAdminClient(testRealmResource(), user, PASSWORD); final RoleScopeResource realmRoleRes = testRealmResource().users().get(userId).roles().realmLevel(); List<RoleRepresentation> availableRoles = realmRoleRes.listAvailable(); realmRoleRes.add(availableRoles.stream().filter(r -> r.getName().equalsIgnoreCase("manager")).collect(Collectors.toList())); UserRepresentation storedUser = testRealmResource().users().get(userId).toRepresentation(); assertThat(storedUser, notNullValue()); assertThat("Database seems to be unable to store Unicode for username. Refer to KEYCLOAK-3439 and related issues.", storedUser.getUsername(), equalToIgnoringCase(username)); assertSuccessfulLogin(employeeSigServletPage, user, testRealmSAMLRedirectLoginPage, "principal=" + storedUser.getUsername()); employeeSigServletPage.logout(); checkLoggedOut(employeeSigServletPage, testRealmSAMLRedirectLoginPage); } @Test public void salesPostSigEmailTest() { testSuccessfulAndUnauthorizedLogin(salesPostSigEmailServletPage, testRealmSAMLPostLoginPage, "principal=bburke@redhat.com"); } @Test public void salesPostSigPersistentTest() { salesPostSigPersistentServletPage.navigateTo(); testRealmSAMLPostLoginPage.form().login(bburkeUser); waitUntilElement(By.xpath("//body")).text().not().contains("bburke"); waitUntilElement(By.xpath("//body")).text().contains("principal=G-"); salesPostSigPersistentServletPage.logout(); checkLoggedOut(salesPostSigPersistentServletPage, testRealmSAMLPostLoginPage); assertForbiddenLogin(salesPostSigPersistentServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage, "principal="); salesPostSigPersistentServletPage.logout(); checkLoggedOut(salesPostSigPersistentServletPage, testRealmSAMLPostLoginPage); } @Test public void salesPostSigTransientTest() { salesPostSigTransientServletPage.navigateTo(); testRealmSAMLPostLoginPage.form().login(bburkeUser); waitUntilElement(By.xpath("//body")).text().not().contains("bburke"); waitUntilElement(By.xpath("//body")).text().contains("principal=G-"); salesPostSigTransientServletPage.logout(); checkLoggedOut(salesPostSigTransientServletPage, testRealmSAMLPostLoginPage); assertForbiddenLogin(salesPostSigTransientServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage, "principal="); salesPostSigTransientServletPage.logout(); checkLoggedOut(salesPostSigTransientServletPage, testRealmSAMLPostLoginPage); } @Test public void idpInitiatedLoginTest() { samlidpInitiatedLoginPage.setAuthRealm(SAMLSERVLETDEMO); samlidpInitiatedLoginPage.setUrlName("employee2"); samlidpInitiatedLoginPage.navigateTo(); samlidpInitiatedLoginPage.form().login(bburkeUser); waitUntilElement(By.xpath("//body")).text().contains("principal=bburke"); assertSuccessfullyLoggedIn(salesPostSigServletPage, "principal=bburke"); employee2ServletPage.logout(); checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage); } @Test public void idpInitiatedUnauthorizedLoginTest() { 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(FORBIDDEN_TEXT)); assertForbidden(employee2ServletPage, "principal="); employee2ServletPage.logout(); checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage); } @Test public void testSavedPostRequest() { inputPortalPage.navigateTo(); assertCurrentUrlStartsWith(inputPortalPage); inputPortalPage.execute("hello"); assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage); testRealmLoginPage.form().login("bburke@redhat.com", "password"); Assert.assertEquals(driver.getCurrentUrl(), inputPortalPage + "/secured/post"); waitUntilElement(By.xpath("//body")).text().contains("parameter=hello"); // test that user principal and KeycloakSecurityContext available driver.navigate().to(inputPortalPage + "/insecure"); waitUntilElement(By.xpath("//body")).text().contains("Insecure Page"); if (System.getProperty("insecure.user.principal.unsupported") == null) waitUntilElement(By.xpath("//body")).text().contains("UserPrincipal"); // test logout inputPortalPage.logout(); // test unsecured POST KEYCLOAK-901 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"); 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"); assertEquals(driver.getCurrentUrl(), missingAssertionSigPage + "/saml"); } @Test public void testErrorHandlingUnsigned() throws Exception { Client client = ClientBuilder.newClient(); // make sure Response response = client.target(employeeServletPage.toString()).request().get(); response.close(); SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder() .destination(employeeServletPage.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(employeeServletPage.toString() + "/saml", false); response = client.target(uri).request().get(); String errorPage = response.readEntity(String.class); response.close(); Assert.assertEquals(403, response.getStatus()); } @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); waitForPageToLoad(driver); String pageSource = driver.getPageSource(); assertThat(pageSource, containsString("Relay state: " + SamlSPFacade.RELAY_STATE)); assertThat(pageSource, not(containsString("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); } @Test public void idpMetadataValidation() throws Exception { driver.navigate().to(authServerPage.toString() + "/realms/" + SAMLSERVLETDEMO + "/protocol/saml/descriptor"); validateXMLWithSchema(driver.getPageSource(), "/adapter-test/keycloak-saml/metadata-schema/saml-schema-metadata-2.0.xsd"); } @Test public void spMetadataValidation() throws Exception { ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "http://localhost:8081/sales-post-sig/"); ClientRepresentation representation = clientResource.toRepresentation(); Client client = ClientBuilder.newClient(); WebTarget target = client.target(authServerPage.toString() + "/admin/realms/" + SAMLSERVLETDEMO + "/clients/" + representation.getId() + "/installation/providers/saml-sp-descriptor"); Response response = target.request().header(HttpHeaders.AUTHORIZATION, "Bearer " + adminClient.tokenManager().getAccessToken().getToken()).get(); validateXMLWithSchema(response.readEntity(String.class), "/adapter-test/keycloak-saml/metadata-schema/saml-schema-metadata-2.0.xsd"); response.close(); } @Test //KEYCLOAK-4020 public void testBooleanAttribute() throws Exception { AuthnRequestType req = SamlClient.createLoginRequestDocument("http://localhost:8081/employee2/", getAppServerSamlEndpoint(employee2ServletPage).toString(), getAuthServerSamlEndpoint(SAMLSERVLETDEMO)); Document doc = SAML2Request.convert(req); SAMLDocumentHolder res = login(bburkeUser, getAuthServerSamlEndpoint(SAMLSERVLETDEMO), doc, null, SamlClient.Binding.POST, SamlClient.Binding.POST); Document responseDoc = res.getSamlDocument(); Element attribute = responseDoc.createElement("saml:Attribute"); attribute.setAttribute("Name", "boolean-attribute"); attribute.setAttribute("NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic"); Element attributeValue = responseDoc.createElement("saml:AttributeValue"); attributeValue.setAttribute("xmlns:xs", "http://www.w3.org/2001/XMLSchema"); attributeValue.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributeValue.setAttribute("xsi:type", "xs:boolean"); attributeValue.setTextContent("true"); attribute.appendChild(attributeValue); IOUtil.appendChildInDocument(responseDoc, "samlp:Response/saml:Assertion/saml:AttributeStatement", attribute); CloseableHttpResponse response = null; try (CloseableHttpClient client = HttpClientBuilder.create().build()) { HttpClientContext context = HttpClientContext.create(); HttpUriRequest post = SamlClient.Binding.POST.createSamlUnsignedResponse(getAppServerSamlEndpoint(employee2ServletPage), null, responseDoc); response = client.execute(post, context); assertThat(response, statusCodeIsHC(Response.Status.FOUND)); response.close(); HttpGet get = new HttpGet(employee2ServletPage.toString() + "/getAttributes"); response = client.execute(get); assertThat(response, statusCodeIsHC(Response.Status.OK)); assertThat(response, bodyHC(containsString("boolean-attribute: true"))); } catch (Exception ex) { throw new RuntimeException(ex); } finally { if (response != null) { EntityUtils.consumeQuietly(response.getEntity()); try { response.close(); } catch (IOException ex) { } } } } // KEYCLOAK-4329 @Test public void testEmptyKeyInfoElement() { samlidpInitiatedLoginPage.setAuthRealm(SAMLSERVLETDEMO); samlidpInitiatedLoginPage.setUrlName("sales-post-sig-email"); System.out.println(samlidpInitiatedLoginPage.toString()); URI idpInitiatedLoginPage = URI.create(samlidpInitiatedLoginPage.toString()); log.debug("Log in using idp initiated login"); SAMLDocumentHolder documentHolder = idpInitiatedLogin(bburkeUser, idpInitiatedLoginPage, SamlClient.Binding.POST); log.debug("Removing KeyInfo from Keycloak response"); Document responseDoc = documentHolder.getSamlDocument(); IOUtil.removeElementFromDoc(responseDoc, "samlp:Response/dsig:Signature/dsig:KeyInfo"); CloseableHttpResponse response = null; try (CloseableHttpClient client = HttpClientBuilder.create().build()) { HttpClientContext context = HttpClientContext.create(); log.debug("Sending response to SP"); HttpUriRequest post = SamlClient.Binding.POST.createSamlUnsignedResponse(getAppServerSamlEndpoint(salesPostSigEmailServletPage), null, responseDoc); response = client.execute(post, context); System.out.println(EntityUtils.toString(response.getEntity())); assertThat(response, statusCodeIsHC(Response.Status.FOUND)); response.close(); HttpGet get = new HttpGet(salesPostSigEmailServletPage.toString()); response = client.execute(get); assertThat(response, statusCodeIsHC(Response.Status.OK)); assertThat(response, bodyHC(containsString("principal=bburke"))); } catch (Exception ex) { throw new RuntimeException(ex); } finally { if (response != null) { EntityUtils.consumeQuietly(response.getEntity()); try { response.close(); } catch (IOException ex) { } } } } @Test // KEYCLOAK-4141 public void testDifferentCookieName() { assertSuccessfulLogin(differentCookieNameServletPage, bburkeUser, testRealmSAMLPostLoginPage, "principal=bburke"); assertThat(driver.manage().getCookieNamed("DIFFERENT_SESSION_ID"), notNullValue()); assertThat(driver.manage().getCookieNamed("JSESSIONID"), nullValue()); salesPost2ServletPage.logout(); checkLoggedOut(differentCookieNameServletPage, testRealmSAMLPostLoginPage); } private URI getAuthServerSamlEndpoint(String realm) throws IllegalArgumentException, UriBuilderException { return RealmsResource .protocolUrl(UriBuilder.fromUri(getAuthServerRoot())) .build(realm, SamlProtocol.LOGIN_PROTOCOL); } private URI getAppServerSamlEndpoint(SAMLServlet page) throws IllegalArgumentException, UriBuilderException { return UriBuilder.fromPath(page.toString()).path("/saml").build(); } private void validateXMLWithSchema(String xml, String schemaFileName) throws SAXException, IOException { URL schemaFile = getClass().getResource(schemaFileName); Source xmlFile = new StreamSource(new ByteArrayInputStream(xml.getBytes()), xml); SchemaFactory schemaFactory = SchemaFactory .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = schemaFactory.newSchema(schemaFile); Validator validator = schema.newValidator(); try { validator.validate(xmlFile); System.out.println(xmlFile.getSystemId() + " is valid"); } catch (SAXException e) { System.out.println(xmlFile.getSystemId() + " is NOT valid"); System.out.println("Reason: " + e.getLocalizedMessage()); Assert.fail(); } } 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(); } private void assertOnForbiddenPage() { waitUntilElement(By.xpath("//body")).text().contains(FORBIDDEN_TEXT); } }