예제 #1
0
  @Test
  public void testAddingAndUpdatingAnApprovalPublishesEvents() throws Exception {
    UaaTestAccounts testAccounts = UaaTestAccounts.standard(null);

    Approval approval =
        new Approval()
            .setUserId(testAccounts.getUserName())
            .setClientId("app")
            .setScope("cloud_controller.read")
            .setExpiresAt(Approval.timeFromNow(1000))
            .setStatus(ApprovalStatus.APPROVED);

    eventPublisher.clearEvents();

    MockAuthentication authentication = new MockAuthentication();
    SecurityContextHolder.getContext().setAuthentication(authentication);

    dao.addApproval(approval);

    Assert.assertEquals(1, eventPublisher.getEventCount());

    ApprovalModifiedEvent addEvent = eventPublisher.getLatestEvent();
    Assert.assertEquals(approval, addEvent.getSource());
    Assert.assertEquals(authentication, addEvent.getAuthentication());
    Assert.assertEquals(
        "{\"scope\":\"cloud_controller.read\",\"status\":\"APPROVED\"}",
        addEvent.getAuditEvent().getData());

    approval.setStatus(DENIED);

    eventPublisher.clearEvents();
    dao.addApproval(approval);

    Assert.assertEquals(1, eventPublisher.getEventCount());

    ApprovalModifiedEvent modifyEvent = eventPublisher.getLatestEvent();
    Assert.assertEquals(approval, modifyEvent.getSource());
    Assert.assertEquals(authentication, modifyEvent.getAuthentication());
    Assert.assertEquals(
        "{\"scope\":\"cloud_controller.read\",\"status\":\"DENIED\"}",
        addEvent.getAuditEvent().getData());
  }
  @Before
  public void createRestTemplate() throws Exception {
    Assume.assumeTrue(!testAccounts.isProfileActive("vcap"));
    client = serverRunning.getRestTemplate();
    ((RestTemplate) serverRunning.getRestTemplate())
        .setErrorHandler(
            new OAuth2ErrorHandler(context.getResource()) {
              // Pass errors through in response entity for status code analysis
              @Override
              public boolean hasError(ClientHttpResponse response) throws IOException {
                return false;
              }

              @Override
              public void handleError(ClientHttpResponse response) throws IOException {}
            });
  }
  /**
   * tests a happy-day flow of the Resource Owner Password Credentials grant type. (formerly native
   * application profile).
   */
  @Test
  public void testHappyDay() throws Exception {

    MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
    formData.add("grant_type", "password");
    formData.add("username", resource.getUsername());
    formData.add("password", resource.getPassword());
    formData.add("scope", "cloud_controller.read");
    HttpHeaders headers = new HttpHeaders();
    headers.set(
        "Authorization",
        testAccounts.getAuthorizationHeader(resource.getClientId(), resource.getClientSecret()));
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    ResponseEntity<String> response =
        serverRunning.postForString("/oauth/token", formData, headers);
    assertEquals(HttpStatus.OK, response.getStatusCode());
    assertEquals(
        "no-cache, no-store, max-age=0, must-revalidate",
        response.getHeaders().getFirst("Cache-Control"));
  }
  @Test
  public void testCreateZone() throws Exception {
    String zoneId = UUID.randomUUID().toString();
    String requestBody =
        "{\"id\":\""
            + zoneId
            + "\", \"subdomain\":\""
            + zoneId
            + "\", \"name\":\"testCreateZone() "
            + zoneId
            + "\"}";

    HttpHeaders headers = new HttpHeaders();
    headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
    headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);

    ResponseEntity<Void> response =
        client.exchange(
            serverRunning.getUrl("/identity-zones"),
            HttpMethod.POST,
            new HttpEntity<>(requestBody, headers),
            new ParameterizedTypeReference<Void>() {});

    assertEquals(HttpStatus.CREATED, response.getStatusCode());

    RestTemplate adminClient =
        IntegrationTestUtils.getClientCredentialsTemplate(
            IntegrationTestUtils.getClientCredentialsResource(
                serverRunning.getBaseUrl(), new String[0], "admin", "adminsecret"));
    String email = new RandomValueStringGenerator().generate() + "@samltesting.org";
    ScimUser user =
        IntegrationTestUtils.createUser(
            adminClient, serverRunning.getBaseUrl(), email, "firstname", "lastname", email, true);
    IntegrationTestUtils.makeZoneAdmin(client, serverRunning.getBaseUrl(), user.getId(), zoneId);

    String zoneAdminToken =
        IntegrationTestUtils.getAuthorizationCodeToken(
            serverRunning,
            UaaTestAccounts.standard(serverRunning),
            "identity",
            "identitysecret",
            email,
            "secr3T");

    headers.add("Authorization", "bearer " + zoneAdminToken);
    headers.add(IdentityZoneSwitchingFilter.HEADER, zoneId);
    ResponseEntity<List<IdentityProvider>> idpList =
        new RestTemplate()
            .exchange(
                serverRunning.getUrl("/identity-providers"),
                HttpMethod.GET,
                new HttpEntity<>(null, headers),
                new ParameterizedTypeReference<List<IdentityProvider>>() {});

    IdentityProvider identityProvider = idpList.getBody().get(0);
    assertThat(identityProvider.getIdentityZoneId(), is(zoneId));
    assertThat(identityProvider.getOriginKey(), is(Origin.UAA));

    // the default created zone does have a definition, but no policy
    assertNotNull(identityProvider.getConfigValue(UaaIdentityProviderDefinition.class));
    assertNull(
        identityProvider.getConfigValue(UaaIdentityProviderDefinition.class).getPasswordPolicy());
  }
@OAuth2ContextConfiguration(IdentityZoneEndpointsIntegrationTests.IdentityClient.class)
public class IdentityZoneEndpointsIntegrationTests {
  @Rule public ServerRunning serverRunning = ServerRunning.isRunning();

  private UaaTestAccounts testAccounts = UaaTestAccounts.standard(serverRunning);

  @Rule public OAuth2ContextSetup context = OAuth2ContextSetup.standard(serverRunning);

  @Rule
  public TestAccountSetup testAccountSetup = TestAccountSetup.standard(serverRunning, testAccounts);

  private RestTemplate client;

  @Before
  public void createRestTemplate() throws Exception {
    client = (OAuth2RestTemplate) serverRunning.getRestTemplate();
    client.setErrorHandler(
        new OAuth2ErrorHandler(context.getResource()) {
          // Pass errors through in response entity for status code analysis
          @Override
          public boolean hasError(ClientHttpResponse response) throws IOException {
            return false;
          }

          @Override
          public void handleError(ClientHttpResponse response) throws IOException {}
        });
  }

  @Test
  public void testCreateZone() throws Exception {
    String zoneId = UUID.randomUUID().toString();
    String requestBody =
        "{\"id\":\""
            + zoneId
            + "\", \"subdomain\":\""
            + zoneId
            + "\", \"name\":\"testCreateZone() "
            + zoneId
            + "\"}";

    HttpHeaders headers = new HttpHeaders();
    headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
    headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);

    ResponseEntity<Void> response =
        client.exchange(
            serverRunning.getUrl("/identity-zones"),
            HttpMethod.POST,
            new HttpEntity<>(requestBody, headers),
            new ParameterizedTypeReference<Void>() {});

    assertEquals(HttpStatus.CREATED, response.getStatusCode());

    RestTemplate adminClient =
        IntegrationTestUtils.getClientCredentialsTemplate(
            IntegrationTestUtils.getClientCredentialsResource(
                serverRunning.getBaseUrl(), new String[0], "admin", "adminsecret"));
    String email = new RandomValueStringGenerator().generate() + "@samltesting.org";
    ScimUser user =
        IntegrationTestUtils.createUser(
            adminClient, serverRunning.getBaseUrl(), email, "firstname", "lastname", email, true);
    IntegrationTestUtils.makeZoneAdmin(client, serverRunning.getBaseUrl(), user.getId(), zoneId);

    String zoneAdminToken =
        IntegrationTestUtils.getAuthorizationCodeToken(
            serverRunning,
            UaaTestAccounts.standard(serverRunning),
            "identity",
            "identitysecret",
            email,
            "secr3T");

    headers.add("Authorization", "bearer " + zoneAdminToken);
    headers.add(IdentityZoneSwitchingFilter.HEADER, zoneId);
    ResponseEntity<List<IdentityProvider>> idpList =
        new RestTemplate()
            .exchange(
                serverRunning.getUrl("/identity-providers"),
                HttpMethod.GET,
                new HttpEntity<>(null, headers),
                new ParameterizedTypeReference<List<IdentityProvider>>() {});

    IdentityProvider identityProvider = idpList.getBody().get(0);
    assertThat(identityProvider.getIdentityZoneId(), is(zoneId));
    assertThat(identityProvider.getOriginKey(), is(Origin.UAA));

    // the default created zone does have a definition, but no policy
    assertNotNull(identityProvider.getConfigValue(UaaIdentityProviderDefinition.class));
    assertNull(
        identityProvider.getConfigValue(UaaIdentityProviderDefinition.class).getPasswordPolicy());
  }

  @Test
  public void testCreateZoneWithClient() throws IOException {
    IdentityZone idZone = new IdentityZone();
    String id = UUID.randomUUID().toString();
    idZone.setId(id);
    idZone.setSubdomain(id);
    idZone.setName("testCreateZone() " + id);
    ResponseEntity<Void> response =
        client.exchange(
            serverRunning.getUrl("/identity-zones"),
            HttpMethod.POST,
            new HttpEntity<>(idZone),
            new ParameterizedTypeReference<Void>() {},
            id);
    assertEquals(HttpStatus.CREATED, response.getStatusCode());

    BaseClientDetails clientDetails =
        new BaseClientDetails("test123", null, "openid", "authorization_code", "uaa.resource");
    clientDetails.setClientSecret("testSecret");
    clientDetails.addAdditionalInformation(
        ClientConstants.ALLOWED_PROVIDERS, Collections.singleton(Origin.UAA));

    ResponseEntity<Void> clientCreateResponse =
        client.exchange(
            serverRunning.getUrl("/identity-zones/" + id + "/clients"),
            HttpMethod.POST,
            new HttpEntity<>(clientDetails),
            new ParameterizedTypeReference<Void>() {},
            id);

    assertEquals(HttpStatus.CREATED, clientCreateResponse.getStatusCode());

    ResponseEntity<Void> clientDeleteResponse =
        client.exchange(
            serverRunning.getUrl(
                "/identity-zones/" + id + "/clients/" + clientDetails.getClientId()),
            HttpMethod.DELETE,
            null,
            new ParameterizedTypeReference<Void>() {},
            id);

    assertEquals(HttpStatus.OK, clientDeleteResponse.getStatusCode());
  }

  @Test
  public void testCreateZoneWithNonUniqueSubdomain() {
    IdentityZone idZone1 = new IdentityZone();
    String id1 = UUID.randomUUID().toString();
    idZone1.setId(id1);
    idZone1.setSubdomain(id1 + "non-unique");
    idZone1.setName("testCreateZone() " + id1);
    ResponseEntity<Void> response1 =
        client.exchange(
            serverRunning.getUrl("/identity-zones"),
            HttpMethod.POST,
            new HttpEntity<>(idZone1),
            new ParameterizedTypeReference<Void>() {},
            id1);
    assertEquals(HttpStatus.CREATED, response1.getStatusCode());

    IdentityZone idZone2 = new IdentityZone();
    String id2 = UUID.randomUUID().toString();
    idZone2.setId(id2);
    idZone2.setSubdomain(id1 + "non-unique");
    idZone2.setName("testCreateZone() " + id2);
    ResponseEntity<Map<String, String>> response2 =
        client.exchange(
            serverRunning.getUrl("/identity-zones"),
            HttpMethod.POST,
            new HttpEntity<>(idZone2),
            new ParameterizedTypeReference<Map<String, String>>() {},
            id2);
    assertEquals(HttpStatus.CONFLICT, response2.getStatusCode());
    Assert.assertTrue(
        response2.getBody().get("error_description").toLowerCase().contains("subdomain"));
  }

  static class IdentityClient extends ClientCredentialsResourceDetails {
    public IdentityClient(Object target) {
      IdentityZoneEndpointsIntegrationTests test = (IdentityZoneEndpointsIntegrationTests) target;
      ClientCredentialsResourceDetails resource =
          test.testAccounts.getClientCredentialsResource(
              new String[] {"zones.write"}, "identity", "identitysecret");
      setClientId(resource.getClientId());
      setClientSecret(resource.getClientSecret());
      setId(getClientId());
      setAccessTokenUri(test.serverRunning.getAccessTokenUri());
    }
  }
}
예제 #6
0
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DefaultIntegrationTestConfig.class)
@OAuth2ContextConfiguration(OAuth2ContextConfiguration.ClientCredentials.class)
public class AppApprovalIT {

  @Rule public ServerRunning serverRunning = ServerRunning.isRunning();

  UaaTestAccounts testAccounts = UaaTestAccounts.standard(serverRunning);

  @Rule
  public OAuth2ContextSetup context =
      OAuth2ContextSetup.withTestAccounts(serverRunning, testAccounts);

  @Rule
  public TestAccountSetup testAccountSetup = TestAccountSetup.standard(serverRunning, testAccounts);

  public RestOperations restTemplate;

  @Autowired @Rule public IntegrationTestRule integrationTestRule;

  @Autowired WebDriver webDriver;

  @Value("${integration.test.base_url}")
  String baseUrl;

  @Value("${integration.test.app_url}")
  String appUrl;

  @Before
  @After
  public void logout_and_clear_cookies() {
    restTemplate = serverRunning.getRestTemplate();

    try {
      webDriver.get(baseUrl + "/logout.do");
    } catch (org.openqa.selenium.TimeoutException x) {
      // try again - this should not be happening - 20 second timeouts
      webDriver.get(baseUrl + "/logout.do");
    }
    webDriver.get(appUrl + "/j_spring_security_logout");
    webDriver.manage().deleteAllCookies();
  }

  @Test
  public void testApprovingAnApp() throws Exception {
    ResponseEntity<SearchResults<ScimGroup>> getGroups =
        restTemplate.exchange(
            baseUrl + "/Groups?filter=displayName eq '{displayName}'",
            HttpMethod.GET,
            null,
            new ParameterizedTypeReference<SearchResults<ScimGroup>>() {},
            "cloud_controller.read");
    ScimGroup group = getGroups.getBody().getResources().stream().findFirst().get();

    group.setDescription("Read about your clouds.");
    HttpHeaders headers = new HttpHeaders();
    headers.add("If-Match", Integer.toString(group.getVersion()));
    HttpEntity request = new HttpEntity(group, headers);
    restTemplate.exchange(
        baseUrl + "/Groups/{group-id}", HttpMethod.PUT, request, Object.class, group.getId());

    ScimUser user = createUnapprovedUser();

    // Visit app
    webDriver.get(appUrl);

    // Sign in to login server
    webDriver.findElement(By.name("username")).sendKeys(user.getUserName());
    webDriver.findElement(By.name("password")).sendKeys(user.getPassword());
    webDriver.findElement(By.xpath("//input[@value='Sign in']")).click();

    // Authorize the app for some scopes
    Assert.assertEquals(
        "Application Authorization", webDriver.findElement(By.cssSelector("h1")).getText());

    webDriver
        .findElement(By.xpath("//label[text()='Change your password']/preceding-sibling::input"))
        .click();
    webDriver
        .findElement(
            By.xpath(
                "//label[text()='Read user IDs and retrieve users by ID']/preceding-sibling::input"))
        .click();
    webDriver.findElement(
        By.xpath("//label[text()='Read about your clouds.']/preceding-sibling::input"));

    webDriver.findElement(By.xpath("//button[text()='Authorize']")).click();

    Assert.assertEquals("Sample Home Page", webDriver.findElement(By.cssSelector("h1")).getText());

    // View profile on the login server
    webDriver.get(baseUrl + "/profile");

    Assert.assertFalse(
        webDriver.findElement(By.xpath("//input[@value='app-password.write']")).isSelected());
    Assert.assertFalse(
        webDriver.findElement(By.xpath("//input[@value='app-scim.userids']")).isSelected());
    Assert.assertTrue(
        webDriver
            .findElement(By.xpath("//input[@value='app-cloud_controller.read']"))
            .isSelected());
    Assert.assertTrue(
        webDriver
            .findElement(By.xpath("//input[@value='app-cloud_controller.write']"))
            .isSelected());

    // Add approvals
    webDriver.findElement(By.xpath("//input[@value='app-password.write']")).click();
    webDriver.findElement(By.xpath("//input[@value='app-scim.userids']")).click();

    webDriver.findElement(By.xpath("//button[text()='Update']")).click();

    Assert.assertTrue(
        webDriver.findElement(By.xpath("//input[@value='app-password.write']")).isSelected());
    Assert.assertTrue(
        webDriver.findElement(By.xpath("//input[@value='app-scim.userids']")).isSelected());
    Assert.assertTrue(
        webDriver
            .findElement(By.xpath("//input[@value='app-cloud_controller.read']"))
            .isSelected());
    Assert.assertTrue(
        webDriver
            .findElement(By.xpath("//input[@value='app-cloud_controller.write']"))
            .isSelected());

    // Revoke app
    webDriver.findElement(By.linkText("Revoke Access")).click();

    Assert.assertEquals(
        "Are you sure you want to revoke access to The Ultimate Oauth App?",
        webDriver.findElement(By.cssSelector(".revocation-modal p")).getText());

    // click cancel
    webDriver.findElement(By.cssSelector("#app-form .revocation-cancel")).click();

    webDriver.findElement(By.linkText("Revoke Access")).click();

    // click confirm
    webDriver.findElement(By.cssSelector("#app-form .revocation-confirm")).click();

    Assert.assertThat(
        webDriver.findElements(By.xpath("//input[@value='app-password.write']")), Matchers.empty());
  }

  @Test
  public void testInvalidAppRedirectDisplaysError() throws Exception {
    ScimUser user = createUnapprovedUser();

    // given we vist the app (specifying an invalid redirect - incorrect protocol https)
    webDriver.get(appUrl + "?redirect_uri=https://localhost:8080/app/");

    // Sign in to login server
    webDriver.findElement(By.name("username")).sendKeys(user.getUserName());
    webDriver.findElement(By.name("password")).sendKeys(user.getPassword());
    webDriver.findElement(By.xpath("//input[@value='Sign in']")).click();

    // Authorize the app for some scopes
    assertThat(
        webDriver.findElement(By.className("alert-error")).getText(),
        RegexMatcher.matchesRegex(
            "^Invalid redirect (.*) did not match one of the registered values"));
  }

  private ScimUser createUnapprovedUser() throws Exception {
    String userName = "******" + new RandomValueStringGenerator().generate();
    String userEmail = userName + "@example.com";

    RestOperations restTemplate = serverRunning.getRestTemplate();

    ScimUser user = new ScimUser();
    user.setUserName(userName);
    user.setPassword("s3Cretsecret");
    user.addEmail(userEmail);
    user.setActive(true);
    user.setVerified(true);

    ResponseEntity<ScimUser> result =
        restTemplate.postForEntity(serverRunning.getUrl("/Users"), user, ScimUser.class);
    assertEquals(HttpStatus.CREATED, result.getStatusCode());

    return user;
  }

  public static class RegexMatcher extends TypeSafeMatcher<String> {

    private final String regex;

    public RegexMatcher(final String regex) {
      this.regex = regex;
    }

    @Override
    public void describeTo(final Description description) {
      description.appendText("matches regex=`" + regex + "`");
    }

    @Override
    public boolean matchesSafely(final String string) {
      return string.matches(regex);
    }

    public static RegexMatcher matchesRegex(final String regex) {
      return new RegexMatcher(regex);
    }
  }
}
 @Before
 public void init() {
   resource = testAccounts.getDefaultResourceOwnerPasswordResource();
 }
/** @author Dave Syer */
public class NativeApplicationIntegrationTests {

  @Rule public ServerRunning serverRunning = ServerRunning.isRunning();

  private UaaTestAccounts testAccounts = UaaTestAccounts.standard(serverRunning);

  @Rule
  public TestAccountSetup testAccountSetup = TestAccountSetup.standard(serverRunning, testAccounts);

  private ResourceOwnerPasswordResourceDetails resource;

  @Before
  public void init() {
    resource = testAccounts.getDefaultResourceOwnerPasswordResource();
  }

  /**
   * tests a happy-day flow of the Resource Owner Password Credentials grant type. (formerly native
   * application profile).
   */
  @Test
  public void testHappyDay() throws Exception {

    MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
    formData.add("grant_type", "password");
    formData.add("username", resource.getUsername());
    formData.add("password", resource.getPassword());
    formData.add("scope", "cloud_controller.read");
    HttpHeaders headers = new HttpHeaders();
    headers.set(
        "Authorization",
        testAccounts.getAuthorizationHeader(resource.getClientId(), resource.getClientSecret()));
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    ResponseEntity<String> response =
        serverRunning.postForString("/oauth/token", formData, headers);
    assertEquals(HttpStatus.OK, response.getStatusCode());
    assertEquals(
        "no-cache, no-store, max-age=0, must-revalidate",
        response.getHeaders().getFirst("Cache-Control"));
  }

  /** tests that an error occurs if you attempt to use bad client credentials. */
  @Test
  @Ignore
  // Need a custom auth entry point to get the correct JSON response here.
  public void testInvalidClient() throws Exception {

    MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
    formData.add("grant_type", "password");
    formData.add("username", resource.getUsername());
    formData.add("password", resource.getPassword());
    formData.add("scope", "cloud_controller.read");
    HttpHeaders headers = new HttpHeaders();
    headers.set(
        "Authorization", "Basic " + new String(Base64.encode("no-such-client:".getBytes("UTF-8"))));
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    @SuppressWarnings("rawtypes")
    ResponseEntity<Map> response = serverRunning.postForMap("/oauth/token", formData, headers);
    assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
    List<String> newCookies = response.getHeaders().get("Set-Cookie");
    if (newCookies != null && !newCookies.isEmpty()) {
      fail("No cookies should be set. Found: " + newCookies.get(0) + ".");
    }
    assertEquals(
        "no-cache, no-store, max-age=0, must-revalidate",
        response.getHeaders().getFirst("Cache-Control"));

    assertEquals(401, response.getStatusCode().value());

    @SuppressWarnings("unchecked")
    OAuth2Exception error = OAuth2Exception.valueOf(response.getBody());
    assertEquals("Bad credentials", error.getMessage());
    assertEquals("invalid_request", error.getOAuth2ErrorCode());
  }

  /** tests that a client secret is required. */
  @Test
  public void testSecretRequired() throws Exception {
    MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
    formData.add("grant_type", "password");
    formData.add("username", resource.getUsername());
    formData.add("password", resource.getPassword());
    formData.add("scope", "cloud_controller.read");
    HttpHeaders headers = new HttpHeaders();
    headers.set(
        "Authorization", "Basic " + new String(Base64.encode("no-such-client:".getBytes("UTF-8"))));
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    ResponseEntity<String> response =
        serverRunning.postForString("/oauth/token", formData, headers);
    assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
  }
}
/** @author Dave Syer */
public class PasswordChangeEndpointIntegrationTests {

  private final String JOE = "joe_" + new RandomValueStringGenerator().generate().toLowerCase();

  private final String userEndpoint = "/Users";

  @Rule public ServerRunning serverRunning = ServerRunning.isRunning();

  private UaaTestAccounts testAccounts = UaaTestAccounts.standard(serverRunning);

  @Rule
  public TestAccountSetup testAccountSetup = TestAccountSetup.standard(serverRunning, testAccounts);

  @Rule
  public OAuth2ContextSetup context =
      OAuth2ContextSetup.withTestAccounts(serverRunning, testAccounts);

  private RestOperations client;

  private ScimUser joe;

  private ResponseEntity<ScimUser> createUser(
      String username, String firstName, String lastName, String email) {
    ScimUser user = new ScimUser();
    user.setUserName(username);
    user.setName(new ScimUser.Name(firstName, lastName));
    user.addEmail(email);
    user.setPassword("pas5Word");
    user.setVerified(true);
    return client.postForEntity(serverRunning.getUrl(userEndpoint), user, ScimUser.class);
  }

  @Before
  public void createRestTemplate() throws Exception {
    Assume.assumeTrue(!testAccounts.isProfileActive("vcap"));
    client = serverRunning.getRestTemplate();
    ((RestTemplate) serverRunning.getRestTemplate())
        .setErrorHandler(
            new OAuth2ErrorHandler(context.getResource()) {
              // Pass errors through in response entity for status code analysis
              @Override
              public boolean hasError(ClientHttpResponse response) throws IOException {
                return false;
              }

              @Override
              public void handleError(ClientHttpResponse response) throws IOException {}
            });
  }

  @BeforeOAuth2Context
  @OAuth2ContextConfiguration(OAuth2ContextConfiguration.ClientCredentials.class)
  public void createAccount() throws Exception {
    client = serverRunning.getRestTemplate();
    ResponseEntity<ScimUser> response = createUser(JOE, "Joe", "User", "*****@*****.**");
    joe = response.getBody();
    assertEquals(JOE, joe.getUserName());
  }

  // curl -v -H "Content-Type: application/json" -X PUT -H
  // "Accept: application/json" --data
  // "{\"password\":\"newpassword\",\"schemas\":[\"urn:scim:schemas:core:1.0\"]}"
  // http://localhost:8080/uaa/User/{id}/password
  @Test
  @OAuth2ContextConfiguration(OAuth2ContextConfiguration.ClientCredentials.class)
  public void testChangePasswordSucceeds() throws Exception {
    PasswordChangeRequest change = new PasswordChangeRequest();
    change.setPassword("Newpasswo3d");

    HttpHeaders headers = new HttpHeaders();
    ResponseEntity<Void> result =
        client.exchange(
            serverRunning.getUrl(userEndpoint) + "/{id}/password",
            HttpMethod.PUT,
            new HttpEntity<>(change, headers),
            Void.class,
            joe.getId());
    assertEquals(HttpStatus.OK, result.getStatusCode());
  }

  @Test
  @OAuth2ContextConfiguration(OAuth2ContextConfiguration.ClientCredentials.class)
  public void testChangePasswordSameAsOldFails() {
    PasswordChangeRequest change = new PasswordChangeRequest();
    change.setPassword("pas5Word");

    HttpHeaders headers = new HttpHeaders();
    ResponseEntity<Void> result =
        client.exchange(
            serverRunning.getUrl(userEndpoint) + "/{id}/password",
            HttpMethod.PUT,
            new HttpEntity<>(change, headers),
            Void.class,
            joe.getId());
    assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, result.getStatusCode());
  }

  @Test
  @OAuth2ContextConfiguration(
      resource = OAuth2ContextConfiguration.Implicit.class,
      initialize = false)
  public void testUserChangesOwnPassword() throws Exception {

    MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
    parameters.set("source", "credentials");
    parameters.set("username", joe.getUserName());
    parameters.set("password", "pas5Word");
    context.getAccessTokenRequest().putAll(parameters);

    PasswordChangeRequest change = new PasswordChangeRequest();
    change.setOldPassword("pas5Word");
    change.setPassword("Newpasswo3d");

    HttpHeaders headers = new HttpHeaders();
    ResponseEntity<Void> result =
        client.exchange(
            serverRunning.getUrl(userEndpoint) + "/{id}/password",
            HttpMethod.PUT,
            new HttpEntity<>(change, headers),
            Void.class,
            joe.getId());
    assertEquals(HttpStatus.OK, result.getStatusCode());
  }

  @Test
  @OAuth2ContextConfiguration(
      resource = OAuth2ContextConfiguration.Implicit.class,
      initialize = false)
  public void testUserMustSupplyOldPassword() throws Exception {

    MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
    parameters.set("source", "credentials");
    parameters.set("username", joe.getUserName());
    parameters.set("password", "pas5Word");
    context.getAccessTokenRequest().putAll(parameters);

    PasswordChangeRequest change = new PasswordChangeRequest();
    change.setPassword("Newpasswo3d");

    HttpHeaders headers = new HttpHeaders();
    ResponseEntity<Void> result =
        client.exchange(
            serverRunning.getUrl(userEndpoint) + "/{id}/password",
            HttpMethod.PUT,
            new HttpEntity<>(change, headers),
            Void.class,
            joe.getId());
    assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode());
  }

  @Test
  @OAuth2ContextConfiguration(
      resource = OAuth2ContextConfiguration.ClientCredentials.class,
      initialize = false)
  public void testUserAccountGetsUnlockedAfterPasswordChange() throws Exception {

    HttpHeaders headers = new HttpHeaders();
    headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    headers.set("Authorization", testAccounts.getAuthorizationHeader("app", "appclientsecret"));

    MultiValueMap<String, String> data = new LinkedMultiValueMap<String, String>();
    data.put("grant_type", Collections.singletonList("password"));
    data.put("username", Collections.singletonList(joe.getUserName()));
    data.put("password", Collections.singletonList("pas5Word"));

    ResponseEntity<Map> result =
        serverRunning.postForMap(
            serverRunning.buildUri("/oauth/token").build().toString(), data, headers);
    assertEquals(HttpStatus.OK, result.getStatusCode());

    // Lock out the account
    data.put("password", Collections.singletonList("randomPassword1"));

    for (int i = 0; i < 5; i++) {
      result =
          serverRunning.postForMap(
              serverRunning.buildUri("/oauth/token").build().toString(), data, headers);
      assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
    }

    // Check that it is locked
    result =
        serverRunning.postForMap(
            serverRunning.buildUri("/oauth/token").build().toString(), data, headers);
    assertEquals("Login policy rejected authentication", result.getBody().get("error_description"));
    assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());

    PasswordChangeRequest change = new PasswordChangeRequest();
    change.setPassword("Newpasswo3d");

    MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
    parameters.set("grant_type", "client_credentials");
    parameters.set("username", "admin");
    parameters.set("password", "adminsecret");
    context.getAccessTokenRequest().putAll(parameters);

    // Change the password
    HttpHeaders passwordChangeHeaders = new HttpHeaders();
    ResponseEntity<Void> passwordChangeResult =
        client.exchange(
            serverRunning.getUrl(userEndpoint) + "/{id}/password",
            HttpMethod.PUT,
            new HttpEntity<>(change, passwordChangeHeaders),
            Void.class,
            joe.getId());
    assertEquals(HttpStatus.OK, passwordChangeResult.getStatusCode());

    MultiValueMap<String, String> newData = new LinkedMultiValueMap<String, String>();
    newData.put("grant_type", Collections.singletonList("password"));
    newData.put("username", Collections.singletonList(joe.getUserName()));
    newData.put("password", Collections.singletonList("Newpasswo3d"));

    ResponseEntity<Map> updatedResult =
        serverRunning.postForMap(
            serverRunning.buildUri("/oauth/token").build().toString(), newData, headers);
    assertEquals(HttpStatus.OK, updatedResult.getStatusCode());
  }
}
  @Test
  @OAuth2ContextConfiguration(
      resource = OAuth2ContextConfiguration.ClientCredentials.class,
      initialize = false)
  public void testUserAccountGetsUnlockedAfterPasswordChange() throws Exception {

    HttpHeaders headers = new HttpHeaders();
    headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    headers.set("Authorization", testAccounts.getAuthorizationHeader("app", "appclientsecret"));

    MultiValueMap<String, String> data = new LinkedMultiValueMap<String, String>();
    data.put("grant_type", Collections.singletonList("password"));
    data.put("username", Collections.singletonList(joe.getUserName()));
    data.put("password", Collections.singletonList("pas5Word"));

    ResponseEntity<Map> result =
        serverRunning.postForMap(
            serverRunning.buildUri("/oauth/token").build().toString(), data, headers);
    assertEquals(HttpStatus.OK, result.getStatusCode());

    // Lock out the account
    data.put("password", Collections.singletonList("randomPassword1"));

    for (int i = 0; i < 5; i++) {
      result =
          serverRunning.postForMap(
              serverRunning.buildUri("/oauth/token").build().toString(), data, headers);
      assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
    }

    // Check that it is locked
    result =
        serverRunning.postForMap(
            serverRunning.buildUri("/oauth/token").build().toString(), data, headers);
    assertEquals("Login policy rejected authentication", result.getBody().get("error_description"));
    assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());

    PasswordChangeRequest change = new PasswordChangeRequest();
    change.setPassword("Newpasswo3d");

    MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
    parameters.set("grant_type", "client_credentials");
    parameters.set("username", "admin");
    parameters.set("password", "adminsecret");
    context.getAccessTokenRequest().putAll(parameters);

    // Change the password
    HttpHeaders passwordChangeHeaders = new HttpHeaders();
    ResponseEntity<Void> passwordChangeResult =
        client.exchange(
            serverRunning.getUrl(userEndpoint) + "/{id}/password",
            HttpMethod.PUT,
            new HttpEntity<>(change, passwordChangeHeaders),
            Void.class,
            joe.getId());
    assertEquals(HttpStatus.OK, passwordChangeResult.getStatusCode());

    MultiValueMap<String, String> newData = new LinkedMultiValueMap<String, String>();
    newData.put("grant_type", Collections.singletonList("password"));
    newData.put("username", Collections.singletonList(joe.getUserName()));
    newData.put("password", Collections.singletonList("Newpasswo3d"));

    ResponseEntity<Map> updatedResult =
        serverRunning.postForMap(
            serverRunning.buildUri("/oauth/token").build().toString(), newData, headers);
    assertEquals(HttpStatus.OK, updatedResult.getStatusCode());
  }
  @Test
  public void testSuccessfulAuthorizationCodeFlow() throws Exception {

    HttpHeaders headers = new HttpHeaders();
    // TODO: should be able to handle just TEXT_HTML
    headers.setAccept(Arrays.asList(MediaType.TEXT_HTML, MediaType.ALL));

    AuthorizationCodeResourceDetails resource = testAccounts.getDefaultAuthorizationCodeResource();

    URI uri =
        serverRunning
            .buildUri("/oauth/authorize")
            .queryParam("response_type", "code")
            .queryParam("state", "mystateid5")
            .queryParam("client_id", resource.getClientId())
            .queryParam("redirect_uri", resource.getPreEstablishedRedirectUri())
            .build();
    ResponseEntity<Void> result = serverRunning.getForResponse(uri.toString(), headers);
    assertEquals(HttpStatus.FOUND, result.getStatusCode());
    String location = result.getHeaders().getLocation().toString();

    if (result.getHeaders().containsKey("Set-Cookie")) {
      String cookie = result.getHeaders().getFirst("Set-Cookie");
      headers.set("Cookie", cookie);
    }

    ResponseEntity<String> response = serverRunning.getForString(location, headers);
    // should be directed to the login screen...
    String body = response.getBody();
    assertTrue(body.contains("/login.do"));
    assertTrue(body.contains("username"));
    assertTrue(body.contains("password"));

    MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
    formData.add("username", testAccounts.getUserName());
    formData.add("password", testAccounts.getPassword());

    // Should be redirected to the original URL, but now authenticated
    result = serverRunning.postForResponse("/login.do", headers, formData);
    assertEquals(HttpStatus.FOUND, result.getStatusCode());

    if (result.getHeaders().containsKey("Set-Cookie")) {
      String cookie = result.getHeaders().getFirst("Set-Cookie");
      headers.set("Cookie", cookie);
    }

    response = serverRunning.getForString(result.getHeaders().getLocation().toString(), headers);
    if (response.getStatusCode() == HttpStatus.OK) {
      body = response.getBody();
      // The grant access page should be returned
      assertTrue(body.contains("Application Authorization"));
      // Forms should have the right action
      assertTrue(body.matches("(?s).*\\saction=\"\\S*oauth/authorize\".*"));

      formData.clear();
      formData.add("user_oauth_approval", "true");
      result = serverRunning.postForResponse("/oauth/authorize", headers, formData);
      assertEquals(HttpStatus.FOUND, result.getStatusCode());
      location = result.getHeaders().getLocation().toString();
    } else {
      // Token cached so no need for second approval
      assertEquals(HttpStatus.FOUND, response.getStatusCode());
      location = response.getHeaders().getLocation().toString();
    }
    assertTrue(
        "Wrong location: " + location,
        location.matches(resource.getPreEstablishedRedirectUri() + ".*code=.+"));
    assertFalse(
        "Location should not contain cookie: " + location,
        location.matches(resource.getPreEstablishedRedirectUri() + ".*cookie=.+"));

    formData.clear();
    formData.add("client_id", resource.getClientId());
    formData.add("redirect_uri", resource.getPreEstablishedRedirectUri());
    formData.add("grant_type", "authorization_code");
    formData.add("code", location.split("code=")[1].split("&")[0]);
    HttpHeaders tokenHeaders = new HttpHeaders();
    tokenHeaders.set(
        "Authorization",
        testAccounts.getAuthorizationHeader(resource.getClientId(), resource.getClientSecret()));
    @SuppressWarnings("rawtypes")
    ResponseEntity<Map> tokenResponse =
        serverRunning.postForMap("/oauth/token", formData, tokenHeaders);
    assertEquals(HttpStatus.OK, tokenResponse.getStatusCode());
  }