When joining a group, don't rely on cached values if user has already been updated

Closes #44480

Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>
This commit is contained in:
Alexander Schwartz
2025-11-26 10:52:14 +01:00
committed by GitHub
parent 2acfd41b19
commit 37f2488441
2 changed files with 37 additions and 1 deletions

View File

@@ -485,7 +485,7 @@ public class UserAdapter implements CachedUserModel {
@Override
public void joinGroup(GroupModel group) {
if (group.getType() == Type.REALM && cached.getGroups(keycloakSession, modelSupplier).contains(group.getId())) {
if (group.getType() == Type.REALM && updated == null && cached.getGroups(keycloakSession, modelSupplier).contains(group.getId())) {
return;
}
getDelegateForUpdate();

View File

@@ -15,6 +15,7 @@ import org.keycloak.models.IdentityProviderMapperSyncMode;
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.util.AccountHelper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -83,4 +84,39 @@ public class KcSamlAdvancedAttributeToGroupMapperTest extends AbstractGroupBroke
assertThatUserHasBeenAssignedToGroup(user, MAPPER_TEST_GROUP_PATH);
}
@Test
public void removingAndAddingTheGroupKeepsTheGroup() {
// Create a mapper that is always executed (force)
String idpMapperId = createAdvancedGroupMapper(ATTRIBUTES, false, KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2);
IdentityProviderResource idp = adminClient.realm(bc.consumerRealmName()).identityProviders().get(BrokerTestConstants.IDP_SAML_ALIAS);
IdentityProviderMapperRepresentation idpMapper = idp.getMapperById(idpMapperId);
idpMapper.getConfig().put(IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString());
idp.update(idpMapperId, idpMapper);
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
.put(ATTRIBUTE_TO_MAP_FRIENDLY_NAME, ImmutableList.<String>builder().add("value 1").add("value 2").build())
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2,
ImmutableList.<String>builder().add("value 2").build())
.build());
// Login once and logout on both sides
logInAsUserInIDPForFirstTimeAndAssertSuccess();
AccountHelper.logout(adminClient.realm(bc.consumerRealmName()), bc.getUserLogin());
AccountHelper.logout(adminClient.realm(bc.providerRealmName()), bc.getUserLogin());
// Ensure that the expected group exists
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
assertThatUserHasBeenAssignedToGroup(user, MAPPER_TEST_GROUP_PATH);
// Add a mapper to remove the group, and ensure that it has a smaller ID than the other one to ensure that it is executed first
idpMapper.getConfig().put("attributes", "[{\"key\": \"key\", \"value\": \"value\"}]");
idpMapper.setId("00000000-00000000-00000000-00000000");
idpMapper.setName(idpMapper.getName() + "-2");
CreatedResponseUtil.getCreatedId(idp.addMapper(idpMapper));
logInAsUserInIDP();
user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
assertThatUserHasBeenAssignedToGroup(user, MAPPER_TEST_GROUP_PATH);
}
}