From a912558d29c685ef912baa04b8cc823a70c6fd2d Mon Sep 17 00:00:00 2001 From: Martin Kanis Date: Mon, 30 Jan 2023 11:48:31 +0100 Subject: [PATCH] Add MapKeycloakTransaction.exists methods --- .../map/storage/hotRod/HotRodMapStorage.java | 8 +++++++ .../MapRootAuthenticationSessionProvider.java | 2 +- .../MapPermissionTicketStore.java | 2 +- .../map/authorization/MapPolicyStore.java | 2 +- .../map/authorization/MapResourceStore.java | 2 +- .../map/authorization/MapScopeStore.java | 2 +- .../models/map/client/MapClientProvider.java | 2 +- .../clientscope/MapClientScopeProvider.java | 4 ++-- .../map/events/MapEventStoreProvider.java | 4 ++-- .../models/map/group/MapGroupProvider.java | 4 ++-- .../models/map/realm/MapRealmProvider.java | 2 +- .../models/map/role/MapRoleProvider.java | 4 ++-- .../map/storage/MapKeycloakTransaction.java | 23 +++++++++++++++++++ .../chm/ConcurrentHashMapCrudOperations.java | 22 ++++++++++++++++++ .../ConcurrentHashMapKeycloakTransaction.java | 17 ++++++++++++++ .../models/map/user/MapUserProvider.java | 4 ++-- .../userSession/MapUserSessionProvider.java | 2 +- 17 files changed, 88 insertions(+), 18 deletions(-) diff --git a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/HotRodMapStorage.java b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/HotRodMapStorage.java index 250cc9d2c5..cba513f795 100644 --- a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/HotRodMapStorage.java +++ b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/HotRodMapStorage.java @@ -205,6 +205,14 @@ public class HotRodMapStorage createCriteriaBuilder() { return new IckleQueryMapModelCriteriaBuilder<>(storedEntityDescriptor.getEntityTypeClass()); } diff --git a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java index 2c51316778..842b65a73d 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java @@ -105,7 +105,7 @@ public class MapRootAuthenticationSessionProvider implements AuthenticationSessi int authSessionLifespanSeconds = getAuthSessionLifespan(realm); entity.setExpiration(timestamp + TimeAdapter.fromSecondsToMilliseconds(authSessionLifespanSeconds)); - if (id != null && tx.read(id) != null) { + if (id != null && tx.exists(id)) { throw new ModelDuplicateException("Root authentication session exists: " + entity.getId()); } diff --git a/model/map/src/main/java/org/keycloak/models/map/authorization/MapPermissionTicketStore.java b/model/map/src/main/java/org/keycloak/models/map/authorization/MapPermissionTicketStore.java index ca95690049..d9a70645c7 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authorization/MapPermissionTicketStore.java +++ b/model/map/src/main/java/org/keycloak/models/map/authorization/MapPermissionTicketStore.java @@ -110,7 +110,7 @@ public class MapPermissionTicketStore implements PermissionTicketStore { mcb = mcb.compare(SearchableFields.SCOPE_ID, Operator.EQ, scope.getId()); } - if (tx.getCount(withCriteria(mcb)) > 0) { + if (tx.exists(withCriteria(mcb))) { throw new ModelDuplicateException("Permission ticket for resource server: '" + resourceServer.getId() + ", Resource: " + resource + ", owner: " + owner + ", scopeId: " + scope + " already exists."); } diff --git a/model/map/src/main/java/org/keycloak/models/map/authorization/MapPolicyStore.java b/model/map/src/main/java/org/keycloak/models/map/authorization/MapPolicyStore.java index 5376b590b0..b83460e97c 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authorization/MapPolicyStore.java +++ b/model/map/src/main/java/org/keycloak/models/map/authorization/MapPolicyStore.java @@ -84,7 +84,7 @@ public class MapPolicyStore implements PolicyStore { DefaultModelCriteria mcb = forRealmAndResourceServer(realm, resourceServer) .compare(SearchableFields.NAME, Operator.EQ, representation.getName()); - if (tx.getCount(withCriteria(mcb)) > 0) { + if (tx.exists(withCriteria(mcb))) { throw new ModelDuplicateException("Policy with name '" + representation.getName() + "' for " + resourceServer.getId() + " already exists"); } diff --git a/model/map/src/main/java/org/keycloak/models/map/authorization/MapResourceStore.java b/model/map/src/main/java/org/keycloak/models/map/authorization/MapResourceStore.java index ab88535dca..bcf8e2b1d9 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authorization/MapResourceStore.java +++ b/model/map/src/main/java/org/keycloak/models/map/authorization/MapResourceStore.java @@ -85,7 +85,7 @@ public class MapResourceStore implements ResourceStore { .compare(SearchableFields.NAME, Operator.EQ, name) .compare(SearchableFields.OWNER, Operator.EQ, owner); - if (tx.getCount(withCriteria(mcb)) > 0) { + if (tx.exists(withCriteria(mcb))) { throw new ModelDuplicateException("Resource with name '" + name + "' for " + resourceServer.getId() + " already exists for request owner " + owner); } diff --git a/model/map/src/main/java/org/keycloak/models/map/authorization/MapScopeStore.java b/model/map/src/main/java/org/keycloak/models/map/authorization/MapScopeStore.java index c1e7cc759d..ded5d8d71a 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authorization/MapScopeStore.java +++ b/model/map/src/main/java/org/keycloak/models/map/authorization/MapScopeStore.java @@ -81,7 +81,7 @@ public class MapScopeStore implements ScopeStore { DefaultModelCriteria mcb = forRealmAndResourceServer(realm, resourceServer) .compare(SearchableFields.NAME, Operator.EQ, name); - if (tx.getCount(withCriteria(mcb)) > 0) { + if (tx.exists(withCriteria(mcb))) { throw new ModelDuplicateException("Scope with name '" + name + "' for " + resourceServer.getId() + " already exists"); } diff --git a/model/map/src/main/java/org/keycloak/models/map/client/MapClientProvider.java b/model/map/src/main/java/org/keycloak/models/map/client/MapClientProvider.java index d3f24e5c7c..1e10185217 100644 --- a/model/map/src/main/java/org/keycloak/models/map/client/MapClientProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/client/MapClientProvider.java @@ -148,7 +148,7 @@ public class MapClientProvider implements ClientProvider { public ClientModel addClient(RealmModel realm, String id, String clientId) { LOG.tracef("addClient(%s, %s, %s)%s", realm, id, clientId, getShortStackTrace()); - if (id != null && tx.read(id) != null) { + if (id != null && tx.exists(id)) { throw new ModelDuplicateException("Client with same id exists: " + id); } if (clientId != null && getClientByClientId(realm, clientId) != null) { diff --git a/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProvider.java b/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProvider.java index a3c3dd13ff..7b546df95f 100644 --- a/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProvider.java @@ -84,11 +84,11 @@ public class MapClientScopeProvider implements ClientScopeProvider { mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId()) .compare(SearchableFields.NAME, Operator.EQ, name); - if (tx.getCount(withCriteria(mcb)) > 0) { + if (tx.exists(withCriteria(mcb))) { throw new ModelDuplicateException("Client scope with name '" + name + "' in realm " + realm.getName()); } - if (id != null && tx.read(id) != null) { + if (id != null && tx.exists(id)) { throw new ModelDuplicateException("Client scope exists: " + id); } diff --git a/model/map/src/main/java/org/keycloak/models/map/events/MapEventStoreProvider.java b/model/map/src/main/java/org/keycloak/models/map/events/MapEventStoreProvider.java index a3f355f99c..1b87322c59 100644 --- a/model/map/src/main/java/org/keycloak/models/map/events/MapEventStoreProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/events/MapEventStoreProvider.java @@ -63,7 +63,7 @@ public class MapEventStoreProvider implements EventStoreProvider { LOG.tracef("onEvent(%s)%s", event, getShortStackTrace()); String id = event.getId(); - if (id != null && authEventsTX.read(id) != null) { + if (id != null && authEventsTX.exists(id)) { throw new ModelDuplicateException("Event already exists: " + id); } @@ -132,7 +132,7 @@ public class MapEventStoreProvider implements EventStoreProvider { public void onEvent(AdminEvent event, boolean includeRepresentation) { LOG.tracef("clear(%s, %s)%s", event, includeRepresentation, getShortStackTrace()); String id = event.getId(); - if (id != null && authEventsTX.read(id) != null) { + if (id != null && authEventsTX.exists(id)) { throw new ModelDuplicateException("Event already exists: " + id); } String realmId = event.getRealmId(); diff --git a/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProvider.java b/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProvider.java index a48534da9e..456b1a6151 100644 --- a/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProvider.java @@ -218,7 +218,7 @@ public class MapGroupProvider implements GroupProvider { mcb.compare(SearchableFields.PARENT_ID, Operator.NOT_EXISTS) : mcb.compare(SearchableFields.PARENT_ID, Operator.EQ, toParent.getId()); - if (tx.getCount(withCriteria(mcb)) > 0) { + if (tx.exists(withCriteria(mcb))) { throw new ModelDuplicateException("Group with name '" + name + "' in realm " + realm.getName() + " already exists for requested parent" ); } @@ -227,7 +227,7 @@ public class MapGroupProvider implements GroupProvider { entity.setRealmId(realm.getId()); entity.setName(name); entity.setParentId(toParent == null ? null : toParent.getId()); - if (id != null && tx.read(id) != null) { + if (id != null && tx.exists(id)) { throw new ModelDuplicateException("Group exists: " + id); } entity = tx.create(entity); diff --git a/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProvider.java b/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProvider.java index 877bd311e4..946c5943cc 100644 --- a/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProvider.java @@ -72,7 +72,7 @@ public class MapRealmProvider implements RealmProvider { throw new ModelDuplicateException("Realm with given name exists: " + name); } - if (id != null && tx.read(id) != null) { + if (id != null && tx.exists(id)) { throw new ModelDuplicateException("Realm exists: " + id); } diff --git a/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProvider.java b/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProvider.java index a3171535a5..8f60eaa9eb 100644 --- a/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProvider.java @@ -71,7 +71,7 @@ public class MapRoleProvider implements RoleProvider { entity.setRealmId(realm.getId()); entity.setName(name); entity.setClientRole(false); - if (entity.getId() != null && tx.read(entity.getId()) != null) { + if (entity.getId() != null && tx.exists(entity.getId())) { throw new ModelDuplicateException("Role exists: " + id); } entity = tx.create(entity); @@ -129,7 +129,7 @@ public class MapRoleProvider implements RoleProvider { entity.setName(name); entity.setClientRole(true); entity.setClientId(client.getId()); - if (entity.getId() != null && tx.read(entity.getId()) != null) { + if (entity.getId() != null && tx.exists(entity.getId())) { throw new ModelDuplicateException("Role exists: " + id); } entity = tx.create(entity); diff --git a/model/map/src/main/java/org/keycloak/models/map/storage/MapKeycloakTransaction.java b/model/map/src/main/java/org/keycloak/models/map/storage/MapKeycloakTransaction.java index 1a43646ff6..4e664d5fc0 100644 --- a/model/map/src/main/java/org/keycloak/models/map/storage/MapKeycloakTransaction.java +++ b/model/map/src/main/java/org/keycloak/models/map/storage/MapKeycloakTransaction.java @@ -94,4 +94,27 @@ public interface MapKeycloakTransaction extends Key */ long delete(QueryParameters queryParameters); + /** + * Returns {@code true} if the object with the given {@code key} exists in the underlying storage with respect to changes done + * in current transaction. {@code false} otherwise. + * + * @param key Key of the object. Must not be {@code null}. + * @return See description + * @throws NullPointerException if the {@code key} is {@code null} + */ + default boolean exists(String key) { + return read(key) != null; + } + + /** + * Returns {@code true} if at least one object is satisfying given {@code criteria} from the underlying storage with respect to changes done + * in current transaction. {@code false} otherwise. + * The criteria are specified in the given criteria builder based on model properties. + * + * @param queryParameters parameters for the query + * @return See description + */ + default boolean exists(QueryParameters queryParameters) { + return getCount(queryParameters) > 0; + } } diff --git a/model/map/src/main/java/org/keycloak/models/map/storage/chm/ConcurrentHashMapCrudOperations.java b/model/map/src/main/java/org/keycloak/models/map/storage/chm/ConcurrentHashMapCrudOperations.java index d982456520..dd9ab67051 100644 --- a/model/map/src/main/java/org/keycloak/models/map/storage/chm/ConcurrentHashMapCrudOperations.java +++ b/model/map/src/main/java/org/keycloak/models/map/storage/chm/ConcurrentHashMapCrudOperations.java @@ -79,4 +79,26 @@ public interface ConcurrentHashMapCrudOperations queryParameters); + + /** + * Returns {@code true} if the object with the given {@code key} exists in the storage. {@code false} otherwise. + * + * @param key Key of the object. Must not be {@code null}. + * @return See description + * @throws NullPointerException if the {@code key} is {@code null} + */ + default boolean exists(String key) { + return read(key) != null; + } + + /** + * Returns {@code true} if at least one object is satisfying given {@code criteria} from the storage. {@code false} otherwise. + * The criteria are specified in the given criteria builder based on model properties. + * + * @param queryParameters parameters for the query + * @return See description + */ + default boolean exists(QueryParameters queryParameters) { + return getCount(queryParameters) > 0; + } } diff --git a/model/map/src/main/java/org/keycloak/models/map/storage/chm/ConcurrentHashMapKeycloakTransaction.java b/model/map/src/main/java/org/keycloak/models/map/storage/chm/ConcurrentHashMapKeycloakTransaction.java index 705aa945ba..16986e9dd4 100644 --- a/model/map/src/main/java/org/keycloak/models/map/storage/chm/ConcurrentHashMapKeycloakTransaction.java +++ b/model/map/src/main/java/org/keycloak/models/map/storage/chm/ConcurrentHashMapKeycloakTransaction.java @@ -277,6 +277,23 @@ public class ConcurrentHashMapKeycloakTransaction createdValuesStream(Predicate keyFilter, Predicate entityFilter) { return this.tasks.entrySet().stream() .filter(me -> keyFilter.test(keyConverter.fromStringSafe(me.getKey()))) diff --git a/model/map/src/main/java/org/keycloak/models/map/user/MapUserProvider.java b/model/map/src/main/java/org/keycloak/models/map/user/MapUserProvider.java index c33390541f..902d7dcd56 100644 --- a/model/map/src/main/java/org/keycloak/models/map/user/MapUserProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/user/MapUserProvider.java @@ -336,11 +336,11 @@ public class MapUserProvider implements UserProvider { SearchableFields.USERNAME : SearchableFields.USERNAME_CASE_INSENSITIVE, Operator.EQ, username); - if (tx.getCount(withCriteria(mcb)) > 0) { + if (tx.exists(withCriteria(mcb))) { throw new ModelDuplicateException("User with username '" + username + "' in realm " + realm.getName() + " already exists" ); } - if (id != null && tx.read(id) != null) { + if (id != null && tx.exists(id)) { throw new ModelDuplicateException("User exists: " + id); } diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java index ed364cdef1..0dd263051d 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java @@ -158,7 +158,7 @@ public class MapUserSessionProvider implements UserSessionProvider { } transientUserSessions.put(entity.getId(), entity); } else { - if (id != null && userSessionTx.read(id) != null) { + if (id != null && userSessionTx.exists(id)) { throw new ModelDuplicateException("User session exists: " + id); } entity = userSessionTx.create(entity);