diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java index 40a54a93959..72e0fbe9c81 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java @@ -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(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlAdvancedAttributeToGroupMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlAdvancedAttributeToGroupMapperTest.java index b3390e53271..58926c28f91 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlAdvancedAttributeToGroupMapperTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlAdvancedAttributeToGroupMapperTest.java @@ -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.>builder() + .put(ATTRIBUTE_TO_MAP_FRIENDLY_NAME, ImmutableList.builder().add("value 1").add("value 2").build()) + .put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, + ImmutableList.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); + } + }