Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@
import org.keycloak.models.cache.UserCacheProviderFactory;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.provider.InvalidationHandler;

/**
* @author <a href="mailto:[email protected]">Stian Thorgersen</a>
*/
public class InfinispanUserCacheProviderFactory implements UserCacheProviderFactory, InvalidationHandler {
public class InfinispanUserCacheProviderFactory implements UserCacheProviderFactory {

private static final Logger log = Logger.getLogger(InfinispanUserCacheProviderFactory.class);
public static final String USER_CLEAR_CACHE_EVENTS = "USER_CLEAR_CACHE_EVENTS";
Expand Down Expand Up @@ -79,15 +78,6 @@ private void lazyInit(KeycloakSession session) {
}
}

@Override
public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (type == ObjectType.REALM || type == ObjectType.USER) {
if (this.userCache != null) {
this.userCache.clear();
}
}
}

@Override
public void init(Config.Scope config) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,45 @@
package org.keycloak.models.cache.infinispan;

import org.keycloak.Config;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.*;
import org.keycloak.models.AbstractKeycloakTransaction;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.CibaConfig;
import org.keycloak.models.ClientInitialAccessModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuth2DeviceConfig;
import org.keycloak.models.OTPPolicy;
import org.keycloak.models.OrganizationModel;
import org.keycloak.models.ParConfig;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredActionConfigModel;
import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.WebAuthnPolicy;
import org.keycloak.models.cache.CachedRealmModel;
import org.keycloak.models.cache.UserCache;
import org.keycloak.models.cache.infinispan.entities.CachedRealm;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.UserStorageUtil;
import org.keycloak.storage.client.ClientStorageProvider;

import java.util.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Stream;
Expand Down Expand Up @@ -362,6 +390,22 @@ public boolean isDuplicateEmailsAllowed() {
@Override
public void setDuplicateEmailsAllowed(boolean duplicateEmailsAllowed) {
getDelegateForUpdate();
if (updated.isDuplicateEmailsAllowed() != duplicateEmailsAllowed) {
// If the flag changed, we need to clear all entries from the user cache as there are entries with the key of the email address which need to be re-evaluated.
// Still, this must only happen after all changes have been written to the database, therefore we enlist this to run after the completion of the transaction.
session.getTransactionManager().enlistAfterCompletion(new AbstractKeycloakTransaction() {
@Override
protected void commitImpl() {
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
cluster.notify(InfinispanUserCacheProviderFactory.USER_CLEAR_CACHE_EVENTS, ClearCacheEvent.getInstance(), false, ClusterProvider.DCNotify.ALL_DCS);
}

@Override
protected void rollbackImpl() {

}
});
}
updated.setDuplicateEmailsAllowed(duplicateEmailsAllowed);
}

Expand Down Expand Up @@ -1074,7 +1118,7 @@ public RoleModel getRole(String name) {
public Stream<RoleModel> getRolesStream() {
return cacheSession.getRealmRolesStream(this);
}

@Override
public Stream<RoleModel> getRolesStream(Integer first, Integer max) {
return cacheSession.getRealmRolesStream(this, first, max);
Expand All @@ -1084,7 +1128,7 @@ public Stream<RoleModel> getRolesStream(Integer first, Integer max) {
public Stream<RoleModel> searchForRolesStream(String search, Integer first, Integer max) {
return cacheSession.searchForRolesStream(this, search, first, max);
}

@Override
public RoleModel addRole(String name) {
return cacheSession.addRealmRole(this, name);
Expand Down Expand Up @@ -1601,10 +1645,10 @@ public ComponentModel importComponentModel(ComponentModel model) {

public void executeEvictions(ComponentModel model) {
if (model == null) return;

// if user cache is disabled this is null
UserCache userCache = UserStorageUtil.userCache(session);
if (userCache != null) {
if (userCache != null) {
// If not realm component, check to see if it is a user storage provider child component (i.e. LDAP mapper)
if (model.getParentId() != null && !model.getParentId().equals(getId())) {
ComponentModel parent = getComponent(model.getParentId());
Expand All @@ -1613,13 +1657,13 @@ public void executeEvictions(ComponentModel model) {
}
return;
}

// invalidate entire user cache if we're dealing with user storage SPI
if (UserStorageProvider.class.getName().equals(model.getProviderType())) {
userCache.evict(this);
}
}

// invalidate entire realm if we're dealing with client storage SPI
// entire realm because of client roles, client lists, and clients
if (ClientStorageProvider.class.getName().equals(model.getProviderType())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,23 @@ public static void assertKeycloakStatusCondition(KeycloakStatus kcStatus, String

public static ObjectAssert<KeycloakStatusCondition> assertKeycloakStatusCondition(KeycloakStatus kcStatus, String condition, Boolean status, String containedMessage, Long observedGeneration) {
KeycloakStatusCondition statusCondition = kcStatus.findCondition(condition).orElseThrow();
assertThat(statusCondition.getStatus()).isEqualTo(status);
assertThat(statusCondition.getStatus())
.withFailMessage(() -> "found status " + statusCondition + " and expected status " + status)
.isEqualTo(status);
if (containedMessage != null) {
assertThat(statusCondition.getMessage()).contains(containedMessage);
assertThat(statusCondition.getMessage())
.withFailMessage(() -> "found status " + statusCondition + " and expected it to contain " + containedMessage)
.contains(containedMessage);
}
if (observedGeneration != null) {
assertThat(statusCondition.getObservedGeneration()).isEqualTo(observedGeneration);
assertThat(statusCondition.getObservedGeneration())
.withFailMessage(() -> "found status " + statusCondition + " and expected it to contain an observed generation of " + observedGeneration)
.isEqualTo(observedGeneration);
}
if (status != null) {
assertThat(statusCondition.getLastTransitionTime()).isNotNull();
assertThat(statusCondition.getLastTransitionTime())
.withFailMessage(() -> "found status " + statusCondition + " and expected the last transition time to not be null")
.isNotNull();
}
return assertThat(statusCondition);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@
import org.keycloak.partialimport.ErrorResponseException;
import org.keycloak.partialimport.PartialImportResult;
import org.keycloak.partialimport.PartialImportResults;
import org.keycloak.provider.InvalidationHandler;
import org.keycloak.representations.adapters.action.GlobalRequestResult;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
Expand Down Expand Up @@ -446,7 +445,6 @@ public Response updateRealm(final RealmRepresentation rep) {
}
}

boolean wasDuplicateEmailsAllowed = realm.isDuplicateEmailsAllowed();
RepresentationToModel.updateRealm(rep, realm, session);

// Refresh periodic sync tasks for configured federationProviders
Expand All @@ -457,10 +455,6 @@ public Response updateRealm(final RealmRepresentation rep) {

adminEvent.operation(OperationType.UPDATE).representation(rep).success();

if (rep.isDuplicateEmailsAllowed() != null && rep.isDuplicateEmailsAllowed() != wasDuplicateEmailsAllowed) {
session.invalidate(InvalidationHandler.ObjectType.REALM, realm.getId());
}

return Response.noContent().build();
} catch (ModelDuplicateException e) {
throw ErrorResponse.exists("Realm with same name exists");
Expand Down