KEYCLOAK-18845 Remove key type in map storage (move StringKeyConvertor to CHM)

This commit is contained in:
Hynek Mlnarik 2021-07-19 18:04:13 +02:00 committed by Hynek Mlnařík
parent 9018fe9fad
commit 07402d9aac
76 changed files with 636 additions and 635 deletions

View file

@ -31,12 +31,17 @@ import java.util.stream.Collectors;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public abstract class MapRootAuthenticationSessionAdapter<K> extends AbstractRootAuthenticationSessionModel<MapRootAuthenticationSessionEntity<K>> {
public class MapRootAuthenticationSessionAdapter extends AbstractRootAuthenticationSessionModel<MapRootAuthenticationSessionEntity> {
public MapRootAuthenticationSessionAdapter(KeycloakSession session, RealmModel realm, MapRootAuthenticationSessionEntity<K> entity) {
public MapRootAuthenticationSessionAdapter(KeycloakSession session, RealmModel realm, MapRootAuthenticationSessionEntity entity) {
super(session, realm, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public RealmModel getRealm() {
return session.realms().getRealm(entity.getRealmId());

View file

@ -26,9 +26,9 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public class MapRootAuthenticationSessionEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapRootAuthenticationSessionEntity implements AbstractEntity, UpdatableEntity {
private K id;
private String id;
private String realmId;
/**
@ -43,8 +43,7 @@ public class MapRootAuthenticationSessionEntity<K> implements AbstractEntity<K>,
this.realmId = null;
}
public MapRootAuthenticationSessionEntity(K id, String realmId) {
Objects.requireNonNull(id, "id");
public MapRootAuthenticationSessionEntity(String id, String realmId) {
Objects.requireNonNull(realmId, "realmId");
this.id = id;
@ -52,7 +51,7 @@ public class MapRootAuthenticationSessionEntity<K> implements AbstractEntity<K>,
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -48,12 +48,12 @@ public class MapRootAuthenticationSessionProvider<K> implements AuthenticationSe
private static final Logger LOG = Logger.getLogger(MapRootAuthenticationSessionProvider.class);
private final KeycloakSession session;
protected final MapKeycloakTransaction<K, MapRootAuthenticationSessionEntity<K>, RootAuthenticationSessionModel> tx;
private final MapStorage<K, MapRootAuthenticationSessionEntity<K>, RootAuthenticationSessionModel> sessionStore;
protected final MapKeycloakTransaction<K, MapRootAuthenticationSessionEntity, RootAuthenticationSessionModel> tx;
private final MapStorage<K, MapRootAuthenticationSessionEntity, RootAuthenticationSessionModel> sessionStore;
private static final String AUTHENTICATION_SESSION_EVENTS = "AUTHENTICATION_SESSION_EVENTS";
public MapRootAuthenticationSessionProvider(KeycloakSession session, MapStorage<K, MapRootAuthenticationSessionEntity<K>, RootAuthenticationSessionModel> sessionStore) {
public MapRootAuthenticationSessionProvider(KeycloakSession session, MapStorage<K, MapRootAuthenticationSessionEntity, RootAuthenticationSessionModel> sessionStore) {
this.session = session;
this.sessionStore = sessionStore;
this.tx = sessionStore.createTransaction(session);
@ -61,18 +61,13 @@ public class MapRootAuthenticationSessionProvider<K> implements AuthenticationSe
session.getTransactionManager().enlistAfterCompletion(tx);
}
private Function<MapRootAuthenticationSessionEntity<K>, RootAuthenticationSessionModel> entityToAdapterFunc(RealmModel realm) {
private Function<MapRootAuthenticationSessionEntity, RootAuthenticationSessionModel> entityToAdapterFunc(RealmModel realm) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return origEntity -> new MapRootAuthenticationSessionAdapter<K>(session, realm, origEntity) {
@Override
public String getId() {
return sessionStore.getKeyConvertor().keyToString(entity.getId());
}
};
return origEntity -> new MapRootAuthenticationSessionAdapter(session, realm, origEntity);
}
private Predicate<MapRootAuthenticationSessionEntity<K>> entityRealmFilter(String realmId) {
private Predicate<MapRootAuthenticationSessionEntity> entityRealmFilter(String realmId) {
if (realmId == null) {
return c -> false;
}
@ -89,16 +84,13 @@ public class MapRootAuthenticationSessionProvider<K> implements AuthenticationSe
public RootAuthenticationSessionModel createRootAuthenticationSession(RealmModel realm, String id) {
Objects.requireNonNull(realm, "The provided realm can't be null!");
final K entityId = id == null ? sessionStore.getKeyConvertor().yieldNewUniqueKey() : sessionStore.getKeyConvertor().fromString(id);
LOG.tracef("createRootAuthenticationSession(%s)%s", realm.getName(), getShortStackTrace());
// create map authentication session entity
MapRootAuthenticationSessionEntity<K> entity = new MapRootAuthenticationSessionEntity<>(entityId, realm.getId());
entity.setRealmId(realm.getId());
MapRootAuthenticationSessionEntity entity = new MapRootAuthenticationSessionEntity(null, realm.getId());
entity.setTimestamp(Time.currentTime());
if (tx.read(entity.getId()) != null) {
if (id != null && tx.read(id) != null) {
throw new ModelDuplicateException("Root authentication session exists: " + entity.getId());
}
@ -116,7 +108,7 @@ public class MapRootAuthenticationSessionProvider<K> implements AuthenticationSe
LOG.tracef("getRootAuthenticationSession(%s, %s)%s", realm.getName(), authenticationSessionId, getShortStackTrace());
MapRootAuthenticationSessionEntity<K> entity = tx.read(sessionStore.getKeyConvertor().fromStringSafe(authenticationSessionId));
MapRootAuthenticationSessionEntity entity = tx.read(authenticationSessionId);
return (entity == null || !entityRealmFilter(realm.getId()).test(entity))
? null
: entityToAdapterFunc(realm).apply(entity);
@ -125,7 +117,7 @@ public class MapRootAuthenticationSessionProvider<K> implements AuthenticationSe
@Override
public void removeRootAuthenticationSession(RealmModel realm, RootAuthenticationSessionModel authenticationSession) {
Objects.requireNonNull(authenticationSession, "The provided root authentication session can't be null!");
tx.delete(sessionStore.getKeyConvertor().fromString(authenticationSession.getId()));
tx.delete(authenticationSession.getId());
}
@Override

View file

@ -26,7 +26,7 @@ import org.keycloak.sessions.RootAuthenticationSessionModel;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public class MapRootAuthenticationSessionProviderFactory<K> extends AbstractMapProviderFactory<AuthenticationSessionProvider, K, MapRootAuthenticationSessionEntity<K>, RootAuthenticationSessionModel>
public class MapRootAuthenticationSessionProviderFactory<K> extends AbstractMapProviderFactory<AuthenticationSessionProvider, K, MapRootAuthenticationSessionEntity, RootAuthenticationSessionModel>
implements AuthenticationSessionProviderFactory {
public MapRootAuthenticationSessionProviderFactory() {

View file

@ -52,25 +52,20 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
private static final Logger LOG = Logger.getLogger(MapPermissionTicketStore.class);
private final AuthorizationProvider authorizationProvider;
final MapKeycloakTransaction<K, MapPermissionTicketEntity<K>, PermissionTicket> tx;
private final MapStorage<K, MapPermissionTicketEntity<K>, PermissionTicket> permissionTicketStore;
final MapKeycloakTransaction<K, MapPermissionTicketEntity, PermissionTicket> tx;
private final MapStorage<K, MapPermissionTicketEntity, PermissionTicket> permissionTicketStore;
public MapPermissionTicketStore(KeycloakSession session, MapStorage<K, MapPermissionTicketEntity<K>, PermissionTicket> permissionTicketStore, AuthorizationProvider provider) {
public MapPermissionTicketStore(KeycloakSession session, MapStorage<K, MapPermissionTicketEntity, PermissionTicket> permissionTicketStore, AuthorizationProvider provider) {
this.authorizationProvider = provider;
this.permissionTicketStore = permissionTicketStore;
this.tx = permissionTicketStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
private PermissionTicket entityToAdapter(MapPermissionTicketEntity<K> origEntity) {
private PermissionTicket entityToAdapter(MapPermissionTicketEntity origEntity) {
if (origEntity == null) return null;
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return new MapPermissionTicketAdapter<K>(origEntity, authorizationProvider.getStoreFactory()) {
@Override
public String getId() {
return permissionTicketStore.getKeyConvertor().keyToString(entity.getId());
}
};
return new MapPermissionTicketAdapter(origEntity, authorizationProvider.getStoreFactory());
}
private ModelCriteriaBuilder<PermissionTicket> forResourceServer(String resourceServerId) {
@ -114,8 +109,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
+ ", Resource: " + resourceId + ", owner: " + owner + ", scopeId: " + scopeId + " already exists.");
}
final K newId = permissionTicketStore.getKeyConvertor().yieldNewUniqueKey();
MapPermissionTicketEntity<K> entity = new MapPermissionTicketEntity<>(newId);
MapPermissionTicketEntity entity = new MapPermissionTicketEntity(null);
entity.setResourceId(resourceId);
entity.setRequester(requester);
entity.setCreatedTimestamp(System.currentTimeMillis());
@ -135,7 +129,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
@Override
public void delete(String id) {
LOG.tracef("delete(%s)%s", id, getShortStackTrace());
tx.delete(permissionTicketStore.getKeyConvertor().fromString(id));
tx.delete(id);
}
@Override
@ -276,7 +270,7 @@ public class MapPermissionTicketStore<K extends Comparable<K>> implements Permis
.compare(SearchableFields.REQUESTER, Operator.EQ, requester)
.compare(SearchableFields.GRANTED_TIMESTAMP, Operator.EXISTS);
Function<MapPermissionTicketEntity<K>, Resource> ticketResourceMapper;
Function<MapPermissionTicketEntity, Resource> ticketResourceMapper;
ResourceStore resourceStore = authorizationProvider.getStoreFactory().getResourceStore();
if (name != null) {

View file

@ -47,25 +47,20 @@ public class MapPolicyStore<K> implements PolicyStore {
private static final Logger LOG = Logger.getLogger(MapPolicyStore.class);
private final AuthorizationProvider authorizationProvider;
final MapKeycloakTransaction<K, MapPolicyEntity<K>, Policy> tx;
private final MapStorage<K, MapPolicyEntity<K>, Policy> policyStore;
final MapKeycloakTransaction<K, MapPolicyEntity, Policy> tx;
private final MapStorage<K, MapPolicyEntity, Policy> policyStore;
public MapPolicyStore(KeycloakSession session, MapStorage<K, MapPolicyEntity<K>, Policy> policyStore, AuthorizationProvider provider) {
public MapPolicyStore(KeycloakSession session, MapStorage<K, MapPolicyEntity, Policy> policyStore, AuthorizationProvider provider) {
this.authorizationProvider = provider;
this.policyStore = policyStore;
this.tx = policyStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
private Policy entityToAdapter(MapPolicyEntity<K> origEntity) {
private Policy entityToAdapter(MapPolicyEntity origEntity) {
if (origEntity == null) return null;
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return new MapPolicyAdapter<K>(origEntity, authorizationProvider.getStoreFactory()) {
@Override
public String getId() {
return policyStore.getKeyConvertor().keyToString(entity.getId());
}
};
return new MapPolicyAdapter(origEntity, authorizationProvider.getStoreFactory());
}
private ModelCriteriaBuilder<Policy> forResourceServer(String resourceServerId) {
@ -89,8 +84,8 @@ public class MapPolicyStore<K> implements PolicyStore {
throw new ModelDuplicateException("Policy with name '" + representation.getName() + "' for " + resourceServer.getId() + " already exists");
}
K uid = representation.getId() == null ? policyStore.getKeyConvertor().yieldNewUniqueKey() : policyStore.getKeyConvertor().fromString(representation.getId());
MapPolicyEntity<K> entity = new MapPolicyEntity<>(uid);
String uid = representation.getId();
MapPolicyEntity entity = new MapPolicyEntity(uid);
entity.setType(representation.getType());
entity.setName(representation.getName());
entity.setResourceServerId(resourceServer.getId());
@ -103,7 +98,7 @@ public class MapPolicyStore<K> implements PolicyStore {
@Override
public void delete(String id) {
LOG.tracef("delete(%s)%s", id, getShortStackTrace());
tx.delete(policyStore.getKeyConvertor().fromString(id));
tx.delete(id);
}
@Override
@ -153,8 +148,7 @@ public class MapPolicyStore<K> implements PolicyStore {
}
return tx.read(withCriteria(mcb).pagination(firstResult, maxResult, SearchableFields.NAME))
.map(MapPolicyEntity<K>::getId)
.map(policyStore.getKeyConvertor()::keyToString)
.map(MapPolicyEntity::getId)
// We need to go through cache
.map(id -> authorizationProvider.getStoreFactory().getPolicyStore().findById(id, resourceServerId))
.collect(Collectors.toList());

View file

@ -44,25 +44,20 @@ public class MapResourceServerStore<K> implements ResourceServerStore {
private static final Logger LOG = Logger.getLogger(MapResourceServerStore.class);
private final AuthorizationProvider authorizationProvider;
final MapKeycloakTransaction<K, MapResourceServerEntity<K>, ResourceServer> tx;
private final MapStorage<K, MapResourceServerEntity<K>, ResourceServer> resourceServerStore;
final MapKeycloakTransaction<K, MapResourceServerEntity, ResourceServer> tx;
private final MapStorage<K, MapResourceServerEntity, ResourceServer> resourceServerStore;
public MapResourceServerStore(KeycloakSession session, MapStorage<K, MapResourceServerEntity<K>, ResourceServer> resourceServerStore, AuthorizationProvider provider) {
public MapResourceServerStore(KeycloakSession session, MapStorage<K, MapResourceServerEntity, ResourceServer> resourceServerStore, AuthorizationProvider provider) {
this.resourceServerStore = resourceServerStore;
this.tx = resourceServerStore.createTransaction(session);
this.authorizationProvider = provider;
session.getTransactionManager().enlist(tx);
}
private ResourceServer entityToAdapter(MapResourceServerEntity<K> origEntity) {
private ResourceServer entityToAdapter(MapResourceServerEntity origEntity) {
if (origEntity == null) return null;
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return new MapResourceServerAdapter<K>(origEntity, authorizationProvider.getStoreFactory()) {
@Override
public String getId() {
return resourceServerStore.getKeyConvertor().keyToString(entity.getId());
}
};
return new MapResourceServerAdapter(origEntity, authorizationProvider.getStoreFactory());
}
@Override
@ -75,15 +70,13 @@ public class MapResourceServerStore<K> implements ResourceServerStore {
throw new ModelException("Creating resource server from federated ClientModel not supported");
}
if (tx.read(resourceServerStore.getKeyConvertor().fromString(clientId)) != null) {
if (tx.read(clientId) != null) {
throw new ModelDuplicateException("Resource server already exists: " + clientId);
}
MapResourceServerEntity<K> entity = new MapResourceServerEntity<>(resourceServerStore.getKeyConvertor().fromString(clientId));
MapResourceServerEntity entity = new MapResourceServerEntity(clientId);
entity = tx.create(entity);
return entityToAdapter(entity);
return entityToAdapter(tx.create(entity));
}
@Override
@ -91,6 +84,7 @@ public class MapResourceServerStore<K> implements ResourceServerStore {
LOG.tracef("delete(%s, %s)%s", id, getShortStackTrace());
if (id == null) return;
// TODO: Simplify the following, ideally by leveraging triggers, stored procedures or ref integrity
PolicyStore policyStore = authorizationProvider.getStoreFactory().getPolicyStore();
policyStore.findByResourceServer(id).stream()
.map(Policy::getId)
@ -111,7 +105,7 @@ public class MapResourceServerStore<K> implements ResourceServerStore {
.map(Scope::getId)
.forEach(scopeStore::delete);
tx.delete(resourceServerStore.getKeyConvertor().fromString(id));
tx.delete(id);
}
@Override
@ -122,8 +116,7 @@ public class MapResourceServerStore<K> implements ResourceServerStore {
return null;
}
MapResourceServerEntity<K> entity = tx.read(resourceServerStore.getKeyConvertor().fromStringSafe(id));
MapResourceServerEntity entity = tx.read(id);
return entityToAdapter(entity);
}
}

View file

@ -46,25 +46,20 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
private static final Logger LOG = Logger.getLogger(MapResourceStore.class);
private final AuthorizationProvider authorizationProvider;
final MapKeycloakTransaction<K, MapResourceEntity<K>, Resource> tx;
private final MapStorage<K, MapResourceEntity<K>, Resource> resourceStore;
final MapKeycloakTransaction<K, MapResourceEntity, Resource> tx;
private final MapStorage<K, MapResourceEntity, Resource> resourceStore;
public MapResourceStore(KeycloakSession session, MapStorage<K, MapResourceEntity<K>, Resource> resourceStore, AuthorizationProvider provider) {
public MapResourceStore(KeycloakSession session, MapStorage<K, MapResourceEntity, Resource> resourceStore, AuthorizationProvider provider) {
this.resourceStore = resourceStore;
this.tx = resourceStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
authorizationProvider = provider;
}
private Resource entityToAdapter(MapResourceEntity<K> origEntity) {
private Resource entityToAdapter(MapResourceEntity origEntity) {
if (origEntity == null) return null;
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return new MapResourceAdapter<K>(origEntity, authorizationProvider.getStoreFactory()) {
@Override
public String getId() {
return resourceStore.getKeyConvertor().keyToString(entity.getId());
}
};
return new MapResourceAdapter(origEntity, authorizationProvider.getStoreFactory());
}
private ModelCriteriaBuilder<Resource> forResourceServer(String resourceServerId) {
@ -88,8 +83,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
throw new ModelDuplicateException("Resource with name '" + name + "' for " + resourceServer.getId() + " already exists for request owner " + owner);
}
K uid = id == null ? resourceStore.getKeyConvertor().yieldNewUniqueKey(): resourceStore.getKeyConvertor().fromString(id);
MapResourceEntity<K> entity = new MapResourceEntity<>(uid);
MapResourceEntity entity = new MapResourceEntity(id);
entity.setName(name);
entity.setResourceServerId(resourceServer.getId());
@ -104,7 +98,7 @@ public class MapResourceStore<K extends Comparable<K>> implements ResourceStore
public void delete(String id) {
LOG.tracef("delete(%s)%s", id, getShortStackTrace());
tx.delete(resourceStore.getKeyConvertor().fromString(id));
tx.delete(id);
}
@Override

View file

@ -44,25 +44,20 @@ public class MapScopeStore<K> implements ScopeStore {
private static final Logger LOG = Logger.getLogger(MapScopeStore.class);
private final AuthorizationProvider authorizationProvider;
final MapKeycloakTransaction<K, MapScopeEntity<K>, Scope> tx;
private final MapStorage<K, MapScopeEntity<K>, Scope> scopeStore;
final MapKeycloakTransaction<K, MapScopeEntity, Scope> tx;
private final MapStorage<K, MapScopeEntity, Scope> scopeStore;
public MapScopeStore(KeycloakSession session, MapStorage<K, MapScopeEntity<K>, Scope> scopeStore, AuthorizationProvider provider) {
public MapScopeStore(KeycloakSession session, MapStorage<K, MapScopeEntity, Scope> scopeStore, AuthorizationProvider provider) {
this.authorizationProvider = provider;
this.scopeStore = scopeStore;
this.tx = scopeStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
private Scope entityToAdapter(MapScopeEntity<K> origEntity) {
private Scope entityToAdapter(MapScopeEntity origEntity) {
if (origEntity == null) return null;
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return new MapScopeAdapter<K>(origEntity, authorizationProvider.getStoreFactory()) {
@Override
public String getId() {
return scopeStore.getKeyConvertor().keyToString(entity.getId());
}
};
return new MapScopeAdapter(origEntity, authorizationProvider.getStoreFactory());
}
private ModelCriteriaBuilder<Scope> forResourceServer(String resourceServerId) {
@ -87,8 +82,7 @@ public class MapScopeStore<K> implements ScopeStore {
throw new ModelDuplicateException("Scope with name '" + name + "' for " + resourceServer.getId() + " already exists");
}
K uid = id == null ? scopeStore.getKeyConvertor().yieldNewUniqueKey(): scopeStore.getKeyConvertor().fromString(id);
MapScopeEntity<K> entity = new MapScopeEntity<>(uid);
MapScopeEntity entity = new MapScopeEntity(id);
entity.setName(name);
entity.setResourceServerId(resourceServer.getId());
@ -101,7 +95,7 @@ public class MapScopeStore<K> implements ScopeStore {
@Override
public void delete(String id) {
LOG.tracef("delete(%s)%s", id, getShortStackTrace());
tx.delete(scopeStore.getKeyConvertor().fromString(id));
tx.delete(id);
}
@Override

View file

@ -24,7 +24,7 @@ import org.keycloak.models.map.common.AbstractEntity;
import java.util.Objects;
public abstract class AbstractPolicyModel<E extends AbstractEntity<?>> extends AbstractAuthorizationModel implements Policy {
public abstract class AbstractPolicyModel<E extends AbstractEntity> extends AbstractAuthorizationModel implements Policy {
protected final E entity;

View file

@ -24,7 +24,7 @@ import org.keycloak.models.map.common.AbstractEntity;
import java.util.Objects;
public abstract class AbstractResourceModel<E extends AbstractEntity<?>> extends AbstractAuthorizationModel implements Resource {
public abstract class AbstractResourceModel<E extends AbstractEntity> extends AbstractAuthorizationModel implements Resource {
protected final E entity;

View file

@ -28,12 +28,17 @@ import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.map.authorization.entity.MapPermissionTicketEntity;
import static org.keycloak.authorization.UserManagedPermissionUtil.updatePolicy;
public abstract class MapPermissionTicketAdapter<K extends Comparable<K>> extends AbstractPermissionTicketModel<MapPermissionTicketEntity<K>> {
public class MapPermissionTicketAdapter extends AbstractPermissionTicketModel<MapPermissionTicketEntity> {
public MapPermissionTicketAdapter(MapPermissionTicketEntity<K> entity, StoreFactory storeFactory) {
public MapPermissionTicketAdapter(MapPermissionTicketEntity entity, StoreFactory storeFactory) {
super(entity, storeFactory);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getOwner() {
return entity.getOwner();

View file

@ -30,12 +30,17 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public abstract class MapPolicyAdapter<K> extends AbstractPolicyModel<MapPolicyEntity<K>> {
public class MapPolicyAdapter<K> extends AbstractPolicyModel<MapPolicyEntity> {
public MapPolicyAdapter(MapPolicyEntity<K> entity, StoreFactory storeFactory) {
public MapPolicyAdapter(MapPolicyEntity entity, StoreFactory storeFactory) {
super(entity, storeFactory);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getType() {
return entity.getType();

View file

@ -28,12 +28,17 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public abstract class MapResourceAdapter<K> extends AbstractResourceModel<MapResourceEntity<K>> {
public class MapResourceAdapter extends AbstractResourceModel<MapResourceEntity> {
public MapResourceAdapter(MapResourceEntity<K> entity, StoreFactory storeFactory) {
public MapResourceAdapter(MapResourceEntity entity, StoreFactory storeFactory) {
super(entity, storeFactory);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getName() {
return entity.getName();

View file

@ -23,12 +23,17 @@ import org.keycloak.models.map.authorization.entity.MapResourceServerEntity;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
public abstract class MapResourceServerAdapter<K> extends AbstractResourceServerModel<MapResourceServerEntity<K>> {
public class MapResourceServerAdapter extends AbstractResourceServerModel<MapResourceServerEntity> {
public MapResourceServerAdapter(MapResourceServerEntity<K> entity, StoreFactory storeFactory) {
public MapResourceServerAdapter(MapResourceServerEntity entity, StoreFactory storeFactory) {
super(entity, storeFactory);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public boolean isAllowRemoteResourceManagement() {
return entity.isAllowRemoteResourceManagement();

View file

@ -22,12 +22,17 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.map.authorization.entity.MapScopeEntity;
public abstract class MapScopeAdapter<K> extends AbstractScopeModel<MapScopeEntity<K>> {
public class MapScopeAdapter extends AbstractScopeModel<MapScopeEntity> {
public MapScopeAdapter(MapScopeEntity<K> entity, StoreFactory storeFactory) {
public MapScopeAdapter(MapScopeEntity entity, StoreFactory storeFactory) {
super(entity, storeFactory);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getName() {
return entity.getName();

View file

@ -22,9 +22,9 @@ import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.UpdatableEntity;
import java.util.Objects;
public class MapPermissionTicketEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapPermissionTicketEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private String owner;
private String requester;
private Long createdTimestamp;
@ -35,7 +35,7 @@ public class MapPermissionTicketEntity<K> implements AbstractEntity<K>, Updatabl
private String policyId;
private boolean updated = false;
public MapPermissionTicketEntity(K id) {
public MapPermissionTicketEntity(String id) {
this.id = id;
}
@ -44,7 +44,7 @@ public class MapPermissionTicketEntity<K> implements AbstractEntity<K>, Updatabl
}
@Override
public K getId() {
public String getId() {
return id;
}

View file

@ -28,9 +28,9 @@ import java.util.Set;
import java.util.Map;
import java.util.Objects;
public class MapPolicyEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapPolicyEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private String name;
private String description;
private String type;
@ -44,7 +44,7 @@ public class MapPolicyEntity<K> implements AbstractEntity<K>, UpdatableEntity {
private String owner;
private boolean updated = false;
public MapPolicyEntity(K id) {
public MapPolicyEntity(String id) {
this.id = id;
}
@ -178,7 +178,7 @@ public class MapPolicyEntity<K> implements AbstractEntity<K>, UpdatableEntity {
}
@Override
public K getId() {
public String getId() {
return id;
}

View file

@ -27,9 +27,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class MapResourceEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapResourceEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private String name;
private String displayName;
private final Set<String> uris = new HashSet<>();
@ -43,7 +43,7 @@ public class MapResourceEntity<K> implements AbstractEntity<K>, UpdatableEntity
private final Map<String, List<String>> attributes = new HashMap<>();
private boolean updated = false;
public MapResourceEntity(K id) {
public MapResourceEntity(String id) {
this.id = id;
}
@ -52,7 +52,7 @@ public class MapResourceEntity<K> implements AbstractEntity<K>, UpdatableEntity
}
@Override
public K getId() {
public String getId() {
return id;
}

View file

@ -24,16 +24,16 @@ import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
import java.util.Objects;
public class MapResourceServerEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapResourceServerEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private boolean updated = false;
private boolean allowRemoteResourceManagement;
private PolicyEnforcementMode policyEnforcementMode = PolicyEnforcementMode.ENFORCING;
private DecisionStrategy decisionStrategy = DecisionStrategy.UNANIMOUS;
public MapResourceServerEntity(K id) {
public MapResourceServerEntity(String id) {
this.id = id;
}
@ -42,7 +42,7 @@ public class MapResourceServerEntity<K> implements AbstractEntity<K>, UpdatableE
}
@Override
public K getId() {
public String getId() {
return id;
}

View file

@ -22,16 +22,16 @@ import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.UpdatableEntity;
import java.util.Objects;
public class MapScopeEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapScopeEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private String name;
private String displayName;
private String iconUri;
private String resourceServerId;
private boolean updated = false;
public MapScopeEntity(K id) {
public MapScopeEntity(String id) {
this.id = id;
}
@ -40,7 +40,7 @@ public class MapScopeEntity<K> implements AbstractEntity<K>, UpdatableEntity {
}
@Override
public K getId() {
public String getId() {
return id;
}

View file

@ -36,12 +36,17 @@ import java.util.stream.Stream;
*
* @author hmlnarik
*/
public abstract class MapClientAdapter<K> extends AbstractClientModel<MapClientEntity<K>> implements ClientModel {
public abstract class MapClientAdapter extends AbstractClientModel<MapClientEntity> implements ClientModel {
public MapClientAdapter(KeycloakSession session, RealmModel realm, MapClientEntity<K> entity) {
public MapClientAdapter(KeycloakSession session, RealmModel realm, MapClientEntity entity) {
super(session, realm, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getClientId() {
return entity.getClientId();

View file

@ -29,7 +29,7 @@ import java.util.stream.Stream;
*
* @author hmlnarik
*/
public interface MapClientEntity<K> extends AbstractEntity<K>, UpdatableEntity {
public interface MapClientEntity extends AbstractEntity, UpdatableEntity {
void addClientScope(String id, Boolean defaultScope);

View file

@ -22,15 +22,15 @@ package org.keycloak.models.map.client;
*/
public class MapClientEntityDelegate<K> extends MapClientEntityLazyDelegate<K> {
private final MapClientEntity<K> delegate;
private final MapClientEntity delegate;
public MapClientEntityDelegate(MapClientEntity<K> delegate) {
public MapClientEntityDelegate(MapClientEntity delegate) {
super(null);
this.delegate = delegate;
}
@Override
protected MapClientEntity<K> getDelegate() {
protected MapClientEntity getDelegate() {
return delegate;
}
}

View file

@ -36,9 +36,9 @@ import java.util.stream.Stream;
*
* @author hmlnarik
*/
public class MapClientEntityImpl<K> implements MapClientEntity<K> {
public class MapClientEntityImpl<K> implements MapClientEntity {
private K id;
private String id;
private String realmId;
private String clientId;
@ -84,8 +84,7 @@ public class MapClientEntityImpl<K> implements MapClientEntity<K> {
this.realmId = null;
}
public MapClientEntityImpl(K id, String realmId) {
Objects.requireNonNull(id, "id");
public MapClientEntityImpl(String id, String realmId) {
Objects.requireNonNull(realmId, "realmId");
this.id = id;
@ -93,7 +92,7 @@ public class MapClientEntityImpl<K> implements MapClientEntity<K> {
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -29,21 +29,21 @@ import java.util.stream.Stream;
*
* @author hmlnarik
*/
public class MapClientEntityLazyDelegate<K> implements MapClientEntity<K> {
public class MapClientEntityLazyDelegate<K> implements MapClientEntity {
private final Supplier<MapClientEntity<K>> delegateSupplier;
private final Supplier<MapClientEntity> delegateSupplier;
private final AtomicMarkableReference<MapClientEntity<K>> delegate = new AtomicMarkableReference<>(null, false);
private final AtomicMarkableReference<MapClientEntity> delegate = new AtomicMarkableReference<>(null, false);
public MapClientEntityLazyDelegate(Supplier<MapClientEntity<K>> delegateSupplier) {
public MapClientEntityLazyDelegate(Supplier<MapClientEntity> delegateSupplier) {
this.delegateSupplier = delegateSupplier;
}
protected MapClientEntity<K> getDelegate() {
protected MapClientEntity getDelegate() {
if (! delegate.isMarked()) {
delegate.compareAndSet(null, delegateSupplier == null ? null : delegateSupplier.get(), false, true);
}
MapClientEntity<K> ref = delegate.getReference();
MapClientEntity ref = delegate.getReference();
if (ref == null) {
throw new IllegalStateException("Invalid delegate obtained");
}
@ -456,7 +456,7 @@ public class MapClientEntityLazyDelegate<K> implements MapClientEntity<K> {
}
@Override
public K getId() {
public String getId() {
return getDelegate().getId();
}

View file

@ -54,11 +54,11 @@ public class MapClientProvider<K> implements ClientProvider {
private static final Logger LOG = Logger.getLogger(MapClientProvider.class);
private final KeycloakSession session;
final MapKeycloakTransaction<K, MapClientEntity<K>, ClientModel> tx;
private final MapStorage<K, MapClientEntity<K>, ClientModel> clientStore;
private final ConcurrentMap<K, ConcurrentMap<String, Integer>> clientRegisteredNodesStore;
final MapKeycloakTransaction<K, MapClientEntity, ClientModel> tx;
private final MapStorage<K, MapClientEntity, ClientModel> clientStore;
private final ConcurrentMap<String, ConcurrentMap<String, Integer>> clientRegisteredNodesStore;
public MapClientProvider(KeycloakSession session, MapStorage<K, MapClientEntity<K>, ClientModel> clientStore, ConcurrentMap<K, ConcurrentMap<String, Integer>> clientRegisteredNodesStore) {
public MapClientProvider(KeycloakSession session, MapStorage<K, MapClientEntity, ClientModel> clientStore, ConcurrentMap<String, ConcurrentMap<String, Integer>> clientRegisteredNodesStore) {
this.session = session;
this.clientStore = clientStore;
this.clientRegisteredNodesStore = clientRegisteredNodesStore;
@ -80,15 +80,10 @@ public class MapClientProvider<K> implements ClientProvider {
};
}
private <T extends MapClientEntity<K>> Function<T, ClientModel> entityToAdapterFunc(RealmModel realm) {
private <T extends MapClientEntity> Function<T, ClientModel> entityToAdapterFunc(RealmModel realm) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return origEntity -> new MapClientAdapter<K>(session, realm, origEntity) {
@Override
public String getId() {
return clientStore.getKeyConvertor().keyToString(entity.getId());
}
return origEntity -> new MapClientAdapter(session, realm, origEntity) {
@Override
public void updateClient() {
LOG.tracef("updateClient(%s)%s", realm, origEntity.getId(), getShortStackTrace());
@ -115,7 +110,7 @@ public class MapClientProvider<K> implements ClientProvider {
};
}
private Predicate<MapClientEntity<K>> entityRealmFilter(RealmModel realm) {
private Predicate<MapClientEntity> entityRealmFilter(RealmModel realm) {
if (realm == null || realm.getId() == null) {
return c -> false;
}
@ -143,22 +138,22 @@ public class MapClientProvider<K> implements ClientProvider {
@Override
public ClientModel addClient(RealmModel realm, String id, String clientId) {
final K entityId = id == null ? clientStore.getKeyConvertor().yieldNewUniqueKey() : clientStore.getKeyConvertor().fromString(id);
if (clientId == null) {
clientId = entityId.toString();
}
LOG.tracef("addClient(%s, %s, %s)%s", realm, id, clientId, getShortStackTrace());
MapClientEntity<K> entity = new MapClientEntityImpl<>(entityId, realm.getId());
entity.setClientId(clientId);
MapClientEntity entity = new MapClientEntityImpl<>(null, realm.getId());
if (clientId != null) {
entity.setClientId(clientId);
}
entity.setEnabled(true);
entity.setStandardFlowEnabled(true);
if (tx.read(entity.getId()) != null) {
if (id != null && tx.read(id) != null) {
throw new ModelDuplicateException("Client exists: " + id);
}
entity = tx.create(entity);
if (clientId == null) {
clientId = entity.getId();
entity.setClientId(clientId);
}
final ClientModel resource = entityToAdapterFunc(realm).apply(entity);
// TODO: Sending an event should be extracted to store layer
@ -211,7 +206,7 @@ public class MapClientProvider<K> implements ClientProvider {
});
// TODO: ^^^^^^^ Up to here
tx.delete(clientStore.getKeyConvertor().fromString(id));
tx.delete(id);
return true;
}
@ -232,7 +227,7 @@ public class MapClientProvider<K> implements ClientProvider {
LOG.tracef("getClientById(%s, %s)%s", realm, id, getShortStackTrace());
MapClientEntity<K> entity = tx.read(clientStore.getKeyConvertor().fromStringSafe(id));
MapClientEntity entity = tx.read(id);
return (entity == null || ! entityRealmFilter(realm).test(entity))
? null
: entityToAdapterFunc(realm).apply(entity);
@ -286,7 +281,7 @@ public class MapClientProvider<K> implements ClientProvider {
@Override
public void addClientScopes(RealmModel realm, ClientModel client, Set<ClientScopeModel> clientScopes, boolean defaultScope) {
final String id = client.getId();
MapClientEntity<K> entity = tx.read(clientStore.getKeyConvertor().fromString(id));
MapClientEntity entity = tx.read(id);
if (entity == null) return;
@ -307,7 +302,7 @@ public class MapClientProvider<K> implements ClientProvider {
@Override
public void removeClientScope(RealmModel realm, ClientModel client, ClientScopeModel clientScope) {
final String id = client.getId();
MapClientEntity<K> entity = tx.read(clientStore.getKeyConvertor().fromString(id));
MapClientEntity entity = tx.read(id);
if (entity == null) return;
@ -319,7 +314,7 @@ public class MapClientProvider<K> implements ClientProvider {
@Override
public Map<String, ClientScopeModel> getClientScopes(RealmModel realm, ClientModel client, boolean defaultScopes) {
final String id = client.getId();
MapClientEntity<K> entity = tx.read(clientStore.getKeyConvertor().fromString(id));
MapClientEntity entity = tx.read(id);
if (entity == null) return null;
@ -341,7 +336,7 @@ public class MapClientProvider<K> implements ClientProvider {
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.ENABLED, Operator.EQ, Boolean.TRUE);
try (Stream<MapClientEntity<K>> st = tx.read(withCriteria(mcb))) {
try (Stream<MapClientEntity> st = tx.read(withCriteria(mcb))) {
return st
.filter(mce -> mce.getRedirectUris() != null && ! mce.getRedirectUris().isEmpty())
.collect(Collectors.toMap(
@ -355,7 +350,7 @@ public class MapClientProvider<K> implements ClientProvider {
ModelCriteriaBuilder<ClientModel> mcb = clientStore.createCriteriaBuilder()
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.SCOPE_MAPPING_ROLE, Operator.EQ, role.getId());
try (Stream<MapClientEntity<K>> toRemove = tx.read(withCriteria(mcb))) {
try (Stream<MapClientEntity> toRemove = tx.read(withCriteria(mcb))) {
toRemove
.map(clientEntity -> session.clients().getClientById(realm, clientEntity.getId().toString()))
.filter(Objects::nonNull)

View file

@ -35,9 +35,9 @@ import java.util.concurrent.ConcurrentMap;
*
* @author hmlnarik
*/
public class MapClientProviderFactory<K> extends AbstractMapProviderFactory<ClientProvider, K, MapClientEntity<K>, ClientModel> implements ClientProviderFactory, ProviderEventListener {
public class MapClientProviderFactory<K> extends AbstractMapProviderFactory<ClientProvider, K, MapClientEntity, ClientModel> implements ClientProviderFactory, ProviderEventListener {
private final ConcurrentHashMap<K, ConcurrentMap<String, Integer>> REGISTERED_NODES_STORE = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, ConcurrentMap<String, Integer>> REGISTERED_NODES_STORE = new ConcurrentHashMap<>();
private Runnable onClose;

View file

@ -31,12 +31,17 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RoleUtils;
public abstract class MapClientScopeAdapter<K> extends AbstractClientScopeModel<MapClientScopeEntity<K>> implements ClientScopeModel {
public class MapClientScopeAdapter extends AbstractClientScopeModel<MapClientScopeEntity> implements ClientScopeModel {
public MapClientScopeAdapter(KeycloakSession session, RealmModel realm, MapClientScopeEntity<K> entity) {
public MapClientScopeAdapter(KeycloakSession session, RealmModel realm, MapClientScopeEntity entity) {
super(session, realm, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getName() {
return entity.getName();

View file

@ -31,9 +31,9 @@ import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.UpdatableEntity;
public class MapClientScopeEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapClientScopeEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private final String realmId;
private String name;
@ -54,8 +54,7 @@ public class MapClientScopeEntity<K> implements AbstractEntity<K>, UpdatableEnti
this.realmId = null;
}
public MapClientScopeEntity(K id, String realmId) {
Objects.requireNonNull(id, "id");
public MapClientScopeEntity(String id, String realmId) {
Objects.requireNonNull(realmId, "realmId");
this.id = id;
@ -63,7 +62,7 @@ public class MapClientScopeEntity<K> implements AbstractEntity<K>, UpdatableEnti
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -43,28 +43,23 @@ public class MapClientScopeProvider<K> implements ClientScopeProvider {
private static final Logger LOG = Logger.getLogger(MapClientScopeProvider.class);
private final KeycloakSession session;
private final MapKeycloakTransaction<K, MapClientScopeEntity<K>, ClientScopeModel> tx;
private final MapStorage<K, MapClientScopeEntity<K>, ClientScopeModel> clientScopeStore;
private final MapKeycloakTransaction<K, MapClientScopeEntity, ClientScopeModel> tx;
private final MapStorage<K, MapClientScopeEntity, ClientScopeModel> clientScopeStore;
public MapClientScopeProvider(KeycloakSession session, MapStorage<K, MapClientScopeEntity<K>, ClientScopeModel> clientScopeStore) {
public MapClientScopeProvider(KeycloakSession session, MapStorage<K, MapClientScopeEntity, ClientScopeModel> clientScopeStore) {
this.session = session;
this.clientScopeStore = clientScopeStore;
this.tx = clientScopeStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
private Function<MapClientScopeEntity<K>, ClientScopeModel> entityToAdapterFunc(RealmModel realm) {
private Function<MapClientScopeEntity, ClientScopeModel> entityToAdapterFunc(RealmModel realm) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return origEntity -> new MapClientScopeAdapter<K>(session, realm, origEntity) {
@Override
public String getId() {
return clientScopeStore.getKeyConvertor().keyToString(entity.getId());
}
};
return origEntity -> new MapClientScopeAdapter(session, realm, origEntity);
}
private Predicate<MapClientScopeEntity<K>> entityRealmFilter(RealmModel realm) {
private Predicate<MapClientScopeEntity> entityRealmFilter(RealmModel realm) {
if (realm == null || realm.getId() == null) {
return c -> false;
}
@ -92,13 +87,11 @@ public class MapClientScopeProvider<K> implements ClientScopeProvider {
throw new ModelDuplicateException("Client scope with name '" + name + "' in realm " + realm.getName());
}
final K entityId = id == null ? clientScopeStore.getKeyConvertor().yieldNewUniqueKey() : clientScopeStore.getKeyConvertor().fromString(id);
LOG.tracef("addClientScope(%s, %s, %s)%s", realm, id, name, getShortStackTrace());
MapClientScopeEntity<K> entity = new MapClientScopeEntity<>(entityId, realm.getId());
MapClientScopeEntity entity = new MapClientScopeEntity(id, realm.getId());
entity.setName(KeycloakModelUtils.convertClientScopeName(name));
if (tx.read(entity.getId()) != null) {
if (tx.read(id) != null) {
throw new ModelDuplicateException("Client scope exists: " + id);
}
entity = tx.create(entity);
@ -127,7 +120,7 @@ public class MapClientScopeProvider<K> implements ClientScopeProvider {
}
});
tx.delete(clientScopeStore.getKeyConvertor().fromString(id));
tx.delete(id);
return true;
}
@ -149,14 +142,7 @@ public class MapClientScopeProvider<K> implements ClientScopeProvider {
LOG.tracef("getClientScopeById(%s, %s)%s", realm, id, getShortStackTrace());
K uuid;
try {
uuid = clientScopeStore.getKeyConvertor().fromStringSafe(id);
} catch (IllegalArgumentException ex) {
return null;
}
MapClientScopeEntity<K> entity = tx.read(uuid);
MapClientScopeEntity entity = tx.read(id);
return (entity == null || ! entityRealmFilter(realm).test(entity))
? null
: entityToAdapterFunc(realm).apply(entity);

View file

@ -22,7 +22,7 @@ import org.keycloak.models.ClientScopeProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.map.common.AbstractMapProviderFactory;
public class MapClientScopeProviderFactory<K> extends AbstractMapProviderFactory<ClientScopeProvider, K, MapClientScopeEntity<K>, ClientScopeModel> implements ClientScopeProviderFactory {
public class MapClientScopeProviderFactory<K> extends AbstractMapProviderFactory<ClientScopeProvider, K, MapClientScopeEntity, ClientScopeModel> implements ClientScopeProviderFactory {
public MapClientScopeProviderFactory() {
super(ClientScopeModel.class);

View file

@ -20,8 +20,8 @@ package org.keycloak.models.map.common;
*
* @author hmlnarik
*/
public interface AbstractEntity<K> {
public interface AbstractEntity {
K getId();
String getId();
}

View file

@ -34,7 +34,7 @@ import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory;
*
* @author hmlnarik
*/
public abstract class AbstractMapProviderFactory<T extends Provider, K, V extends AbstractEntity<K>, M> implements AmphibianProviderFactory<T>, EnvironmentDependentProviderFactory {
public abstract class AbstractMapProviderFactory<T extends Provider, K, V extends AbstractEntity, M> implements AmphibianProviderFactory<T>, EnvironmentDependentProviderFactory {
public static final String PROVIDER_ID = "map";

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.models.map.common;
import org.keycloak.common.util.reflections.Reflections;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -32,7 +33,10 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.jdk8.StreamSerializer;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
/**
@ -47,15 +51,19 @@ public class Serialization {
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.setVisibility(PropertyAccessor.ALL, Visibility.NONE)
.setVisibility(PropertyAccessor.FIELD, Visibility.ANY)
.addMixIn(UpdatableEntity.class, IgnoreUpdatedMixIn.class);
.addMixIn(UpdatableEntity.class, IgnoreUpdatedMixIn.class)
.addMixIn(AbstractEntity.class, AbstractEntityMixIn.class)
;
public static final ConcurrentHashMap<Class<?>, ObjectReader> READERS = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<Class<?>, ObjectWriter> WRITERS = new ConcurrentHashMap<>();
abstract class IgnoreUpdatedMixIn {
@JsonIgnore public abstract boolean isUpdated();
@JsonTypeInfo(use=Id.CLASS, include=As.WRAPPER_ARRAY)
}
abstract class AbstractEntityMixIn {
@JsonTypeInfo(property="id", use=Id.CLASS, include=As.WRAPPER_ARRAY)
abstract Object getId();
}
@ -68,6 +76,10 @@ public class Serialization {
public static <T extends AbstractEntity> T from(T orig) {
return from(orig, null);
}
public static <T extends AbstractEntity> T from(T orig, String newId) {
if (orig == null) {
return null;
}
@ -78,11 +90,28 @@ public class Serialization {
try {
ObjectReader reader = READERS.computeIfAbsent(origClass, MAPPER::readerFor);
ObjectWriter writer = WRITERS.computeIfAbsent(origClass, MAPPER::writerFor);
final T res = reader.readValue(writer.writeValueAsBytes(orig));
final T res;
res = reader.readValue(writer.writeValueAsBytes(orig));
if (newId != null) {
updateId(origClass, res, newId);
}
return res;
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
private static <K> void updateId(Class<?> origClass, AbstractEntity res, K newId) {
Field field = Reflections.findDeclaredField(origClass, "id");
if (field == null) {
throw new IllegalArgumentException("Cannot find id for " + origClass + " class");
}
try {
Reflections.setAccessible(field).set(res, newId);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(Serialization.class.getName()).log(Level.SEVERE, null, ex);
throw new IllegalArgumentException("Cannot set id for " + origClass + " class");
}
}
}

View file

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.map.storage;
package org.keycloak.models.map.common;
import java.security.SecureRandom;
import java.util.UUID;

View file

@ -29,11 +29,16 @@ import java.util.Map;
import java.util.stream.Stream;
public abstract class MapGroupAdapter<K> extends AbstractGroupModel<MapGroupEntity<K>> {
public MapGroupAdapter(KeycloakSession session, RealmModel realm, MapGroupEntity<K> entity) {
public class MapGroupAdapter extends AbstractGroupModel<MapGroupEntity> {
public MapGroupAdapter(KeycloakSession session, RealmModel realm, MapGroupEntity entity) {
super(session, realm, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getName() {
return entity.getName();

View file

@ -31,9 +31,9 @@ import java.util.Set;
*
* @author mhajas
*/
public class MapGroupEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapGroupEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private final String realmId;
private String name;
@ -51,8 +51,7 @@ public class MapGroupEntity<K> implements AbstractEntity<K>, UpdatableEntity {
this.realmId = null;
}
public MapGroupEntity(K id, String realmId) {
Objects.requireNonNull(id, "id");
public MapGroupEntity(String id, String realmId) {
Objects.requireNonNull(realmId, "realmId");
this.id = id;
@ -60,7 +59,7 @@ public class MapGroupEntity<K> implements AbstractEntity<K>, UpdatableEntity {
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -46,24 +46,19 @@ public class MapGroupProvider<K> implements GroupProvider {
private static final Logger LOG = Logger.getLogger(MapGroupProvider.class);
private final KeycloakSession session;
final MapKeycloakTransaction<K, MapGroupEntity<K>, GroupModel> tx;
private final MapStorage<K, MapGroupEntity<K>, GroupModel> groupStore;
final MapKeycloakTransaction<K, MapGroupEntity, GroupModel> tx;
private final MapStorage<K, MapGroupEntity, GroupModel> groupStore;
public MapGroupProvider(KeycloakSession session, MapStorage<K, MapGroupEntity<K>, GroupModel> groupStore) {
public MapGroupProvider(KeycloakSession session, MapStorage<K, MapGroupEntity, GroupModel> groupStore) {
this.session = session;
this.groupStore = groupStore;
this.tx = groupStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
private Function<MapGroupEntity<K>, GroupModel> entityToAdapterFunc(RealmModel realm) {
private Function<MapGroupEntity, GroupModel> entityToAdapterFunc(RealmModel realm) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return origEntity -> new MapGroupAdapter<K>(session, realm, origEntity) {
@Override
public String getId() {
return groupStore.getKeyConvertor().keyToString(entity.getId());
}
};
return origEntity -> new MapGroupAdapter(session, realm, origEntity);
}
@Override
@ -74,14 +69,7 @@ public class MapGroupProvider<K> implements GroupProvider {
LOG.tracef("getGroupById(%s, %s)%s", realm, id, getShortStackTrace());
K uid;
try {
uid = groupStore.getKeyConvertor().fromStringSafe(id);
} catch (IllegalArgumentException ex) {
return null;
}
MapGroupEntity<K> entity = tx.read(uid);
MapGroupEntity entity = tx.read(id);
String realmId = realm.getId();
return (entity == null || ! Objects.equals(realmId, entity.getRealmId()))
? null
@ -115,7 +103,7 @@ public class MapGroupProvider<K> implements GroupProvider {
@Override
public Stream<GroupModel> getGroupsStream(RealmModel realm, Stream<String> ids, String search, Integer first, Integer max) {
ModelCriteriaBuilder<GroupModel> mcb = groupStore.createCriteriaBuilder()
.compare(SearchableFields.ID, Operator.IN, ids.map(groupStore.getKeyConvertor()::fromString))
.compare(SearchableFields.ID, Operator.IN, ids)
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
if (search != null) {
@ -187,7 +175,6 @@ public class MapGroupProvider<K> implements GroupProvider {
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.NAME))
.map(MapGroupEntity::getId)
.map(groupStore.getKeyConvertor()::keyToString)
.map(id -> {
GroupModel groupById = session.groups().getGroupById(realm, id);
while (Objects.nonNull(groupById.getParentId())) {
@ -200,8 +187,6 @@ public class MapGroupProvider<K> implements GroupProvider {
@Override
public GroupModel createGroup(RealmModel realm, String id, String name, GroupModel toParent) {
LOG.tracef("createGroup(%s, %s, %s, %s)%s", realm, id, name, toParent, getShortStackTrace());
final K entityId = id == null ? groupStore.getKeyConvertor().yieldNewUniqueKey() : groupStore.getKeyConvertor().fromString(id);
// Check Db constraint: uniqueConstraints = { @UniqueConstraint(columnNames = {"REALM_ID", "PARENT_GROUP", "NAME"})}
String parentId = toParent == null ? null : toParent.getId();
ModelCriteriaBuilder<GroupModel> mcb = groupStore.createCriteriaBuilder()
@ -213,11 +198,11 @@ public class MapGroupProvider<K> implements GroupProvider {
throw new ModelDuplicateException("Group with name '" + name + "' in realm " + realm.getName() + " already exists for requested parent" );
}
MapGroupEntity<K> entity = new MapGroupEntity<K>(entityId, realm.getId());
MapGroupEntity entity = new MapGroupEntity(id, realm.getId());
entity.setName(name);
entity.setParentId(toParent == null ? null : toParent.getId());
if (tx.read(entity.getId()) != null) {
throw new ModelDuplicateException("Group exists: " + entityId);
if (id != null && tx.read(id) != null) {
throw new ModelDuplicateException("Group exists: " + id);
}
entity = tx.create(entity);
@ -255,7 +240,7 @@ public class MapGroupProvider<K> implements GroupProvider {
// TODO: ^^^^^^^ Up to here
tx.delete(groupStore.getKeyConvertor().fromString(group.getId()));
tx.delete(group.getId());
return true;
}
@ -276,7 +261,7 @@ public class MapGroupProvider<K> implements GroupProvider {
.compare(SearchableFields.PARENT_ID, Operator.EQ, parentId)
.compare(SearchableFields.NAME, Operator.EQ, group.getName());
try (Stream<MapGroupEntity<K>> possibleSiblings = tx.read(withCriteria(mcb))) {
try (Stream<MapGroupEntity> possibleSiblings = tx.read(withCriteria(mcb))) {
if (possibleSiblings.findAny().isPresent()) {
throw new ModelDuplicateException("Parent already contains subgroup named '" + group.getName() + "'");
}
@ -298,7 +283,7 @@ public class MapGroupProvider<K> implements GroupProvider {
.compare(SearchableFields.PARENT_ID, Operator.EQ, (Object) null)
.compare(SearchableFields.NAME, Operator.EQ, subGroup.getName());
try (Stream<MapGroupEntity<K>> possibleSiblings = tx.read(withCriteria(mcb))) {
try (Stream<MapGroupEntity> possibleSiblings = tx.read(withCriteria(mcb))) {
if (possibleSiblings.findAny().isPresent()) {
throw new ModelDuplicateException("There is already a top level group named '" + subGroup.getName() + "'");
}
@ -312,9 +297,9 @@ public class MapGroupProvider<K> implements GroupProvider {
ModelCriteriaBuilder<GroupModel> mcb = groupStore.createCriteriaBuilder()
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.ASSIGNED_ROLE, Operator.EQ, role.getId());
try (Stream<MapGroupEntity<K>> toRemove = tx.read(withCriteria(mcb))) {
try (Stream<MapGroupEntity> toRemove = tx.read(withCriteria(mcb))) {
toRemove
.map(groupEntity -> session.groups().getGroupById(realm, groupEntity.getId().toString()))
.map(groupEntity -> session.groups().getGroupById(realm, groupEntity.getId()))
.forEach(groupModel -> groupModel.deleteRoleMapping(role));
}
}

View file

@ -35,7 +35,7 @@ import org.keycloak.models.map.common.AbstractMapProviderFactory;
*
* @author mhajas
*/
public class MapGroupProviderFactory<K> extends AbstractMapProviderFactory<GroupProvider, K, MapGroupEntity<K>, GroupModel> implements GroupProviderFactory, ProviderEventListener {
public class MapGroupProviderFactory<K> extends AbstractMapProviderFactory<GroupProvider, K, MapGroupEntity, GroupModel> implements GroupProviderFactory, ProviderEventListener {
private Runnable onClose;

View file

@ -22,11 +22,16 @@ import org.keycloak.models.RealmModel;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public abstract class MapUserLoginFailureAdapter<K> extends AbstractUserLoginFailureModel<MapUserLoginFailureEntity<K>> {
public MapUserLoginFailureAdapter(KeycloakSession session, RealmModel realm, MapUserLoginFailureEntity<K> entity) {
public class MapUserLoginFailureAdapter extends AbstractUserLoginFailureModel<MapUserLoginFailureEntity> {
public MapUserLoginFailureAdapter(KeycloakSession session, RealmModel realm, MapUserLoginFailureEntity entity) {
super(session, realm, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getUserId() {
return entity.getUserId();

View file

@ -24,8 +24,8 @@ import java.util.Objects;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public class MapUserLoginFailureEntity<K> implements AbstractEntity<K>, UpdatableEntity {
private K id;
public class MapUserLoginFailureEntity implements AbstractEntity, UpdatableEntity {
private String id;
private String realmId;
private String userId;
@ -45,14 +45,14 @@ public class MapUserLoginFailureEntity<K> implements AbstractEntity<K>, Updatabl
this.userId = null;
}
public MapUserLoginFailureEntity(K id, String realmId, String userId) {
public MapUserLoginFailureEntity(String id, String realmId, String userId) {
this.id = id;
this.realmId = realmId;
this.userId = userId;
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -37,10 +37,10 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
private static final Logger LOG = Logger.getLogger(MapUserLoginFailureProvider.class);
private final KeycloakSession session;
protected final MapKeycloakTransaction<K, MapUserLoginFailureEntity<K>, UserLoginFailureModel> userLoginFailureTx;
private final MapStorage<K, MapUserLoginFailureEntity<K>, UserLoginFailureModel> userLoginFailureStore;
protected final MapKeycloakTransaction<K, MapUserLoginFailureEntity, UserLoginFailureModel> userLoginFailureTx;
private final MapStorage<K, MapUserLoginFailureEntity, UserLoginFailureModel> userLoginFailureStore;
public MapUserLoginFailureProvider(KeycloakSession session, MapStorage<K, MapUserLoginFailureEntity<K>, UserLoginFailureModel> userLoginFailureStore) {
public MapUserLoginFailureProvider(KeycloakSession session, MapStorage<K, MapUserLoginFailureEntity, UserLoginFailureModel> userLoginFailureStore) {
this.session = session;
this.userLoginFailureStore = userLoginFailureStore;
@ -48,14 +48,9 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
session.getTransactionManager().enlistAfterCompletion(userLoginFailureTx);
}
private Function<MapUserLoginFailureEntity<K>, UserLoginFailureModel> userLoginFailureEntityToAdapterFunc(RealmModel realm) {
private Function<MapUserLoginFailureEntity, UserLoginFailureModel> userLoginFailureEntityToAdapterFunc(RealmModel realm) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return origEntity -> new MapUserLoginFailureAdapter<K>(session, realm, origEntity) {
@Override
public String getId() {
return userLoginFailureStore.getKeyConvertor().keyToString(entity.getId());
}
};
return origEntity -> new MapUserLoginFailureAdapter(session, realm, origEntity);
}
@Override
@ -80,10 +75,10 @@ public class MapUserLoginFailureProvider<K> implements UserLoginFailureProvider
LOG.tracef("addUserLoginFailure(%s, %s)%s", realm, userId, getShortStackTrace());
MapUserLoginFailureEntity<K> userLoginFailureEntity = userLoginFailureTx.read(withCriteria(mcb)).findFirst().orElse(null);
MapUserLoginFailureEntity userLoginFailureEntity = userLoginFailureTx.read(withCriteria(mcb)).findFirst().orElse(null);
if (userLoginFailureEntity == null) {
userLoginFailureEntity = new MapUserLoginFailureEntity<>(userLoginFailureStore.getKeyConvertor().yieldNewUniqueKey(), realm.getId(), userId);
userLoginFailureEntity = new MapUserLoginFailureEntity(null, realm.getId(), userId);
userLoginFailureEntity = userLoginFailureTx.create(userLoginFailureEntity);
}

View file

@ -31,7 +31,7 @@ import org.keycloak.provider.ProviderEventListener;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public class MapUserLoginFailureProviderFactory<K> extends AbstractMapProviderFactory<UserLoginFailureProvider, K, MapUserLoginFailureEntity<K>, UserLoginFailureModel>
public class MapUserLoginFailureProviderFactory<K> extends AbstractMapProviderFactory<UserLoginFailureProvider, K, MapUserLoginFailureEntity, UserLoginFailureModel>
implements UserLoginFailureProviderFactory, ProviderEventListener {
private Runnable onClose;

View file

@ -62,7 +62,7 @@ import org.keycloak.models.map.realm.entity.MapRequiredCredentialEntity;
import org.keycloak.models.map.realm.entity.MapWebAuthnPolicyEntity;
import org.keycloak.models.utils.ComponentUtil;
public abstract class MapRealmAdapter<K> extends AbstractRealmModel<MapRealmEntity<K>> implements RealmModel {
public class MapRealmAdapter extends AbstractRealmModel<MapRealmEntity> implements RealmModel {
private static final String ACTION_TOKEN_GENERATED_BY_USER_LIFESPAN = "actionTokenGeneratedByUserLifespan";
private static final String DEFAULT_SIGNATURE_ALGORITHM = "defaultSignatureAlgorithm";
@ -77,10 +77,15 @@ public abstract class MapRealmAdapter<K> extends AbstractRealmModel<MapRealmEnti
private PasswordPolicy passwordPolicy;
public MapRealmAdapter(KeycloakSession session, MapRealmEntity<K> entity) {
public MapRealmAdapter(KeycloakSession session, MapRealmEntity entity) {
super(session, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getName() {
return entity.getName();

View file

@ -43,9 +43,9 @@ import org.keycloak.models.map.realm.entity.MapRequiredActionProviderEntity;
import org.keycloak.models.map.realm.entity.MapRequiredCredentialEntity;
import org.keycloak.models.map.realm.entity.MapWebAuthnPolicyEntity;
public class MapRealmEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapRealmEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private String name;
private Boolean enabled = false;
@ -134,14 +134,12 @@ public class MapRealmEntity<K> implements AbstractEntity<K>, UpdatableEntity {
this.id = null;
}
public MapRealmEntity(K id) {
Objects.requireNonNull(id, "id");
public MapRealmEntity(String id) {
this.id = id;
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -44,23 +44,18 @@ public class MapRealmProvider<K> implements RealmProvider {
private static final Logger LOG = Logger.getLogger(MapRealmProvider.class);
private final KeycloakSession session;
final MapKeycloakTransaction<K, MapRealmEntity<K>, RealmModel> tx;
private final MapStorage<K, MapRealmEntity<K>, RealmModel> realmStore;
final MapKeycloakTransaction<K, MapRealmEntity, RealmModel> tx;
private final MapStorage<K, MapRealmEntity, RealmModel> realmStore;
public MapRealmProvider(KeycloakSession session, MapStorage<K, MapRealmEntity<K>, RealmModel> realmStore) {
public MapRealmProvider(KeycloakSession session, MapStorage<K, MapRealmEntity, RealmModel> realmStore) {
this.session = session;
this.realmStore = realmStore;
this.tx = realmStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
private RealmModel entityToAdapter(MapRealmEntity<K> entity) {
return new MapRealmAdapter<K>(session, entity) {
@Override
public String getId() {
return realmStore.getKeyConvertor().keyToString(entity.getId());
}
};
private RealmModel entityToAdapter(MapRealmEntity entity) {
return new MapRealmAdapter(session, entity);
}
@Override
@ -74,18 +69,13 @@ public class MapRealmProvider<K> implements RealmProvider {
throw new ModelDuplicateException("Realm with given name exists: " + name);
}
K kId = id == null ? null : realmStore.getKeyConvertor().fromString(id);
if (kId != null) {
if (tx.read(kId) != null) {
throw new ModelDuplicateException("Realm exists: " + kId);
}
} else {
kId = realmStore.getKeyConvertor().yieldNewUniqueKey();
if (id != null && tx.read(id) != null) {
throw new ModelDuplicateException("Realm exists: " + id);
}
LOG.tracef("createRealm(%s, %s)%s", kId, name, getShortStackTrace());
LOG.tracef("createRealm(%s, %s)%s", id, name, getShortStackTrace());
MapRealmEntity<K> entity = new MapRealmEntity<>(kId);
MapRealmEntity entity = new MapRealmEntity(id);
entity.setName(name);
entity = tx.create(entity);
@ -98,7 +88,7 @@ public class MapRealmProvider<K> implements RealmProvider {
LOG.tracef("getRealm(%s)%s", id, getShortStackTrace());
MapRealmEntity<K> entity = tx.read(realmStore.getKeyConvertor().fromStringSafe(id));
MapRealmEntity entity = tx.read(id);
return entity == null ? null : entityToAdapter(entity);
}
@ -111,12 +101,12 @@ public class MapRealmProvider<K> implements RealmProvider {
ModelCriteriaBuilder<RealmModel> mcb = realmStore.createCriteriaBuilder()
.compare(SearchableFields.NAME, Operator.EQ, name);
K realmId = tx.read(withCriteria(mcb))
String realmId = tx.read(withCriteria(mcb))
.findFirst()
.map(MapRealmEntity<K>::getId)
.map(MapRealmEntity::getId)
.orElse(null);
//we need to go via session.realms() not to bypass cache
return realmId == null ? null : session.realms().getRealm(realmStore.getKeyConvertor().keyToString(realmId));
return realmId == null ? null : session.realms().getRealm(realmId);
}
@Override
@ -165,7 +155,7 @@ public class MapRealmProvider<K> implements RealmProvider {
});
// TODO: ^^^^^^^ Up to here
tx.delete(realmStore.getKeyConvertor().fromString(id));
tx.delete(id);
return true;
}
@ -175,7 +165,7 @@ public class MapRealmProvider<K> implements RealmProvider {
.compare(SearchableFields.CLIENT_INITIAL_ACCESS, Operator.EXISTS);
tx.read(withCriteria(mcb))
.forEach(MapRealmEntity<K>::removeExpiredClientInitialAccesses);
.forEach(MapRealmEntity::removeExpiredClientInitialAccesses);
}
//TODO move the following method to adapter

View file

@ -22,7 +22,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmProviderFactory;
public class MapRealmProviderFactory<K> extends AbstractMapProviderFactory<RealmProvider, K, MapRealmEntity<K>, RealmModel> implements RealmProviderFactory {
public class MapRealmProviderFactory<K> extends AbstractMapProviderFactory<RealmProvider, K, MapRealmEntity, RealmModel> implements RealmProviderFactory {
public MapRealmProviderFactory() {
super(RealmModel.class);

View file

@ -30,14 +30,19 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.utils.KeycloakModelUtils;
public abstract class MapRoleAdapter<K> extends AbstractRoleModel<MapRoleEntity<K>> implements RoleModel {
public class MapRoleAdapter extends AbstractRoleModel<MapRoleEntity> implements RoleModel {
private static final Logger LOG = Logger.getLogger(MapRoleAdapter.class);
public MapRoleAdapter(KeycloakSession session, RealmModel realm, MapRoleEntity<K> entity) {
public MapRoleAdapter(KeycloakSession session, RealmModel realm, MapRoleEntity entity) {
super(session, realm, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getName() {
return entity.getName();

View file

@ -25,9 +25,9 @@ import java.util.Set;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.UpdatableEntity;
public class MapRoleEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapRoleEntity implements AbstractEntity, UpdatableEntity {
private K id;
private String id;
private String realmId;
private String name;
@ -47,8 +47,7 @@ public class MapRoleEntity<K> implements AbstractEntity<K>, UpdatableEntity {
this.realmId = null;
}
public MapRoleEntity(K id, String realmId) {
Objects.requireNonNull(id, "id");
public MapRoleEntity(String id, String realmId) {
Objects.requireNonNull(realmId, "realmId");
this.id = id;
@ -56,7 +55,7 @@ public class MapRoleEntity<K> implements AbstractEntity<K>, UpdatableEntity {
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -44,24 +44,19 @@ public class MapRoleProvider<K> implements RoleProvider {
private static final Logger LOG = Logger.getLogger(MapRoleProvider.class);
private final KeycloakSession session;
final MapKeycloakTransaction<K, MapRoleEntity<K>, RoleModel> tx;
private final MapStorage<K, MapRoleEntity<K>, RoleModel> roleStore;
final MapKeycloakTransaction<K, MapRoleEntity, RoleModel> tx;
private final MapStorage<K, MapRoleEntity, RoleModel> roleStore;
public MapRoleProvider(KeycloakSession session, MapStorage<K, MapRoleEntity<K>, RoleModel> roleStore) {
public MapRoleProvider(KeycloakSession session, MapStorage<K, MapRoleEntity, RoleModel> roleStore) {
this.session = session;
this.roleStore = roleStore;
this.tx = roleStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
private Function<MapRoleEntity<K>, RoleModel> entityToAdapterFunc(RealmModel realm) {
private Function<MapRoleEntity, RoleModel> entityToAdapterFunc(RealmModel realm) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return origEntity -> new MapRoleAdapter<K>(session, realm, origEntity) {
@Override
public String getId() {
return roleStore.getKeyConvertor().keyToString(entity.getId());
}
};
return origEntity -> new MapRoleAdapter(session, realm, origEntity);
}
@Override
@ -70,11 +65,9 @@ public class MapRoleProvider<K> implements RoleProvider {
throw new ModelDuplicateException("Role exists: " + id);
}
final K entityId = id == null ? roleStore.getKeyConvertor().yieldNewUniqueKey() : roleStore.getKeyConvertor().fromString(id);
LOG.tracef("addRealmRole(%s, %s, %s)%s", realm, id, name, getShortStackTrace());
MapRoleEntity<K> entity = new MapRoleEntity<K>(entityId, realm.getId());
MapRoleEntity entity = new MapRoleEntity(id, realm.getId());
entity.setName(name);
entity.setRealmId(realm.getId());
if (tx.read(entity.getId()) != null) {
@ -110,11 +103,9 @@ public class MapRoleProvider<K> implements RoleProvider {
throw new ModelDuplicateException("Role exists: " + id);
}
final K entityId = id == null ? roleStore.getKeyConvertor().yieldNewUniqueKey() : roleStore.getKeyConvertor().fromString(id);
LOG.tracef("addClientRole(%s, %s, %s)%s", client, id, name, getShortStackTrace());
MapRoleEntity<K> entity = new MapRoleEntity<K>(entityId, client.getRealm().getId());
MapRoleEntity entity = new MapRoleEntity(id, client.getRealm().getId());
entity.setName(name);
entity.setClientRole(true);
entity.setClientId(client.getId());
@ -166,7 +157,7 @@ public class MapRoleProvider<K> implements RoleProvider {
});
// TODO: ^^^^^^^ Up to here
tx.delete(roleStore.getKeyConvertor().fromString(role.getId()));
tx.delete(role.getId());
return true;
}
@ -230,7 +221,7 @@ public class MapRoleProvider<K> implements RoleProvider {
LOG.tracef("getRoleById(%s, %s)%s", realm, id, getShortStackTrace());
MapRoleEntity<K> entity = tx.read(roleStore.getKeyConvertor().fromStringSafe(id));
MapRoleEntity entity = tx.read(id);
String realmId = realm.getId();
return (entity == null || ! Objects.equals(realmId, entity.getRealmId()))
? null

View file

@ -22,7 +22,7 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.RoleProvider;
import org.keycloak.models.RoleProviderFactory;
public class MapRoleProviderFactory<K> extends AbstractMapProviderFactory<RoleProvider, K, MapRoleEntity<K>, RoleModel> implements RoleProviderFactory {
public class MapRoleProviderFactory<K> extends AbstractMapProviderFactory<RoleProvider, K, MapRoleEntity, RoleModel> implements RoleProviderFactory {
public MapRoleProviderFactory() {
super(RoleModel.class);

View file

@ -23,7 +23,7 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
public interface MapKeycloakTransaction<K, V extends AbstractEntity<K>, M> extends KeycloakTransaction {
public interface MapKeycloakTransaction<K, V extends AbstractEntity, M> extends KeycloakTransaction {
/**
* Instructs this transaction to add a new value into the underlying store on commit.
@ -44,7 +44,7 @@ public interface MapKeycloakTransaction<K, V extends AbstractEntity<K>, M> exten
* @param key identifier of a value
* @return a value associated with the given {@code key}
*/
V read(K key);
V read(String key);
/**
* Returns a stream of values from underlying storage that are updated based on the current transaction changes;
@ -76,7 +76,7 @@ public interface MapKeycloakTransaction<K, V extends AbstractEntity<K>, M> exten
* @return Returns {@code true} if the object has been deleted or result cannot be determined, {@code false} otherwise.
* @param key identifier of a value
*/
boolean delete(K key);
boolean delete(String key);
/**
* Instructs this transaction to remove values (identified by {@code mcb} filter) from the underlying store on commit.

View file

@ -36,7 +36,7 @@ import java.util.stream.Stream;
* filtering via model fields in {@link ModelCriteriaBuilder} which is necessary to abstract from physical
* layout and thus to support no-downtime upgrade.
*/
public interface MapStorage<K, V extends AbstractEntity<K>, M> {
public interface MapStorage<K, V extends AbstractEntity, M> {
/**
* Creates an object in the store. ID of the {@code value} may be prescribed in id of the {@code value}.
@ -56,7 +56,7 @@ public interface MapStorage<K, V extends AbstractEntity<K>, M> {
* @return See description
* @throws NullPointerException if the {@code key} is {@code null}
*/
V read(K key);
V read(String key);
/**
* Returns stream of objects satisfying given {@code criteria} from the storage.
@ -94,7 +94,7 @@ public interface MapStorage<K, V extends AbstractEntity<K>, M> {
* @param key
* @return Returns {@code true} if the object has been deleted or result cannot be determined, {@code false} otherwise.
*/
boolean delete(K key);
boolean delete(String key);
/**
* Deletes objects that match the given criteria.
@ -131,12 +131,4 @@ public interface MapStorage<K, V extends AbstractEntity<K>, M> {
*/
MapKeycloakTransaction<K, V, M> createTransaction(KeycloakSession session);
/**
* Returns a {@link StringKeyConvertor} that is used to convert primary keys
* from {@link String} to internal representation and vice versa.
*
* @return See above. Never returns {@code null}.
*/
StringKeyConvertor<K> getKeyConvertor();
}

View file

@ -36,5 +36,5 @@ public interface MapStorageProvider extends Provider {
* @return
* @throws IllegalArgumentException If some of the types is not supported by the underlying implementation.
*/
<K, V extends AbstractEntity<K>, M> MapStorage<K, V, M> getStorage(Class<M> modelType, Flag... flags);
<K, V extends AbstractEntity, M> MapStorage<K, V, M> getStorage(Class<M> modelType, Flag... flags);
}

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.models.map.storage.chm;
import org.keycloak.models.map.common.StringKeyConvertor;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.Serialization;
import org.keycloak.models.map.common.UpdatableEntity;
@ -35,21 +36,23 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder;
import org.keycloak.models.map.storage.QueryParameters;
import org.keycloak.utils.StreamsUtil;
public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K> & UpdatableEntity, M> implements MapKeycloakTransaction<K, V, M> {
public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity & UpdatableEntity, M> implements MapKeycloakTransaction<K, V, M> {
private final static Logger log = Logger.getLogger(ConcurrentHashMapKeycloakTransaction.class);
private boolean active;
private boolean rollback;
private final Map<K, MapTaskWithValue> tasks = new LinkedHashMap<>();
private final Map<String, MapTaskWithValue> tasks = new LinkedHashMap<>();
private final MapStorage<K, V, M> map;
private final StringKeyConvertor<K> keyConvertor;
enum MapOperation {
CREATE, UPDATE, DELETE,
}
public ConcurrentHashMapKeycloakTransaction(MapStorage<K, V, M> map) {
public ConcurrentHashMapKeycloakTransaction(MapStorage<K, V, M> map, StringKeyConvertor<K> keyConvertor) {
this.map = map;
this.keyConvertor = keyConvertor;
}
@Override
@ -93,11 +96,10 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
/**
* Adds a given task if not exists for the given key
*/
protected void addTask(K key, MapTaskWithValue task) {
protected void addTask(String key, MapTaskWithValue task) {
log.tracef("Adding operation %s for %s @ %08x", task.getOperation(), key, System.identityHashCode(task.getValue()));
K taskKey = key;
tasks.merge(taskKey, task, MapTaskCompose::new);
tasks.merge(key, task, MapTaskCompose::new);
}
/**
@ -109,7 +111,7 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
* @return
*/
public V registerEntityForChanges(V origEntity) {
final K key = origEntity.getId();
final String key = origEntity.getId();
// If the entity is listed in the transaction already, return it directly
if (tasks.containsKey(key)) {
MapTaskWithValue current = tasks.get(key);
@ -121,17 +123,17 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
}
@Override
public V read(K key) {
public V read(String sKey) {
try {
// TODO: Consider using Optional rather than handling NPE
final V entity = read(key, map::read);
final V entity = read(sKey, map::read);
return registerEntityForChanges(entity);
} catch (NullPointerException ex) {
return null;
}
}
public V read(K key, Function<K, V> defaultValueFunc) {
public V read(String key, Function<String, V> defaultValueFunc) {
MapTaskWithValue current = tasks.get(key);
// If the key exists, then it has entered the "tasks" after bulk delete that could have
// removed it, so looking through bulk deletes is irrelevant
@ -207,16 +209,21 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
@Override
public V create(V value) {
K key = value.getId();
String key = value.getId();
if (key == null) {
K newKey = keyConvertor.yieldNewUniqueKey();
key = keyConvertor.keyToString(newKey);
value = Serialization.from(value, key);
}
addTask(key, new CreateOperation(value));
return value;
}
public V updateIfChanged(V value, Predicate<V> shouldPut) {
K key = value.getId();
String key = value.getId();
log.tracef("Adding operation UPDATE_IF_CHANGED for %s @ %08x", key, System.identityHashCode(value));
K taskKey = key;
String taskKey = key;
MapTaskWithValue op = new MapTaskWithValue(value) {
@Override
public void execute() {
@ -230,7 +237,7 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
}
@Override
public boolean delete(K key) {
public boolean delete(String key) {
addTask(key, new DeleteOperation(key));
return true;
}
@ -240,14 +247,14 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
public long delete(QueryParameters<M> queryParameters) {
log.tracef("Adding operation DELETE_BULK");
K artificialKey = map.getKeyConvertor().yieldNewUniqueKey();
K artificialKey = keyConvertor.yieldNewUniqueKey();
// Remove all tasks that create / update / delete objects deleted by the bulk removal.
final BulkDeleteOperation bdo = new BulkDeleteOperation(queryParameters);
Predicate<V> filterForNonDeletedObjects = bdo.getFilterForNonDeletedObjects();
long res = 0;
for (Iterator<Entry<K, MapTaskWithValue>> it = tasks.entrySet().iterator(); it.hasNext();) {
Entry<K, MapTaskWithValue> me = it.next();
for (Iterator<Entry<String, MapTaskWithValue>> it = tasks.entrySet().iterator(); it.hasNext();) {
Entry<String, MapTaskWithValue> me = it.next();
if (! filterForNonDeletedObjects.test(me.getValue().getValue())) {
log.tracef(" [DELETE_BULK] removing %s", me.getKey());
it.remove();
@ -255,14 +262,14 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
}
}
tasks.put(artificialKey, bdo);
tasks.put(keyConvertor.keyToString(artificialKey), bdo);
return res + bdo.getCount();
}
private Stream<V> createdValuesStream(Predicate<? super K> keyFilter, Predicate<? super V> entityFilter) {
return this.tasks.entrySet().stream()
.filter(me -> keyFilter.test(me.getKey()))
.filter(me -> keyFilter.test(keyConvertor.fromStringSafe(me.getKey())))
.map(Map.Entry::getValue)
.filter(v -> v.containsCreate() && ! v.isReplace())
.map(MapTaskWithValue::getValue)
@ -362,9 +369,9 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
}
private class DeleteOperation extends MapTaskWithValue {
private final K key;
private final String key;
public DeleteOperation(K key) {
public DeleteOperation(String key) {
super(null);
this.key = key;
}
@ -398,7 +405,7 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity<K>
Predicate<? super V> entityFilter = mmcb.getEntityFilter();
Predicate<? super K> keyFilter = mmcb.getKeyFilter();
return v -> v == null || ! (keyFilter.test(v.getId()) && entityFilter.test(v));
return v -> v == null || ! (keyFilter.test(keyConvertor.fromStringSafe(v.getId())) && entityFilter.test(v));
}
@Override

View file

@ -16,9 +16,11 @@
*/
package org.keycloak.models.map.storage.chm;
import org.keycloak.models.map.common.StringKeyConvertor;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.map.storage.MapKeycloakTransaction;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.Serialization;
import org.keycloak.models.map.common.UpdatableEntity;
import org.keycloak.models.map.storage.MapStorage;
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
@ -32,7 +34,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;
import org.keycloak.models.map.storage.StringKeyConvertor;
import org.keycloak.models.map.storage.chm.MapModelCriteriaBuilder.UpdatePredicatesFunc;
import java.util.Objects;
import java.util.function.Predicate;
@ -43,7 +44,7 @@ import static org.keycloak.utils.StreamsUtil.paginatedStream;
*
* @author hmlnarik
*/
public class ConcurrentHashMapStorage<K, V extends AbstractEntity<K> & UpdatableEntity, M> implements MapStorage<K, V, M> {
public class ConcurrentHashMapStorage<K, V extends AbstractEntity & UpdatableEntity, M> implements MapStorage<K, V, M> {
private final ConcurrentMap<K, V> store = new ConcurrentHashMap<>();
@ -58,25 +59,31 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity<K> & Updatable
@Override
public V create(V value) {
K key = value.getId();
return store.putIfAbsent(key, value);
K key = keyConvertor.fromStringSafe(value.getId());
if (key == null) {
key = keyConvertor.yieldNewUniqueKey();
value = Serialization.from(value, keyConvertor.keyToString(key));
}
store.putIfAbsent(key, value);
return value;
}
@Override
public V read(K key) {
public V read(String key) {
Objects.requireNonNull(key, "Key must be non-null");
return store.get(key);
return store.get(keyConvertor.fromString(key));
}
@Override
public V update(V value) {
K key = value.getId();
K key = getKeyConvertor().fromStringSafe(value.getId());
return store.replace(key, value);
}
@Override
public boolean delete(K key) {
return store.remove(key) != null;
public boolean delete(String key) {
K k = getKeyConvertor().fromStringSafe(key);
return store.remove(k) != null;
}
@Override
@ -114,17 +121,16 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity<K> & Updatable
@Override
public ModelCriteriaBuilder<M> createCriteriaBuilder() {
return new MapModelCriteriaBuilder<>(fieldPredicates);
return new MapModelCriteriaBuilder<>(keyConvertor, fieldPredicates);
}
@Override
@SuppressWarnings("unchecked")
public MapKeycloakTransaction<K, V, M> createTransaction(KeycloakSession session) {
MapKeycloakTransaction<K, V, M> sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
return sessionTransaction == null ? new ConcurrentHashMapKeycloakTransaction<>(this) : sessionTransaction;
return sessionTransaction == null ? new ConcurrentHashMapKeycloakTransaction<>(this, keyConvertor) : sessionTransaction;
}
@Override
public StringKeyConvertor<K> getKeyConvertor() {
return keyConvertor;
}

View file

@ -39,7 +39,7 @@ public class ConcurrentHashMapStorageProvider implements MapStorageProvider {
@Override
@SuppressWarnings("unchecked")
public <K, V extends AbstractEntity<K>, M> MapStorage<K, V, M> getStorage(Class<M> modelType, Flag... flags) {
public <K, V extends AbstractEntity, M> MapStorage<K, V, M> getStorage(Class<M> modelType, Flag... flags) {
ConcurrentHashMapStorage storage = factory.getStorage(modelType, flags);
return (MapStorage<K, V, M>) storage;
}

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.models.map.storage.chm;
import org.keycloak.models.map.common.StringKeyConvertor;
import org.keycloak.component.AmphibianProviderFactory;
import org.keycloak.Config.Scope;
import org.keycloak.authorization.model.PermissionTicket;
@ -63,7 +64,6 @@ import org.keycloak.models.map.storage.MapStorageProvider;
import org.keycloak.models.map.storage.MapStorageProviderFactory;
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
import org.keycloak.models.map.userSession.MapAuthenticatedClientSessionEntity;
import org.keycloak.models.map.storage.StringKeyConvertor;
import org.keycloak.models.map.user.MapUserEntity;
import org.keycloak.models.map.userSession.MapUserSessionEntity;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
@ -241,7 +241,7 @@ public class ConcurrentHashMapStorageProviderFactory implements AmphibianProvide
}
}
private <K, V extends AbstractEntity<K> & UpdatableEntity, M> ConcurrentHashMapStorage<K, V, M> loadMap(String mapName,
private <K, V extends AbstractEntity & UpdatableEntity, M> ConcurrentHashMapStorage<K, V, M> loadMap(String mapName,
Class<M> modelType, EnumSet<Flag> flags) {
final StringKeyConvertor kc = keyConvertors.getOrDefault(mapName, defaultKeyConvertor);
Class<?> valueType = MODEL_TO_VALUE_TYPE.get(modelType);
@ -291,7 +291,7 @@ public class ConcurrentHashMapStorageProviderFactory implements AmphibianProvide
}
@SuppressWarnings("unchecked")
public <K, V extends AbstractEntity<K> & UpdatableEntity, M> ConcurrentHashMapStorage<K, V, M> getStorage(
public <K, V extends AbstractEntity & UpdatableEntity, M> ConcurrentHashMapStorage<K, V, M> getStorage(
Class<M> modelType, Flag... flags) {
EnumSet<Flag> f = flags == null || flags.length == 0 ? EnumSet.noneOf(Flag.class) : EnumSet.of(flags[0], flags);
String name = MODEL_TO_NAME.getOrDefault(modelType, modelType.getSimpleName());

View file

@ -75,21 +75,21 @@ import static org.keycloak.models.UserSessionModel.CORRESPONDING_SESSION_ID;
*/
public class MapFieldPredicates {
public static final Map<SearchableModelField<AuthenticatedClientSessionModel>, UpdatePredicatesFunc<Object, MapAuthenticatedClientSessionEntity<Object>, AuthenticatedClientSessionModel>> CLIENT_SESSION_PREDICATES = basePredicates(AuthenticatedClientSessionModel.SearchableFields.ID);
public static final Map<SearchableModelField<ClientModel>, UpdatePredicatesFunc<Object, MapClientEntity<Object>, ClientModel>> CLIENT_PREDICATES = basePredicates(ClientModel.SearchableFields.ID);
public static final Map<SearchableModelField<ClientScopeModel>, UpdatePredicatesFunc<Object, MapClientScopeEntity<Object>, ClientScopeModel>> CLIENT_SCOPE_PREDICATES = basePredicates(ClientScopeModel.SearchableFields.ID);
public static final Map<SearchableModelField<GroupModel>, UpdatePredicatesFunc<Object, MapGroupEntity<Object>, GroupModel>> GROUP_PREDICATES = basePredicates(GroupModel.SearchableFields.ID);
public static final Map<SearchableModelField<RoleModel>, UpdatePredicatesFunc<Object, MapRoleEntity<Object>, RoleModel>> ROLE_PREDICATES = basePredicates(RoleModel.SearchableFields.ID);
public static final Map<SearchableModelField<RootAuthenticationSessionModel>, UpdatePredicatesFunc<Object, MapRootAuthenticationSessionEntity<Object>, RootAuthenticationSessionModel>> AUTHENTICATION_SESSION_PREDICATES = basePredicates(RootAuthenticationSessionModel.SearchableFields.ID);
public static final Map<SearchableModelField<RealmModel>, UpdatePredicatesFunc<Object, MapRealmEntity<Object>, RealmModel>> REALM_PREDICATES = basePredicates(RealmModel.SearchableFields.ID);
public static final Map<SearchableModelField<ResourceServer>, UpdatePredicatesFunc<Object, MapResourceServerEntity<Object>, ResourceServer>> AUTHZ_RESOURCE_SERVER_PREDICATES = basePredicates(ResourceServer.SearchableFields.ID);
public static final Map<SearchableModelField<Resource>, UpdatePredicatesFunc<Object, MapResourceEntity<Object>, Resource>> AUTHZ_RESOURCE_PREDICATES = basePredicates(Resource.SearchableFields.ID);
public static final Map<SearchableModelField<Scope>, UpdatePredicatesFunc<Object, MapScopeEntity<Object>, Scope>> AUTHZ_SCOPE_PREDICATES = basePredicates(Scope.SearchableFields.ID);
public static final Map<SearchableModelField<PermissionTicket>, UpdatePredicatesFunc<Object, MapPermissionTicketEntity<Object>, PermissionTicket>> AUTHZ_PERMISSION_TICKET_PREDICATES = basePredicates(PermissionTicket.SearchableFields.ID);
public static final Map<SearchableModelField<Policy>, UpdatePredicatesFunc<Object, MapPolicyEntity<Object>, Policy>> AUTHZ_POLICY_PREDICATES = basePredicates(Policy.SearchableFields.ID);
public static final Map<SearchableModelField<UserLoginFailureModel>, UpdatePredicatesFunc<Object, MapUserLoginFailureEntity<Object>, UserLoginFailureModel>> USER_LOGIN_FAILURE_PREDICATES = basePredicates(UserLoginFailureModel.SearchableFields.ID);
public static final Map<SearchableModelField<UserModel>, UpdatePredicatesFunc<Object, MapUserEntity<Object>, UserModel>> USER_PREDICATES = basePredicates(UserModel.SearchableFields.ID);
public static final Map<SearchableModelField<UserSessionModel>, UpdatePredicatesFunc<Object, MapUserSessionEntity<Object>, UserSessionModel>> USER_SESSION_PREDICATES = basePredicates(UserSessionModel.SearchableFields.ID);
public static final Map<SearchableModelField<AuthenticatedClientSessionModel>, UpdatePredicatesFunc<Object, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel>> CLIENT_SESSION_PREDICATES = basePredicates(AuthenticatedClientSessionModel.SearchableFields.ID);
public static final Map<SearchableModelField<ClientModel>, UpdatePredicatesFunc<Object, MapClientEntity, ClientModel>> CLIENT_PREDICATES = basePredicates(ClientModel.SearchableFields.ID);
public static final Map<SearchableModelField<ClientScopeModel>, UpdatePredicatesFunc<Object, MapClientScopeEntity, ClientScopeModel>> CLIENT_SCOPE_PREDICATES = basePredicates(ClientScopeModel.SearchableFields.ID);
public static final Map<SearchableModelField<GroupModel>, UpdatePredicatesFunc<Object, MapGroupEntity, GroupModel>> GROUP_PREDICATES = basePredicates(GroupModel.SearchableFields.ID);
public static final Map<SearchableModelField<RoleModel>, UpdatePredicatesFunc<Object, MapRoleEntity, RoleModel>> ROLE_PREDICATES = basePredicates(RoleModel.SearchableFields.ID);
public static final Map<SearchableModelField<RootAuthenticationSessionModel>, UpdatePredicatesFunc<Object, MapRootAuthenticationSessionEntity, RootAuthenticationSessionModel>> AUTHENTICATION_SESSION_PREDICATES = basePredicates(RootAuthenticationSessionModel.SearchableFields.ID);
public static final Map<SearchableModelField<RealmModel>, UpdatePredicatesFunc<Object, MapRealmEntity, RealmModel>> REALM_PREDICATES = basePredicates(RealmModel.SearchableFields.ID);
public static final Map<SearchableModelField<ResourceServer>, UpdatePredicatesFunc<Object, MapResourceServerEntity, ResourceServer>> AUTHZ_RESOURCE_SERVER_PREDICATES = basePredicates(ResourceServer.SearchableFields.ID);
public static final Map<SearchableModelField<Resource>, UpdatePredicatesFunc<Object, MapResourceEntity, Resource>> AUTHZ_RESOURCE_PREDICATES = basePredicates(Resource.SearchableFields.ID);
public static final Map<SearchableModelField<Scope>, UpdatePredicatesFunc<Object, MapScopeEntity, Scope>> AUTHZ_SCOPE_PREDICATES = basePredicates(Scope.SearchableFields.ID);
public static final Map<SearchableModelField<PermissionTicket>, UpdatePredicatesFunc<Object, MapPermissionTicketEntity, PermissionTicket>> AUTHZ_PERMISSION_TICKET_PREDICATES = basePredicates(PermissionTicket.SearchableFields.ID);
public static final Map<SearchableModelField<Policy>, UpdatePredicatesFunc<Object, MapPolicyEntity, Policy>> AUTHZ_POLICY_PREDICATES = basePredicates(Policy.SearchableFields.ID);
public static final Map<SearchableModelField<UserLoginFailureModel>, UpdatePredicatesFunc<Object, MapUserLoginFailureEntity, UserLoginFailureModel>> USER_LOGIN_FAILURE_PREDICATES = basePredicates(UserLoginFailureModel.SearchableFields.ID);
public static final Map<SearchableModelField<UserModel>, UpdatePredicatesFunc<Object, MapUserEntity, UserModel>> USER_PREDICATES = basePredicates(UserModel.SearchableFields.ID);
public static final Map<SearchableModelField<UserSessionModel>, UpdatePredicatesFunc<Object, MapUserSessionEntity, UserSessionModel>> USER_SESSION_PREDICATES = basePredicates(UserSessionModel.SearchableFields.ID);
@SuppressWarnings("unchecked")
private static final Map<Class<?>, Map> PREDICATES = new HashMap<>();
@ -212,26 +212,26 @@ public class MapFieldPredicates {
PREDICATES.put(UserLoginFailureModel.class, USER_LOGIN_FAILURE_PREDICATES);
}
private static <K, V extends AbstractEntity<K>, M, L extends Comparable<L>> void put(
private static <K, V extends AbstractEntity, M, L extends Comparable<L>> void put(
Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> map,
SearchableModelField<M> field, Function<V, L> extractor) {
COMPARATORS.put(field, Comparator.comparing(extractor));
map.put(field, (mcb, op, values) -> mcb.fieldCompare(op, extractor, values));
}
private static <K, V extends AbstractEntity<K>, M> void putIncomparable(
private static <K, V extends AbstractEntity, M> void putIncomparable(
Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> map,
SearchableModelField<M> field, Function<V, Object> extractor) {
map.put(field, (mcb, op, values) -> mcb.fieldCompare(op, extractor, values));
}
private static <K, V extends AbstractEntity<K>, M> void put(
private static <K, V extends AbstractEntity, M> void put(
Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> map,
SearchableModelField<M> field, UpdatePredicatesFunc<K, V, M> function) {
map.put(field, function);
}
private static <V extends AbstractEntity<?>> Function<V, String> predicateForKeyField(Function<V, Object> extractor) {
private static <V extends AbstractEntity> Function<V, String> predicateForKeyField(Function<V, Object> extractor) {
return entity -> {
Object o = extractor.apply(entity);
return o == null ? null : o.toString();
@ -258,30 +258,30 @@ public class MapFieldPredicates {
return expectedType.cast(ob);
}
private static MapModelCriteriaBuilder<Object, MapClientEntity<Object>, ClientModel> checkScopeMappingRole(MapModelCriteriaBuilder<Object, MapClientEntity<Object>, ClientModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapClientEntity, ClientModel> checkScopeMappingRole(MapModelCriteriaBuilder<Object, MapClientEntity, ClientModel> mcb, Operator op, Object[] values) {
String roleIdS = ensureEqSingleValue(ClientModel.SearchableFields.SCOPE_MAPPING_ROLE, "role_id", op, values);
Function<MapClientEntity<Object>, ?> getter;
Function<MapClientEntity, ?> getter;
getter = ce -> ce.getScopeMappings().contains(roleIdS);
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapGroupEntity<Object>, GroupModel> checkGrantedGroupRole(MapModelCriteriaBuilder<Object, MapGroupEntity<Object>, GroupModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapGroupEntity, GroupModel> checkGrantedGroupRole(MapModelCriteriaBuilder<Object, MapGroupEntity, GroupModel> mcb, Operator op, Object[] values) {
String roleIdS = ensureEqSingleValue(GroupModel.SearchableFields.ASSIGNED_ROLE, "role_id", op, values);
Function<MapGroupEntity<Object>, ?> getter;
Function<MapGroupEntity, ?> getter;
getter = ge -> ge.getGrantedRoles().contains(roleIdS);
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> getUserConsentClientFederationLink(MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> getUserConsentClientFederationLink(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
String providerId = ensureEqSingleValue(UserModel.SearchableFields.CONSENT_CLIENT_FEDERATION_LINK, "provider_id", op, values);
String providerIdS = new StorageId((String) providerId, "").getId();
Function<MapUserEntity<Object>, ?> getter;
Function<MapUserEntity, ?> getter;
getter = ue -> ue.getUserConsents().map(UserConsentEntity::getClientId).anyMatch(v -> v != null && v.startsWith(providerIdS));
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> checkUserAttributes(MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> checkUserAttributes(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
if (values == null || values.length <= 1) {
throw new CriterionNotSupportedException(UserModel.SearchableFields.ATTRIBUTE, op, "Invalid arguments, expected (attribute_name, ...), got: " + Arrays.toString(values));
}
@ -291,7 +291,7 @@ public class MapFieldPredicates {
throw new CriterionNotSupportedException(UserModel.SearchableFields.ATTRIBUTE, op, "Invalid arguments, expected (String attribute_name), got: " + Arrays.toString(values));
}
String attrNameS = (String) attrName;
Function<MapUserEntity<Object>, ?> getter;
Function<MapUserEntity, ?> getter;
Object[] realValues = new Object[values.length - 1];
System.arraycopy(values, 1, realValues, 0, values.length - 1);
Predicate<Object> valueComparator = CriteriaOperator.predicateFor(op, realValues);
@ -303,7 +303,7 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapClientEntity<Object>, ClientModel> checkClientAttributes(MapModelCriteriaBuilder<Object, MapClientEntity<Object>, ClientModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapClientEntity, ClientModel> checkClientAttributes(MapModelCriteriaBuilder<Object, MapClientEntity, ClientModel> mcb, Operator op, Object[] values) {
if (values == null || values.length != 2) {
throw new CriterionNotSupportedException(ClientModel.SearchableFields.ATTRIBUTE, op, "Invalid arguments, expected attribute_name-value pair, got: " + Arrays.toString(values));
}
@ -316,7 +316,7 @@ public class MapFieldPredicates {
Object[] realValues = new Object[values.length - 1];
System.arraycopy(values, 1, realValues, 0, values.length - 1);
Predicate<Object> valueComparator = CriteriaOperator.predicateFor(op, realValues);
Function<MapClientEntity<Object>, ?> getter = ue -> {
Function<MapClientEntity, ?> getter = ue -> {
final List<String> attrs = ue.getAttribute(attrNameS);
return attrs != null && attrs.stream().anyMatch(valueComparator);
};
@ -324,16 +324,16 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> checkGrantedUserRole(MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> checkGrantedUserRole(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
String roleIdS = ensureEqSingleValue(UserModel.SearchableFields.ASSIGNED_ROLE, "role_id", op, values);
Function<MapUserEntity<Object>, ?> getter;
Function<MapUserEntity, ?> getter;
getter = ue -> ue.getRolesMembership().contains(roleIdS);
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapResourceEntity<Object>, Resource> checkResourceUri(MapModelCriteriaBuilder<Object, MapResourceEntity<Object>, Resource> mcb, Operator op, Object[] values) {
Function<MapResourceEntity<Object>, ?> getter;
private static MapModelCriteriaBuilder<Object, MapResourceEntity, Resource> checkResourceUri(MapModelCriteriaBuilder<Object, MapResourceEntity, Resource> mcb, Operator op, Object[] values) {
Function<MapResourceEntity, ?> getter;
if (Operator.EXISTS.equals(op)) {
getter = re -> re.getUris() != null && !re.getUris().isEmpty();
@ -348,8 +348,8 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapResourceEntity<Object>, Resource> checkResourceScopes(MapModelCriteriaBuilder<Object, MapResourceEntity<Object>, Resource> mcb, Operator op, Object[] values) {
Function<MapResourceEntity<Object>, ?> getter;
private static MapModelCriteriaBuilder<Object, MapResourceEntity, Resource> checkResourceScopes(MapModelCriteriaBuilder<Object, MapResourceEntity, Resource> mcb, Operator op, Object[] values) {
Function<MapResourceEntity, ?> getter;
if (op == Operator.IN && values != null && values.length == 1 && (values[0] instanceof Collection)) {
Collection<?> c = (Collection<?>) values[0];
@ -362,8 +362,8 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapPolicyEntity<Object>, Policy> checkPolicyResources(MapModelCriteriaBuilder<Object, MapPolicyEntity<Object>, Policy> mcb, Operator op, Object[] values) {
Function<MapPolicyEntity<Object>, ?> getter;
private static MapModelCriteriaBuilder<Object, MapPolicyEntity, Policy> checkPolicyResources(MapModelCriteriaBuilder<Object, MapPolicyEntity, Policy> mcb, Operator op, Object[] values) {
Function<MapPolicyEntity, ?> getter;
if (op == Operator.NOT_EXISTS) {
getter = re -> re.getResourceIds().isEmpty();
@ -378,8 +378,8 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapPolicyEntity<Object>, Policy> checkPolicyScopes(MapModelCriteriaBuilder<Object, MapPolicyEntity<Object>, Policy> mcb, Operator op, Object[] values) {
Function<MapPolicyEntity<Object>, ?> getter;
private static MapModelCriteriaBuilder<Object, MapPolicyEntity, Policy> checkPolicyScopes(MapModelCriteriaBuilder<Object, MapPolicyEntity, Policy> mcb, Operator op, Object[] values) {
Function<MapPolicyEntity, ?> getter;
if (op == Operator.IN && values != null && values.length == 1 && (values[0] instanceof Collection)) {
Collection<?> c = (Collection<?>) values[0];
@ -392,8 +392,8 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapPolicyEntity<Object>, Policy> checkPolicyConfig(MapModelCriteriaBuilder<Object, MapPolicyEntity<Object>, Policy> mcb, Operator op, Object[] values) {
Function<MapPolicyEntity<Object>, ?> getter;
private static MapModelCriteriaBuilder<Object, MapPolicyEntity, Policy> checkPolicyConfig(MapModelCriteriaBuilder<Object, MapPolicyEntity, Policy> mcb, Operator op, Object[] values) {
Function<MapPolicyEntity, ?> getter;
final Object attrName = values[0];
if (!(attrName instanceof String)) {
@ -412,8 +412,8 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapPolicyEntity<Object>, Policy> checkAssociatedPolicy(MapModelCriteriaBuilder<Object, MapPolicyEntity<Object>, Policy> mcb, Operator op, Object[] values) {
Function<MapPolicyEntity<Object>, ?> getter;
private static MapModelCriteriaBuilder<Object, MapPolicyEntity, Policy> checkAssociatedPolicy(MapModelCriteriaBuilder<Object, MapPolicyEntity, Policy> mcb, Operator op, Object[] values) {
Function<MapPolicyEntity, ?> getter;
if (op == Operator.IN && values != null && values.length == 1 && (values[0] instanceof Collection)) {
Collection<?> c = (Collection<?>) values[0];
@ -426,8 +426,8 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> checkUserGroup(MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> mcb, Operator op, Object[] values) {
Function<MapUserEntity<Object>, ?> getter;
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> checkUserGroup(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
Function<MapUserEntity, ?> getter;
if (op == Operator.IN && values != null && values.length == 1 && (values[0] instanceof Collection)) {
Collection<?> c = (Collection<?>) values[0];
getter = ue -> ue.getGroupsMembership().stream().anyMatch(c::contains);
@ -439,23 +439,23 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> checkUserClientConsent(MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> checkUserClientConsent(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
String clientIdS = ensureEqSingleValue(UserModel.SearchableFields.CONSENT_FOR_CLIENT, "client_id", op, values);
Function<MapUserEntity<Object>, ?> getter;
Function<MapUserEntity, ?> getter;
getter = ue -> ue.getUserConsent(clientIdS);
return mcb.fieldCompare(Operator.EXISTS, getter, null);
}
private static MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> checkUserConsentsWithClientScope(MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> checkUserConsentsWithClientScope(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
String clientScopeIdS = ensureEqSingleValue(UserModel.SearchableFields.CONSENT_FOR_CLIENT, "client_scope_id", op, values);
Function<MapUserEntity<Object>, ?> getter;
Function<MapUserEntity, ?> getter;
getter = ue -> ue.getUserConsents().anyMatch(consent -> consent.getGrantedClientScopesIds().contains(clientScopeIdS));
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> getUserIdpAliasAtIdentityProviderPredicate(MapModelCriteriaBuilder<Object, MapUserEntity<Object>, UserModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> getUserIdpAliasAtIdentityProviderPredicate(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
if (op != Operator.EQ) {
throw new CriterionNotSupportedException(UserModel.SearchableFields.IDP_AND_USER, op);
}
@ -464,7 +464,7 @@ public class MapFieldPredicates {
}
final Object idpAlias = values[0];
Function<MapUserEntity<Object>, ?> getter;
Function<MapUserEntity, ?> getter;
if (values.length == 1) {
getter = ue -> ue.getFederatedIdentities()
.anyMatch(aue -> Objects.equals(idpAlias, aue.getIdentityProvider()));
@ -481,25 +481,25 @@ public class MapFieldPredicates {
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapRealmEntity<Object>, RealmModel> checkRealmsWithComponentType(MapModelCriteriaBuilder<Object, MapRealmEntity<Object>, RealmModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapRealmEntity, RealmModel> checkRealmsWithComponentType(MapModelCriteriaBuilder<Object, MapRealmEntity, RealmModel> mcb, Operator op, Object[] values) {
String providerType = ensureEqSingleValue(RealmModel.SearchableFields.COMPONENT_PROVIDER_TYPE, "component_provider_type", op, values);
Function<MapRealmEntity<Object>, ?> getter = realmEntity -> realmEntity.getComponents().anyMatch(component -> component.getProviderType().equals(providerType));
Function<MapRealmEntity, ?> getter = realmEntity -> realmEntity.getComponents().anyMatch(component -> component.getProviderType().equals(providerType));
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
private static MapModelCriteriaBuilder<Object, MapUserSessionEntity<Object>, UserSessionModel> checkUserSessionContainsAuthenticatedClientSession(MapModelCriteriaBuilder<Object, MapUserSessionEntity<Object>, UserSessionModel> mcb, Operator op, Object[] values) {
private static MapModelCriteriaBuilder<Object, MapUserSessionEntity, UserSessionModel> checkUserSessionContainsAuthenticatedClientSession(MapModelCriteriaBuilder<Object, MapUserSessionEntity, UserSessionModel> mcb, Operator op, Object[] values) {
String clientId = ensureEqSingleValue(UserSessionModel.SearchableFields.CLIENT_ID, "client_id", op, values);
Function<MapUserSessionEntity<Object>, ?> getter = use -> (use.getAuthenticatedClientSessions().containsKey(clientId));
Function<MapUserSessionEntity, ?> getter = use -> (use.getAuthenticatedClientSessions().containsKey(clientId));
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
}
protected static <K, V extends AbstractEntity<K>, M> Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> basePredicates(SearchableModelField<M> idField) {
protected static <K, V extends AbstractEntity, M> Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> basePredicates(SearchableModelField<M> idField) {
Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates = new HashMap<>();
fieldPredicates.put(idField, MapModelCriteriaBuilder::idCompare);
return fieldPredicates;
}
public static <K, V extends AbstractEntity<K>, M> Comparator<V> getComparator(QueryParameters.OrderBy<M> orderBy) {
public static <K, V extends AbstractEntity, M> Comparator<V> getComparator(QueryParameters.OrderBy<M> orderBy) {
SearchableModelField<M> searchableModelField = orderBy.getModelField();
QueryParameters.Order order = orderBy.getOrder();
@ -518,14 +518,14 @@ public class MapFieldPredicates {
}
@SuppressWarnings("unchecked")
public static <K, V extends AbstractEntity<K>, M> Comparator<V> getComparator(Stream<QueryParameters.OrderBy<M>> ordering) {
public static <K, V extends AbstractEntity, M> Comparator<V> getComparator(Stream<QueryParameters.OrderBy<M>> ordering) {
return (Comparator<V>) ordering.map(MapFieldPredicates::getComparator)
.reduce(Comparator::thenComparing)
.orElseThrow(() -> new IllegalArgumentException("Cannot create comparator for " + ordering));
}
@SuppressWarnings("unchecked")
public static <K, V extends AbstractEntity<K>, M> Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> getPredicates(Class<M> clazz) {
public static <K, V extends AbstractEntity, M> Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> getPredicates(Class<M> clazz) {
return PREDICATES.get(clazz);
}
}

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.models.map.storage.chm;
import org.keycloak.models.map.common.StringKeyConvertor;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.storage.SearchableModelField;
import java.util.Map;
@ -23,15 +24,18 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
*
* @author hmlnarik
*/
public class MapModelCriteriaBuilder<K, V extends AbstractEntity<K>, M> implements ModelCriteriaBuilder<M> {
public class MapModelCriteriaBuilder<K, V extends AbstractEntity, M> implements ModelCriteriaBuilder<M> {
@FunctionalInterface
public static interface UpdatePredicatesFunc<K, V extends AbstractEntity<K>, M> {
public static interface UpdatePredicatesFunc<K, V extends AbstractEntity, M> {
MapModelCriteriaBuilder<K, V, M> apply(MapModelCriteriaBuilder<K, V, M> builder, Operator op, Object[] params);
}
@ -40,12 +44,14 @@ public class MapModelCriteriaBuilder<K, V extends AbstractEntity<K>, M> implemen
private final Predicate<? super K> keyFilter;
private final Predicate<? super V> entityFilter;
private final Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates;
private final StringKeyConvertor<K> keyConvertor;
public MapModelCriteriaBuilder(Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates) {
this(fieldPredicates, ALWAYS_TRUE, ALWAYS_TRUE);
public MapModelCriteriaBuilder(StringKeyConvertor<K> keyConvertor, Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates) {
this(keyConvertor, fieldPredicates, ALWAYS_TRUE, ALWAYS_TRUE);
}
private MapModelCriteriaBuilder(Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates, Predicate<? super K> indexReadFilter, Predicate<? super V> sequentialReadFilter) {
private MapModelCriteriaBuilder(StringKeyConvertor<K> keyConvertor, Map<SearchableModelField<M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates, Predicate<? super K> indexReadFilter, Predicate<? super V> sequentialReadFilter) {
this.keyConvertor = keyConvertor;
this.fieldPredicates = fieldPredicates;
this.keyFilter = indexReadFilter;
this.entityFilter = sequentialReadFilter;
@ -67,7 +73,7 @@ public class MapModelCriteriaBuilder<K, V extends AbstractEntity<K>, M> implemen
public final MapModelCriteriaBuilder<K, V, M> and(ModelCriteriaBuilder<M>... builders) {
Predicate<? super K> resIndexFilter = Stream.of(builders).map(MapModelCriteriaBuilder.class::cast).map(MapModelCriteriaBuilder::getKeyFilter).reduce(keyFilter, Predicate::and);
Predicate<V> resEntityFilter = Stream.of(builders).map(MapModelCriteriaBuilder.class::cast).map(MapModelCriteriaBuilder::getEntityFilter).reduce(entityFilter, Predicate::and);
return new MapModelCriteriaBuilder<>(fieldPredicates, resIndexFilter, resEntityFilter);
return new MapModelCriteriaBuilder<>(keyConvertor, fieldPredicates, resIndexFilter, resEntityFilter);
}
@SafeVarargs
@ -77,6 +83,7 @@ public class MapModelCriteriaBuilder<K, V extends AbstractEntity<K>, M> implemen
Predicate<? super K> resIndexFilter = Stream.of(builders).map(MapModelCriteriaBuilder.class::cast).map(MapModelCriteriaBuilder::getKeyFilter).reduce(ALWAYS_FALSE, Predicate::or);
Predicate<V> resEntityFilter = Stream.of(builders).map(MapModelCriteriaBuilder.class::cast).map(MapModelCriteriaBuilder::getEntityFilter).reduce(ALWAYS_FALSE, Predicate::or);
return new MapModelCriteriaBuilder<>(
keyConvertor,
fieldPredicates,
v -> keyFilter.test(v) && resIndexFilter.test(v),
v -> entityFilter.test(v) && resEntityFilter.test(v)
@ -94,6 +101,7 @@ public class MapModelCriteriaBuilder<K, V extends AbstractEntity<K>, M> implemen
Predicate<? super V> resEntityFilter = b.getEntityFilter() == ALWAYS_TRUE ? ALWAYS_TRUE : b.getEntityFilter().negate();
return new MapModelCriteriaBuilder<>(
keyConvertor,
fieldPredicates,
v -> keyFilter.test(v) && resIndexFilter.test(v),
v -> entityFilter.test(v) && resEntityFilter.test(v)
@ -109,7 +117,7 @@ public class MapModelCriteriaBuilder<K, V extends AbstractEntity<K>, M> implemen
}
protected MapModelCriteriaBuilder<K, V, M> idCompare(Operator op, Object[] values) {
Object[] convertedValues = convertValuesToKeyType(values);
switch (op) {
case LT:
case LE:
@ -120,12 +128,35 @@ public class MapModelCriteriaBuilder<K, V extends AbstractEntity<K>, M> implemen
case EXISTS:
case NOT_EXISTS:
case IN:
return new MapModelCriteriaBuilder<>(fieldPredicates, this.keyFilter.and(CriteriaOperator.predicateFor(op, values)), this.entityFilter);
return new MapModelCriteriaBuilder<>(keyConvertor, fieldPredicates, this.keyFilter.and(CriteriaOperator.predicateFor(op, convertedValues)), this.entityFilter);
default:
throw new AssertionError("Invalid operator: " + op);
}
}
protected Object[] convertValuesToKeyType(Object[] values) {
if (values == null) {
return null;
}
Object[] res = new Object[values.length];
for (int i = 0; i < values.length; i ++) {
Object v = values[i];
if (v instanceof String) {
res[i] = keyConvertor.fromStringSafe((String) v);
} else if (v instanceof Stream) {
res[i] = ((Stream<?>) v).map(o -> (o instanceof String) ? keyConvertor.fromStringSafe((String) o) : o);
} else if (v instanceof Collection) {
res[i] = ((List<?>) v).stream().map(o -> (o instanceof String) ? keyConvertor.fromStringSafe((String) o) : o).collect(Collectors.toList());
} else if (v == null) {
res[i] = null;
} else {
throw new IllegalArgumentException("Unknown type: " + v);
}
}
return res;
}
protected MapModelCriteriaBuilder<K, V, M> fieldCompare(Operator op, Function<V, ?> getter, Object[] values) {
Predicate<Object> valueComparator = CriteriaOperator.predicateFor(op, values);
return fieldCompare(valueComparator, getter);
@ -139,6 +170,6 @@ public class MapModelCriteriaBuilder<K, V extends AbstractEntity<K>, M> implemen
final Predicate<V> p = v -> valueComparator.test(getter.apply(v));
resEntityFilter = p.and(entityFilter);
}
return new MapModelCriteriaBuilder<>(fieldPredicates, this.keyFilter, resEntityFilter);
return new MapModelCriteriaBuilder<>(keyConvertor, fieldPredicates, this.keyFilter, resEntityFilter);
}
}

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.models.map.storage.chm;
import org.keycloak.models.map.common.StringKeyConvertor;
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserSessionModel;
@ -24,7 +25,6 @@ import org.keycloak.models.map.storage.MapKeycloakTransaction;
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
import org.keycloak.models.map.storage.QueryParameters;
import org.keycloak.models.map.storage.StringKeyConvertor;
import org.keycloak.models.map.userSession.MapAuthenticatedClientSessionEntity;
import org.keycloak.models.map.userSession.MapUserSessionEntity;
import java.util.Set;
@ -38,31 +38,29 @@ import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
*
* @author hmlnarik
*/
public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapStorage<K, MapUserSessionEntity<K>, UserSessionModel> {
public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapStorage<K, MapUserSessionEntity, UserSessionModel> {
private final ConcurrentHashMapStorage<K, MapAuthenticatedClientSessionEntity<K>, AuthenticatedClientSessionModel> clientSessionStore;
private final ConcurrentHashMapStorage<K, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionStore;
private class Transaction extends ConcurrentHashMapKeycloakTransaction<K, MapUserSessionEntity<K>, UserSessionModel> {
private class Transaction extends ConcurrentHashMapKeycloakTransaction<K, MapUserSessionEntity, UserSessionModel> {
private final MapKeycloakTransaction<K, MapAuthenticatedClientSessionEntity<K>, AuthenticatedClientSessionModel> clientSessionTr;
private final MapKeycloakTransaction<K, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionTr;
public Transaction(MapKeycloakTransaction<K, MapAuthenticatedClientSessionEntity<K>, AuthenticatedClientSessionModel> clientSessionTr) {
super(UserSessionConcurrentHashMapStorage.this);
public Transaction(MapKeycloakTransaction<K, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionTr, StringKeyConvertor<K> keyConvertor) {
super(UserSessionConcurrentHashMapStorage.this, keyConvertor);
this.clientSessionTr = clientSessionTr;
}
@Override
public long delete(QueryParameters<UserSessionModel> queryParameters) {
ModelCriteriaBuilder<UserSessionModel> mcb = queryParameters.getModelCriteriaBuilder();
Set<K> ids = read(queryParameters).map(AbstractEntity::getId).collect(Collectors.toSet());
Set<String> ids = read(queryParameters).map(AbstractEntity::getId).collect(Collectors.toSet());
ModelCriteriaBuilder<AuthenticatedClientSessionModel> csMcb = clientSessionStore.createCriteriaBuilder().compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.IN, ids);
clientSessionTr.delete(withCriteria(csMcb));
return super.delete(queryParameters);
}
@Override
public boolean delete(K key) {
public boolean delete(String key) {
ModelCriteriaBuilder<AuthenticatedClientSessionModel> csMcb = clientSessionStore.createCriteriaBuilder().compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.EQ, key);
clientSessionTr.delete(withCriteria(csMcb));
return super.delete(key);
@ -71,7 +69,7 @@ public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapSto
}
@SuppressWarnings("unchecked")
public UserSessionConcurrentHashMapStorage(ConcurrentHashMapStorage<K, MapAuthenticatedClientSessionEntity<K>, AuthenticatedClientSessionModel> clientSessionStore,
public UserSessionConcurrentHashMapStorage(ConcurrentHashMapStorage<K, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionStore,
StringKeyConvertor<K> keyConvertor) {
super(UserSessionModel.class, keyConvertor);
this.clientSessionStore = clientSessionStore;
@ -79,8 +77,8 @@ public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapSto
@Override
@SuppressWarnings("unchecked")
public MapKeycloakTransaction<K, MapUserSessionEntity<K>, UserSessionModel> createTransaction(KeycloakSession session) {
MapKeycloakTransaction<K, MapUserSessionEntity<K>, UserSessionModel> sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
return sessionTransaction == null ? new Transaction(clientSessionStore.createTransaction(session)) : sessionTransaction;
public MapKeycloakTransaction<K, MapUserSessionEntity, UserSessionModel> createTransaction(KeycloakSession session) {
MapKeycloakTransaction<K, MapUserSessionEntity, UserSessionModel> sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
return sessionTransaction == null ? new Transaction(clientSessionStore.createTransaction(session), clientSessionStore.getKeyConvertor()) : sessionTransaction;
}
}

View file

@ -36,11 +36,16 @@ import java.util.Optional;
import java.util.stream.Stream;
public abstract class MapUserAdapter<K> extends AbstractUserModel<MapUserEntity<K>> {
public MapUserAdapter(KeycloakSession session, RealmModel realm, MapUserEntity<K> entity) {
public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
public MapUserAdapter(KeycloakSession session, RealmModel realm, MapUserEntity entity) {
super(session, realm, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getUsername() {
return entity.getUsername();

View file

@ -40,9 +40,9 @@ import java.util.stream.Stream;
*
* @author mhajas
*/
public class MapUserEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapUserEntity implements AbstractEntity, UpdatableEntity {
private final K id;
private final String id;
private final String realmId;
private String username;
@ -76,8 +76,7 @@ public class MapUserEntity<K> implements AbstractEntity<K>, UpdatableEntity {
this.realmId = null;
}
public MapUserEntity(K id, String realmId) {
Objects.requireNonNull(id, "id");
public MapUserEntity(String id, String realmId) {
Objects.requireNonNull(realmId, "realmId");
this.id = id;
@ -85,7 +84,7 @@ public class MapUserEntity<K> implements AbstractEntity<K>, UpdatableEntity {
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -76,24 +76,19 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
private static final Logger LOG = Logger.getLogger(MapUserProvider.class);
private final KeycloakSession session;
final MapKeycloakTransaction<K, MapUserEntity<K>, UserModel> tx;
private final MapStorage<K, MapUserEntity<K>, UserModel> userStore;
final MapKeycloakTransaction<K, MapUserEntity, UserModel> tx;
private final MapStorage<K, MapUserEntity, UserModel> userStore;
public MapUserProvider(KeycloakSession session, MapStorage<K, MapUserEntity<K>, UserModel> store) {
public MapUserProvider(KeycloakSession session, MapStorage<K, MapUserEntity, UserModel> store) {
this.session = session;
this.userStore = store;
this.tx = userStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
private Function<MapUserEntity<K>, UserModel> entityToAdapterFunc(RealmModel realm) {
private Function<MapUserEntity, UserModel> entityToAdapterFunc(RealmModel realm) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return origEntity -> new MapUserAdapter<K>(session, realm, origEntity) {
@Override
public String getId() {
return userStore.getKeyConvertor().keyToString(entity.getId());
}
return origEntity -> new MapUserAdapter(session, realm, origEntity) {
@Override
public boolean checkEmailUniqueness(RealmModel realm, String email) {
return getUserByEmail(realm, email) != null;
@ -106,7 +101,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
};
}
private Predicate<MapUserEntity<K>> entityRealmFilter(RealmModel realm) {
private Predicate<MapUserEntity> entityRealmFilter(RealmModel realm) {
if (realm == null || realm.getId() == null) {
return c -> false;
}
@ -118,26 +113,26 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
return new ModelException("Specified user doesn't exist.");
}
private Optional<MapUserEntity<K>> getEntityById(RealmModel realm, String id) {
private Optional<MapUserEntity> getEntityById(RealmModel realm, String id) {
try {
return getEntityById(realm, userStore.getKeyConvertor().fromString(id));
MapUserEntity mapUserEntity = tx.read(id);
if (mapUserEntity != null && entityRealmFilter(realm).test(mapUserEntity)) {
return Optional.of(mapUserEntity);
}
return Optional.empty();
} catch (IllegalArgumentException ex) {
return Optional.empty();
}
}
private MapUserEntity<K> getEntityByIdOrThrow(RealmModel realm, String id) {
private MapUserEntity getEntityByIdOrThrow(RealmModel realm, String id) {
return getEntityById(realm, id)
.orElseThrow(this::userDoesntExistException);
}
private Optional<MapUserEntity<K>> getEntityById(RealmModel realm, K id) {
MapUserEntity<K> mapUserEntity = tx.read(id);
if (mapUserEntity != null && entityRealmFilter(realm).test(mapUserEntity)) {
return Optional.of(mapUserEntity);
}
return Optional.empty();
private Optional<MapUserEntity> getRegisteredEntityById(RealmModel realm, String id) {
return getEntityById(realm, id);
}
@Override
@ -248,7 +243,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
public void updateConsent(RealmModel realm, String userId, UserConsentModel consent) {
LOG.tracef("updateConsent(%s, %s, %s)%s", realm, userId, consent, getShortStackTrace());
MapUserEntity<K> user = getEntityByIdOrThrow(realm, userId);
MapUserEntity user = getEntityByIdOrThrow(realm, userId);
UserConsentEntity userConsentEntity = user.getUserConsent(consent.getClient().getId());
if (userConsentEntity == null) {
throw new ModelException("Consent not found for client [" + consent.getClient().getId() + "] and user [" + userId + "]");
@ -319,13 +314,11 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
throw new ModelDuplicateException("User with username '" + username + "' in realm " + realm.getName() + " already exists" );
}
final K entityId = id == null ? userStore.getKeyConvertor().yieldNewUniqueKey() : userStore.getKeyConvertor().fromString(id);
if (tx.read(entityId) != null) {
throw new ModelDuplicateException("User exists: " + entityId);
if (tx.read(id) != null) {
throw new ModelDuplicateException("User exists: " + id);
}
MapUserEntity<K> entity = new MapUserEntity<>(entityId, realm.getId());
MapUserEntity entity = new MapUserEntity(id, realm.getId());
entity.setUsername(username.toLowerCase());
entity.setCreatedTimestamp(Time.currentTimeMillis());
@ -376,7 +369,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.FEDERATION_LINK, Operator.EQ, storageProviderId);
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
s.forEach(userEntity -> userEntity.setFederationLink(null));
}
}
@ -389,7 +382,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.ASSIGNED_ROLE, Operator.EQ, roleId);
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
s.forEach(userEntity -> userEntity.removeRolesMembership(roleId));
}
}
@ -402,7 +395,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.ASSIGNED_GROUP, Operator.EQ, groupId);
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
s.forEach(userEntity -> userEntity.removeGroupsMembership(groupId));
}
}
@ -415,7 +408,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.CONSENT_FOR_CLIENT, Operator.EQ, clientId);
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
s.forEach(userEntity -> userEntity.removeUserConsent(clientId));
}
}
@ -434,7 +427,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.compare(SearchableFields.REALM_ID, Operator.EQ, clientScope.getRealm().getId())
.compare(SearchableFields.CONSENT_WITH_CLIENT_SCOPE, Operator.EQ, clientScopeId);
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
s.flatMap(MapUserEntity::getUserConsents)
.forEach(consent -> consent.removeGrantedClientScopesIds(clientScopeId));
}
@ -452,14 +445,14 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.CONSENT_CLIENT_FEDERATION_LINK, Operator.EQ, componentId);
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
String providerIdS = new StorageId(componentId, "").getId();
s.forEach(removeConsentsForExternalClient(providerIdS));
}
}
}
private Consumer<MapUserEntity<K>> removeConsentsForExternalClient(String idPrefix) {
private Consumer<MapUserEntity> removeConsentsForExternalClient(String idPrefix) {
return userEntity -> {
List<String> consentClientIds = userEntity.getUserConsents()
.map(UserConsentEntity::getClientId)
@ -479,7 +472,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
ModelCriteriaBuilder<UserModel> mcb = userStore.createCriteriaBuilder()
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
s.forEach(entity -> entity.addRolesMembership(roleId));
}
}
@ -498,7 +491,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.USERNAME, Operator.ILIKE, username);
try (Stream<MapUserEntity<K>> s = tx.read(withCriteria(mcb))) {
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
return s.findFirst()
.map(entityToAdapterFunc(realm)).orElse(null);
}
@ -511,7 +504,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(SearchableFields.EMAIL, Operator.EQ, email);
List<MapUserEntity<K>> usersWithEmail = tx.read(withCriteria(mcb))
List<MapUserEntity> usersWithEmail = tx.read(withCriteria(mcb))
.filter(userEntity -> Objects.equals(userEntity.getEmail(), email))
.collect(Collectors.toList());
if (usersWithEmail.isEmpty()) return null;
@ -522,7 +515,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
throw new ModelDuplicateException("Multiple users with email '" + email + "' exist in Keycloak.");
}
MapUserEntity<K> userEntity = usersWithEmail.get(0);
MapUserEntity userEntity = usersWithEmail.get(0);
if (!realm.isDuplicateEmailsAllowed()) {
if (userEntity.getEmail() != null && !userEntity.getEmail().equals(userEntity.getEmailConstraint())) {
@ -709,9 +702,9 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
String userId = user.getId();
Optional<MapUserEntity<K>> userById = getEntityById(realm, userId);
Optional<MapUserEntity> userById = getEntityById(realm, userId);
if (userById.isPresent()) {
tx.delete(userStore.getKeyConvertor().fromString(userId));
tx.delete(userId);
return true;
}
@ -735,7 +728,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
.ifPresent(updateCredential(cred));
}
private Consumer<MapUserEntity<K>> updateCredential(CredentialModel credentialModel) {
private Consumer<MapUserEntity> updateCredential(CredentialModel credentialModel) {
return user -> {
UserCredentialEntity credentialEntity = user.getCredential(credentialModel.getId());
if (credentialEntity == null) return;
@ -804,7 +797,7 @@ public class MapUserProvider<K> implements UserProvider.Streams, UserCredentialS
public boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId) {
LOG.tracef("moveCredentialTo(%s, %s, %s, %s)%s", realm, user.getId(), id, newPreviousCredentialId, getShortStackTrace());
String userId = user.getId();
MapUserEntity<K> userEntity = getEntityById(realm, userId).orElse(null);
MapUserEntity userEntity = getEntityById(realm, userId).orElse(null);
if (userEntity == null) {
LOG.warnf("User with id: [%s] not found", userId);
return false;

View file

@ -27,7 +27,7 @@ import org.keycloak.models.map.common.AbstractMapProviderFactory;
*
* @author mhajas
*/
public class MapUserProviderFactory<K> extends AbstractMapProviderFactory<UserProvider, K, MapUserEntity<K>, UserModel> implements UserProviderFactory {
public class MapUserProviderFactory<K> extends AbstractMapProviderFactory<UserProvider, K, MapUserEntity, UserModel> implements UserProviderFactory {
public MapUserProviderFactory() {
super(UserModel.class);

View file

@ -28,15 +28,15 @@ import java.util.Objects;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public abstract class AbstractAuthenticatedClientSessionModel<K> implements AuthenticatedClientSessionModel {
public abstract class AbstractAuthenticatedClientSessionModel implements AuthenticatedClientSessionModel {
protected final KeycloakSession session;
protected final RealmModel realm;
protected ClientModel client;
protected UserSessionModel userSession;
protected final MapAuthenticatedClientSessionEntity<K> entity;
protected final MapAuthenticatedClientSessionEntity entity;
public AbstractAuthenticatedClientSessionModel(KeycloakSession session, RealmModel realm, ClientModel client,
UserSessionModel userSession, MapAuthenticatedClientSessionEntity<K> entity) {
UserSessionModel userSession, MapAuthenticatedClientSessionEntity entity) {
Objects.requireNonNull(entity, "entity");
Objects.requireNonNull(realm, "realm");
Objects.requireNonNull(client, "client");

View file

@ -29,9 +29,9 @@ import java.util.Objects;
public abstract class AbstractUserSessionModel<K> implements UserSessionModel {
protected final KeycloakSession session;
protected final RealmModel realm;
protected final MapUserSessionEntity<K> entity;
protected final MapUserSessionEntity entity;
public AbstractUserSessionModel(KeycloakSession session, RealmModel realm, MapUserSessionEntity<K> entity) {
public AbstractUserSessionModel(KeycloakSession session, RealmModel realm, MapUserSessionEntity entity) {
Objects.requireNonNull(entity, "entity");
Objects.requireNonNull(realm, "realm");

View file

@ -26,13 +26,18 @@ import java.util.Map;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public abstract class MapAuthenticatedClientSessionAdapter<K> extends AbstractAuthenticatedClientSessionModel<K> {
public abstract class MapAuthenticatedClientSessionAdapter extends AbstractAuthenticatedClientSessionModel {
public MapAuthenticatedClientSessionAdapter(KeycloakSession session, RealmModel realm, ClientModel client,
UserSessionModel userSession, MapAuthenticatedClientSessionEntity<K> entity) {
UserSessionModel userSession, MapAuthenticatedClientSessionEntity entity) {
super(session, realm, client, userSession, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public int getTimestamp() {
return entity.getTimestamp();

View file

@ -27,9 +27,9 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public class MapAuthenticatedClientSessionEntity<K> implements AbstractEntity<K>, UpdatableEntity {
public class MapAuthenticatedClientSessionEntity implements AbstractEntity, UpdatableEntity {
private K id;
private String id;
private String userSessionId;
private String realmId;
private String clientId;
@ -57,8 +57,7 @@ public class MapAuthenticatedClientSessionEntity<K> implements AbstractEntity<K>
this.realmId = null;
}
public MapAuthenticatedClientSessionEntity(K id, String userSessionId, String realmId, String clientId, boolean offline) {
Objects.requireNonNull(id, "id");
public MapAuthenticatedClientSessionEntity(String id, String userSessionId, String realmId, String clientId, boolean offline) {
Objects.requireNonNull(userSessionId, "userSessionId");
Objects.requireNonNull(realmId, "realmId");
Objects.requireNonNull(clientId, "clientId");
@ -72,7 +71,7 @@ public class MapAuthenticatedClientSessionEntity<K> implements AbstractEntity<K>
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -30,18 +30,22 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public abstract class MapUserSessionAdapter<K> extends AbstractUserSessionModel<K> {
public abstract class MapUserSessionAdapter extends AbstractUserSessionModel {
public MapUserSessionAdapter(KeycloakSession session, RealmModel realm, MapUserSessionEntity<K> entity) {
public MapUserSessionAdapter(KeycloakSession session, RealmModel realm, MapUserSessionEntity entity) {
super(session, realm, entity);
}
@Override
public String getId() {
return entity.getId();
}
@Override
public RealmModel getRealm() {
return realm;

View file

@ -30,8 +30,8 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
public class MapUserSessionEntity<K> implements AbstractEntity<K>, UpdatableEntity {
private K id;
public class MapUserSessionEntity implements AbstractEntity, UpdatableEntity {
private String id;
private String realmId;
@ -74,15 +74,14 @@ public class MapUserSessionEntity<K> implements AbstractEntity<K>, UpdatableEnti
this.realmId = null;
}
public MapUserSessionEntity(K id, String realmId) {
Objects.requireNonNull(id, "id");
public MapUserSessionEntity(String id, String realmId) {
Objects.requireNonNull(realmId, "realmId");
this.id = id;
this.realmId = realmId;
}
public MapUserSessionEntity(K id, RealmModel realm, UserModel user, String loginUsername, String ipAddress,
public MapUserSessionEntity(String id, RealmModel realm, UserModel user, String loginUsername, String ipAddress,
String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId,
boolean offline) {
this.id = id;
@ -100,7 +99,7 @@ public class MapUserSessionEntity<K> implements AbstractEntity<K>, UpdatableEnti
}
@Override
public K getId() {
public String getId() {
return this.id;
}

View file

@ -57,18 +57,18 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
private static final Logger LOG = Logger.getLogger(MapUserSessionProvider.class);
private final KeycloakSession session;
protected final MapKeycloakTransaction<UK, MapUserSessionEntity<UK>, UserSessionModel> userSessionTx;
protected final MapKeycloakTransaction<CK, MapAuthenticatedClientSessionEntity<CK>, AuthenticatedClientSessionModel> clientSessionTx;
private final MapStorage<UK, MapUserSessionEntity<UK>, UserSessionModel> userSessionStore;
private final MapStorage<CK, MapAuthenticatedClientSessionEntity<CK>, AuthenticatedClientSessionModel> clientSessionStore;
protected final MapKeycloakTransaction<UK, MapUserSessionEntity, UserSessionModel> userSessionTx;
protected final MapKeycloakTransaction<CK, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionTx;
private final MapStorage<UK, MapUserSessionEntity, UserSessionModel> userSessionStore;
private final MapStorage<CK, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionStore;
/**
* Storage for transient user sessions which lifespan is limited to one request.
*/
private final Map<UK, MapUserSessionEntity<UK>> transientUserSessions = new HashMap<>();
private final Map<String, MapUserSessionEntity> transientUserSessions = new HashMap<>();
public MapUserSessionProvider(KeycloakSession session, MapStorage<UK, MapUserSessionEntity<UK>, UserSessionModel> userSessionStore,
MapStorage<CK, MapAuthenticatedClientSessionEntity<CK>, AuthenticatedClientSessionModel> clientSessionStore) {
public MapUserSessionProvider(KeycloakSession session, MapStorage<UK, MapUserSessionEntity, UserSessionModel> userSessionStore,
MapStorage<CK, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionStore) {
this.session = session;
this.userSessionStore = userSessionStore;
this.clientSessionStore = clientSessionStore;
@ -79,7 +79,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
session.getTransactionManager().enlistAfterCompletion(clientSessionTx);
}
private Function<MapUserSessionEntity<UK>, UserSessionModel> userEntityToAdapterFunc(RealmModel realm) {
private Function<MapUserSessionEntity, UserSessionModel> userEntityToAdapterFunc(RealmModel realm) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
return (origEntity) -> {
if (origEntity.getExpiration() <= Time.currentTime()) {
@ -89,12 +89,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
userSessionTx.delete(origEntity.getId());
return null;
} else {
return new MapUserSessionAdapter<UK>(session, realm, origEntity) {
@Override
public String getId() {
return userSessionStore.getKeyConvertor().keyToString(entity.getId());
}
return new MapUserSessionAdapter(session, realm, origEntity) {
@Override
public void removeAuthenticatedClientSessions(Collection<String> removedClientUKS) {
removedClientUKS.forEach(entity::removeAuthenticatedClientSession);
@ -111,7 +106,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
};
}
private Function<MapAuthenticatedClientSessionEntity<CK>, AuthenticatedClientSessionModel> clientEntityToAdapterFunc(RealmModel realm,
private Function<MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientEntityToAdapterFunc(RealmModel realm,
ClientModel client,
UserSessionModel userSession) {
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
@ -121,12 +116,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
clientSessionTx.delete(origEntity.getId());
return null;
} else {
return new MapAuthenticatedClientSessionAdapter<CK>(session, realm, client, userSession, origEntity) {
@Override
public String getId() {
return clientSessionStore.getKeyConvertor().keyToString(entity.getId());
}
return new MapAuthenticatedClientSessionAdapter(session, realm, client, userSession, origEntity) {
@Override
public void detachFromUserSession() {
this.userSession = null;
@ -152,8 +142,8 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
@Override
public AuthenticatedClientSessionModel createClientSession(RealmModel realm, ClientModel client, UserSessionModel userSession) {
MapAuthenticatedClientSessionEntity<CK> entity =
new MapAuthenticatedClientSessionEntity<>(clientSessionStore.getKeyConvertor().yieldNewUniqueKey(), userSession.getId(), realm.getId(), client.getId(), false);
MapAuthenticatedClientSessionEntity entity =
new MapAuthenticatedClientSessionEntity(null, userSession.getId(), realm.getId(), client.getId(), false);
entity.getNotes().put(AuthenticatedClientSessionModel.STARTED_AT_NOTE, String.valueOf(entity.getTimestamp()));
setClientSessionExpiration(entity, realm, client);
@ -161,13 +151,13 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
entity = clientSessionTx.create(entity);
MapUserSessionEntity<UK> userSessionEntity = getUserSessionById(userSessionStore.getKeyConvertor().fromString(userSession.getId()));
MapUserSessionEntity userSessionEntity = getUserSessionById(userSession.getId());
if (userSessionEntity == null) {
throw new IllegalStateException("User session entity does not exist: " + userSession.getId());
}
userSessionEntity.addAuthenticatedClientSession(client.getId(), clientSessionStore.getKeyConvertor().keyToString(entity.getId()));
userSessionEntity.addAuthenticatedClientSession(client.getId(), entity.getId());
return clientEntityToAdapterFunc(realm, client, userSession).apply(entity);
}
@ -184,9 +174,8 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
return null;
}
CK ck = clientSessionStore.getKeyConvertor().fromStringSafe(clientSessionId);
ModelCriteriaBuilder<AuthenticatedClientSessionModel> mcb = clientSessionStore.createCriteriaBuilder()
.compare(AuthenticatedClientSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, ck)
.compare(AuthenticatedClientSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, clientSessionId)
.compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, ModelCriteriaBuilder.Operator.EQ, userSession.getId())
.compare(AuthenticatedClientSessionModel.SearchableFields.REALM_ID, ModelCriteriaBuilder.Operator.EQ, userSession.getRealm().getId())
.compare(AuthenticatedClientSessionModel.SearchableFields.CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, client.getId())
@ -209,16 +198,14 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
public UserSessionModel createUserSession(String id, RealmModel realm, UserModel user, String loginUsername,
String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId,
String brokerUserId, UserSessionModel.SessionPersistenceState persistenceState) {
final UK entityId = id == null ? userSessionStore.getKeyConvertor().yieldNewUniqueKey(): userSessionStore.getKeyConvertor().fromString(id);
LOG.tracef("createUserSession(%s, %s, %s, %s)%s", id, realm, loginUsername, persistenceState, getShortStackTrace());
MapUserSessionEntity<UK> entity = new MapUserSessionEntity<>(entityId, realm, user, loginUsername, ipAddress, authMethod, rememberMe, brokerSessionId, brokerUserId, false);
MapUserSessionEntity entity = new MapUserSessionEntity(id, realm, user, loginUsername, ipAddress, authMethod, rememberMe, brokerSessionId, brokerUserId, false);
entity.setPersistenceState(persistenceState);
setUserSessionExpiration(entity, realm);
if (Objects.equals(persistenceState, TRANSIENT)) {
transientUserSessions.put(entityId, entity);
transientUserSessions.put(entity.getId(), entity);
} else {
if (userSessionTx.read(entity.getId()) != null) {
throw new ModelDuplicateException("User session exists: " + entity.getId());
@ -242,18 +229,13 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
LOG.tracef("getUserSession(%s, %s)%s", realm, id, getShortStackTrace());
UK uuid = userSessionStore.getKeyConvertor().fromStringSafe(id);
if (uuid == null) {
return null;
}
MapUserSessionEntity<UK> userSessionEntity = transientUserSessions.get(uuid);
MapUserSessionEntity userSessionEntity = transientUserSessions.get(id);
if (userSessionEntity != null) {
return userEntityToAdapterFunc(realm).apply(userSessionEntity);
}
ModelCriteriaBuilder<UserSessionModel> mcb = realmAndOfflineCriteriaBuilder(realm, false)
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uuid);
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, id);
return userSessionTx.read(withCriteria(mcb))
.findFirst()
@ -374,9 +356,8 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
public void removeUserSession(RealmModel realm, UserSessionModel session) {
Objects.requireNonNull(session, "The provided user session can't be null!");
UK uk = userSessionStore.getKeyConvertor().fromString(session.getId());
ModelCriteriaBuilder<UserSessionModel> mcb = realmAndOfflineCriteriaBuilder(realm, false)
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uk);
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, session.getId());
LOG.tracef("removeUserSession(%s, %s)%s", realm, session, getShortStackTrace());
@ -429,7 +410,7 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
public UserSessionModel createOfflineUserSession(UserSessionModel userSession) {
LOG.tracef("createOfflineUserSession(%s)%s", userSession, getShortStackTrace());
MapUserSessionEntity<UK> offlineUserSession = createUserSessionEntityInstance(userSession, true);
MapUserSessionEntity offlineUserSession = createUserSessionEntityInstance(userSession, true);
// set a reference for the offline user session to the original online user session
userSession.setNote(CORRESPONDING_SESSION_ID, offlineUserSession.getId().toString());
@ -462,9 +443,9 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
ModelCriteriaBuilder<UserSessionModel> mcb;
if (userSession.isOffline()) {
userSessionTx.delete(userSessionStore.getKeyConvertor().fromString(userSession.getId()));
userSessionTx.delete(userSession.getId());
} else if (userSession.getNote(CORRESPONDING_SESSION_ID) != null) {
UK uk = userSessionStore.getKeyConvertor().fromString(userSession.getNote(CORRESPONDING_SESSION_ID));
String uk = userSession.getNote(CORRESPONDING_SESSION_ID);
mcb = realmAndOfflineCriteriaBuilder(realm, true)
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uk);
userSessionTx.delete(withCriteria(mcb));
@ -477,15 +458,15 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
UserSessionModel offlineUserSession) {
LOG.tracef("createOfflineClientSession(%s, %s)%s", clientSession, offlineUserSession, getShortStackTrace());
MapAuthenticatedClientSessionEntity<CK> clientSessionEntity = createAuthenticatedClientSessionInstance(clientSession, offlineUserSession, true);
MapAuthenticatedClientSessionEntity clientSessionEntity = createAuthenticatedClientSessionInstance(clientSession, offlineUserSession, true);
int currentTime = Time.currentTime();
clientSessionEntity.getNotes().put(AuthenticatedClientSessionModel.STARTED_AT_NOTE, String.valueOf(currentTime));
clientSessionEntity.setTimestamp(currentTime);
setClientSessionExpiration(clientSessionEntity, clientSession.getRealm(), clientSession.getClient());
Optional<MapUserSessionEntity<UK>> userSessionEntity = getOfflineUserSessionEntityStream(clientSession.getRealm(), offlineUserSession.getId()).findFirst();
Optional<MapUserSessionEntity> userSessionEntity = getOfflineUserSessionEntityStream(clientSession.getRealm(), offlineUserSession.getId()).findFirst();
if (userSessionEntity.isPresent()) {
userSessionEntity.get().addAuthenticatedClientSession(clientSession.getClient().getId(), clientSessionStore.getKeyConvertor().keyToString(clientSessionEntity.getId()));
userSessionEntity.get().addAuthenticatedClientSession(clientSession.getClient().getId(), clientSessionEntity.getId());
}
clientSessionEntity = clientSessionTx.create(clientSessionEntity);
@ -563,17 +544,17 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
persistentUserSessions.stream()
.map(pus -> {
MapUserSessionEntity<UK> userSessionEntity = new MapUserSessionEntity<UK>(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), pus.getRealm(), pus.getUser(),
MapUserSessionEntity userSessionEntity = new MapUserSessionEntity(null, pus.getRealm(), pus.getUser(),
pus.getLoginUsername(), pus.getIpAddress(), pus.getAuthMethod(),
pus.isRememberMe(), pus.getBrokerSessionId(), pus.getBrokerUserId(), offline);
for (Map.Entry<String, AuthenticatedClientSessionModel> entry : pus.getAuthenticatedClientSessions().entrySet()) {
MapAuthenticatedClientSessionEntity<CK> clientSession = createAuthenticatedClientSessionInstance(entry.getValue(), entry.getValue().getUserSession(), offline);
MapAuthenticatedClientSessionEntity clientSession = createAuthenticatedClientSessionInstance(entry.getValue(), entry.getValue().getUserSession(), offline);
// Update timestamp to same value as userSession. LastSessionRefresh of userSession from DB will have correct value
clientSession.setTimestamp(userSessionEntity.getLastSessionRefresh());
userSessionEntity.addAuthenticatedClientSession(entry.getKey(), clientSessionStore.getKeyConvertor().keyToString(clientSession.getId()));
userSessionEntity.addAuthenticatedClientSession(entry.getKey(), clientSession.getId());
clientSession = clientSessionTx.create(clientSession);
}
@ -588,19 +569,18 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
}
private Stream<MapUserSessionEntity<UK>> getOfflineUserSessionEntityStream(RealmModel realm, String userSessionId) {
UK uuid = userSessionStore.getKeyConvertor().fromStringSafe(userSessionId);
if (uuid == null) {
private Stream<MapUserSessionEntity> getOfflineUserSessionEntityStream(RealmModel realm, String userSessionId) {
if (userSessionId == null) {
return Stream.empty();
}
// first get a user entity by ID
ModelCriteriaBuilder<UserSessionModel> mcb = userSessionStore.createCriteriaBuilder()
.compare(UserSessionModel.SearchableFields.REALM_ID, ModelCriteriaBuilder.Operator.EQ, realm.getId())
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uuid);
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, userSessionId);
// check if it's an offline user session
MapUserSessionEntity<UK> userSessionEntity = userSessionTx.read(withCriteria(mcb)).findFirst().orElse(null);
MapUserSessionEntity userSessionEntity = userSessionTx.read(withCriteria(mcb)).findFirst().orElse(null);
if (userSessionEntity != null) {
if (userSessionEntity.isOffline()) {
return Stream.of(userSessionEntity);
@ -615,9 +595,8 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
// it's online user session so lookup offline user session by corresponding session id reference
String offlineUserSessionId = userSessionEntity.getNote(CORRESPONDING_SESSION_ID);
if (offlineUserSessionId != null) {
UK uk = userSessionStore.getKeyConvertor().fromStringSafe(offlineUserSessionId);
mcb = realmAndOfflineCriteriaBuilder(realm, true)
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, uk);
.compare(UserSessionModel.SearchableFields.ID, ModelCriteriaBuilder.Operator.EQ, offlineUserSessionId);
return userSessionTx.read(withCriteria(mcb));
}
@ -630,18 +609,18 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
.compare(UserSessionModel.SearchableFields.IS_OFFLINE, ModelCriteriaBuilder.Operator.EQ, offline);
}
private MapUserSessionEntity<UK> getUserSessionById(UK id) {
MapUserSessionEntity<UK> userSessionEntity = transientUserSessions.get(id);
private MapUserSessionEntity getUserSessionById(String id) {
MapUserSessionEntity userSessionEntity = transientUserSessions.get(id);
if (userSessionEntity == null) {
MapUserSessionEntity<UK> userSession = userSessionTx.read(id);
MapUserSessionEntity userSession = userSessionTx.read(id);
return userSession;
}
return userSessionEntity;
}
private MapUserSessionEntity<UK> createUserSessionEntityInstance(UserSessionModel userSession, boolean offline) {
MapUserSessionEntity<UK> entity = new MapUserSessionEntity<UK>(userSessionStore.getKeyConvertor().yieldNewUniqueKey(), userSession.getRealm().getId());
private MapUserSessionEntity createUserSessionEntityInstance(UserSessionModel userSession, boolean offline) {
MapUserSessionEntity entity = new MapUserSessionEntity(null, userSession.getRealm().getId());
entity.setAuthMethod(userSession.getAuthMethod());
entity.setBrokerSessionId(userSession.getBrokerSessionId());
@ -663,9 +642,9 @@ public class MapUserSessionProvider<UK, CK> implements UserSessionProvider {
return entity;
}
private MapAuthenticatedClientSessionEntity<CK> createAuthenticatedClientSessionInstance(AuthenticatedClientSessionModel clientSession,
private MapAuthenticatedClientSessionEntity createAuthenticatedClientSessionInstance(AuthenticatedClientSessionModel clientSession,
UserSessionModel userSession, boolean offline) {
MapAuthenticatedClientSessionEntity<CK> entity = new MapAuthenticatedClientSessionEntity<CK>(clientSessionStore.getKeyConvertor().yieldNewUniqueKey(),
MapAuthenticatedClientSessionEntity entity = new MapAuthenticatedClientSessionEntity(null,
userSession.getId(), clientSession.getRealm().getId(), clientSession.getClient().getId(), offline);
entity.setAction(clientSession.getAction());

View file

@ -26,7 +26,7 @@ import org.keycloak.protocol.oidc.OIDCConfigAttributes;
*/
public class SessionExpiration {
public static <K> void setClientSessionExpiration(MapAuthenticatedClientSessionEntity<K> entity, RealmModel realm, ClientModel client) {
public static <K> void setClientSessionExpiration(MapAuthenticatedClientSessionEntity entity, RealmModel realm, ClientModel client) {
if (entity.isOffline()) {
long sessionExpires = entity.getTimestamp() + realm.getOfflineSessionIdleTimeout();
if (realm.isOfflineSessionMaxLifespanEnabled()) {
@ -99,7 +99,7 @@ public class SessionExpiration {
}
}
public static <K> void setUserSessionExpiration(MapUserSessionEntity<K> entity, RealmModel realm) {
public static <K> void setUserSessionExpiration(MapUserSessionEntity entity, RealmModel realm) {
if (entity.isOffline()) {
long sessionExpires = entity.getLastSessionRefresh() + realm.getOfflineSessionIdleTimeout();
if (realm.isOfflineSessionMaxLifespanEnabled()) {

View file

@ -28,11 +28,11 @@ import java.util.stream.Collectors;
public class AbstractUserEntityCredentialsOrderTest {
private MapUserEntity<Integer> user;
private MapUserEntity user;
@Before
public void init() {
user = new MapUserEntity<Integer>(1, "realmId") {};
user = new MapUserEntity("1", "realmId");
for (int i = 1; i <= 5; i++) {
UserCredentialEntity credentialModel = new UserCredentialEntity();

View file

@ -29,7 +29,7 @@ import org.keycloak.models.map.client.MapClientProviderFactory;
import org.keycloak.models.map.storage.MapStorage;
import org.keycloak.models.map.storage.MapStorageProvider;
import org.keycloak.models.map.storage.MapStorageProviderFactory;
import org.keycloak.models.map.storage.StringKeyConvertor;
import org.keycloak.models.map.common.StringKeyConvertor;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.InvalidationHandler.ObjectType;
import org.hamcrest.Matchers;
@ -81,10 +81,10 @@ public class MapStorageTest extends KeycloakModelTest {
String component1Id = createMapStorageComponent("component1", "keyType", "ulong");
String component2Id = createMapStorageComponent("component2", "keyType", "string");
Object[] ids = withRealm(realmId, (session, realm) -> {
MapStorage<K, MapClientEntity<K>, ClientModel> storageMain = (MapStorage) session.getProvider(MapStorageProvider.class).getStorage(ClientModel.class);
MapStorage<K1, MapClientEntity<K1>, ClientModel> storage1 = (MapStorage) session.getComponentProvider(MapStorageProvider.class, component1Id).getStorage(ClientModel.class);
MapStorage<K2, MapClientEntity<K2>, ClientModel> storage2 = (MapStorage) session.getComponentProvider(MapStorageProvider.class, component2Id).getStorage(ClientModel.class);
String[] ids = withRealm(realmId, (session, realm) -> {
MapStorage<K, MapClientEntity, ClientModel> storageMain = (MapStorage) session.getProvider(MapStorageProvider.class).getStorage(ClientModel.class);
MapStorage<K1, MapClientEntity, ClientModel> storage1 = (MapStorage) session.getComponentProvider(MapStorageProvider.class, component1Id).getStorage(ClientModel.class);
MapStorage<K2, MapClientEntity, ClientModel> storage2 = (MapStorage) session.getComponentProvider(MapStorageProvider.class, component2Id).getStorage(ClientModel.class);
// Assert that the map storage can be used both as a standalone store and a component
assertThat(storageMain, notNullValue());
@ -95,9 +95,9 @@ public class MapStorageTest extends KeycloakModelTest {
final StringKeyConvertor<K1> kc1 = storage1.getKeyConvertor();
final StringKeyConvertor<K2> kc2 = storage2.getKeyConvertor();
K idMain = kcMain.yieldNewUniqueKey();
K1 id1 = kc1.yieldNewUniqueKey();
K2 id2 = kc2.yieldNewUniqueKey();
String idMain = kcMain.keyToString(kcMain.yieldNewUniqueKey());
String id1 = kc1.keyToString(kc1.yieldNewUniqueKey());
String id2 = kc2.keyToString(kc2.yieldNewUniqueKey());
assertThat(idMain, notNullValue());
assertThat(id1, notNullValue());
@ -115,20 +115,20 @@ public class MapStorageTest extends KeycloakModelTest {
assertClientDoesNotExist(storage2, idMain, kcMain, kc2);
assertClientDoesNotExist(storage2, id1, kc1, kc2);
MapClientEntity<K> clientMain = new MapClientEntityImpl<>(idMain, realmId);
MapClientEntity<K1> client1 = new MapClientEntityImpl<>(id1, realmId);
MapClientEntity<K2> client2 = new MapClientEntityImpl<>(id2, realmId);
MapClientEntity clientMain = new MapClientEntityImpl<>(idMain, realmId);
MapClientEntity client1 = new MapClientEntityImpl<>(id1, realmId);
MapClientEntity client2 = new MapClientEntityImpl<>(id2, realmId);
storageMain.create(clientMain);
storage1.create(client1);
storage2.create(client2);
clientMain = storageMain.create(clientMain);
client1 = storage1.create(client1);
client2 = storage2.create(client2);
return new Object[] {idMain, id1, id2};
return new String[] {clientMain.getId(), client1.getId(), client2.getId()};
});
K idMain = (K) ids[0];
K1 id1 = (K1) ids[1];
K2 id2 = (K2) ids[2];
String idMain = ids[0];
String id1 = ids[1];
String id2 = ids[2];
LOG.debugf("Object IDs: %s, %s, %s", idMain, id1, id2);
@ -147,25 +147,24 @@ public class MapStorageTest extends KeycloakModelTest {
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
}
private <K,K1> void assertClientDoesNotExist(MapStorage<K, MapClientEntity<K>, ClientModel> storage, K1 id, final StringKeyConvertor<K1> kc, final StringKeyConvertor<K> kcStorage) {
private <K,K1> void assertClientDoesNotExist(MapStorage<K, MapClientEntity, ClientModel> storage, String id, final StringKeyConvertor<K1> kc, final StringKeyConvertor<K> kcStorage) {
// Assert that the other stores do not contain the to-be-created clients (if they use compatible key format)
try {
final K keyInStorageFormat = kcStorage.fromString(kc.keyToString(id));
assertThat(storage.read(keyInStorageFormat), nullValue());
assertThat(storage.read(id), nullValue());
} catch (Exception ex) {
// If the format is incompatible then the object does not exist in the store
}
}
private <K, K1, K2> void assertClientsPersisted(String component1Id, String component2Id, K idMain, K1 id1, K2 id2) {
private <K, K1, K2> void assertClientsPersisted(String component1Id, String component2Id, String idMain, String id1, String id2) {
// Check that in the next transaction, the objects are still there
withRealm(realmId, (session, realm) -> {
@SuppressWarnings("unchecked")
MapStorage<K, MapClientEntity<K>, ClientModel> storageMain = (MapStorage) session.getProvider(MapStorageProvider.class).getStorage(ClientModel.class);
MapStorage<K, MapClientEntity, ClientModel> storageMain = (MapStorage) session.getProvider(MapStorageProvider.class).getStorage(ClientModel.class);
@SuppressWarnings("unchecked")
MapStorage<K1, MapClientEntity<K1>, ClientModel> storage1 = (MapStorage) session.getComponentProvider(MapStorageProvider.class, component1Id).getStorage(ClientModel.class);
MapStorage<K1, MapClientEntity, ClientModel> storage1 = (MapStorage) session.getComponentProvider(MapStorageProvider.class, component1Id).getStorage(ClientModel.class);
@SuppressWarnings("unchecked")
MapStorage<K2, MapClientEntity<K2>, ClientModel> storage2 = (MapStorage) session.getComponentProvider(MapStorageProvider.class, component2Id).getStorage(ClientModel.class);
MapStorage<K2, MapClientEntity, ClientModel> storage2 = (MapStorage) session.getComponentProvider(MapStorageProvider.class, component2Id).getStorage(ClientModel.class);
final StringKeyConvertor<K> kcMain = storageMain.getKeyConvertor();
final StringKeyConvertor<K1> kc1 = storage1.getKeyConvertor();