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"); } }
@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()); }
@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(); }
@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); }
@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"); }