protected ScimUser updateUser(String token, int status, ScimUser user) throws Exception {
    MockHttpServletRequestBuilder put =
        put("/Users/" + user.getId())
            .header("Authorization", "Bearer " + token)
            .header("If-Match", "\"" + user.getVersion() + "\"")
            .accept(APPLICATION_JSON)
            .contentType(APPLICATION_JSON)
            .content(JsonUtils.writeValueAsBytes(user));
    if (status == HttpStatus.OK.value()) {
      String json =
          getMockMvc()
              .perform(put)
              .andExpect(status().isOk())
              .andExpect(header().string("ETag", "\"1\""))
              .andExpect(jsonPath("$.userName").value(user.getUserName()))
              .andExpect(jsonPath("$.emails[0].value").value(user.getPrimaryEmail()))
              .andExpect(jsonPath("$.name.givenName").value(user.getGivenName()))
              .andExpect(jsonPath("$.name.familyName").value(user.getFamilyName()))
              .andReturn()
              .getResponse()
              .getContentAsString();

      return JsonUtils.readValue(json, ScimUser.class);
    } else {
      getMockMvc().perform(put).andExpect(status().is(status));
      return null;
    }
  }
  @Test
  public void verification_link() throws Exception {
    ScimUser joel = setUpScimUser();

    MockHttpServletRequestBuilder get = setUpVerificationLinkRequest(joel, scimCreateToken);

    MvcResult result = getMockMvc().perform(get).andExpect(status().isOk()).andReturn();

    VerificationResponse verificationResponse =
        JsonUtils.readValue(result.getResponse().getContentAsString(), VerificationResponse.class);
    assertThat(
        verificationResponse.getVerifyLink().toString(),
        startsWith("http://localhost/verify_user"));

    String query = verificationResponse.getVerifyLink().getQuery();

    String code = getQueryStringParam(query, "code");
    assertThat(code, is(notNullValue()));

    ExpiringCode expiringCode = codeStore.retrieveCode(code);
    assertThat(expiringCode.getExpiresAt().getTime(), is(greaterThan(System.currentTimeMillis())));
    assertThat(expiringCode.getIntent(), is(REGISTRATION.name()));
    Map<String, String> data =
        JsonUtils.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {});
    assertThat(data.get(InvitationConstants.USER_ID), is(notNullValue()));
    assertThat(data.get(CLIENT_ID), is(clientDetails.getClientId()));
    assertThat(data.get(REDIRECT_URI), is(HTTP_REDIRECT_EXAMPLE_COM));
  }
  @Test
  public void patch_user_to_inactive_then_login() throws Exception {
    ScimUser user = setUpScimUser();
    user.setVerified(true);
    boolean active = true;
    user.setActive(active);
    getMockMvc()
        .perform(
            patch("/Users/" + user.getId())
                .header("Authorization", "Bearer " + scimReadWriteToken)
                .header("If-Match", "\"" + user.getVersion() + "\"")
                .contentType(APPLICATION_JSON)
                .content(JsonUtils.writeValueAsString(user)))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.active", equalTo(active)));

    performAuthentication(user, true);

    active = false;
    user.setActive(active);
    getMockMvc()
        .perform(
            patch("/Users/" + user.getId())
                .header("Authorization", "Bearer " + scimReadWriteToken)
                .header("If-Match", "\"" + (user.getVersion() + 1) + "\"")
                .contentType(APPLICATION_JSON)
                .content(JsonUtils.writeValueAsString(user)))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.active", equalTo(active)));

    performAuthentication(user, false);
  }
  @Test
  public void listUsers_in_anotherZone() throws Exception {
    String subdomain = generator.generate();
    MockMvcUtils.IdentityZoneCreationResult result =
        utils()
            .createOtherIdentityZoneAndReturnResult(
                subdomain, getMockMvc(), getWebApplicationContext(), null);
    String zoneAdminToken = result.getZoneAdminToken();
    createUser(
        getScimUser(),
        zoneAdminToken,
        IdentityZone.getUaa().getSubdomain(),
        result.getIdentityZone().getId());

    MockHttpServletRequestBuilder get =
        MockMvcRequestBuilders.get("/Users")
            .header("X-Identity-Zone-Subdomain", subdomain)
            .header("Authorization", "Bearer " + zoneAdminToken)
            .accept(APPLICATION_JSON);

    MvcResult mvcResult = getMockMvc().perform(get).andExpect(status().isOk()).andReturn();
    SearchResults searchResults =
        JsonUtils.readValue(mvcResult.getResponse().getContentAsString(), SearchResults.class);
    MatcherAssert.assertThat(searchResults.getResources().size(), is(1));
  }
  @Test
  public void testUnlockAccountWhenNotLocked() throws Exception {
    ScimUser userToLockout = createUser(uaaAdminToken);

    UserAccountStatus alteredAccountStatus = new UserAccountStatus();
    alteredAccountStatus.setLocked(false);
    String jsonStatus = JsonUtils.writeValueAsString(alteredAccountStatus);
    getMockMvc()
        .perform(
            patch("/Users/" + userToLockout.getId() + "/status")
                .header("Authorization", "Bearer " + uaaAdminToken)
                .accept(APPLICATION_JSON)
                .contentType(APPLICATION_JSON)
                .content(jsonStatus))
        .andExpect(status().isOk())
        .andExpect(content().json(jsonStatus));

    getMockMvc()
        .perform(
            post("/login.do")
                .with(cookieCsrf())
                .param("username", userToLockout.getUserName())
                .param("password", userToLockout.getPassword()))
        .andExpect(redirectedUrl("/"));
  }
  @Test
  public void createUserInOtherZoneWithUaaAdminTokenFromNonDefaultZone() throws Exception {
    IdentityZone identityZone = getIdentityZone();

    String authorities = "uaa.admin";
    clientDetails =
        utils()
            .createClient(
                this.getMockMvc(),
                uaaAdminToken,
                "testClientId",
                "testClientSecret",
                null,
                null,
                Collections.singletonList("client_credentials"),
                authorities,
                null,
                identityZone);
    String uaaAdminTokenFromOtherZone =
        testClient.getClientCredentialsOAuthAccessToken(
            "testClientId", "testClientSecret", "uaa.admin", identityZone.getSubdomain());

    byte[] requestBody = JsonUtils.writeValueAsBytes(getScimUser());
    MockHttpServletRequestBuilder post =
        post("/Users")
            .header("Authorization", "Bearer " + uaaAdminTokenFromOtherZone)
            .contentType(APPLICATION_JSON)
            .content(requestBody);
    post.with(new SetServerNameRequestPostProcessor(identityZone.getSubdomain() + ".localhost"));
    post.header(IdentityZoneSwitchingFilter.HEADER, IdentityZone.getUaa().getId());

    getMockMvc().perform(post).andExpect(status().isForbidden());
  }
  @Test
  public void acceptInvitationWithInvalidRedirectUri() throws Exception {
    ScimUser user = new ScimUser("user-id-001", "*****@*****.**", "first", "last");
    user.setOrigin(UAA);
    BaseClientDetails clientDetails =
        new BaseClientDetails("client-id", null, null, null, null, "http://example.com/redirect");
    when(scimUserProvisioning.verifyUser(anyString(), anyInt())).thenReturn(user);
    when(scimUserProvisioning.update(anyString(), anyObject())).thenReturn(user);
    when(scimUserProvisioning.retrieve(eq("user-id-001"))).thenReturn(user);
    when(clientDetailsService.loadClientByClientId("acmeClientId")).thenReturn(clientDetails);
    Map<String, String> userData = new HashMap<>();
    userData.put(USER_ID, "user-id-001");
    userData.put(EMAIL, "*****@*****.**");
    userData.put(REDIRECT_URI, "http://someother/redirect");
    userData.put(CLIENT_ID, "acmeClientId");
    when(expiringCodeStore.retrieveCode(anyString()))
        .thenReturn(
            new ExpiringCode(
                "code",
                new Timestamp(System.currentTimeMillis()),
                JsonUtils.writeValueAsString(userData)));

    String redirectLocation =
        emailInvitationsService.acceptInvitation("code", "password").getRedirectUri();

    verify(scimUserProvisioning).verifyUser(user.getId(), user.getVersion());
    verify(scimUserProvisioning).changePassword(user.getId(), null, "password");
    assertEquals("/home", redirectLocation);
  }
 private String getData(Approval source) {
   try {
     return JsonUtils.writeValueAsString(new ApprovalModifiedEventData(source));
   } catch (JsonUtils.JsonUtilException e) {
     logger.error("error writing approval event data", e);
   }
   return null;
 }
  @Test
  public void verification_link_in_non_default_zone_using_switch() throws Exception {
    String subdomain = generator.generate().toLowerCase();
    MockMvcUtils.IdentityZoneCreationResult zoneResult =
        utils()
            .createOtherIdentityZoneAndReturnResult(
                subdomain, getMockMvc(), getWebApplicationContext(), null);
    String zonedClientId = "admin";
    String zonedClientSecret = "adminsecret";
    String zonedScimCreateToken =
        utils()
            .getClientCredentialsOAuthAccessToken(
                getMockMvc(), zonedClientId, zonedClientSecret, "uaa.admin", null);

    ScimUser joel = setUpScimUser(zoneResult.getIdentityZone());

    MockHttpServletRequestBuilder get =
        MockMvcRequestBuilders.get("/Users/" + joel.getId() + "/verify-link")
            .header("Host", "localhost")
            .header("Authorization", "Bearer " + zonedScimCreateToken)
            .header(IdentityZoneSwitchingFilter.SUBDOMAIN_HEADER, subdomain)
            .param("redirect_uri", HTTP_REDIRECT_EXAMPLE_COM)
            .accept(APPLICATION_JSON);

    MvcResult result = getMockMvc().perform(get).andExpect(status().isOk()).andReturn();
    VerificationResponse verificationResponse =
        JsonUtils.readValue(result.getResponse().getContentAsString(), VerificationResponse.class);
    assertThat(
        verificationResponse.getVerifyLink().toString(),
        startsWith("http://" + subdomain + ".localhost/verify_user"));

    String query = verificationResponse.getVerifyLink().getQuery();

    String code = getQueryStringParam(query, "code");
    assertThat(code, is(notNullValue()));

    ExpiringCode expiringCode = codeStore.retrieveCode(code);
    assertThat(expiringCode.getExpiresAt().getTime(), is(greaterThan(System.currentTimeMillis())));
    assertThat(expiringCode.getIntent(), is(REGISTRATION.name()));
    Map<String, String> data =
        JsonUtils.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {});
    assertThat(data.get(InvitationConstants.USER_ID), is(notNullValue()));
    assertThat(data.get(CLIENT_ID), is("admin"));
    assertThat(data.get(REDIRECT_URI), is(HTTP_REDIRECT_EXAMPLE_COM));
  }
  private ResultActions createUserAndReturnResult(
      ScimUser user, String token, String subdomain, String switchZone) throws Exception {
    byte[] requestBody = JsonUtils.writeValueAsBytes(user);
    MockHttpServletRequestBuilder post =
        post("/Users")
            .header("Authorization", "Bearer " + token)
            .contentType(APPLICATION_JSON)
            .content(requestBody);
    if (subdomain != null && !subdomain.equals(""))
      post.with(new SetServerNameRequestPostProcessor(subdomain + ".localhost"));
    if (switchZone != null) post.header(IdentityZoneSwitchingFilter.HEADER, switchZone);

    return getMockMvc().perform(post);
  }
Exemple #11
0
  private void validateToken(String paramName, Map params, String[] scopes, String[] aud)
      throws java.io.IOException {
    Jwt access_token = JwtHelper.decode((String) params.get(paramName));

    Map<String, Object> claims =
        JsonUtils.readValue(access_token.getClaims(), new TypeReference<Map<String, Object>>() {});

    Assert.assertThat(claims.get("jti"), is(params.get("jti")));
    Assert.assertThat(claims.get("client_id"), is("cf"));
    Assert.assertThat(claims.get("cid"), is("cf"));
    Assert.assertThat(claims.get("user_name"), is(user.getUserName()));
    Assert.assertThat(((List<String>) claims.get(Claims.SCOPE)), containsInAnyOrder(scopes));
    Assert.assertThat(((List<String>) claims.get(Claims.AUD)), containsInAnyOrder(aud));
  }
  @Test
  public void testDeleteUserWithUaaAdminToken() throws Exception {
    ScimUser user = setUpScimUser();

    getMockMvc()
        .perform(
            (delete("/Users/" + user.getId()))
                .header("Authorization", "Bearer " + uaaAdminToken)
                .contentType(APPLICATION_JSON)
                .content(JsonUtils.writeValueAsBytes(user)))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.userName").value(user.getUserName()))
        .andExpect(jsonPath("$.emails[0].value").value(user.getPrimaryEmail()))
        .andExpect(jsonPath("$.name.givenName").value(user.getGivenName()))
        .andExpect(jsonPath("$.name.familyName").value(user.getFamilyName()));
  }
 private ScimUser createUser(ScimUser user, String token, String subdomain, String switchZone)
     throws Exception {
   String password = hasText(user.getPassword()) ? user.getPassword() : "pas5word";
   user.setPassword(password);
   MvcResult result =
       createUserAndReturnResult(user, token, subdomain, switchZone)
           .andExpect(status().isCreated())
           .andExpect(header().string("ETag", "\"0\""))
           .andExpect(jsonPath("$.userName").value(user.getUserName()))
           .andExpect(jsonPath("$.emails[0].value").value(user.getUserName()))
           .andExpect(jsonPath("$.name.familyName").value(user.getFamilyName()))
           .andExpect(jsonPath("$.name.givenName").value(user.getGivenName()))
           .andReturn();
   user = JsonUtils.readValue(result.getResponse().getContentAsString(), ScimUser.class);
   user.setPassword(password);
   return user;
 }
  // TODO: add cases for username no existing external user with username not email
  @Test
  public void accept_invitation_with_external_user_that_does_not_have_email_as_their_username() {
    String userId = "user-id-001";
    String email = "*****@*****.**";
    String actualUsername = "******";
    ScimUser userBeforeAccept = new ScimUser(userId, email, "first", "last");
    userBeforeAccept.setPrimaryEmail(email);
    userBeforeAccept.setOrigin(Origin.SAML);

    when(scimUserProvisioning.verifyUser(eq(userId), anyInt())).thenReturn(userBeforeAccept);
    when(scimUserProvisioning.retrieve(eq(userId))).thenReturn(userBeforeAccept);

    BaseClientDetails clientDetails =
        new BaseClientDetails("client-id", null, null, null, null, "http://example.com/redirect");
    when(clientDetailsService.loadClientByClientId("acmeClientId")).thenReturn(clientDetails);

    Map<String, String> userData = new HashMap<>();
    userData.put(USER_ID, userBeforeAccept.getId());
    userData.put(EMAIL, userBeforeAccept.getPrimaryEmail());
    userData.put(REDIRECT_URI, "http://someother/redirect");
    userData.put(CLIENT_ID, "acmeClientId");
    when(expiringCodeStore.retrieveCode(anyString()))
        .thenReturn(
            new ExpiringCode(
                "code",
                new Timestamp(System.currentTimeMillis()),
                JsonUtils.writeValueAsString(userData)));

    ScimUser userAfterAccept =
        new ScimUser(
            userId,
            actualUsername,
            userBeforeAccept.getGivenName(),
            userBeforeAccept.getFamilyName());
    userAfterAccept.setPrimaryEmail(email);

    when(scimUserProvisioning.verifyUser(eq(userId), anyInt())).thenReturn(userAfterAccept);

    ScimUser acceptedUser = emailInvitationsService.acceptInvitation("code", "password").getUser();
    assertEquals(userAfterAccept.getUserName(), acceptedUser.getUserName());
    assertEquals(userAfterAccept.getName(), acceptedUser.getName());
    assertEquals(userAfterAccept.getPrimaryEmail(), acceptedUser.getPrimaryEmail());

    verify(scimUserProvisioning).verifyUser(eq(userId), anyInt());
  }
  @Test
  public void cannotCreateUserWithInvalidPasswordInDefaultZone() throws Exception {
    ScimUser user = getScimUser();
    user.setPassword(new RandomValueStringGenerator(260).generate());
    byte[] requestBody = JsonUtils.writeValueAsBytes(user);
    MockHttpServletRequestBuilder post =
        post("/Users")
            .header("Authorization", "Bearer " + scimCreateToken)
            .contentType(APPLICATION_JSON)
            .content(requestBody);

    getMockMvc()
        .perform(post)
        .andExpect(status().isBadRequest())
        .andExpect(jsonPath("$.error").value("invalid_password"))
        .andExpect(
            jsonPath("$.message").value("Password must be no more than 255 characters in length."));
  }
  @Test
  public void create_user_without_email() throws Exception {
    ScimUser joel = new ScimUser(null, "a_user", "Joel", "D'sa");

    getMockMvc()
        .perform(
            post("/Users")
                .header("Authorization", "Bearer " + scimReadWriteToken)
                .contentType(APPLICATION_JSON)
                .content(JsonUtils.writeValueAsString(joel)))
        .andExpect(status().isBadRequest())
        .andExpect(
            content()
                .string(
                    JsonObjectMatcherUtils.matchesJsonObject(
                        new JSONObject()
                            .put("error_description", "Exactly one email must be provided.")
                            .put("message", "Exactly one email must be provided.")
                            .put("error", "invalid_scim_resource"))));
  }
  @Test
  public void testUpdateUserInOtherZoneWithUaaAdminToken() throws Exception {
    IdentityZone identityZone = getIdentityZone();
    ScimUser user = setUpScimUser(identityZone);
    user.setName(new ScimUser.Name("changed", "name"));

    getMockMvc()
        .perform(
            put("/Users/" + user.getId())
                .header("Authorization", "Bearer " + uaaAdminToken)
                .header(IdentityZoneSwitchingFilter.HEADER, identityZone.getId())
                .header("If-Match", "\"" + user.getVersion() + "\"")
                .contentType(APPLICATION_JSON)
                .content(JsonUtils.writeValueAsBytes(user)))
        .andExpect(status().isOk())
        .andExpect(header().string("ETag", "\"1\""))
        .andExpect(jsonPath("$.userName").value(user.getUserName()))
        .andExpect(jsonPath("$.emails[0].value").value(user.getPrimaryEmail()))
        .andExpect(jsonPath("$.name.givenName").value(user.getGivenName()))
        .andExpect(jsonPath("$.name.familyName").value(user.getFamilyName()));
  }
  @Test
  public void testGetUserWithInvalidAttributes() throws Exception {

    String nonexistentAttribute = "displayBlaBla";

    MockHttpServletRequestBuilder get =
        get("/Users")
            .header("Authorization", "Bearer " + scimReadWriteToken)
            .contentType(MediaType.APPLICATION_JSON)
            .param("attributes", nonexistentAttribute)
            .accept(APPLICATION_JSON);

    MvcResult mvcResult = getMockMvc().perform(get).andExpect(status().isOk()).andReturn();

    String body = mvcResult.getResponse().getContentAsString();

    List<Map> attList = (List) JsonUtils.readValue(body, Map.class).get("resources");
    for (Map<String, Object> attMap : attList) {
      assertNull(attMap.get(nonexistentAttribute));
    }
  }
  @Test
  public void create_user_then_update_without_email() throws Exception {
    ScimUser user = setUpScimUser();
    user.setEmails(null);

    getMockMvc()
        .perform(
            put("/Users/" + user.getId())
                .header("Authorization", "Bearer " + scimReadWriteToken)
                .header("If-Match", "\"" + user.getVersion() + "\"")
                .contentType(APPLICATION_JSON)
                .content(JsonUtils.writeValueAsString(user)))
        .andExpect(status().isBadRequest())
        .andExpect(
            content()
                .string(
                    JsonObjectMatcherUtils.matchesJsonObject(
                        new JSONObject()
                            .put("error_description", "Exactly one email must be provided.")
                            .put("message", "Exactly one email must be provided.")
                            .put("error", "invalid_scim_resource"))));
  }
  @Test
  public void testAccountStatusEmptyPatchDoesNotUnlock() throws Exception {
    ScimUser userToLockout = createUser(uaaAdminToken);
    attemptFailedLogin(5, userToLockout.getUserName(), "");

    String jsonStatus = JsonUtils.writeValueAsString(Collections.emptyMap());
    getMockMvc()
        .perform(
            patch("/Users/" + userToLockout.getId() + "/status")
                .header("Authorization", "Bearer " + uaaAdminToken)
                .accept(APPLICATION_JSON)
                .contentType(APPLICATION_JSON)
                .content(jsonStatus))
        .andExpect(status().isOk())
        .andExpect(content().json(jsonStatus));

    getMockMvc()
        .perform(
            post("/login.do")
                .with(cookieCsrf())
                .param("username", userToLockout.getUserName())
                .param("password", userToLockout.getPassword()))
        .andExpect(redirectedUrl("/login?error=account_locked"));
  }
  @Test
  public void testCreateUserInOtherZoneIsUnauthorized() throws Exception {
    String subdomain = generator.generate();
    mockMvcUtils.createOtherIdentityZone(subdomain, getMockMvc(), getWebApplicationContext());

    String otherSubdomain = generator.generate();
    mockMvcUtils.createOtherIdentityZone(otherSubdomain, getMockMvc(), getWebApplicationContext());

    String zoneAdminToken =
        testClient.getClientCredentialsOAuthAccessToken(
            "admin", "admin-secret", "scim.write", subdomain);

    ScimUser user = getScimUser();

    byte[] requestBody = JsonUtils.writeValueAsBytes(user);
    MockHttpServletRequestBuilder post =
        post("/Users")
            .with(new SetServerNameRequestPostProcessor(otherSubdomain + ".localhost"))
            .header("Authorization", "Bearer " + zoneAdminToken)
            .contentType(APPLICATION_JSON)
            .content(requestBody);

    getMockMvc().perform(post).andExpect(status().isUnauthorized());
  }
  @Test
  public void testLoginUsingPasscodeWithSamlToken() throws Exception {
    ExpiringUsernameAuthenticationToken et =
        new ExpiringUsernameAuthenticationToken(USERNAME, null);
    LoginSamlAuthenticationToken auth = new LoginSamlAuthenticationToken(marissa, et);
    final MockSecurityContext mockSecurityContext = new MockSecurityContext(auth);

    SecurityContextHolder.setContext(mockSecurityContext);
    MockHttpSession session = new MockHttpSession();

    session.setAttribute(
        HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, mockSecurityContext);

    MockHttpServletRequestBuilder get = get("/passcode").accept(APPLICATION_JSON).session(session);

    String passcode =
        JsonUtils.readValue(
            getMockMvc()
                .perform(get)
                .andExpect(status().isOk())
                .andReturn()
                .getResponse()
                .getContentAsString(),
            String.class);

    mockSecurityContext.setAuthentication(null);
    session = new MockHttpSession();
    session.setAttribute(
        HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, mockSecurityContext);

    String basicDigestHeaderValue = "Basic " + new String(Base64.encodeBase64(("cf:").getBytes()));
    MockHttpServletRequestBuilder post =
        post("/oauth/token")
            .accept(APPLICATION_JSON)
            .contentType(APPLICATION_FORM_URLENCODED)
            .header("Authorization", basicDigestHeaderValue)
            .param("grant_type", "password")
            .param("passcode", passcode)
            .param("response_type", "token");

    Map accessToken =
        JsonUtils.readValue(
            getMockMvc()
                .perform(post)
                .andExpect(status().isOk())
                .andReturn()
                .getResponse()
                .getContentAsString(),
            Map.class);
    assertEquals("bearer", accessToken.get("token_type"));
    assertNotNull(accessToken.get("access_token"));
    assertNotNull(accessToken.get("refresh_token"));
    String[] scopes = ((String) accessToken.get("scope")).split(" ");
    assertThat(
        Arrays.asList(scopes),
        containsInAnyOrder(
            "uaa.user",
            "scim.userids",
            "password.write",
            "cloud_controller.write",
            "openid",
            "cloud_controller.read"));

    Authentication authentication = captureSecurityContextFilter.getAuthentication();
    assertNotNull(authentication);
    assertTrue(authentication instanceof OAuth2Authentication);
    assertTrue(
        ((OAuth2Authentication) authentication).getUserAuthentication()
            instanceof UsernamePasswordAuthenticationToken);
    assertTrue(authentication.getPrincipal() instanceof UaaPrincipal);
    assertEquals(marissa.getOrigin(), ((UaaPrincipal) authentication.getPrincipal()).getOrigin());
  }
Exemple #23
0
  @RequestMapping(
      value = "/invite_users",
      method = RequestMethod.POST,
      consumes = "application/json")
  public ResponseEntity<InvitationsResponse> inviteUsers(
      @RequestBody InvitationsRequest invitations,
      @RequestParam(value = "client_id", required = false) String clientId,
      @RequestParam(value = "redirect_uri") String redirectUri) {

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication instanceof OAuth2Authentication) {
      OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) authentication;

      if (clientId == null) {
        clientId = oAuth2Authentication.getOAuth2Request().getClientId();
      }
    }

    InvitationsResponse invitationsResponse = new InvitationsResponse();

    DomainFilter filter = new DomainFilter();
    List<IdentityProvider> activeProviders =
        providers.retrieveActive(IdentityZoneHolder.get().getId());
    ClientDetails client = clients.loadClientByClientId(clientId);
    for (String email : invitations.getEmails()) {
      try {
        List<IdentityProvider> providers = filter.filter(activeProviders, client, email);
        if (providers.size() == 1) {
          ScimUser user = findOrCreateUser(email, providers.get(0).getOriginKey());

          String accountsUrl = UaaUrlUtils.getUaaUrl("/invitations/accept");

          Map<String, String> data = new HashMap<>();
          data.put(InvitationConstants.USER_ID, user.getId());
          data.put(InvitationConstants.EMAIL, user.getPrimaryEmail());
          data.put(CLIENT_ID, clientId);
          data.put(REDIRECT_URI, redirectUri);
          data.put(ORIGIN, user.getOrigin());
          Timestamp expiry =
              new Timestamp(
                  System.currentTimeMillis() + (INVITATION_EXPIRY_DAYS * 24 * 60 * 60 * 1000));
          ExpiringCode code =
              expiringCodeStore.generateCode(JsonUtils.writeValueAsString(data), expiry, null);

          String invitationLink = accountsUrl + "?code=" + code.getCode();
          try {
            URL inviteLink = new URL(invitationLink);
            invitationsResponse
                .getNewInvites()
                .add(
                    InvitationsResponse.success(
                        user.getPrimaryEmail(), user.getId(), user.getOrigin(), inviteLink));
          } catch (MalformedURLException mue) {
            invitationsResponse
                .getFailedInvites()
                .add(
                    InvitationsResponse.failure(
                        email,
                        "invitation.exception.url",
                        String.format("Malformed url", invitationLink)));
          }
        } else if (providers.size() == 0) {
          invitationsResponse
              .getFailedInvites()
              .add(
                  InvitationsResponse.failure(
                      email, "provider.non-existent", "No authentication provider found."));
        } else {
          invitationsResponse
              .getFailedInvites()
              .add(
                  InvitationsResponse.failure(
                      email, "provider.ambiguous", "Multiple authentication providers found."));
        }
      } catch (ScimResourceConflictException x) {
        invitationsResponse
            .getFailedInvites()
            .add(
                InvitationsResponse.failure(
                    email,
                    "user.ambiguous",
                    "Multiple users with the same origin matched to the email address."));
      } catch (UaaException uaae) {
        invitationsResponse
            .getFailedInvites()
            .add(InvitationsResponse.failure(email, "invitation.exception", uaae.getMessage()));
      }
    }
    return new ResponseEntity<>(invitationsResponse, HttpStatus.OK);
  }
  @Test
  public void inviteUsers() throws Exception {
    String[] emails = new String[] {"user1@" + domain, "user2@" + domain};
    String redirectUri = "example.com";

    InvitationsRequest invitationsRequest = new InvitationsRequest(emails);
    String requestBody = JsonUtils.writeValueAsString(invitationsRequest);

    Snippet requestFields =
        requestFields(
            fieldWithPath("emails")
                .attributes(key("constraints").value("Required"))
                .description(
                    "User is invited by providing an email address. More than one email addresses can be provided."));

    Snippet requestParameters =
        requestParameters(
            parameterWithName("client_id")
                .attributes(key("constraints").value("Optional"), key("type").value(STRING))
                .description(
                    "A unique string representing the registration information provided by the client"),
            parameterWithName("redirect_uri")
                .attributes(key("constraints").value("Required"), key("type").value(STRING))
                .description(
                    "The user will be redirected to this uri, when user accepts the invitation. The redirect_uri will be validated against allowed redirect_uri for the client."));

    Snippet responseFields =
        responseFields(
            fieldWithPath("new_invites[].email")
                .type(STRING)
                .description("Primary email id of the invited user"),
            fieldWithPath("new_invites[].userId")
                .type(STRING)
                .description("A unique string for the invited user"),
            fieldWithPath("new_invites[].origin")
                .type(STRING)
                .description("Unique alias of the provider"),
            fieldWithPath("new_invites[].success")
                .type(BOOLEAN)
                .description("Flag to determine whether the invitation was sent successfully"),
            fieldWithPath("new_invites[].errorCode")
                .type(STRING)
                .description("Error code in case of failure to send invitation"),
            fieldWithPath("new_invites[].errorMessage")
                .type(STRING)
                .description("Error message in case of failure to send invitation"),
            fieldWithPath("new_invites[].inviteLink")
                .type(STRING)
                .description("Invitation link to invite users"),
            fieldWithPath("failed_invites")
                .type(STRING)
                .description("List of invites having exception in sending the invitation"));

    getMockMvc()
        .perform(
            post("/invite_users?"
                    + String.format("%s=%s&%s=%s", CLIENT_ID, clientId, REDIRECT_URI, redirectUri))
                .header("Authorization", "Bearer " + token)
                .contentType(APPLICATION_JSON)
                .content(requestBody))
        .andExpect(status().isOk())
        .andDo(
            document(
                "{ClassName}/{methodName}",
                preprocessRequest(prettyPrint()),
                preprocessResponse(prettyPrint()),
                requestHeaders(
                    headerWithName("Authorization")
                        .description("Bearer token containing `scim.invite`")),
                requestParameters,
                requestFields,
                responseFields));
  }