Fixes #9482: A user could be assigned to a parent group if he is already assigned to a subgroup.
This commit is contained in:
parent
c70b4eaade
commit
cc2bb96abc
7 changed files with 93 additions and 6 deletions
|
@ -751,7 +751,7 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
|||
|
||||
@Override
|
||||
public boolean isMemberOf(GroupModel group) {
|
||||
return getGroupsStream().anyMatch(Predicate.isEqual(group));
|
||||
return RoleUtils.isDirectMember(getGroupsStream(),group);
|
||||
}
|
||||
|
||||
protected Stream<GroupModel> getLDAPGroupMappingsConverted() {
|
||||
|
|
|
@ -392,7 +392,7 @@ public class UserAdapter implements UserModel.Streams, JpaModel<UserEntity> {
|
|||
|
||||
@Override
|
||||
public void joinGroup(GroupModel group) {
|
||||
if (isMemberOf(group)) return;
|
||||
if (RoleUtils.isDirectMember(getGroupsStream(), group)) return;
|
||||
joinGroupImpl(group);
|
||||
|
||||
}
|
||||
|
|
|
@ -255,6 +255,7 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
|
||||
@Override
|
||||
public void joinGroup(GroupModel group) {
|
||||
if (RoleUtils.isDirectMember(getGroupsStream(), group)) return;
|
||||
entity.addGroupsMembership(group.getId());
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.stream.Collectors;
|
|||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.RoleUtils;
|
||||
import org.keycloak.models.utils.UserModelDelegate;
|
||||
|
||||
import static org.keycloak.common.util.ObjectUtil.isEqualOrBothNull;
|
||||
|
@ -170,7 +171,7 @@ public class UpdateOnlyChangeUserModelDelegate extends UserModelDelegate {
|
|||
|
||||
@Override
|
||||
public void joinGroup(GroupModel group) {
|
||||
if (!isMemberOf(group)) {
|
||||
if (!RoleUtils.isDirectMember(getGroupsStream(),group)) {
|
||||
delegate.joinGroup(group);
|
||||
}
|
||||
|
||||
|
@ -178,7 +179,7 @@ public class UpdateOnlyChangeUserModelDelegate extends UserModelDelegate {
|
|||
|
||||
@Override
|
||||
public void leaveGroup(GroupModel group) {
|
||||
if (isMemberOf(group)) {
|
||||
if (RoleUtils.isDirectMember(getGroupsStream(),group)) {
|
||||
delegate.leaveGroup(group);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,16 @@ public class RoleUtils {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param groups
|
||||
* @param targetGroup
|
||||
* @return true if targetGroup is in groups directly
|
||||
*/
|
||||
public static boolean isDirectMember(Stream<GroupModel> groups, GroupModel targetGroup) {
|
||||
return groups.anyMatch(g -> targetGroup.getId().equals(g.getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param roles
|
||||
* @param targetRole
|
||||
|
|
|
@ -50,6 +50,7 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.models.utils.RoleUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.utils.RedirectUtils;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
@ -943,7 +944,7 @@ public class UserResource {
|
|||
throw new NotFoundException("Group not found");
|
||||
}
|
||||
auth.groups().requireManageMembership(group);
|
||||
if (!user.isMemberOf(group)){
|
||||
if (!RoleUtils.isDirectMember(user.getGroupsStream(),group)){
|
||||
user.joinGroup(group);
|
||||
adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(session.getContext().getUri()).success();
|
||||
}
|
||||
|
|
|
@ -3057,4 +3057,78 @@ public class UserTest extends AbstractAdminTest {
|
|||
testRealm().roles().get("realm-role").remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for #9482
|
||||
*/
|
||||
@Test
|
||||
public void joinParentGroupAfterSubGroup() {
|
||||
String username = "user-with-sub-and-parent-group";
|
||||
String parentGroupName = "parent-group";
|
||||
String subGroupName = "sub-group";
|
||||
|
||||
UserRepresentation userRepresentation = UserBuilder.create().username(username).build();
|
||||
|
||||
GroupRepresentation subGroupRep = GroupBuilder.create().name(subGroupName).build();
|
||||
GroupRepresentation parentGroupRep = GroupBuilder.create().name(parentGroupName).subGroups(List.of(subGroupRep)).build();
|
||||
|
||||
try (Creator<UserResource> u = Creator.create(realm, userRepresentation);
|
||||
Creator<GroupResource> subgroup = Creator.create(realm, subGroupRep);
|
||||
Creator<GroupResource> parentGroup = Creator.create(realm, parentGroupRep)) {
|
||||
|
||||
UserResource user = u.resource();
|
||||
|
||||
//when
|
||||
user.joinGroup(subgroup.id());
|
||||
List<GroupRepresentation> obtainedGroups = realm.users().get(u.id()).groups();
|
||||
|
||||
//then
|
||||
assertEquals(1, obtainedGroups.size());
|
||||
assertEquals(subGroupName, obtainedGroups.get(0).getName());
|
||||
|
||||
//when
|
||||
user.joinGroup(parentGroup.id());
|
||||
obtainedGroups = realm.users().get(u.id()).groups();
|
||||
|
||||
//then
|
||||
assertEquals(2, obtainedGroups.size());
|
||||
assertEquals(parentGroupName, obtainedGroups.get(0).getName());
|
||||
assertEquals(subGroupName, obtainedGroups.get(1).getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void joinSubGroupAfterParentGroup() {
|
||||
String username = "user-with-sub-and-parent-group";
|
||||
String parentGroupName = "parent-group";
|
||||
String subGroupName = "sub-group";
|
||||
|
||||
UserRepresentation userRepresentation = UserBuilder.create().username(username).build();
|
||||
GroupRepresentation subGroupRep = GroupBuilder.create().name(subGroupName).build();
|
||||
GroupRepresentation parentGroupRep = GroupBuilder.create().name(parentGroupName).subGroups(List.of(subGroupRep)).build();
|
||||
|
||||
try (Creator<UserResource> u = Creator.create(realm, userRepresentation);
|
||||
Creator<GroupResource> subgroup = Creator.create(realm, subGroupRep);
|
||||
Creator<GroupResource> parentGroup = Creator.create(realm, parentGroupRep)) {
|
||||
|
||||
UserResource user = u.resource();
|
||||
|
||||
//when
|
||||
user.joinGroup(parentGroup.id());
|
||||
List<GroupRepresentation> obtainedGroups = realm.users().get(u.id()).groups();
|
||||
|
||||
//then
|
||||
assertEquals(1, obtainedGroups.size());
|
||||
assertEquals(parentGroupName, obtainedGroups.get(0).getName());
|
||||
|
||||
//when
|
||||
user.joinGroup(subgroup.id());
|
||||
obtainedGroups = realm.users().get(u.id()).groups();
|
||||
|
||||
//then
|
||||
assertEquals(2, obtainedGroups.size());
|
||||
assertEquals(parentGroupName, obtainedGroups.get(0).getName());
|
||||
assertEquals(subGroupName, obtainedGroups.get(1).getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue