parent
fdd5e51dbc
commit
8c58f39a49
24 changed files with 131 additions and 54 deletions
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,6 +201,8 @@ public interface KeycloakSession extends AutoCloseable {
|
||||||
|
|
||||||
AuthenticationSessionProvider authenticationSessions();
|
AuthenticationSessionProvider authenticationSessions();
|
||||||
|
|
||||||
|
SingleUseObjectProvider singleUseObjects();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1126,7 +1126,7 @@ public class SamlService extends AuthorizationEndpointBase {
|
||||||
|
|
||||||
|
|
||||||
private SingleUseObjectProvider getSingleUseStore() {
|
private SingleUseObjectProvider getSingleUseStore() {
|
||||||
return session.getProvider(SingleUseObjectProvider.class);
|
return session.singleUseObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue