diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
index bd171a04bf..f632e2acc3 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
@@ -23,6 +23,7 @@ import org.keycloak.credential.CredentialInput;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.LegacySessionSupportProvider;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.common.constants.ServiceAccountConstants;
import org.keycloak.component.ComponentModel;
@@ -372,7 +373,7 @@ public class UserCacheSession implements UserCache.Streams, OnCreateComponent, O
private void onCache(RealmModel realm, UserAdapter adapter, UserModel delegate) {
((OnUserCache)getDelegate()).onCache(realm, adapter, delegate);
- ((OnUserCache)session.userCredentialManager()).onCache(realm, adapter, delegate);
+ ((OnUserCache) session.getProvider(LegacySessionSupportProvider.class).userCredentialManager()).onCache(realm, adapter, delegate);
}
@Override
diff --git a/services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java b/model/legacy-services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java
similarity index 86%
rename from services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java
rename to model/legacy-services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java
index 45e2cb992b..d6086a10bd 100644
--- a/services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java
+++ b/model/legacy-services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java
@@ -16,6 +16,7 @@
*/
package org.keycloak.credential;
+import org.jboss.logging.Logger;
import org.keycloak.common.util.reflections.Types;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.KeycloakSession;
@@ -33,8 +34,10 @@ import java.util.stream.Stream;
* @author Bill Burke
* @version $Revision: 1 $
*/
-public class UserCredentialStoreManager
- implements UserCredentialManager.Streams, OnUserCache {
+@Deprecated
+public class UserCredentialStoreManager implements UserCredentialManager.Streams, OnUserCache {
+
+ private final static Logger log = Logger.getLogger(UserCredentialStoreManager.class);
private final KeycloakSession session;
@@ -45,90 +48,91 @@ public class UserCredentialStoreManager
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public void updateCredential(RealmModel realm, UserModel user, CredentialModel cred) {
- // TODO: no longer used in non-legacy code, can be removed
+ warnAboutUsage();
user.getUserCredentialManager().updateStoredCredential(cred);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public CredentialModel createCredential(RealmModel realm, UserModel user, CredentialModel cred) {
- // TODO: no longer used in non-legacy code, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().createStoredCredential(cred);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public boolean removeStoredCredential(RealmModel realm, UserModel user, String id) {
- // TODO: no longer used in non-legacy code, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().removeStoredCredentialById(id);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public CredentialModel getStoredCredentialById(RealmModel realm, UserModel user, String id) {
- // TODO: no longer used in non-legacy code, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().getStoredCredentialById(id);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public Stream getStoredCredentialsStream(RealmModel realm, UserModel user) {
- // TODO: no longer used in non-legacy code, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().getStoredCredentialsStream();
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public Stream getStoredCredentialsByTypeStream(RealmModel realm, UserModel user, String type) {
- // TODO: no longer used in non-legacy code, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().getStoredCredentialsByTypeStream(type);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public CredentialModel getStoredCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type) {
- // TODO: no longer used in non-legacy code, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().getStoredCredentialByNameAndType(name, type);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId){
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().moveStoredCredentialTo(id, newPreviousCredentialId);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public boolean isValid(RealmModel realm, UserModel user, CredentialInput... inputs) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return isValid(realm, user, Arrays.asList(inputs));
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public CredentialModel createCredentialThroughProvider(RealmModel realm, UserModel user, CredentialModel model){
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().createCredentialThroughProvider(model);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public void updateCredentialLabel(RealmModel realm, UserModel user, String credentialId, String userLabel){
- // TODO: no longer used, can be removed
+ warnAboutUsage();
user.getUserCredentialManager().updateCredentialLabel(credentialId, userLabel);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public boolean isValid(RealmModel realm, UserModel user, List inputs) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().isValid(inputs);
}
@Deprecated // Keep this up to and including Keycloak 19, then inline
public static Stream getCredentialProviders(KeycloakSession session, Class type) {
- // TODO: no longer used, can be removed
+ // called via #onCache()
+ // warnAboutUsage();
return session.getKeycloakSessionFactory().getProviderFactoriesStream(CredentialProvider.class)
.filter(f -> Types.supports(type, f, CredentialProviderFactory.class))
.map(f -> (T) session.getProvider(CredentialProvider.class, f.getId()));
@@ -137,56 +141,57 @@ public class UserCredentialStoreManager
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().updateCredential(input);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
user.getUserCredentialManager().disableCredentialType(credentialType);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public Stream getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().getDisableableCredentialTypesStream();
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public boolean isConfiguredFor(RealmModel realm, UserModel user, String type) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().isConfiguredFor(type);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public boolean isConfiguredLocally(RealmModel realm, UserModel user, String type) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().isConfiguredLocally(type);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public CredentialValidationOutput authenticate(KeycloakSession session, RealmModel realm, CredentialInput input) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return session.users().getUserByCredential(realm, input);
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, then remove it together with the OnUserCache class
public void onCache(RealmModel realm, CachedUserModel user, UserModel delegate) {
- // TODO: only called from legacy code (infinispan), can be removed
+ // called by UserCacheSession#onCache, therefore don't warn here
+ // warnAboutUsage();
getCredentialProviders(session, OnUserCache.class).forEach(validator -> validator.onCache(realm, user, delegate));
}
@Override
@Deprecated // Keep this up to and including Keycloak 19, the use methods on user.getUserCredentialManager() instead
public Stream getConfiguredUserStorageCredentialTypesStream(RealmModel realm, UserModel user) {
- // TODO: no longer used, can be removed
+ warnAboutUsage();
return user.getUserCredentialManager().getConfiguredUserStorageCredentialTypesStream();
}
@@ -195,4 +200,11 @@ public class UserCredentialStoreManager
}
+ private static void warnAboutUsage() {
+ if (log.isEnabled(Logger.Level.WARN)) {
+ // check if warning is enabled first before constructing the exception that is expensive to construct
+ log.warn("Calls to session.userCredentialManager() now deprecated. Use user.getUserCredentialManager() instead!", new RuntimeException());
+ }
+ }
+
}
diff --git a/model/legacy-services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderFactoryImpl.java b/model/legacy-services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderFactoryImpl.java
new file mode 100644
index 0000000000..10d3af571f
--- /dev/null
+++ b/model/legacy-services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderFactoryImpl.java
@@ -0,0 +1,37 @@
+package org.keycloak.services.legacysessionsupport;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.LegacySessionSupportProvider;
+
+/**
+ * @author Alexander Schwartz
+ */
+public class LegacySessionSupportProviderFactoryImpl implements LegacySessionSupportProviderFactory {
+
+ private static final String PROVIDER_ID = "default";
+
+ @Override
+ public LegacySessionSupportProvider create(KeycloakSession session) {
+ return new LegacySessionSupportProviderImpl(session);
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+}
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
new file mode 100644
index 0000000000..b1db22d3df
--- /dev/null
+++ b/model/legacy-services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderImpl.java
@@ -0,0 +1,31 @@
+package org.keycloak.services.legacysessionsupport;
+
+import org.keycloak.credential.UserCredentialStoreManager;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.UserCredentialManager;
+import org.keycloak.models.LegacySessionSupportProvider;
+
+/**
+ * @author Alexander Schwartz
+ */
+public class LegacySessionSupportProviderImpl implements LegacySessionSupportProvider {
+
+ private final KeycloakSession session;
+
+ public LegacySessionSupportProviderImpl(KeycloakSession session) {
+ this.session = session;
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ @Deprecated
+ public UserCredentialManager userCredentialManager() {
+ // UserCacheSession calls session.userCredentialManager().onCache(), therefore can't trigger a warning here at the moment.
+ return new UserCredentialStoreManager(session);
+ }
+
+}
diff --git a/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.services.legacysessionsupport.LegacySessionSupportProviderFactory b/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.services.legacysessionsupport.LegacySessionSupportProviderFactory
new file mode 100644
index 0000000000..182d5fb380
--- /dev/null
+++ b/model/legacy-services/src/main/resources/META-INF/services/org.keycloak.services.legacysessionsupport.LegacySessionSupportProviderFactory
@@ -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.services.legacysessionsupport.LegacySessionSupportProviderFactoryImpl
\ No newline at end of file
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
new file mode 100644
index 0000000000..f853de1b95
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/LegacySessionSupportProvider.java
@@ -0,0 +1,15 @@
+package org.keycloak.models;
+
+import org.keycloak.provider.Provider;
+
+/**
+ * Support for elements in Keycloak's session that are deprecated.
+ * This allows the deprecated implementations to be moved to the legacy module.
+ *
+ * @author Alexander Schwartz
+ */
+public interface LegacySessionSupportProvider extends Provider {
+
+ @Deprecated
+ UserCredentialManager userCredentialManager();
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/SingleUserCredentialManager.java b/server-spi/src/main/java/org/keycloak/models/SingleUserCredentialManager.java
index 7e2ec039f3..1e452b2246 100644
--- a/server-spi/src/main/java/org/keycloak/models/SingleUserCredentialManager.java
+++ b/server-spi/src/main/java/org/keycloak/models/SingleUserCredentialManager.java
@@ -68,7 +68,9 @@ public interface SingleUserCredentialManager {
@Deprecated
boolean isConfiguredLocally(String type);
+ // TODO: not needed for new store? -> no, will be removed without replacement
Stream getConfiguredUserStorageCredentialTypesStream();
+ // TODO: not needed for new store? -> no, will be removed without replacement
CredentialModel createCredentialThroughProvider(CredentialModel model);
}
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
index 3f9c0260d8..ea84261e97 100644
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
@@ -18,7 +18,6 @@ package org.keycloak.services;
import org.keycloak.component.ComponentFactory;
import org.keycloak.component.ComponentModel;
-import org.keycloak.credential.UserCredentialStoreManager;
import org.keycloak.jose.jws.DefaultTokenManager;
import org.keycloak.keys.DefaultKeyManager;
import org.keycloak.models.ClientProvider;
@@ -45,6 +44,7 @@ import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;
import org.keycloak.provider.InvalidationHandler.ObjectType;
import org.keycloak.services.clientpolicy.ClientPolicyManager;
+import org.keycloak.models.LegacySessionSupportProvider;
import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.DatastoreProvider;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
@@ -76,12 +76,13 @@ public class DefaultKeycloakSession implements KeycloakSession {
private final Map attributes = new HashMap<>();
private final Map> invalidationMap = new HashMap<>();
private DatastoreProvider datastoreProvider;
- private UserCredentialStoreManager userCredentialStorageManager;
+ @Deprecated
+ private UserCredentialManager userCredentialStorageManager;
private UserSessionProvider sessionProvider;
private UserLoginFailureProvider userLoginFailureProvider;
private AuthenticationSessionProvider authenticationSessionProvider;
private UserFederatedStorageProvider userFederatedStorageProvider;
- private KeycloakContext context;
+ private final KeycloakContext context;
private KeyManager keyManager;
private ThemeManager themeManager;
private TokenManager tokenManager;
@@ -229,8 +230,15 @@ public class DefaultKeycloakSession implements KeycloakSession {
}
@Override
+ @Deprecated
public UserCredentialManager userCredentialManager() {
- if (userCredentialStorageManager == null) userCredentialStorageManager = new UserCredentialStoreManager(this);
+ if (userCredentialStorageManager == null) {
+ LegacySessionSupportProvider provider = this.getProvider(LegacySessionSupportProvider.class);
+ if (provider == null) {
+ throw new IllegalStateException("legacy support for a UserCredentialManager is not enabled");
+ }
+ userCredentialStorageManager = provider.userCredentialManager();
+ }
return userCredentialStorageManager;
}
diff --git a/services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderFactory.java b/services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderFactory.java
new file mode 100644
index 0000000000..5495784c8c
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportProviderFactory.java
@@ -0,0 +1,10 @@
+package org.keycloak.services.legacysessionsupport;
+
+import org.keycloak.models.LegacySessionSupportProvider;
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author Alexander Schwartz
+ */
+public interface LegacySessionSupportProviderFactory extends ProviderFactory {
+}
diff --git a/services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportSpi.java b/services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportSpi.java
new file mode 100644
index 0000000000..7f26000c63
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/legacysessionsupport/LegacySessionSupportSpi.java
@@ -0,0 +1,32 @@
+package org.keycloak.services.legacysessionsupport;
+
+import org.keycloak.models.LegacySessionSupportProvider;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author Alexander Schwartz
+ */
+public class LegacySessionSupportSpi implements Spi {
+
+ @Override
+ public boolean isInternal() {
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return "legacy-session-support";
+ }
+
+ @Override
+ public Class extends Provider> getProviderClass() {
+ return LegacySessionSupportProvider.class;
+ }
+
+ @Override
+ public Class extends LegacySessionSupportProviderFactory> getProviderFactoryClass() {
+ return LegacySessionSupportProviderFactory.class;
+ }
+
+}
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index 997589cf63..baf42d0345 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -28,4 +28,4 @@ org.keycloak.protocol.oidc.grants.ciba.channel.AuthenticationChannelSpi
org.keycloak.protocol.oidc.grants.ciba.resolvers.CIBALoginUserResolverSpi
org.keycloak.protocol.oidc.rar.AuthorizationRequestParserSpi
org.keycloak.services.resources.admin.ext.AdminRealmResourceSpi
-org.keycloak.credential.SingleUserCredentialManagerSpi
+org.keycloak.services.legacysessionsupport.LegacySessionSupportSpi
diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Infinispan.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Infinispan.java
index efb73e0379..18dce7dbca 100644
--- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Infinispan.java
+++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Infinispan.java
@@ -27,6 +27,8 @@ import org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionPr
import org.keycloak.models.sessions.infinispan.InfinispanSingleUseObjectProviderFactory;
import org.keycloak.models.sessions.infinispan.InfinispanUserLoginFailureProviderFactory;
import org.keycloak.models.sessions.infinispan.InfinispanUserSessionProviderFactory;
+import org.keycloak.services.legacysessionsupport.LegacySessionSupportProviderFactory;
+import org.keycloak.services.legacysessionsupport.LegacySessionSupportSpi;
import org.keycloak.sessions.AuthenticationSessionSpi;
import org.keycloak.sessions.StickySessionEncoderProviderFactory;
import org.keycloak.sessions.StickySessionEncoderSpi;
@@ -62,6 +64,8 @@ public class Infinispan extends KeycloakModelParameters {
.add(ActionTokenStoreSpi.class)
.add(SingleUseObjectSpi.class)
+ .add(LegacySessionSupportSpi.class) // necessary as it will call session.userCredentialManager().onCache()
+
.build();
static final Set> ALLOWED_FACTORIES = ImmutableSet.>builder()
@@ -76,6 +80,7 @@ public class Infinispan extends KeycloakModelParameters {
.add(InfinispanSingleUseObjectProviderFactory.class)
.add(StickySessionEncoderProviderFactory.class)
.add(TimerProviderFactory.class)
+ .add(LegacySessionSupportProviderFactory.class)
.build();
@Override