diff --git a/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml b/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml
index c89a501b7f..8b9c164347 100755
--- a/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml
+++ b/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml
@@ -31,6 +31,7 @@
+
diff --git a/model/infinispan/pom.xml b/model/infinispan/pom.xml
index f58499c349..ada22daefd 100755
--- a/model/infinispan/pom.xml
+++ b/model/infinispan/pom.xml
@@ -42,6 +42,10 @@
org.keycloak
keycloak-model-legacy
+
+ org.keycloak
+ keycloak-model-legacy-private
+
org.keycloak
keycloak-server-spi-private
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCacheProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCacheProviderFactory.java
index 4d0f445dea..1677c537dd 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCacheProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCacheProviderFactory.java
@@ -29,11 +29,14 @@ import org.keycloak.models.cache.UserCache;
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;
+import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;;
+import org.keycloak.provider.InvalidationHandler.ObjectType;;
/**
* @author Stian Thorgersen
*/
-public class InfinispanUserCacheProviderFactory implements UserCacheProviderFactory {
+public class InfinispanUserCacheProviderFactory implements UserCacheProviderFactory, InvalidationHandler {
private static final Logger log = Logger.getLogger(InfinispanUserCacheProviderFactory.class);
public static final String USER_CLEAR_CACHE_EVENTS = "USER_CLEAR_CACHE_EVENTS";
@@ -78,6 +81,15 @@ public class InfinispanUserCacheProviderFactory implements UserCacheProviderFact
}
}
+ @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) {
}
@@ -95,6 +107,4 @@ public class InfinispanUserCacheProviderFactory implements UserCacheProviderFact
public String getId() {
return "default";
}
-
-
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java b/model/legacy-private/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
similarity index 100%
rename from server-spi-private/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
rename to model/legacy-private/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
diff --git a/server-spi-private/src/main/java/org/keycloak/models/cache/UserCacheProviderFactory.java b/model/legacy-private/src/main/java/org/keycloak/models/cache/UserCacheProviderFactory.java
similarity index 100%
rename from server-spi-private/src/main/java/org/keycloak/models/cache/UserCacheProviderFactory.java
rename to model/legacy-private/src/main/java/org/keycloak/models/cache/UserCacheProviderFactory.java
diff --git a/model/legacy-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/model/legacy-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000000..a59266b1d8
--- /dev/null
+++ b/model/legacy-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1,18 @@
+#
+# Copyright 2022 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.models.cache.CacheUserProviderSpi
diff --git a/model/legacy-services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderImpl.java b/model/legacy-services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderImpl.java
index de1927af4e..c3a1c431aa 100644
--- a/model/legacy-services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderImpl.java
+++ b/model/legacy-services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderImpl.java
@@ -21,6 +21,7 @@ import org.keycloak.credential.UserCredentialStoreManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserCredentialManager;
import org.keycloak.models.LegacySessionSupportProvider;
+import org.keycloak.models.cache.UserCache;
/**
* @author Alexander Schwartz
@@ -45,4 +46,9 @@ public class LegacySessionSupportProviderImpl implements LegacySessionSupportPro
return new UserCredentialStoreManager(session);
}
+ @Override
+ public UserCache userCache() {
+ return session.getProvider(UserCache.class);
+ }
+
}
diff --git a/model/legacy-services/src/main/java/org/keycloak/services/resources/admin/ClearUserCacheRealmAdminProvider.java b/model/legacy-services/src/main/java/org/keycloak/services/resources/admin/ClearUserCacheRealmAdminProvider.java
new file mode 100644
index 0000000000..298ceaee5e
--- /dev/null
+++ b/model/legacy-services/src/main/java/org/keycloak/services/resources/admin/ClearUserCacheRealmAdminProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2022 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.services.resources.admin;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.resources.admin.ext.AdminRealmResourceProvider;
+import org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+
+public class ClearUserCacheRealmAdminProvider implements AdminRealmResourceProviderFactory, AdminRealmResourceProvider {
+
+ @Override
+ public AdminRealmResourceProvider create(KeycloakSession session) {
+ return this;
+ }
+
+ @Override
+ public void init(Scope config) {
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return "clear-user-cache";
+ }
+
+ @Override
+ public Object getResource(KeycloakSession session, RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
+ return new ClearUserCacheResource(realm, auth, adminEvent);
+ }
+
+}
diff --git a/model/legacy-services/src/main/java/org/keycloak/services/resources/admin/ClearUserCacheResource.java b/model/legacy-services/src/main/java/org/keycloak/services/resources/admin/ClearUserCacheResource.java
new file mode 100644
index 0000000000..8e73da06e8
--- /dev/null
+++ b/model/legacy-services/src/main/java/org/keycloak/services/resources/admin/ClearUserCacheResource.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.services.resources.admin;
+
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.cache.UserCache;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.core.Context;
+
+/**
+ * Clear user cache.
+ */
+public class ClearUserCacheResource {
+ protected RealmModel realm;
+
+ protected AdminPermissionEvaluator auth;
+
+ protected AdminEventBuilder adminEvent;
+
+ @Context
+ protected KeycloakSession session;
+
+ public ClearUserCacheResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
+ this.auth = auth;
+ this.realm = realm;
+ this.adminEvent = adminEvent;
+ }
+
+ /**
+ * Clear user cache
+ */
+ @POST
+ public void clearUserCache() {
+ auth.realm().requireManageRealm();
+
+ UserCache cache = session.getProvider(UserCache.class);
+ if (cache != null) {
+ cache.clear();
+ }
+
+ adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).success();
+ }
+
+}
diff --git a/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory b/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory
index ac600edf4c..b6ec273fac 100644
--- a/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory
+++ b/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory
@@ -16,3 +16,4 @@
#
org.keycloak.services.resources.admin.UserStorageProviderRealmAdminProvider
+org.keycloak.services.resources.admin.ClearUserCacheRealmAdminProvider
diff --git a/server-spi/src/main/java/org/keycloak/models/cache/UserCache.java b/model/legacy/src/main/java/org/keycloak/models/cache/UserCache.java
similarity index 100%
rename from server-spi/src/main/java/org/keycloak/models/cache/UserCache.java
rename to model/legacy/src/main/java/org/keycloak/models/cache/UserCache.java
diff --git a/server-spi-private/src/main/java/org/keycloak/models/LegacySessionSupportProvider.java b/server-spi-private/src/main/java/org/keycloak/models/LegacySessionSupportProvider.java
index 1123234a8a..0e39999d18 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/LegacySessionSupportProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/LegacySessionSupportProvider.java
@@ -29,4 +29,7 @@ public interface LegacySessionSupportProvider extends Provider {
@Deprecated
UserCredentialManager userCredentialManager();
+
+ @Deprecated
+ UserProvider userCache();
}
diff --git a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index e3badf2987..62dd831eaf 100755
--- a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -58,7 +58,6 @@ org.keycloak.theme.ThemeSpi
org.keycloak.truststore.TruststoreSpi
org.keycloak.connections.httpclient.HttpClientSpi
org.keycloak.models.cache.CacheRealmProviderSpi
-org.keycloak.models.cache.CacheUserProviderSpi
org.keycloak.authentication.AuthenticatorSpi
org.keycloak.authentication.ClientAuthenticatorSpi
org.keycloak.authentication.RequiredActionSpi
diff --git a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
index 1ab564612f..5bda6b6f90 100755
--- a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -18,7 +18,6 @@
package org.keycloak.models;
import org.keycloak.component.ComponentModel;
-import org.keycloak.models.cache.UserCache;
import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;
import org.keycloak.provider.Provider;
import org.keycloak.services.clientpolicy.ClientPolicyManager;
@@ -210,7 +209,7 @@ public interface KeycloakSession {
* @return may be null if cache is disabled
*/
@Deprecated
- UserCache userCache();
+ UserProvider userCache();
/**
* A cached view of all users in system including users loaded by UserStorageProviders
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
index 1127a9f799..a6493503b0 100644
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
@@ -39,7 +39,6 @@ import org.keycloak.models.UserCredentialManager;
import org.keycloak.models.UserLoginFailureProvider;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserSessionProvider;
-import org.keycloak.models.cache.UserCache;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
@@ -111,9 +110,13 @@ public class DefaultKeycloakSession implements KeycloakSession {
}
@Override
- public UserCache userCache() {
- return getProvider(UserCache.class);
-
+ @Deprecated
+ public UserProvider userCache() {
+ LegacySessionSupportProvider provider = this.getProvider(LegacySessionSupportProvider.class);
+ if (provider == null) {
+ throw new IllegalStateException("legacy support for userCache is not enabled");
+ }
+ return provider.userCache();
}
@Override
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 70c259ab8d..4771d323a4 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -78,6 +78,7 @@ import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.Constants;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.LegacySessionSupportProvider;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel;
@@ -85,13 +86,13 @@ import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.CacheRealmProvider;
-import org.keycloak.models.cache.UserCache;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.models.utils.StripSecretsUtils;
import org.keycloak.partialimport.PartialImportManager;
import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.provider.InvalidationHandler;
import org.keycloak.representations.adapters.action.GlobalRequestResult;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
@@ -440,8 +441,7 @@ public class RealmAdminResource {
adminEvent.operation(OperationType.UPDATE).representation(StripSecretsUtils.strip(rep)).success();
if (rep.isDuplicateEmailsAllowed() != null && rep.isDuplicateEmailsAllowed() != wasDuplicateEmailsAllowed) {
- UserCache cache = session.getProvider(UserCache.class);
- if (cache != null) cache.clear();
+ session.invalidate(InvalidationHandler.ObjectType.REALM, realm.getId());
}
return Response.noContent().build();
@@ -1097,23 +1097,6 @@ public class RealmAdminResource {
adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).success();
}
- /**
- * Clear user cache
- *
- */
- @Path("clear-user-cache")
- @POST
- public void clearUserCache() {
- auth.realm().requireManageRealm();
-
- UserCache cache = session.getProvider(UserCache.class);
- if (cache != null) {
- cache.clear();
- }
-
- adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).success();
- }
-
/**
* Clear cache of external public keys (Public keys of clients or Identity providers)
*