Send UserRemovedEvent containing all user attributes
Invalidate CachedUserModel before UserRemovedEvent closes #32194 Signed-off-by: Christian Janker <christian.janker@gmx.at>
This commit is contained in:
parent
900c496ffe
commit
21f90145ac
2 changed files with 38 additions and 2 deletions
|
@ -24,7 +24,6 @@ import org.keycloak.credential.CredentialInput;
|
||||||
import org.keycloak.models.ClientScopeModel;
|
import org.keycloak.models.ClientScopeModel;
|
||||||
import org.keycloak.models.CredentialValidationOutput;
|
import org.keycloak.models.CredentialValidationOutput;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.OrganizationModel;
|
|
||||||
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
|
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
|
||||||
import org.keycloak.common.constants.ServiceAccountConstants;
|
import org.keycloak.common.constants.ServiceAccountConstants;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
|
@ -834,6 +833,10 @@ public class UserCacheSession implements UserCache, OnCreateComponent, OnUpdateC
|
||||||
|
|
||||||
// just in case the transaction is rolled back you need to invalidate the user and all cache queries for that user
|
// just in case the transaction is rolled back you need to invalidate the user and all cache queries for that user
|
||||||
protected void fullyInvalidateUser(RealmModel realm, UserModel user) {
|
protected void fullyInvalidateUser(RealmModel realm, UserModel user) {
|
||||||
|
if (user instanceof CachedUserModel) {
|
||||||
|
((CachedUserModel) user).invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
Stream<FederatedIdentityModel> federatedIdentities = realm.isIdentityFederationEnabled() ?
|
Stream<FederatedIdentityModel> federatedIdentities = realm.isIdentityFederationEnabled() ?
|
||||||
getFederatedIdentitiesStream(realm, user) : Stream.empty();
|
getFederatedIdentitiesStream(realm, user) : Stream.empty();
|
||||||
|
|
||||||
|
@ -845,7 +848,7 @@ public class UserCacheSession implements UserCache, OnCreateComponent, OnUpdateC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||||
fullyInvalidateUser(realm, user);
|
fullyInvalidateUser(realm, user);
|
||||||
return getDelegate().removeUser(realm, user);
|
return getDelegate().removeUser(realm, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.ResetTimeOffsetEvent;
|
import org.keycloak.models.utils.ResetTimeOffsetEvent;
|
||||||
import org.keycloak.models.utils.SessionTimeoutHelper;
|
import org.keycloak.models.utils.SessionTimeoutHelper;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
|
import org.keycloak.provider.ProviderEventListener;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.ModelTest;
|
import org.keycloak.testsuite.arquillian.annotation.ModelTest;
|
||||||
|
@ -830,6 +831,7 @@ public class UserSessionProviderTest extends AbstractTestRealmKeycloakTest {
|
||||||
public void testOnUserRemoved() {
|
public void testOnUserRemoved() {
|
||||||
testingClient.server().run(UserSessionProviderTest::testOnUserRemoved);
|
testingClient.server().run(UserSessionProviderTest::testOnUserRemoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void testOnUserRemoved(KeycloakSession session) {
|
public static void testOnUserRemoved(KeycloakSession session) {
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
session.getContext().setRealm(realm);
|
session.getContext().setRealm(realm);
|
||||||
|
@ -857,6 +859,37 @@ public class UserSessionProviderTest extends AbstractTestRealmKeycloakTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnUserRemovedLazyUserAttributesAreLoaded() {
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
|
UserModel user1 = session.users().getUserByUsername(realm, "user1");
|
||||||
|
user1.setSingleAttribute("customAttribute", "value1");
|
||||||
|
});
|
||||||
|
testingClient.server().run(UserSessionProviderTest::testOnUserRemovedLazyUserAttributesAreLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testOnUserRemovedLazyUserAttributesAreLoaded(KeycloakSession session) {
|
||||||
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
|
UserModel user1 = session.users().getUserByUsername(realm, "user1");
|
||||||
|
|
||||||
|
Map<String, List<String>> attributes = new HashMap<>();
|
||||||
|
ProviderEventListener providerEventListener = event -> {
|
||||||
|
if (event instanceof UserModel.UserRemovedEvent) {
|
||||||
|
UserModel.UserRemovedEvent userRemovedEvent = (UserModel.UserRemovedEvent) event;
|
||||||
|
attributes.putAll(userRemovedEvent.getUser().getAttributes());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
session.getKeycloakSessionFactory().register(providerEventListener);
|
||||||
|
try {
|
||||||
|
new UserManager(session).removeUser(realm, user1);
|
||||||
|
// UserModel.FIRST_NAME, UserModel.LAST_NAME, UserModel.EMAIL, UserModel.USERNAME, customAttribute;
|
||||||
|
assertEquals(5, attributes.size());
|
||||||
|
} finally {
|
||||||
|
session.getKeycloakSessionFactory().unregister(providerEventListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static AuthenticatedClientSessionModel createClientSession(KeycloakSession session, ClientModel client, UserSessionModel userSession, String redirect, String state) {
|
private static AuthenticatedClientSessionModel createClientSession(KeycloakSession session, ClientModel client, UserSessionModel userSession, String redirect, String state) {
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(realm, client, userSession);
|
AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(realm, client, userSession);
|
||||||
|
|
Loading…
Reference in a new issue