private String getGroupAuthorities(ScimGroupMember member) {
   if (member.getRoles() != null && !member.getRoles().isEmpty()) {
     return StringUtils.collectionToCommaDelimitedString(member.getRoles());
   } else {
     return StringUtils.collectionToCommaDelimitedString(ScimGroupMember.GROUP_MEMBER);
   }
 }
  @Override
  public List<ScimGroupMember> updateOrAddMembers(String groupId, List<ScimGroupMember> members)
      throws ScimResourceNotFoundException {
    List<ScimGroupMember> currentMembers = getMembers(groupId);
    logger.debug("current-members: " + currentMembers + ", in request: " + members);

    List<ScimGroupMember> currentMembersToRemove = new ArrayList<>(currentMembers);
    currentMembersToRemove.removeAll(members);
    logger.debug("removing members: " + currentMembersToRemove);
    for (ScimGroupMember member : currentMembersToRemove) {
      removeMemberById(groupId, member.getMemberId());
    }

    List<ScimGroupMember> newMembersToAdd = new ArrayList<>(members);
    newMembersToAdd.removeAll(currentMembers);
    logger.debug("adding new members: " + newMembersToAdd);
    for (ScimGroupMember member : newMembersToAdd) {
      addMember(groupId, member);
    }

    List<ScimGroupMember> membersToUpdate = new ArrayList<>(members);
    membersToUpdate.retainAll(currentMembers);
    logger.debug("updating members: " + membersToUpdate);
    for (ScimGroupMember member : membersToUpdate) {
      updateMember(groupId, member);
    }

    return getMembers(groupId);
  }
  @Override
  public ScimGroupMember updateMember(final String groupId, final ScimGroupMember member)
      throws ScimResourceNotFoundException, MemberNotFoundException {
    validateRequest(groupId, member);
    final String authorities = getGroupAuthorities(member);
    int updated =
        jdbcTemplate.update(
            UPDATE_MEMBER_SQL,
            new PreparedStatementSetter() {
              @Override
              public void setValues(PreparedStatement ps) throws SQLException {
                ps.setString(1, authorities);
                ps.setString(2, groupId);
                ps.setString(3, member.getMemberId());
              }
            });

    if (updated == 0) {
      throw new MemberNotFoundException(
          "Member " + member.getMemberId() + " does not exist in group " + groupId);
    }

    if (updated != 1) {
      throw new IncorrectResultSizeDataAccessException(
          "unexpected number of members updated", 1, updated);
    }

    return getMemberById(groupId, member.getMemberId());
  }
  @Override
  public ScimGroupMember addMember(final String groupId, final ScimGroupMember member)
      throws ScimResourceNotFoundException, MemberAlreadyExistsException {

    if (isDefaultGroup(groupId)) {
      throw new MemberAlreadyExistsException("Trying to add member to default group");
    }
    // first validate the supplied groupId, memberId
    validateRequest(groupId, member);
    final String authorities = getGroupAuthorities(member);
    final String type =
        (member.getType() == null ? ScimGroupMember.Type.USER : member.getType()).toString();
    try {
      logger.debug("Associating group:" + groupId + " with member:" + member);
      jdbcTemplate.update(
          ADD_MEMBER_SQL,
          new PreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps) throws SQLException {
              ps.setString(1, groupId);
              ps.setString(2, member.getMemberId());
              ps.setString(3, type);
              ps.setString(4, authorities);
              ps.setTimestamp(5, new Timestamp(new Date().getTime()));
              ps.setString(6, member.getOrigin());
            }
          });
    } catch (DuplicateKeyException e) {
      throw new MemberAlreadyExistsException(
          member.getMemberId() + " is already part of the group: " + groupId);
    }
    return getMemberById(groupId, member.getMemberId());
  }
  @Test
  public void canGetMemberById() throws Exception {
    addMember("g3", "m2", "USER", "READER,WRITER");

    ScimGroupMember m = dao.getMemberById("g3", "m2");
    assertEquals(ScimGroupMember.Type.USER, m.getType());
    assertEquals(ScimGroupMember.GROUP_ADMIN, m.getRoles());
  }
 @Test(expected = ScimResourceNotFoundException.class)
 public void addMember_In_Different_Zone_Causes_Issues() throws Exception {
   String subdomain = generator.generate();
   IdentityZone otherZone = MultitenancyFixture.identityZone(subdomain, subdomain);
   IdentityZoneHolder.set(otherZone);
   ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, null);
   m1.setOrigin(OriginKeys.UAA);
   dao.addMember("g2", m1);
 }
  @Override
  public ScimGroup deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
    ScimGroup group = new ScimGroup();

    Map<ScimGroupMember.Role, List<ScimGroupMember>> roles =
        new HashMap<ScimGroupMember.Role, List<ScimGroupMember>>();
    for (ScimGroupMember.Role role : ScimGroupMember.Role.values()) {
      roles.put(role, new ArrayList<ScimGroupMember>());
    }
    Set<ScimGroupMember> allMembers = new HashSet<ScimGroupMember>();

    while (jp.nextToken() != JsonToken.END_OBJECT) {
      if (jp.getCurrentToken() == JsonToken.FIELD_NAME) {
        String fieldName = jp.getCurrentName();
        jp.nextToken();

        if ("id".equalsIgnoreCase(fieldName)) {
          group.setId(jp.readValueAs(String.class));
        } else if ("displayname".equalsIgnoreCase(fieldName)) {
          group.setDisplayName(jp.readValueAs(String.class));
        } else if ("meta".equalsIgnoreCase(fieldName)) {
          group.setMeta(jp.readValueAs(ScimMeta.class));
        } else if ("schemas".equalsIgnoreCase(fieldName)) {
          group.setSchemas(jp.readValueAs(String[].class));
        } else {
          String value = fieldName.substring(0, fieldName.length() - 1);
          ScimGroupMember.Role role;
          try {
            role = ScimGroupMember.Role.valueOf(value.toUpperCase());
          } catch (IllegalArgumentException ex) {
            role = null;
          }
          if (role != null) {
            ScimGroupMember[] members = jp.readValueAs(ScimGroupMember[].class);
            for (ScimGroupMember member : members) {
              member.setRoles(new ArrayList<ScimGroupMember.Role>());
            }
            roles.get(role).addAll(Arrays.asList(members));
            allMembers.addAll(Arrays.asList(members));
          }
        }
      }
    }

    for (ScimGroupMember member : allMembers) {
      for (ScimGroupMember.Role role : roles.keySet()) {
        if (roles.get(role).contains(member)) {
          member.getRoles().add(role);
        }
      }
    }
    group.setMembers(new ArrayList<ScimGroupMember>(allMembers));

    return group;
  }
 @Test(expected = ScimResourceNotFoundException.class)
 public void canAddMember_Validate_Origin_and_ZoneId() throws Exception {
   String subdomain = generator.generate();
   IdentityZone otherZone = MultitenancyFixture.identityZone(subdomain, subdomain);
   IdentityZoneHolder.set(otherZone);
   validateCount(0);
   ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, null);
   m1.setOrigin(OriginKeys.UAA);
   dao.addMember("g2", m1);
 }
Example #9
0
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    ScimGroupMember member = (ScimGroupMember) o;
    if (getMemberId() != null
        ? !getMemberId().equals(member.getMemberId())
        : member.getMemberId() != null) return false;
    return getType() == member.getType();
  }
 @Test
 public void canAddMember() throws Exception {
   validateCount(0);
   ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, null);
   ScimGroupMember m2 = dao.addMember("g2", m1);
   validateCount(1);
   assertEquals(ScimGroupMember.Type.USER, m2.getType());
   assertEquals(ScimGroupMember.GROUP_MEMBER, m2.getRoles());
   assertEquals("m1", m2.getMemberId());
   validateUserGroups("m1", "test2");
 }
  @Test
  public void canAddNestedGroupMember() {
    addMember("g2", "m1", "USER", "READER");

    ScimGroupMember g2 =
        new ScimGroupMember("g2", ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_ADMIN);
    g2 = dao.addMember("g1", g2);
    assertEquals(ScimGroupMember.Type.GROUP, g2.getType());
    assertEquals(ScimGroupMember.GROUP_ADMIN, g2.getRoles());
    assertEquals("g2", g2.getMemberId());
    validateUserGroups("m1", "test1.i", "test2");
  }
  @Test
  public void canUpdateMember() throws Exception {
    addMember("g1", "m1", "USER", "READER");
    validateCount(1);
    ScimGroupMember m1 =
        new ScimGroupMember("m1", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_ADMIN);
    ScimGroupMember m2 = dao.updateMember("g1", m1);
    assertEquals(ScimGroupMember.GROUP_ADMIN, m2.getRoles());
    assertNotSame(m1, m2);

    validateCount(1);
    validateUserGroups("m1", "test1");
  }
 @Override
 public ScimGroupMember mapRow(ResultSet rs, int rowNum) throws SQLException {
   String memberId = rs.getString(2);
   String memberType = rs.getString(3);
   String authorities = rs.getString(4);
   Date added = rs.getDate(5);
   String origin = rs.getString(6);
   ScimGroupMember sgm =
       new ScimGroupMember(
           memberId, ScimGroupMember.Type.valueOf(memberType), getAuthorities(authorities));
   sgm.setOrigin(origin);
   return sgm;
 }
  private void validateRequest(String groupId, ScimGroupMember member) {
    if (!StringUtils.hasText(groupId)
        || !StringUtils.hasText(member.getMemberId())
        || !StringUtils.hasText(member.getOrigin())) {
      throw new InvalidScimResourceException(
          "group-id, member-id, origin and member-type must be non-empty");
    }

    if (groupId.equals(member.getMemberId())) { // oops! cycle detected
      throw new InvalidScimResourceException("trying to nest group within itself, aborting");
    }

    // check if the group exists and the member-id is a valid group or user
    // id
    ScimGroup group = groupProvisioning.retrieve(groupId); // this will throw a ScimException
    String memberZoneId;
    // if the group does not exist
    // this will throw a ScimException if the group or user does not exist
    if (member.getType() == ScimGroupMember.Type.GROUP) {
      memberZoneId = groupProvisioning.retrieve(member.getMemberId()).getZoneId();
    } else {
      memberZoneId = userProvisioning.retrieve(member.getMemberId()).getZoneId();
    }
    if (!memberZoneId.equals(group.getZoneId())) {
      throw new ScimResourceConstraintFailedException(
          "The zone of the group and the member must be the same.");
    }
    if (!memberZoneId.equals(IdentityZoneHolder.get().getId())) {
      throw new ScimResourceConstraintFailedException(
          "Unable to make membership changes in a different zone");
    }
  }
  @Test
  public void testBackwardsCompatibilityToMemberAuthorities() {
    addMember("g1", "m1", "USER", "READ");
    addMember("g1", "g2", "GROUP", "member");
    addMember("g1", "m2", "USER", "READER,write");

    List<ScimGroupMember> members = dao.getMembers("g1", null, false);
    assertNotNull(members);
    assertEquals(3, members.size());
    List<ScimGroupMember> readers = new ArrayList<ScimGroupMember>(),
        writers = new ArrayList<ScimGroupMember>();
    for (ScimGroupMember member : members) {
      if (member.getRoles().contains(ScimGroupMember.Role.READER)) {
        readers.add(member);
      }
      if (member.getRoles().contains(ScimGroupMember.Role.WRITER)) {
        writers.add(member);
      }
    }
    assertEquals(2, readers.size());
    assertEquals(1, writers.size());
  }