Java tutorial
/******************************************************************************* * Cloud Foundry * Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved. * * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product includes a number of subcomponents with * separate copyright notices and license terms. Your use of these * subcomponents is subject to the terms and conditions of the * subcomponent's license, as noted in the LICENSE file. *******************************************************************************/ package org.cloudfoundry.identity.uaa.integration.feature; import org.apache.commons.io.FileUtils; import org.cloudfoundry.identity.uaa.ServerRunning; import org.cloudfoundry.identity.uaa.authentication.Origin; import org.cloudfoundry.identity.uaa.client.ClientConstants; import org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils; import org.cloudfoundry.identity.uaa.login.saml.IdentityProviderDefinition; import org.cloudfoundry.identity.uaa.login.test.LoginServerClassRunner; import org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils; import org.cloudfoundry.identity.uaa.scim.ScimUser; import org.cloudfoundry.identity.uaa.test.UaaTestAccounts; import org.cloudfoundry.identity.uaa.util.JsonUtils; import org.cloudfoundry.identity.uaa.zone.IdentityProvider; import org.cloudfoundry.identity.uaa.zone.IdentityZone; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.logging.LogEntry; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.security.oauth2.client.test.TestAccounts; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import org.springframework.security.oauth2.provider.client.BaseClientDetails; import org.springframework.test.context.ContextConfiguration; import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.IOException; import java.net.Inet4Address; import java.net.URLEncoder; import java.net.UnknownHostException; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.TEXT_HTML_VALUE; @RunWith(LoginServerClassRunner.class) @ContextConfiguration(classes = DefaultIntegrationTestConfig.class) public class SamlLoginIT { @Autowired @Rule public IntegrationTestRule integrationTestRule; @Autowired RestOperations restOperations; @Autowired WebDriver webDriver; @Value("${integration.test.base_url}") String baseUrl; @Autowired TestAccounts testAccounts; @Autowired TestClient testClient; ServerRunning serverRunning = ServerRunning.isRunning(); ObjectMapper objectMapper = new ObjectMapper(); public static String getValidRandomIDPMetaData() { return String.format(MockMvcUtils.IDP_META_DATA, new RandomValueStringGenerator().generate()); } @Before public void clearWebDriverOfCookies() throws Exception { webDriver.get(baseUrl + "/logout.do"); webDriver.manage().deleteAllCookies(); webDriver.get(baseUrl.replace("localhost", "testzone1.localhost") + "/logout.do"); webDriver.manage().deleteAllCookies(); webDriver.get(baseUrl.replace("localhost", "testzone2.localhost") + "/logout.do"); webDriver.manage().deleteAllCookies(); webDriver.get("http://simplesamlphp.cfapps.io/module.php/core/authenticate.php?as=example-userpass&logout"); webDriver .get("http://simplesamlphp2.cfapps.io/module.php/core/authenticate.php?as=example-userpass&logout"); } @Test public void testContentTypes() throws Exception { String loginUrl = baseUrl + "/login"; HttpHeaders jsonHeaders = new HttpHeaders(); jsonHeaders.add("Accept", "application/json"); ResponseEntity<Map> jsonResponseEntity = restOperations.exchange(loginUrl, HttpMethod.GET, new HttpEntity<>(jsonHeaders), Map.class); assertThat(jsonResponseEntity.getHeaders().get("Content-Type").get(0), containsString(APPLICATION_JSON_VALUE)); HttpHeaders htmlHeaders = new HttpHeaders(); htmlHeaders.add("Accept", "text/html"); ResponseEntity<Void> htmlResponseEntity = restOperations.exchange(loginUrl, HttpMethod.GET, new HttpEntity<>(htmlHeaders), Void.class); assertThat(htmlResponseEntity.getHeaders().get("Content-Type").get(0), containsString(TEXT_HTML_VALUE)); HttpHeaders defaultHeaders = new HttpHeaders(); defaultHeaders.add("Accept", "*/*"); ResponseEntity<Void> defaultResponseEntity = restOperations.exchange(loginUrl, HttpMethod.GET, new HttpEntity<>(defaultHeaders), Void.class); assertThat(defaultResponseEntity.getHeaders().get("Content-Type").get(0), containsString(TEXT_HTML_VALUE)); } @Test public void testSimpleSamlPhpPasscodeRedirect() throws Exception { testSimpleSamlLogin("/passcode", "Temporary Authentication Code"); } @Test public void testSimpleSamlLoginWithAddShadowUserOnLoginFalse() throws Exception { // Deleting marissa@test.org from simplesamlphp because previous SAML authentications automatically // create a UAA user with the email address as the username. deleteUser("simplesamlphp", testAccounts.getEmail()); IdentityProvider provider = createIdentityProvider("simplesamlphp", false); String clientId = "app-addnew-false" + new RandomValueStringGenerator().generate(); String redirectUri = "http://nosuchhostname:0/nosuchendpoint"; BaseClientDetails client = createClientAndSpecifyProvider(clientId, provider, redirectUri); //tells us that we are on travis assumeTrue("Expected testzone1/2.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); String firstUrl = "/oauth/authorize?" + "client_id=" + clientId + "&response_type=code" + "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8"); webDriver.get(baseUrl + firstUrl); webDriver.findElement(By.xpath("//h2[contains(text(), 'Enter your username and password')]")); webDriver.findElement(By.name("username")).clear(); webDriver.findElement(By.name("username")).sendKeys(testAccounts.getUserName()); webDriver.findElement(By.name("password")).sendKeys(testAccounts.getPassword()); webDriver.findElement(By.xpath("//input[@value='Login']")).click(); // We need to verify the last request URL through the HTTP Archive (HAR) log because the redirect // URI does not exist. When the webDriver follows the non-existent redirect URI it receives a // connection refused error so webDriver.getCurrentURL() will remain as the SAML IdP URL. List<LogEntry> harLogEntries = webDriver.manage().logs().get("har").getAll(); LogEntry lastLogEntry = harLogEntries.get(harLogEntries.size() - 1); String lastRequestUrl = getRequestUrlFromHarLogEntry(lastLogEntry); assertThat("Unexpected URL.", lastRequestUrl, Matchers.containsString(redirectUri + "?error=access_denied" + "&error_description=SAML+user+does+not+exist.+You+can+correct+this+by+creating+a+shadow+user+for+the+SAML+user.")); } private String getRequestUrlFromHarLogEntry(LogEntry logEntry) throws IOException, JsonParseException, JsonMappingException { Map<String, Object> message = this.objectMapper.readValue(logEntry.getMessage(), Map.class); Map<String, Object> log = (Map<String, Object>) message.get("log"); List<Object> entries = (List<Object>) log.get("entries"); Map<String, Object> lastEntry = (Map<String, Object>) entries.get(entries.size() - 1); Map<String, Object> request = (Map<String, Object>) lastEntry.get("request"); String url = (String) request.get("url"); return url; } @Test public void testSimpleSamlPhpLogin() throws Exception { testSimpleSamlLogin("/login", "Where to?"); } private void testSimpleSamlLogin(String firstUrl, String lookfor) throws Exception { IdentityProvider provider = createIdentityProvider("simplesamlphp"); //tells us that we are on travis assumeTrue("Expected testzone1/2.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); webDriver.get(baseUrl + firstUrl); Assert.assertEquals("Cloud Foundry", webDriver.getTitle()); webDriver.findElement(By.xpath( "//a[text()='" + provider.getConfigValue(IdentityProviderDefinition.class).getLinkText() + "']")) .click(); //takeScreenShot(); webDriver.findElement(By.xpath("//h2[contains(text(), 'Enter your username and password')]")); webDriver.findElement(By.name("username")).clear(); webDriver.findElement(By.name("username")).sendKeys(testAccounts.getUserName()); webDriver.findElement(By.name("password")).sendKeys(testAccounts.getPassword()); webDriver.findElement(By.xpath("//input[@value='Login']")).click(); assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString(lookfor)); } protected IdentityProvider createIdentityProvider(String originKey) throws Exception { return createIdentityProvider(originKey, true); } /** * @param originKey The unique identifier used to reference the identity provider in UAA. * @param addShadowUserOnLogin Specifies whether UAA should automatically create shadow users upon successful SAML authentication. * @return An object representation of an identity provider. * @throws Exception on error */ protected IdentityProvider createIdentityProvider(String originKey, boolean addShadowUserOnLogin) throws Exception { RestTemplate identityClient = IntegrationTestUtils.getClientCredentialsTempate(IntegrationTestUtils .getClientCredentialsResource(baseUrl, new String[0], "identity", "identitysecret")); RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTempate( IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret")); String email = new RandomValueStringGenerator().generate() + "@samltesting.org"; ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl, email, "firstname", "lastname", email, true); IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), Origin.UAA); String zoneAdminToken = IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, UaaTestAccounts.standard(serverRunning), "identity", "identitysecret", email, "secr3T"); IdentityProviderDefinition identityProviderDefinition = createSimplePHPSamlIDP(originKey, Origin.UAA); identityProviderDefinition.setAddShadowUserOnLogin(addShadowUserOnLogin); IdentityProvider provider = new IdentityProvider(); provider.setIdentityZoneId(Origin.UAA); provider.setType(Origin.SAML); provider.setActive(true); provider.setConfig(JsonUtils.writeValueAsString(identityProviderDefinition)); provider.setOriginKey(identityProviderDefinition.getIdpEntityAlias()); provider.setName("simplesamlphp for uaa"); provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken, baseUrl, provider); assertNotNull(provider.getId()); return provider; } protected BaseClientDetails createClientAndSpecifyProvider(String clientId, IdentityProvider provider, String redirectUri) throws Exception { RestTemplate identityClient = IntegrationTestUtils.getClientCredentialsTempate(IntegrationTestUtils .getClientCredentialsResource(baseUrl, new String[0], "identity", "identitysecret")); RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTempate( IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret")); String email = new RandomValueStringGenerator().generate() + "@samltesting.org"; ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl, email, "firstname", "lastname", email, true); IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), Origin.UAA); String zoneAdminToken = IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, UaaTestAccounts.standard(serverRunning), "identity", "identitysecret", email, "secr3T"); BaseClientDetails clientDetails = new BaseClientDetails(clientId, null, "openid", "authorization_code", "uaa.resource", redirectUri); clientDetails.setClientSecret("secret"); List<String> idps = Arrays.asList(provider.getOriginKey()); clientDetails.addAdditionalInformation(ClientConstants.ALLOWED_PROVIDERS, idps); clientDetails.addAdditionalInformation(ClientConstants.AUTO_APPROVE, true); IntegrationTestUtils.createClient(zoneAdminToken, baseUrl, clientDetails); return clientDetails; } protected void deleteUser(String origin, String username) throws Exception { String zoneAdminToken = IntegrationTestUtils.getClientCredentialsToken(serverRunning, "admin", "adminsecret"); String userId = IntegrationTestUtils.getUserId(zoneAdminToken, baseUrl, origin, username); if (null == userId) { return; } IntegrationTestUtils.deleteUser(zoneAdminToken, baseUrl, userId); } @Test public void testSamlLoginClientIDPAuthorizationAutomaticRedirectInZone1() throws Exception { //ensure we are able to resolve DNS for hostname testzone1.localhost assumeTrue("Expected testzone1/2.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); String zoneId = "testzone1"; //identity client token RestTemplate identityClient = IntegrationTestUtils .getClientCredentialsTempate(IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[] { "zones.write", "zones.read", "scim.zones" }, "identity", "identitysecret")); //admin client token - to create users RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTempate( IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret")); //create the zone IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId); //create a zone admin user String email = new RandomValueStringGenerator().generate() + "@samltesting.org"; ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl, email, "firstname", "lastname", email, true); IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), zoneId); //get the zone admin token String zoneAdminToken = IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, UaaTestAccounts.standard(serverRunning), "identity", "identitysecret", email, "secr3T"); IdentityProviderDefinition identityProviderDefinition = createTestZone1IDP("simplesamlphp"); IdentityProvider provider = new IdentityProvider(); provider.setIdentityZoneId(zoneId); provider.setType(Origin.SAML); provider.setActive(true); provider.setConfig(JsonUtils.writeValueAsString(identityProviderDefinition)); provider.setOriginKey(identityProviderDefinition.getIdpEntityAlias()); provider.setName("simplesamlphp for testzone1"); provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken, baseUrl, provider); assertEquals(provider.getOriginKey(), provider.getConfigValue(IdentityProviderDefinition.class).getIdpEntityAlias()); List<String> idps = Arrays.asList(provider.getOriginKey()); String clientId = UUID.randomUUID().toString(); BaseClientDetails clientDetails = new BaseClientDetails(clientId, null, "openid", "authorization_code", "uaa.none", baseUrl); clientDetails.setClientSecret("secret"); clientDetails.addAdditionalInformation(ClientConstants.ALLOWED_PROVIDERS, idps); clientDetails.addAdditionalInformation(ClientConstants.AUTO_APPROVE, true); clientDetails = IntegrationTestUtils.createClientAsZoneAdmin(zoneAdminToken, baseUrl, zoneId, clientDetails); String zoneUrl = baseUrl.replace("localhost", "testzone1.localhost"); webDriver.get(zoneUrl + "/logout.do"); String authUrl = zoneUrl + "/oauth/authorize?client_id=" + clientId + "&redirect_uri=" + URLEncoder.encode(zoneUrl) + "&response_type=code&state=8tp0tR"; webDriver.get(authUrl); //we should now be in the Simple SAML PHP site webDriver.findElement(By.xpath("//h2[contains(text(), 'Enter your username and password')]")); webDriver.findElement(By.name("username")).clear(); webDriver.findElement(By.name("username")).sendKeys(testAccounts.getUserName()); webDriver.findElement(By.name("password")).sendKeys("koala"); webDriver.findElement(By.xpath("//input[@value='Login']")).click(); assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Where to?")); webDriver.get(baseUrl + "/logout.do"); webDriver.get(zoneUrl + "/logout.do"); } @Test public void testSimpleSamlPhpLoginInTestZone1Works() throws Exception { assumeTrue("Expected testzone1/2.localhost to resolve to 127.0.0.1", doesSupportZoneDNS()); String zoneId = "testzone1"; RestTemplate identityClient = IntegrationTestUtils .getClientCredentialsTempate(IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[] { "zones.write", "zones.read", "scim.zones" }, "identity", "identitysecret")); RestTemplate adminClient = IntegrationTestUtils.getClientCredentialsTempate( IntegrationTestUtils.getClientCredentialsResource(baseUrl, new String[0], "admin", "adminsecret")); IdentityZone zone = IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId); String email = new RandomValueStringGenerator().generate() + "@samltesting.org"; ScimUser user = IntegrationTestUtils.createUser(adminClient, baseUrl, email, "firstname", "lastname", email, true); IntegrationTestUtils.makeZoneAdmin(identityClient, baseUrl, user.getId(), zoneId); String zoneAdminToken = IntegrationTestUtils.getAuthorizationCodeToken(serverRunning, UaaTestAccounts.standard(serverRunning), "identity", "identitysecret", email, "secr3T"); IdentityProviderDefinition identityProviderDefinition = createTestZone1IDP("simplesamlphp"); IdentityProvider provider = new IdentityProvider(); provider.setIdentityZoneId(zoneId); provider.setType(Origin.SAML); provider.setActive(true); provider.setConfig(JsonUtils.writeValueAsString(identityProviderDefinition)); provider.setOriginKey(identityProviderDefinition.getIdpEntityAlias()); provider.setName("simplesamlphp for testzone1"); provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken, baseUrl, provider); //we have to create two providers to avoid automatic redirect IdentityProviderDefinition identityProviderDefinition1 = identityProviderDefinition.clone(); identityProviderDefinition1.setIdpEntityAlias(identityProviderDefinition.getIdpEntityAlias() + "-1"); identityProviderDefinition1.setMetaDataLocation(getValidRandomIDPMetaData()); IdentityProvider provider1 = new IdentityProvider(); provider1.setIdentityZoneId(zoneId); provider1.setType(Origin.SAML); provider1.setActive(true); provider1.setConfig(JsonUtils.writeValueAsString(identityProviderDefinition1)); provider1.setOriginKey(identityProviderDefinition1.getIdpEntityAlias()); provider1.setName("simplesamlphp 1 for testzone1"); provider1 = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken, baseUrl, provider1); assertNotNull(provider.getId()); String testZone1Url = baseUrl.replace("localhost", zoneId + ".localhost"); webDriver.get(baseUrl + "/logout.do"); webDriver.get(testZone1Url + "/logout.do"); webDriver.get(testZone1Url + "/login"); Assert.assertEquals(zone.getName(), webDriver.getTitle()); List<WebElement> elements = webDriver .findElements(By.xpath("//a[text()='" + identityProviderDefinition.getLinkText() + "']")); assertNotNull(elements); assertEquals(2, elements.size()); WebElement element = webDriver .findElement(By.xpath("//a[text()='" + identityProviderDefinition1.getLinkText() + "']")); assertNotNull(element); element = webDriver.findElement(By.xpath("//a[text()='" + identityProviderDefinition.getLinkText() + "']")); element.click(); webDriver.findElement(By.xpath("//h2[contains(text(), 'Enter your username and password')]")); webDriver.findElement(By.name("username")).clear(); webDriver.findElement(By.name("username")).sendKeys(testAccounts.getUserName()); webDriver.findElement(By.name("password")).sendKeys(testAccounts.getPassword()); webDriver.findElement(By.xpath("//input[@value='Login']")).click(); assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Where to?")); webDriver.get(baseUrl + "/logout.do"); webDriver.get(testZone1Url + "/logout.do"); //disable the provider webDriver.get("http://simplesamlphp.cfapps.io/module.php/core/authenticate.php?as=example-userpass&logout"); provider.setActive(false); provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken, baseUrl, provider); assertNotNull(provider.getId()); webDriver.get(testZone1Url + "/login"); Assert.assertEquals(zone.getName(), webDriver.getTitle()); elements = webDriver .findElements(By.xpath("//a[text()='" + identityProviderDefinition.getLinkText() + "']")); assertNotNull(elements); assertEquals(1, elements.size()); //enable the provider provider.setActive(true); provider = IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken, baseUrl, provider); assertNotNull(provider.getId()); webDriver.get(testZone1Url + "/login"); Assert.assertEquals(zone.getName(), webDriver.getTitle()); elements = webDriver .findElements(By.xpath("//a[text()='" + identityProviderDefinition.getLinkText() + "']")); assertNotNull(elements); assertEquals(2, elements.size()); } @Test public void testLoginPageShowsIDPsForAuthcodeClient() throws Exception { IdentityProvider provider = createIdentityProvider("simplesamlphp"); IdentityProvider provider2 = createIdentityProvider("simplesamlphp2"); List<String> idps = Arrays.asList( provider.getConfigValue(IdentityProviderDefinition.class).getIdpEntityAlias(), provider2.getConfigValue(IdentityProviderDefinition.class).getIdpEntityAlias()); String adminAccessToken = testClient.getOAuthAccessToken("admin", "adminsecret", "client_credentials", "clients.read clients.write clients.secret"); String clientId = UUID.randomUUID().toString(); BaseClientDetails clientDetails = new BaseClientDetails(clientId, null, "openid", "authorization_code", "uaa.none", "http://localhost:8080/login"); clientDetails.setClientSecret("secret"); clientDetails.addAdditionalInformation(ClientConstants.ALLOWED_PROVIDERS, idps); testClient.createClient(adminAccessToken, clientDetails); webDriver.get(baseUrl + "/oauth/authorize?client_id=" + clientId + "&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Flogin&response_type=code&state=8tp0tR"); webDriver.findElement(By.xpath( "//a[text()='" + provider.getConfigValue(IdentityProviderDefinition.class).getLinkText() + "']")); webDriver.findElement(By.xpath( "//a[text()='" + provider2.getConfigValue(IdentityProviderDefinition.class).getLinkText() + "']")); } @Test public void testLoginSamlOnlyProviderNoUsernamePassword() throws Exception { IdentityProvider provider = createIdentityProvider("simplesamlphp"); IdentityProvider provider2 = createIdentityProvider("simplesamlphp2"); List<String> idps = Arrays.asList(provider.getOriginKey(), provider2.getOriginKey()); webDriver.get(baseUrl + "/logout.do"); String adminAccessToken = testClient.getOAuthAccessToken("admin", "adminsecret", "client_credentials", "clients.read clients.write clients.secret"); String clientId = UUID.randomUUID().toString(); BaseClientDetails clientDetails = new BaseClientDetails(clientId, null, "openid", "authorization_code", "uaa.none", "http://localhost:8080/uaa/login"); clientDetails.setClientSecret("secret"); clientDetails.addAdditionalInformation(ClientConstants.ALLOWED_PROVIDERS, idps); testClient.createClient(adminAccessToken, clientDetails); webDriver.get(baseUrl + "/oauth/authorize?client_id=" + clientId + "&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fuaa%3Alogin&response_type=code&state=8tp0tR"); try { webDriver.findElement(By.name("username")); fail("Element username should not be present"); } catch (NoSuchElementException x) { } try { webDriver.findElement(By.name("password")); fail("Element username should not be present"); } catch (NoSuchElementException x) { } webDriver.get(baseUrl + "/logout.do"); } @Test public void testSamlLoginClientIDPAuthorizationAutomaticRedirect() throws Exception { IdentityProvider provider = createIdentityProvider("simplesamlphp"); assertEquals(provider.getOriginKey(), provider.getConfigValue(IdentityProviderDefinition.class).getIdpEntityAlias()); List<String> idps = Arrays.asList(provider.getOriginKey()); webDriver.get(baseUrl + "/logout.do"); String adminAccessToken = testClient.getOAuthAccessToken("admin", "adminsecret", "client_credentials", "clients.read clients.write clients.secret"); String clientId = UUID.randomUUID().toString(); BaseClientDetails clientDetails = new BaseClientDetails(clientId, null, "openid", "authorization_code", "uaa.none", baseUrl); clientDetails.setClientSecret("secret"); clientDetails.addAdditionalInformation(ClientConstants.ALLOWED_PROVIDERS, idps); clientDetails.addAdditionalInformation(ClientConstants.AUTO_APPROVE, true); testClient.createClient(adminAccessToken, clientDetails); webDriver.get(baseUrl + "/oauth/authorize?client_id=" + clientId + "&redirect_uri=" + URLEncoder.encode(baseUrl) + "&response_type=code&state=8tp0tR"); //we should now be in the Simple SAML PHP site webDriver.findElement(By.xpath("//h2[contains(text(), 'Enter your username and password')]")); webDriver.findElement(By.name("username")).clear(); webDriver.findElement(By.name("username")).sendKeys(testAccounts.getUserName()); webDriver.findElement(By.name("password")).sendKeys("koala"); webDriver.findElement(By.xpath("//input[@value='Login']")).click(); assertThat(webDriver.findElement(By.cssSelector("h1")).getText(), Matchers.containsString("Where to?")); webDriver.get(baseUrl + "/logout.do"); } @Test public void testLoginClientIDPAuthorizationAlreadyLoggedIn() throws Exception { webDriver.get(baseUrl + "/logout.do"); String adminAccessToken = testClient.getOAuthAccessToken("admin", "adminsecret", "client_credentials", "clients.read clients.write clients.secret"); String clientId = UUID.randomUUID().toString(); BaseClientDetails clientDetails = new BaseClientDetails(clientId, null, "openid", "authorization_code", "uaa.none", "http://localhost:8080/login"); clientDetails.setClientSecret("secret"); List<String> idps = Arrays.asList("okta-local"); //not authorized for the current IDP clientDetails.addAdditionalInformation(ClientConstants.ALLOWED_PROVIDERS, idps); testClient.createClient(adminAccessToken, clientDetails); webDriver.findElement(By.name("username")).clear(); webDriver.findElement(By.name("username")).sendKeys(testAccounts.getUserName()); webDriver.findElement(By.name("password")).sendKeys("koala"); webDriver.findElement(By.xpath("//input[@value='Sign in']")).click(); webDriver.get(baseUrl + "/oauth/authorize?client_id=" + clientId + "&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Flogin&response_type=code&state=8tp0tR"); assertThat(webDriver.findElement(By.cssSelector("p")).getText(), Matchers.containsString("The application is not authorized for your account.")); webDriver.get(baseUrl + "/logout.do"); } protected boolean doesSupportZoneDNS() { try { return Arrays.equals(Inet4Address.getByName("testzone1.localhost").getAddress(), new byte[] { 127, 0, 0, 1 }) && Arrays.equals(Inet4Address.getByName("testzone2.localhost").getAddress(), new byte[] { 127, 0, 0, 1 }); } catch (UnknownHostException e) { return false; } } public IdentityProviderDefinition createTestZone1IDP(String alias) { return createSimplePHPSamlIDP(alias, "testzone1"); } public IdentityProviderDefinition createSimplePHPSamlIDP(String alias, String zoneId) { if (!("simplesamlphp".equals(alias) || "simplesamlphp2".equals(alias))) { throw new IllegalArgumentException("Only valid origins are: simplesamlphp,simplesamlphp2"); } String idpMetaData = "<?xml version=\"1.0\"?>\n" + "<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" entityID=\"http://" + alias + ".cfapps.io/saml2/idp/metadata.php\" ID=\"pfx06ad4153-c17c-d286-194c-dec30bb92796\"><ds:Signature>\n" + " <ds:SignedInfo><ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>\n" + " <ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/>\n" + " <ds:Reference URI=\"#pfx06ad4153-c17c-d286-194c-dec30bb92796\"><ds:Transforms><ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/><ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/></ds:Transforms><ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><ds:DigestValue>begl1WVCsXSn7iHixtWPP8d/X+k=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>BmbKqA3A0oSLcn5jImz/l5WbpVXj+8JIpT/ENWjOjSd/gcAsZm1QvYg+RxYPBk+iV2bBxD+/yAE/w0wibsHrl0u9eDhoMRUJBUSmeyuN1lYzBuoVa08PdAGtb5cGm4DMQT5Rzakb1P0hhEPPEDDHgTTxop89LUu6xx97t2Q03Khy8mXEmBmNt2NlFxJPNt0FwHqLKOHRKBOE/+BpswlBocjOQKFsI9tG3TyjFC68mM2jo0fpUQCgj5ZfhzolvS7z7c6V201d9Tqig0/mMFFJLTN8WuZPavw22AJlMjsDY9my+4R9HKhK5U53DhcTeECs9fb4gd7p5BJy4vVp7tqqOg==</ds:SignatureValue>\n" + "<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYDVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwXc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0BwaXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAaBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQDDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlrQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduOnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+vZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLuxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6zV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>\n" + " <md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n" + " <md:KeyDescriptor use=\"signing\">\n" + " <ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n" + " <ds:X509Data>\n" + " <ds:X509Certificate>MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYDVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwXc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0BwaXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAaBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQDDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlrQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduOnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+vZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLuxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6zV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk</ds:X509Certificate>\n" + " </ds:X509Data>\n" + " </ds:KeyInfo>\n" + " </md:KeyDescriptor>\n" + " <md:KeyDescriptor use=\"encryption\">\n" + " <ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n" + " <ds:X509Data>\n" + " <ds:X509Certificate>MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYDVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwXc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0BwaXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAaBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQDDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlrQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduOnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+vZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLuxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6zV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk</ds:X509Certificate>\n" + " </ds:X509Data>\n" + " </ds:KeyInfo>\n" + " </md:KeyDescriptor>\n" + " <md:SingleLogoutService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"http://" + alias + ".cfapps.io/saml2/idp/SingleLogoutService.php\"/>\n" + " <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>\n" + " <md:SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"http://" + alias + ".cfapps.io/saml2/idp/SSOService.php\"/>\n" + " </md:IDPSSODescriptor>\n" + " <md:ContactPerson contactType=\"technical\">\n" + " <md:GivenName>Filip</md:GivenName>\n" + " <md:SurName>Hanik</md:SurName>\n" + " <md:EmailAddress>fhanik@pivotal.io</md:EmailAddress>\n" + " </md:ContactPerson>\n" + "</md:EntityDescriptor>"; IdentityProviderDefinition def = new IdentityProviderDefinition(); def.setZoneId(zoneId); def.setMetaDataLocation(idpMetaData); def.setNameID("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"); def.setAssertionConsumerIndex(0); def.setMetadataTrustCheck(false); def.setShowSamlLink(true); def.setIdpEntityAlias(alias); def.setLinkText("Login with Simple SAML PHP(" + alias + ")"); return def; } public void takeScreenShot() throws IOException { File scrFile = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(scrFile, new File("testscreenshot-" + System.currentTimeMillis() + ".png")); } }