Updates Datastore provider to contain full data model

Closes #15490
This commit is contained in:
Dominik Schlosser 2023-04-23 22:37:35 +02:00 committed by Hynek Mlnařík
parent fdd5e51dbc
commit 8c58f39a49
24 changed files with 131 additions and 54 deletions

View file

@ -23,9 +23,13 @@ import org.keycloak.models.GroupProvider;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleProvider; import org.keycloak.models.RoleProvider;
import org.keycloak.models.SingleUseObjectProvider;
import org.keycloak.models.UserLoginFailureProvider;
import org.keycloak.models.UserProvider; import org.keycloak.models.UserProvider;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.cache.CacheRealmProvider; import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.UserCache; import org.keycloak.models.cache.UserCache;
import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.ClientScopeStorageManager; import org.keycloak.storage.ClientScopeStorageManager;
import org.keycloak.storage.ClientStorageManager; import org.keycloak.storage.ClientStorageManager;
import org.keycloak.storage.DatastoreProvider; import org.keycloak.storage.DatastoreProvider;
@ -41,12 +45,16 @@ public class LegacyDatastoreProvider implements DatastoreProvider, LegacyStoreMa
private final LegacyDatastoreProviderFactory factory; private final LegacyDatastoreProviderFactory factory;
private final KeycloakSession session; private final KeycloakSession session;
private AuthenticationSessionProvider authenticationSessionProvider;
private ClientProvider clientProvider; private ClientProvider clientProvider;
private ClientScopeProvider clientScopeProvider; private ClientScopeProvider clientScopeProvider;
private GroupProvider groupProvider; private GroupProvider groupProvider;
private UserLoginFailureProvider userLoginFailureProvider;
private RealmProvider realmProvider; private RealmProvider realmProvider;
private RoleProvider roleProvider; private RoleProvider roleProvider;
private SingleUseObjectProvider singleUseObjectProvider;
private UserProvider userProvider; private UserProvider userProvider;
private UserSessionProvider userSessionProvider;
private ClientScopeStorageManager clientScopeStorageManager; private ClientScopeStorageManager clientScopeStorageManager;
private RoleStorageManager roleStorageManager; private RoleStorageManager roleStorageManager;
@ -170,6 +178,14 @@ public class LegacyDatastoreProvider implements DatastoreProvider, LegacyStoreMa
} }
} }
@Override
public AuthenticationSessionProvider authSessions() {
if (authenticationSessionProvider == null) {
authenticationSessionProvider = session.getProvider(AuthenticationSessionProvider.class);
}
return authenticationSessionProvider;
}
@Override @Override
public ClientProvider clients() { public ClientProvider clients() {
if (clientProvider == null) { if (clientProvider == null) {
@ -194,6 +210,14 @@ public class LegacyDatastoreProvider implements DatastoreProvider, LegacyStoreMa
return groupProvider; return groupProvider;
} }
@Override
public UserLoginFailureProvider loginFailures() {
if (userLoginFailureProvider == null) {
userLoginFailureProvider = session.getProvider(UserLoginFailureProvider.class);
}
return userLoginFailureProvider;
}
@Override @Override
public RealmProvider realms() { public RealmProvider realms() {
if (realmProvider == null) { if (realmProvider == null) {
@ -210,6 +234,14 @@ public class LegacyDatastoreProvider implements DatastoreProvider, LegacyStoreMa
return roleProvider; return roleProvider;
} }
@Override
public SingleUseObjectProvider singleUseObjects() {
if (singleUseObjectProvider == null) {
singleUseObjectProvider = session.getProvider(SingleUseObjectProvider.class);
}
return singleUseObjectProvider;
}
@Override @Override
public UserProvider users() { public UserProvider users() {
if (userProvider == null) { if (userProvider == null) {
@ -218,6 +250,14 @@ public class LegacyDatastoreProvider implements DatastoreProvider, LegacyStoreMa
return userProvider; return userProvider;
} }
@Override
public UserSessionProvider userSessions() {
if (userSessionProvider == null) {
userSessionProvider = session.getProvider(UserSessionProvider.class);
}
return userSessionProvider;
}
@Override @Override
public ExportImportManager getExportImportManager() { public ExportImportManager getExportImportManager() {
return new LegacyExportImportManager(session); return new LegacyExportImportManager(session);

View file

@ -36,6 +36,7 @@ import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmSpi; import org.keycloak.models.RealmSpi;
import org.keycloak.models.RoleProvider; import org.keycloak.models.RoleProvider;
import org.keycloak.models.RoleSpi; import org.keycloak.models.RoleSpi;
import org.keycloak.models.SingleUseObjectProvider;
import org.keycloak.models.ThemeManager; import org.keycloak.models.ThemeManager;
import org.keycloak.models.TokenManager; import org.keycloak.models.TokenManager;
import org.keycloak.models.UserCredentialManager; import org.keycloak.models.UserCredentialManager;
@ -264,6 +265,11 @@ public class ImportKeycloakSession implements KeycloakSession {
throw new ModelException("not supported yet"); throw new ModelException("not supported yet");
} }
@Override
public SingleUseObjectProvider singleUseObjects() {
throw new ModelException("not supported yet");
}
@Override @Override
public void close() { public void close() {
session.close(); session.close();

View file

@ -23,7 +23,11 @@ import org.keycloak.models.GroupProvider;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleProvider; import org.keycloak.models.RoleProvider;
import org.keycloak.models.SingleUseObjectProvider;
import org.keycloak.models.UserLoginFailureProvider;
import org.keycloak.models.UserProvider; import org.keycloak.models.UserProvider;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.DatastoreProvider; import org.keycloak.storage.DatastoreProvider;
import org.keycloak.storage.ExportImportManager; import org.keycloak.storage.ExportImportManager;
@ -39,6 +43,11 @@ public class MapDatastoreProvider implements DatastoreProvider {
public void close() { public void close() {
} }
@Override
public AuthenticationSessionProvider authSessions() {
return session.getProvider(AuthenticationSessionProvider.class);
}
@Override @Override
public ClientScopeProvider clientScopes() { public ClientScopeProvider clientScopes() {
return session.getProvider(ClientScopeProvider.class); return session.getProvider(ClientScopeProvider.class);
@ -54,6 +63,11 @@ public class MapDatastoreProvider implements DatastoreProvider {
return session.getProvider(GroupProvider.class); return session.getProvider(GroupProvider.class);
} }
@Override
public UserLoginFailureProvider loginFailures() {
return session.getProvider(UserLoginFailureProvider.class);
}
@Override @Override
public RealmProvider realms() { public RealmProvider realms() {
return session.getProvider(RealmProvider.class); return session.getProvider(RealmProvider.class);
@ -64,11 +78,21 @@ public class MapDatastoreProvider implements DatastoreProvider {
return session.getProvider(RoleProvider.class); return session.getProvider(RoleProvider.class);
} }
@Override
public SingleUseObjectProvider singleUseObjects() {
return session.getProvider(SingleUseObjectProvider.class);
}
@Override @Override
public UserProvider users() { public UserProvider users() {
return session.getProvider(UserProvider.class); return session.getProvider(UserProvider.class);
} }
@Override
public UserSessionProvider userSessions() {
return session.getProvider(UserSessionProvider.class);
}
@Override @Override
public ExportImportManager getExportImportManager() { public ExportImportManager getExportImportManager() {
return new MapExportImportManager(session); return new MapExportImportManager(session);

View file

@ -22,11 +22,16 @@ import org.keycloak.models.ClientScopeProvider;
import org.keycloak.models.GroupProvider; import org.keycloak.models.GroupProvider;
import org.keycloak.models.RealmProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleProvider; import org.keycloak.models.RoleProvider;
import org.keycloak.models.SingleUseObjectProvider;
import org.keycloak.models.UserLoginFailureProvider;
import org.keycloak.models.UserProvider; import org.keycloak.models.UserProvider;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
import org.keycloak.sessions.AuthenticationSessionProvider;
public interface DatastoreProvider extends Provider { public interface DatastoreProvider extends Provider {
AuthenticationSessionProvider authSessions();
ClientScopeProvider clientScopes(); ClientScopeProvider clientScopes();
@ -34,11 +39,17 @@ public interface DatastoreProvider extends Provider {
GroupProvider groups(); GroupProvider groups();
UserLoginFailureProvider loginFailures();
RealmProvider realms(); RealmProvider realms();
RoleProvider roles(); RoleProvider roles();
SingleUseObjectProvider singleUseObjects();
UserProvider users(); UserProvider users();
UserSessionProvider userSessions();
ExportImportManager getExportImportManager(); ExportImportManager getExportImportManager();
} }

View file

@ -201,6 +201,8 @@ public interface KeycloakSession extends AutoCloseable {
AuthenticationSessionProvider authenticationSessions(); AuthenticationSessionProvider authenticationSessions();
SingleUseObjectProvider singleUseObjects();
void close(); void close();

View file

@ -190,7 +190,7 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator {
throw new RuntimeException("Missing ID on the token"); throw new RuntimeException("Missing ID on the token");
} }
SingleUseObjectProvider singleUseCache = context.getSession().getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseCache = context.getSession().singleUseObjects();
int lifespanInSecs = Math.max(token.getExpiration() - currentTime, 10); int lifespanInSecs = Math.max(token.getExpiration() - currentTime, 10);
if (singleUseCache.putIfAbsent(token.getId(), lifespanInSecs)) { if (singleUseCache.putIfAbsent(token.getId(), lifespanInSecs)) {
logger.tracef("Added token '%s' to single-use cache. Lifespan: %d seconds, client: %s", token.getId(), lifespanInSecs, clientId); logger.tracef("Added token '%s' to single-use cache. Lifespan: %d seconds, client: %s", token.getId(), lifespanInSecs, clientId);

View file

@ -192,7 +192,7 @@ public class JWTClientSecretAuthenticator extends AbstractClientAuthenticator {
throw new RuntimeException("Missing ID on the token"); throw new RuntimeException("Missing ID on the token");
} }
SingleUseObjectProvider singleUseCache = context.getSession().getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseCache = context.getSession().singleUseObjects();
int lifespanInSecs = Math.max(token.getExpiration() - currentTime, 10); int lifespanInSecs = Math.max(token.getExpiration() - currentTime, 10);
if (singleUseCache.putIfAbsent(token.getId(), lifespanInSecs)) { if (singleUseCache.putIfAbsent(token.getId(), lifespanInSecs)) {

View file

@ -117,7 +117,7 @@ public class OTPCredentialProvider implements CredentialProvider<OTPCredentialMo
if (isValid) { if (isValid) {
if (policy.isCodeReusable()) return true; if (policy.isCodeReusable()) return true;
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
final long validLifespan = (long) credentialData.getPeriod() * (2L * policy.getLookAheadWindow() + 1); final long validLifespan = (long) credentialData.getPeriod() * (2L * policy.getLookAheadWindow() + 1);
final String searchKey = credential.getId() + "." + challengeResponse; final String searchKey = credential.getId() + "." + challengeResponse;

View file

@ -1342,7 +1342,7 @@ public class TokenManager {
@Override @Override
public boolean test(JsonWebToken token) { public boolean test(JsonWebToken token) {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
return !singleUseStore.contains(token.getId() + SingleUseObjectProvider.REVOKED_KEY); return !singleUseStore.contains(token.getId() + SingleUseObjectProvider.REVOKED_KEY);
} }
} }

View file

@ -255,7 +255,7 @@ public class TokenRevocationEndpoint {
} }
private void revokeAccessToken() { private void revokeAccessToken() {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
int currentTime = Time.currentTime(); int currentTime = Time.currentTime();
long lifespanInSecs = Math.max(token.getExp() - currentTime, 10); long lifespanInSecs = Math.max(token.getExp() - currentTime, 10);
singleUseStore.put(token.getId() + SingleUseObjectProvider.REVOKED_KEY, lifespanInSecs, Collections.emptyMap()); singleUseStore.put(token.getId() + SingleUseObjectProvider.REVOKED_KEY, lifespanInSecs, Collections.emptyMap());

View file

@ -152,7 +152,7 @@ public class BackchannelAuthenticationEndpoint extends AbstractCibaEndpoint {
// To inform "expired_token" to the client, the lifespan of the cache provider is longer than device code // To inform "expired_token" to the client, the lifespan of the cache provider is longer than device code
int lifespanSeconds = expiresIn + poolingInterval + 10; int lifespanSeconds = expiresIn + poolingInterval + 10;
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
singleUseStore.put(deviceCode.serializeKey(), lifespanSeconds, deviceCode.toMap()); singleUseStore.put(deviceCode.serializeKey(), lifespanSeconds, deviceCode.toMap());
singleUseStore.put(userCode.serializeKey(), lifespanSeconds, userCode.serializeValue()); singleUseStore.put(userCode.serializeKey(), lifespanSeconds, userCode.serializeValue());

View file

@ -146,28 +146,28 @@ public class DeviceGrantType {
} }
public static OAuth2DeviceCodeModel getDeviceByDeviceCode(KeycloakSession session, RealmModel realm, String deviceCode) { public static OAuth2DeviceCodeModel getDeviceByDeviceCode(KeycloakSession session, RealmModel realm, String deviceCode) {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
Map<String, String> notes = singleUseStore.get(OAuth2DeviceCodeModel.createKey(deviceCode)); Map<String, String> notes = singleUseStore.get(OAuth2DeviceCodeModel.createKey(deviceCode));
return notes != null ? OAuth2DeviceCodeModel.fromCache(realm, deviceCode, notes) : null; return notes != null ? OAuth2DeviceCodeModel.fromCache(realm, deviceCode, notes) : null;
} }
public static void removeDeviceByDeviceCode(KeycloakSession session, String deviceCode) { public static void removeDeviceByDeviceCode(KeycloakSession session, String deviceCode) {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
singleUseStore.remove(OAuth2DeviceCodeModel.createKey(deviceCode)); singleUseStore.remove(OAuth2DeviceCodeModel.createKey(deviceCode));
} }
public static void removeDeviceByUserCode(KeycloakSession session, RealmModel realm, String userCode) { public static void removeDeviceByUserCode(KeycloakSession session, RealmModel realm, String userCode) {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
singleUseStore.remove(OAuth2DeviceUserCodeModel.createKey(realm, userCode)); singleUseStore.remove(OAuth2DeviceUserCodeModel.createKey(realm, userCode));
} }
public static boolean isPollingAllowed(KeycloakSession session, OAuth2DeviceCodeModel deviceCodeModel) { public static boolean isPollingAllowed(KeycloakSession session, OAuth2DeviceCodeModel deviceCodeModel) {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
return singleUseStore.putIfAbsent(deviceCodeModel.serializePollingKey(), deviceCodeModel.getPollingInterval()); return singleUseStore.putIfAbsent(deviceCodeModel.serializePollingKey(), deviceCodeModel.getPollingInterval());
} }
public static boolean approveUserCode(KeycloakSession session, RealmModel realm, String userCode, String userSessionId, Map<String, String> additionalParams) { public static boolean approveUserCode(KeycloakSession session, RealmModel realm, String userCode, String userSessionId, Map<String, String> additionalParams) {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
OAuth2DeviceCodeModel deviceCodeModel = DeviceEndpoint.getDeviceByUserCode(session, realm, userCode); OAuth2DeviceCodeModel deviceCodeModel = DeviceEndpoint.getDeviceByUserCode(session, realm, userCode);
if (deviceCodeModel != null) { if (deviceCodeModel != null) {
@ -179,7 +179,7 @@ public class DeviceGrantType {
} }
public static boolean denyUserCode(KeycloakSession session, RealmModel realm, String userCode) { public static boolean denyUserCode(KeycloakSession session, RealmModel realm, String userCode) {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
OAuth2DeviceCodeModel deviceCodeModel = DeviceEndpoint.getDeviceByUserCode(session, realm, userCode); OAuth2DeviceCodeModel deviceCodeModel = DeviceEndpoint.getDeviceByUserCode(session, realm, userCode);
if (deviceCodeModel != null) { if (deviceCodeModel != null) {

View file

@ -164,7 +164,7 @@ public class DeviceEndpoint extends AuthorizationEndpointBase implements RealmRe
// To inform "expired_token" to the client, the lifespan of the cache provider is longer than device code // To inform "expired_token" to the client, the lifespan of the cache provider is longer than device code
int lifespanSeconds = expiresIn + interval + 10; int lifespanSeconds = expiresIn + interval + 10;
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
singleUseStore.put(deviceCode.serializeKey(), lifespanSeconds, deviceCode.toMap()); singleUseStore.put(deviceCode.serializeKey(), lifespanSeconds, deviceCode.toMap());
singleUseStore.put(userCode.serializeKey(), lifespanSeconds, userCode.serializeValue()); singleUseStore.put(userCode.serializeKey(), lifespanSeconds, userCode.serializeValue());
@ -292,7 +292,7 @@ public class DeviceEndpoint extends AuthorizationEndpointBase implements RealmRe
} }
public static OAuth2DeviceCodeModel getDeviceByUserCode(KeycloakSession session, RealmModel realm, String userCode) { public static OAuth2DeviceCodeModel getDeviceByUserCode(KeycloakSession session, RealmModel realm, String userCode) {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
Map<String, String> notes = singleUseStore.get(OAuth2DeviceUserCodeModel.createKey(realm, userCode)); Map<String, String> notes = singleUseStore.get(OAuth2DeviceUserCodeModel.createKey(realm, userCode));
if (notes != null) { if (notes != null) {

View file

@ -157,7 +157,7 @@ public class ParEndpoint extends AbstractParEndpoint {
}); });
params.put(PAR_CREATED_TIME, String.valueOf(System.currentTimeMillis())); params.put(PAR_CREATED_TIME, String.valueOf(System.currentTimeMillis()));
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
singleUseStore.put(key, expiresIn, params); singleUseStore.put(key, expiresIn, params);
ParResponse parResponse = new ParResponse(requestUri, expiresIn); ParResponse parResponse = new ParResponse(requestUri, expiresIn);

View file

@ -49,7 +49,7 @@ public class AuthzEndpointParParser extends AuthzEndpointRequestParser {
public AuthzEndpointParParser(KeycloakSession session, ClientModel client, String requestUri) { public AuthzEndpointParParser(KeycloakSession session, ClientModel client, String requestUri) {
this.session = session; this.session = session;
this.client = client; this.client = client;
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
String key; String key;
try { try {
key = requestUri.substring(ParEndpoint.REQUEST_URI_PREFIX_LENGTH); key = requestUri.substring(ParEndpoint.REQUEST_URI_PREFIX_LENGTH);

View file

@ -52,7 +52,7 @@ public class OAuth2CodeParser {
* @return code parameter to be used in OAuth2 handshake * @return code parameter to be used in OAuth2 handshake
*/ */
public static String persistCode(KeycloakSession session, AuthenticatedClientSessionModel clientSession, OAuth2Code codeData) { public static String persistCode(KeycloakSession session, AuthenticatedClientSessionModel clientSession, OAuth2Code codeData) {
SingleUseObjectProvider codeStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider codeStore = session.singleUseObjects();
String key = codeData.getId(); String key = codeData.getId();
if (key == null) { if (key == null) {
@ -112,7 +112,7 @@ public class OAuth2CodeParser {
result.clientSession = userSession.getAuthenticatedClientSessionByClient(clientUUID); result.clientSession = userSession.getAuthenticatedClientSessionByClient(clientUUID);
SingleUseObjectProvider codeStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider codeStore = session.singleUseObjects();
Map<String, String> codeData = codeStore.remove(codeUUID); Map<String, String> codeData = codeStore.remove(codeUUID);
// Either code not available or was already used // Either code not available or was already used

View file

@ -207,7 +207,7 @@ public class SamlProtocol implements LoginProtocol {
private SingleUseObjectProvider getSingleUseStore() { private SingleUseObjectProvider getSingleUseStore() {
if (singleUseStore == null) { if (singleUseStore == null) {
singleUseStore = session.getProvider(SingleUseObjectProvider.class); singleUseStore = session.singleUseObjects();
} }
return singleUseStore; return singleUseStore;
} }

View file

@ -1126,7 +1126,7 @@ public class SamlService extends AuthorizationEndpointBase {
private SingleUseObjectProvider getSingleUseStore() { private SingleUseObjectProvider getSingleUseStore() {
return session.getProvider(SingleUseObjectProvider.class); return session.singleUseObjects();
} }
/** /**

View file

@ -33,6 +33,7 @@ import org.keycloak.models.KeycloakTransactionManager;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleProvider; import org.keycloak.models.RoleProvider;
import org.keycloak.models.SingleUseObjectProvider;
import org.keycloak.models.ThemeManager; import org.keycloak.models.ThemeManager;
import org.keycloak.models.TokenManager; import org.keycloak.models.TokenManager;
import org.keycloak.models.UserCredentialManager; import org.keycloak.models.UserCredentialManager;
@ -79,9 +80,6 @@ public class DefaultKeycloakSession implements KeycloakSession {
private DatastoreProvider datastoreProvider; private DatastoreProvider datastoreProvider;
@Deprecated @Deprecated
private UserCredentialManager userCredentialStorageManager; private UserCredentialManager userCredentialStorageManager;
private UserSessionProvider sessionProvider;
private UserLoginFailureProvider userLoginFailureProvider;
private AuthenticationSessionProvider authenticationSessionProvider;
private final KeycloakContext context; private final KeycloakContext context;
private KeyManager keyManager; private KeyManager keyManager;
private ThemeManager themeManager; private ThemeManager themeManager;
@ -390,26 +388,22 @@ public class DefaultKeycloakSession implements KeycloakSession {
@Override @Override
public UserSessionProvider sessions() { public UserSessionProvider sessions() {
if (sessionProvider == null) { return getDatastoreProvider().userSessions();
sessionProvider = getProvider(UserSessionProvider.class);
}
return sessionProvider;
} }
@Override @Override
public UserLoginFailureProvider loginFailures() { public UserLoginFailureProvider loginFailures() {
if (userLoginFailureProvider == null) { return getDatastoreProvider().loginFailures();
userLoginFailureProvider = getProvider(UserLoginFailureProvider.class);
}
return userLoginFailureProvider;
} }
@Override @Override
public AuthenticationSessionProvider authenticationSessions() { public AuthenticationSessionProvider authenticationSessions() {
if (authenticationSessionProvider == null) { return getDatastoreProvider().authSessions();
authenticationSessionProvider = getProvider(AuthenticationSessionProvider.class); }
}
return authenticationSessionProvider; @Override
public SingleUseObjectProvider singleUseObjects() {
return getDatastoreProvider().singleUseObjects();
} }
@Override @Override

View file

@ -1052,7 +1052,7 @@ public class AuthenticationManager {
if (actionTokenKeyToInvalidate != null) { if (actionTokenKeyToInvalidate != null) {
SingleUseObjectKeyModel actionTokenKey = DefaultActionTokenKey.from(actionTokenKeyToInvalidate); SingleUseObjectKeyModel actionTokenKey = DefaultActionTokenKey.from(actionTokenKeyToInvalidate);
if (actionTokenKey != null) { if (actionTokenKey != null) {
SingleUseObjectProvider singleUseObjectProvider = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseObjectProvider = session.singleUseObjects();
singleUseObjectProvider.put(actionTokenKeyToInvalidate, actionTokenKey.getExpiration() - Time.currentTime(), null); // Token is invalidated singleUseObjectProvider.put(actionTokenKeyToInvalidate, actionTokenKey.getExpiration() - Time.currentTime(), null); // Token is invalidated
} }
} }

View file

@ -300,7 +300,7 @@ public class LoginActionsServiceChecks {
} }
public static <T extends JsonWebToken & SingleUseObjectKeyModel> void checkTokenWasNotUsedYet(T token, ActionTokenContext<T> context) throws VerificationException { public static <T extends JsonWebToken & SingleUseObjectKeyModel> void checkTokenWasNotUsedYet(T token, ActionTokenContext<T> context) throws VerificationException {
SingleUseObjectProvider singleUseObjectProvider = context.getSession().getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseObjectProvider = context.getSession().singleUseObjects();
if (singleUseObjectProvider.get(token.serializeKey()) != null) { if (singleUseObjectProvider.get(token.serializeKey()) != null) {
throw new ExplainedTokenVerificationException(token, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION); throw new ExplainedTokenVerificationException(token, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION);

View file

@ -196,8 +196,8 @@ public class HandleArtifactStepBuilder extends SamlDocumentStepBuilder<ArtifactR
if (beforeStepChecker != null && beforeStepChecker instanceof SessionStateChecker) { if (beforeStepChecker != null && beforeStepChecker instanceof SessionStateChecker) {
SessionStateChecker sessionStateChecker = (SessionStateChecker) beforeStepChecker; SessionStateChecker sessionStateChecker = (SessionStateChecker) beforeStepChecker;
sessionStateChecker.setUserSessionProvider(session -> session.getProvider(SingleUseObjectProvider.class).get(artifact).get(SamlProtocol.USER_SESSION_ID)); sessionStateChecker.setUserSessionProvider(session -> session.singleUseObjects().get(artifact).get(SamlProtocol.USER_SESSION_ID));
sessionStateChecker.setClientSessionProvider(session -> session.getProvider(SingleUseObjectProvider.class).get(artifact).get(SamlProtocol.CLIENT_SESSION_ID)); sessionStateChecker.setClientSessionProvider(session -> session.singleUseObjects().get(artifact).get(SamlProtocol.CLIENT_SESSION_ID));
} }
HttpPost post = Soap.createMessage().addToBody(DocumentUtil.getDocument(transformed)).buildHttpPost(authServerSamlUrl); HttpPost post = Soap.createMessage().addToBody(DocumentUtil.getDocument(transformed)).buildHttpPost(authServerSamlUrl);

View file

@ -69,7 +69,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
@Test @Test
public void testActionTokens() { public void testActionTokens() {
DefaultActionTokenKey key = withRealm(realmId, (session, realm) -> { DefaultActionTokenKey key = withRealm(realmId, (session, realm) -> {
SingleUseObjectProvider singleUseObjectProvider = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseObjectProvider = session.singleUseObjects();
int time = Time.currentTime(); int time = Time.currentTime();
DefaultActionTokenKey actionTokenKey = new DefaultActionTokenKey(userId, UUID.randomUUID().toString(), time + 60, null); DefaultActionTokenKey actionTokenKey = new DefaultActionTokenKey(userId, UUID.randomUUID().toString(), time + 60, null);
Map<String, String> notes = new HashMap<>(); Map<String, String> notes = new HashMap<>();
@ -79,7 +79,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
}); });
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseObjectProvider = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseObjectProvider = session.singleUseObjects();
Map<String, String> notes = singleUseObjectProvider.get(key.serializeKey()); Map<String, String> notes = singleUseObjectProvider.get(key.serializeKey());
Assert.assertNotNull(notes); Assert.assertNotNull(notes);
Assert.assertEquals("bar", notes.get("foo")); Assert.assertEquals("bar", notes.get("foo"));
@ -90,7 +90,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
}); });
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseObjectProvider = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseObjectProvider = session.singleUseObjects();
Map<String, String> notes = singleUseObjectProvider.get(key.serializeKey()); Map<String, String> notes = singleUseObjectProvider.get(key.serializeKey());
Assert.assertNull(notes); Assert.assertNull(notes);
@ -100,7 +100,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
}); });
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseObjectProvider = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseObjectProvider = session.singleUseObjects();
Map<String, String> notes = singleUseObjectProvider.get(key.serializeKey()); Map<String, String> notes = singleUseObjectProvider.get(key.serializeKey());
Assert.assertNotNull(notes); Assert.assertNotNull(notes);
Assert.assertEquals("bar", notes.get("foo")); Assert.assertEquals("bar", notes.get("foo"));
@ -109,7 +109,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
setTimeOffset(70); setTimeOffset(70);
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseObjectProvider = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseObjectProvider = session.singleUseObjects();
Map<String, String> notes = singleUseObjectProvider.get(key.serializeKey()); Map<String, String> notes = singleUseObjectProvider.get(key.serializeKey());
notes = singleUseObjectProvider.get(key.serializeKey()); notes = singleUseObjectProvider.get(key.serializeKey());
Assert.assertNull(notes); Assert.assertNull(notes);
@ -126,14 +126,14 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
notes2.put("baf", "meow"); notes2.put("baf", "meow");
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
Assert.assertFalse(singleUseStore.replace(key, notes2)); Assert.assertFalse(singleUseStore.replace(key, notes2));
singleUseStore.put(key, 60, notes); singleUseStore.put(key, 60, notes);
}); });
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
Map<String, String> actualNotes = singleUseStore.get(key); Map<String, String> actualNotes = singleUseStore.get(key);
Assert.assertEquals(notes, actualNotes); Assert.assertEquals(notes, actualNotes);
@ -141,7 +141,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
}); });
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
Map<String, String> actualNotes = singleUseStore.get(key); Map<String, String> actualNotes = singleUseStore.get(key);
Assert.assertEquals(notes2, actualNotes); Assert.assertEquals(notes2, actualNotes);
@ -151,12 +151,12 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
}); });
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
Assert.assertTrue(singleUseStore.putIfAbsent(key, 60)); Assert.assertTrue(singleUseStore.putIfAbsent(key, 60));
}); });
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
Map<String, String> actualNotes = singleUseStore.get(key); Map<String, String> actualNotes = singleUseStore.get(key);
assertThat(actualNotes, Matchers.anEmptyMap()); assertThat(actualNotes, Matchers.anEmptyMap());
}); });
@ -164,7 +164,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
setTimeOffset(70); setTimeOffset(70);
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
Assert.assertNull(singleUseStore.get(key)); Assert.assertNull(singleUseStore.get(key));
}); });
} }
@ -196,7 +196,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
if (index.incrementAndGet() == 1) { if (index.incrementAndGet() == 1) {
actionTokenKey.set(withRealm(realmId, (session, realm) -> { actionTokenKey.set(withRealm(realmId, (session, realm) -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
singleUseStore.put(key, 60, notes); singleUseStore.put(key, 60, notes);
int time = Time.currentTime(); int time = Time.currentTime();
@ -212,7 +212,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
// check if single-use object/action token is available on all nodes // check if single-use object/action token is available on all nodes
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
while (singleUseStore.get(key) == null || singleUseStore.get(actionTokenKey.get()) == null) { while (singleUseStore.get(key) == null || singleUseStore.get(actionTokenKey.get()) == null) {
sleep(1000); sleep(1000);
} }
@ -224,7 +224,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
// remove objects on one node // remove objects on one node
if (index.incrementAndGet() == 5) { if (index.incrementAndGet() == 5) {
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
singleUseStore.remove(key); singleUseStore.remove(key);
singleUseStore.remove(actionTokenKey.get()); singleUseStore.remove(actionTokenKey.get());
}); });
@ -236,7 +236,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
// check if single-use object/action token is removed // check if single-use object/action token is removed
inComittedTransaction(session -> { inComittedTransaction(session -> {
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class); SingleUseObjectProvider singleUseStore = session.singleUseObjects();
while (singleUseStore.get(key) != null && singleUseStore.get(actionTokenKey.get()) != null) { while (singleUseStore.get(key) != null && singleUseStore.get(actionTokenKey.get()) != null) {
sleep(1000); sleep(1000);