keycloak-aplcache
Changes
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java 4(+2 -2)
Details
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
index 14f4c0f..2207153 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
@@ -54,7 +54,7 @@ public class ClientAdapter implements ClientModel {
private void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerClientInvalidation(cached.getId(), cached.getClientId(), cachedRealm.getId());
- updated = cacheSession.getDelegate().getClientById(cached.getId(), cachedRealm);
+ updated = cacheSession.getRealmDelegate().getClientById(cached.getId(), cachedRealm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
}
@@ -66,7 +66,7 @@ public class ClientAdapter implements ClientModel {
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
- updated = cacheSession.getDelegate().getClientById(cached.getId(), cachedRealm);
+ updated = cacheSession.getRealmDelegate().getClientById(cached.getId(), cachedRealm);
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java
index a521ef2..4d2ce42 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java
@@ -50,7 +50,7 @@ public class ClientTemplateAdapter implements ClientTemplateModel {
private void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerClientTemplateInvalidation(cached.getId());
- updated = cacheSession.getDelegate().getClientTemplateById(cached.getId(), cachedRealm);
+ updated = cacheSession.getRealmDelegate().getClientTemplateById(cached.getId(), cachedRealm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
}
@@ -63,7 +63,7 @@ public class ClientTemplateAdapter implements ClientTemplateModel {
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
- updated = cacheSession.getDelegate().getClientTemplateById(cached.getId(), cachedRealm);
+ updated = cacheSession.getRealmDelegate().getClientTemplateById(cached.getId(), cachedRealm);
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java
index 21bcc66..0e69c68 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java
@@ -51,7 +51,7 @@ public class GroupAdapter implements GroupModel {
protected void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerGroupInvalidation(cached.getId());
- updated = cacheSession.getDelegate().getGroupById(cached.getId(), realm);
+ updated = cacheSession.getRealmDelegate().getGroupById(cached.getId(), realm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
}
@@ -64,7 +64,7 @@ public class GroupAdapter implements GroupModel {
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
- updated = cacheSession.getDelegate().getGroupById(cached.getId(), realm);
+ updated = cacheSession.getRealmDelegate().getGroupById(cached.getId(), realm);
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
index bfa00e0..b80bbe3 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
@@ -49,7 +49,7 @@ public class RealmAdapter implements CachedRealmModel {
public RealmModel getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerRealmInvalidation(cached.getId(), cached.getName());
- updated = cacheSession.getDelegate().getRealm(cached.getId());
+ updated = cacheSession.getRealmDelegate().getRealm(cached.getId());
if (updated == null) throw new IllegalStateException("Not found in database");
}
return updated;
@@ -81,7 +81,7 @@ public class RealmAdapter implements CachedRealmModel {
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
- updated = cacheSession.getDelegate().getRealm(cached.getId());
+ updated = cacheSession.getRealmDelegate().getRealm(cached.getId());
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
index 83bafb1..6ab385c 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
@@ -94,7 +94,8 @@ public class RealmCacheSession implements CacheRealmProvider {
public static final String ROLES_QUERY_SUFFIX = ".roles";
protected RealmCacheManager cache;
protected KeycloakSession session;
- protected RealmProvider delegate;
+ protected RealmProvider realmDelegate;
+ protected ClientProvider clientDelegate;
protected boolean transactionActive;
protected boolean setRollbackOnly;
@@ -134,16 +135,25 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public MigrationModel getMigrationModel() {
- return getDelegate().getMigrationModel();
+ return getRealmDelegate().getMigrationModel();
}
@Override
- public RealmProvider getDelegate() {
+ public RealmProvider getRealmDelegate() {
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
- if (delegate != null) return delegate;
- delegate = session.getProvider(RealmProvider.class);
- return delegate;
+ if (realmDelegate != null) return realmDelegate;
+ realmDelegate = session.realmLocalStorage();
+ return realmDelegate;
}
+ public ClientProvider getClientDelegate() {
+ if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
+ if (clientDelegate != null) return clientDelegate;
+ clientDelegate = session.clientStorageManager();
+ return clientDelegate;
+ }
+
+
+
@Override
public void registerRealmInvalidation(String id, String name) {
@@ -319,7 +329,7 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public void commit() {
try {
- if (delegate == null) return;
+ if (realmDelegate == null) return;
if (clearAll) {
cache.clear();
}
@@ -360,14 +370,14 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public RealmModel createRealm(String name) {
- RealmModel realm = getDelegate().createRealm(name);
+ RealmModel realm = getRealmDelegate().createRealm(name);
registerRealmInvalidation(realm.getId(), realm.getName());
return realm;
}
@Override
public RealmModel createRealm(String id, String name) {
- RealmModel realm = getDelegate().createRealm(id, name);
+ RealmModel realm = getRealmDelegate().createRealm(id, name);
registerRealmInvalidation(realm.getId(), realm.getName());
return realm;
}
@@ -381,14 +391,14 @@ public class RealmCacheSession implements CacheRealmProvider {
boolean wasCached = false;
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
- RealmModel model = getDelegate().getRealm(id);
+ RealmModel model = getRealmDelegate().getRealm(id);
if (model == null) return null;
if (invalidations.contains(id)) return model;
cached = new CachedRealm(loaded, model);
cache.addRevisioned(cached, startupRevision);
wasCached =true;
} else if (invalidations.contains(id)) {
- return getDelegate().getRealm(id);
+ return getRealmDelegate().getRealm(id);
} else if (managedRealms.containsKey(id)) {
return managedRealms.get(id);
}
@@ -420,18 +430,18 @@ public class RealmCacheSession implements CacheRealmProvider {
}
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- RealmModel model = getDelegate().getRealmByName(name);
+ RealmModel model = getRealmDelegate().getRealmByName(name);
if (model == null) return null;
if (invalidations.contains(model.getId())) return model;
query = new RealmListQuery(loaded, cacheKey, model.getId());
cache.addRevisioned(query, startupRevision);
return model;
} else if (invalidations.contains(cacheKey)) {
- return getDelegate().getRealmByName(name);
+ return getRealmDelegate().getRealmByName(name);
} else {
String realmId = query.getRealms().iterator().next();
if (invalidations.contains(realmId)) {
- return getDelegate().getRealmByName(name);
+ return getRealmDelegate().getRealmByName(name);
}
return getRealm(realmId);
}
@@ -444,7 +454,7 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public List<RealmModel> getRealms() {
// Retrieve realms from backend
- List<RealmModel> backendRealms = getDelegate().getRealms();
+ List<RealmModel> backendRealms = getRealmDelegate().getRealms();
// Return cache delegates to ensure cache invalidated during write operations
List<RealmModel> cachedRealms = new LinkedList<RealmModel>();
@@ -463,19 +473,19 @@ public class RealmCacheSession implements CacheRealmProvider {
cache.invalidateObject(id);
invalidationEvents.add(RealmRemovedEvent.create(id, realm.getName()));
cache.realmRemoval(id, realm.getName(), invalidations);
- return getDelegate().removeRealm(id);
+ return getRealmDelegate().removeRealm(id);
}
@Override
public ClientModel addClient(RealmModel realm, String clientId) {
- ClientModel client = getDelegate().addClient(realm, clientId);
+ ClientModel client = getClientDelegate().addClient(realm, clientId);
return addedClient(realm, client);
}
@Override
public ClientModel addClient(RealmModel realm, String id, String clientId) {
- ClientModel client = getDelegate().addClient(realm, id, clientId);
+ ClientModel client = getClientDelegate().addClient(realm, id, clientId);
return addedClient(realm, client);
}
@@ -515,7 +525,7 @@ public class RealmCacheSession implements CacheRealmProvider {
String cacheKey = getRealmClientsQueryCacheKey(realm.getId());
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
if (queryDB) {
- return getDelegate().getClients(realm);
+ return getClientDelegate().getClients(realm);
}
ClientListQuery query = cache.get(cacheKey, ClientListQuery.class);
@@ -525,7 +535,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- List<ClientModel> model = getDelegate().getClients(realm);
+ List<ClientModel> model = getClientDelegate().getClients(realm);
if (model == null) return null;
Set<String> ids = new HashSet<>();
for (ClientModel client : model) ids.add(client.getId());
@@ -540,7 +550,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (client == null) {
// TODO: Handle with cluster invalidations too
invalidations.add(cacheKey);
- return getDelegate().getClients(realm);
+ return getClientDelegate().getClients(realm);
}
list.add(client);
}
@@ -563,13 +573,14 @@ public class RealmCacheSession implements CacheRealmProvider {
for (RoleModel role : client.getRoles()) {
roleRemovalInvalidations(role.getId(), role.getName(), client.getId());
}
- return getDelegate().removeClient(id, realm);
+ return getClientDelegate().removeClient(id, realm);
}
@Override
public void close() {
- if (delegate != null) delegate.close();
+ if (realmDelegate != null) realmDelegate.close();
+ if (clientDelegate != null) clientDelegate.close();
}
@Override
@@ -579,7 +590,7 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public RoleModel addRealmRole(RealmModel realm, String id, String name) {
- RoleModel role = getDelegate().addRealmRole(realm, id, name);
+ RoleModel role = getRealmDelegate().addRealmRole(realm, id, name);
addedRole(role.getId(), realm.getId());
return role;
}
@@ -589,7 +600,7 @@ public class RealmCacheSession implements CacheRealmProvider {
String cacheKey = getRolesCacheKey(realm.getId());
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
if (queryDB) {
- return getDelegate().getRealmRoles(realm);
+ return getRealmDelegate().getRealmRoles(realm);
}
RoleListQuery query = cache.get(cacheKey, RoleListQuery.class);
@@ -599,7 +610,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- Set<RoleModel> model = getDelegate().getRealmRoles(realm);
+ Set<RoleModel> model = getRealmDelegate().getRealmRoles(realm);
if (model == null) return null;
Set<String> ids = new HashSet<>();
for (RoleModel role : model) ids.add(role.getId());
@@ -613,7 +624,7 @@ public class RealmCacheSession implements CacheRealmProvider {
RoleModel role = session.realms().getRoleById(id, realm);
if (role == null) {
invalidations.add(cacheKey);
- return getDelegate().getRealmRoles(realm);
+ return getRealmDelegate().getRealmRoles(realm);
}
list.add(role);
}
@@ -625,7 +636,7 @@ public class RealmCacheSession implements CacheRealmProvider {
String cacheKey = getRolesCacheKey(client.getId());
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(client.getId());
if (queryDB) {
- return getDelegate().getClientRoles(realm, client);
+ return getClientDelegate().getClientRoles(realm, client);
}
RoleListQuery query = cache.get(cacheKey, RoleListQuery.class);
@@ -635,7 +646,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- Set<RoleModel> model = getDelegate().getClientRoles(realm, client);
+ Set<RoleModel> model = getClientDelegate().getClientRoles(realm, client);
if (model == null) return null;
Set<String> ids = new HashSet<>();
for (RoleModel role : model) ids.add(role.getId());
@@ -649,7 +660,7 @@ public class RealmCacheSession implements CacheRealmProvider {
RoleModel role = session.realms().getRoleById(id, realm);
if (role == null) {
invalidations.add(cacheKey);
- return getDelegate().getClientRoles(realm, client);
+ return getClientDelegate().getClientRoles(realm, client);
}
list.add(role);
}
@@ -663,7 +674,7 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name) {
- RoleModel role = getDelegate().addClientRole(realm, client, id, name);
+ RoleModel role = getClientDelegate().addClientRole(realm, client, id, name);
addedRole(role.getId(), client.getId());
return role;
}
@@ -673,7 +684,7 @@ public class RealmCacheSession implements CacheRealmProvider {
String cacheKey = getRoleByNameCacheKey(realm.getId(), name);
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
if (queryDB) {
- return getDelegate().getRealmRole(realm, name);
+ return getRealmDelegate().getRealmRole(realm, name);
}
RoleListQuery query = cache.get(cacheKey, RoleListQuery.class);
@@ -683,7 +694,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- RoleModel model = getDelegate().getRealmRole(realm, name);
+ RoleModel model = getRealmDelegate().getRealmRole(realm, name);
if (model == null) return null;
query = new RoleListQuery(loaded, cacheKey, realm, model.getId());
logger.tracev("adding realm role cache miss: client {0} key {1}", realm.getName(), cacheKey);
@@ -693,7 +704,7 @@ public class RealmCacheSession implements CacheRealmProvider {
RoleModel role = getRoleById(query.getRoles().iterator().next(), realm);
if (role == null) {
invalidations.add(cacheKey);
- return getDelegate().getRealmRole(realm, name);
+ return getRealmDelegate().getRealmRole(realm, name);
}
return role;
}
@@ -703,7 +714,7 @@ public class RealmCacheSession implements CacheRealmProvider {
String cacheKey = getRoleByNameCacheKey(client.getId(), name);
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(client.getId());
if (queryDB) {
- return getDelegate().getClientRole(realm, client, name);
+ return getClientDelegate().getClientRole(realm, client, name);
}
RoleListQuery query = cache.get(cacheKey, RoleListQuery.class);
@@ -713,7 +724,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- RoleModel model = getDelegate().getClientRole(realm, client, name);
+ RoleModel model = getClientDelegate().getClientRole(realm, client, name);
if (model == null) return null;
query = new RoleListQuery(loaded, cacheKey, realm, model.getId(), client.getClientId());
logger.tracev("adding client role cache miss: client {0} key {1}", client.getClientId(), cacheKey);
@@ -723,7 +734,7 @@ public class RealmCacheSession implements CacheRealmProvider {
RoleModel role = getRoleById(query.getRoles().iterator().next(), realm);
if (role == null) {
invalidations.add(cacheKey);
- return getDelegate().getClientRole(realm, client, name);
+ return getClientDelegate().getClientRole(realm, client, name);
}
return role;
}
@@ -736,7 +747,7 @@ public class RealmCacheSession implements CacheRealmProvider {
invalidationEvents.add(RoleRemovedEvent.create(role.getId(), role.getName(), role.getContainer().getId()));
roleRemovalInvalidations(role.getId(), role.getName(), role.getContainer().getId());
- return getDelegate().removeRole(realm, role);
+ return getRealmDelegate().removeRole(realm, role);
}
@Override
@@ -748,7 +759,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
- RoleModel model = getDelegate().getRoleById(id, realm);
+ RoleModel model = getRealmDelegate().getRoleById(id, realm);
if (model == null) return null;
if (invalidations.contains(id)) return model;
if (model.isClientRole()) {
@@ -759,7 +770,7 @@ public class RealmCacheSession implements CacheRealmProvider {
cache.addRevisioned(cached, startupRevision);
} else if (invalidations.contains(id)) {
- return getDelegate().getRoleById(id, realm);
+ return getRealmDelegate().getRoleById(id, realm);
} else if (managedRoles.containsKey(id)) {
return managedRoles.get(id);
}
@@ -777,14 +788,14 @@ public class RealmCacheSession implements CacheRealmProvider {
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
- GroupModel model = getDelegate().getGroupById(id, realm);
+ GroupModel model = getRealmDelegate().getGroupById(id, realm);
if (model == null) return null;
if (invalidations.contains(id)) return model;
cached = new CachedGroup(loaded, realm, model);
cache.addRevisioned(cached, startupRevision);
} else if (invalidations.contains(id)) {
- return getDelegate().getGroupById(id, realm);
+ return getRealmDelegate().getGroupById(id, realm);
} else if (managedGroups.containsKey(id)) {
return managedGroups.get(id);
}
@@ -800,7 +811,7 @@ public class RealmCacheSession implements CacheRealmProvider {
listInvalidations.add(realm.getId());
invalidationEvents.add(GroupMovedEvent.create(group, toParent, realm.getId()));
- getDelegate().moveGroup(realm, group, toParent);
+ getRealmDelegate().moveGroup(realm, group, toParent);
}
@Override
@@ -808,7 +819,7 @@ public class RealmCacheSession implements CacheRealmProvider {
String cacheKey = getGroupsQueryCacheKey(realm.getId());
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
if (queryDB) {
- return getDelegate().getGroups(realm);
+ return getRealmDelegate().getGroups(realm);
}
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
@@ -818,7 +829,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- List<GroupModel> model = getDelegate().getGroups(realm);
+ List<GroupModel> model = getRealmDelegate().getGroups(realm);
if (model == null) return null;
Set<String> ids = new HashSet<>();
for (GroupModel client : model) ids.add(client.getId());
@@ -832,7 +843,7 @@ public class RealmCacheSession implements CacheRealmProvider {
GroupModel group = session.realms().getGroupById(id, realm);
if (group == null) {
invalidations.add(cacheKey);
- return getDelegate().getGroups(realm);
+ return getRealmDelegate().getGroups(realm);
}
list.add(group);
}
@@ -844,12 +855,12 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public Long getGroupsCount(RealmModel realm, Boolean onlyTopGroups) {
- return getDelegate().getGroupsCount(realm, onlyTopGroups);
+ return getRealmDelegate().getGroupsCount(realm, onlyTopGroups);
}
@Override
public Long getGroupsCountByNameContaining(RealmModel realm, String search) {
- return getDelegate().getGroupsCountByNameContaining(realm, search);
+ return getRealmDelegate().getGroupsCountByNameContaining(realm, search);
}
@Override
@@ -857,7 +868,7 @@ public class RealmCacheSession implements CacheRealmProvider {
String cacheKey = getTopGroupsQueryCacheKey(realm.getId());
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
if (queryDB) {
- return getDelegate().getTopLevelGroups(realm);
+ return getRealmDelegate().getTopLevelGroups(realm);
}
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
@@ -867,7 +878,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- List<GroupModel> model = getDelegate().getTopLevelGroups(realm);
+ List<GroupModel> model = getRealmDelegate().getTopLevelGroups(realm);
if (model == null) return null;
Set<String> ids = new HashSet<>();
for (GroupModel client : model) ids.add(client.getId());
@@ -881,7 +892,7 @@ public class RealmCacheSession implements CacheRealmProvider {
GroupModel group = session.realms().getGroupById(id, realm);
if (group == null) {
invalidations.add(cacheKey);
- return getDelegate().getTopLevelGroups(realm);
+ return getRealmDelegate().getTopLevelGroups(realm);
}
list.add(group);
}
@@ -896,7 +907,7 @@ public class RealmCacheSession implements CacheRealmProvider {
String cacheKey = getTopGroupsQueryCacheKey(realm.getId() + first + max);
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId() + first + max);
if (queryDB) {
- return getDelegate().getTopLevelGroups(realm, first, max);
+ return getRealmDelegate().getTopLevelGroups(realm, first, max);
}
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
@@ -906,7 +917,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (Objects.isNull(query)) {
Long loaded = cache.getCurrentRevision(cacheKey);
- List<GroupModel> model = getDelegate().getTopLevelGroups(realm, first, max);
+ List<GroupModel> model = getRealmDelegate().getTopLevelGroups(realm, first, max);
if (model == null) return null;
Set<String> ids = new HashSet<>();
for (GroupModel client : model) ids.add(client.getId());
@@ -920,7 +931,7 @@ public class RealmCacheSession implements CacheRealmProvider {
GroupModel group = session.realms().getGroupById(id, realm);
if (Objects.isNull(group)) {
invalidations.add(cacheKey);
- return getDelegate().getTopLevelGroups(realm);
+ return getRealmDelegate().getTopLevelGroups(realm);
}
list.add(group);
}
@@ -932,7 +943,7 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public List<GroupModel> searchForGroupByName(RealmModel realm, String search, Integer first, Integer max) {
- return getDelegate().searchForGroupByName(realm, search, first, max);
+ return getRealmDelegate().searchForGroupByName(realm, search, first, max);
}
@Override
@@ -946,12 +957,12 @@ public class RealmCacheSession implements CacheRealmProvider {
invalidationEvents.add(GroupRemovedEvent.create(group, realm.getId()));
- return getDelegate().removeGroup(realm, group);
+ return getRealmDelegate().removeGroup(realm, group);
}
@Override
public GroupModel createGroup(RealmModel realm, String name) {
- GroupModel group = getDelegate().createGroup(realm, name);
+ GroupModel group = getRealmDelegate().createGroup(realm, name);
return groupAdded(realm, group);
}
@@ -965,7 +976,7 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public GroupModel createGroup(RealmModel realm, String id, String name) {
- GroupModel group = getDelegate().createGroup(realm, id, name);
+ GroupModel group = getRealmDelegate().createGroup(realm, id, name);
return groupAdded(realm, group);
}
@@ -978,7 +989,7 @@ public class RealmCacheSession implements CacheRealmProvider {
addGroupEventIfAbsent(GroupMovedEvent.create(subGroup, null, realm.getId()));
- getDelegate().addTopLevelGroup(realm, subGroup);
+ getRealmDelegate().addTopLevelGroup(realm, subGroup);
}
@@ -1007,14 +1018,14 @@ public class RealmCacheSession implements CacheRealmProvider {
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
- ClientModel model = getDelegate().getClientById(id, realm);
+ ClientModel model = getClientDelegate().getClientById(id, realm);
if (model == null) return null;
if (invalidations.contains(id)) return model;
cached = new CachedClient(loaded, realm, model);
logger.tracev("adding client by id cache miss: {0}", cached.getClientId());
cache.addRevisioned(cached, startupRevision);
} else if (invalidations.contains(id)) {
- return getDelegate().getClientById(id, realm);
+ return getClientDelegate().getClientById(id, realm);
} else if (managedApplications.containsKey(id)) {
return managedApplications.get(id);
}
@@ -1035,7 +1046,7 @@ public class RealmCacheSession implements CacheRealmProvider {
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
- ClientModel model = getDelegate().getClientByClientId(clientId, realm);
+ ClientModel model = getClientDelegate().getClientByClientId(clientId, realm);
if (model == null) return null;
if (invalidations.contains(model.getId())) return model;
id = model.getId();
@@ -1043,11 +1054,11 @@ public class RealmCacheSession implements CacheRealmProvider {
logger.tracev("adding client by name cache miss: {0}", clientId);
cache.addRevisioned(query, startupRevision);
} else if (invalidations.contains(cacheKey)) {
- return getDelegate().getClientByClientId(clientId, realm);
+ return getClientDelegate().getClientByClientId(clientId, realm);
} else {
id = query.getClients().iterator().next();
if (invalidations.contains(id)) {
- return getDelegate().getClientByClientId(clientId, realm);
+ return getClientDelegate().getClientByClientId(clientId, realm);
}
}
return getClientById(id, realm);
@@ -1066,13 +1077,13 @@ public class RealmCacheSession implements CacheRealmProvider {
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
- ClientTemplateModel model = getDelegate().getClientTemplateById(id, realm);
+ ClientTemplateModel model = getRealmDelegate().getClientTemplateById(id, realm);
if (model == null) return null;
if (invalidations.contains(id)) return model;
cached = new CachedClientTemplate(loaded, realm, model);
cache.addRevisioned(cached, startupRevision);
} else if (invalidations.contains(id)) {
- return getDelegate().getClientTemplateById(id, realm);
+ return getRealmDelegate().getClientTemplateById(id, realm);
} else if (managedClientTemplates.containsKey(id)) {
return managedClientTemplates.get(id);
}
@@ -1084,31 +1095,31 @@ public class RealmCacheSession implements CacheRealmProvider {
// Don't cache ClientInitialAccessModel for now
@Override
public ClientInitialAccessModel createClientInitialAccessModel(RealmModel realm, int expiration, int count) {
- return getDelegate().createClientInitialAccessModel(realm, expiration, count);
+ return getRealmDelegate().createClientInitialAccessModel(realm, expiration, count);
}
@Override
public ClientInitialAccessModel getClientInitialAccessModel(RealmModel realm, String id) {
- return getDelegate().getClientInitialAccessModel(realm, id);
+ return getRealmDelegate().getClientInitialAccessModel(realm, id);
}
@Override
public void removeClientInitialAccessModel(RealmModel realm, String id) {
- getDelegate().removeClientInitialAccessModel(realm, id);
+ getRealmDelegate().removeClientInitialAccessModel(realm, id);
}
@Override
public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) {
- return getDelegate().listClientInitialAccess(realm);
+ return getRealmDelegate().listClientInitialAccess(realm);
}
@Override
public void removeExpiredClientInitialAccess() {
- getDelegate().removeExpiredClientInitialAccess();
+ getRealmDelegate().removeExpiredClientInitialAccess();
}
@Override
public void decreaseRemainingCount(RealmModel realm, ClientInitialAccessModel clientInitialAccess) {
- getDelegate().decreaseRemainingCount(realm, clientInitialAccess);
+ getRealmDelegate().decreaseRemainingCount(realm, clientInitialAccess);
}
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
index 00e41f3..24ed6d9 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
@@ -49,7 +49,7 @@ public class RoleAdapter implements RoleModel {
protected void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerRoleInvalidation(cached.getId(), cached.getName(), getContainerId());
- updated = cacheSession.getDelegate().getRoleById(cached.getId(), realm);
+ updated = cacheSession.getRealmDelegate().getRoleById(cached.getId(), realm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
}
@@ -62,7 +62,7 @@ public class RoleAdapter implements RoleModel {
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
- updated = cacheSession.getDelegate().getRoleById(cached.getId(), realm);
+ updated = cacheSession.getRealmDelegate().getRoleById(cached.getId(), realm);
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
diff --git a/server-spi/src/main/java/org/keycloak/models/ClientProvider.java b/server-spi/src/main/java/org/keycloak/models/ClientProvider.java
new file mode 100644
index 0000000..b999485
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/ClientProvider.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.storage.client.ClientLookupProvider;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ClientProvider extends ClientLookupProvider, Provider {
+ ClientModel addClient(RealmModel realm, String clientId);
+
+ ClientModel addClient(RealmModel realm, String id, String clientId);
+
+ List<ClientModel> getClients(RealmModel realm);
+
+ RoleModel addClientRole(RealmModel realm, ClientModel client, String name);
+
+ RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name);
+
+ RoleModel getClientRole(RealmModel realm, ClientModel client, String name);
+
+ Set<RoleModel> getClientRoles(RealmModel realm, ClientModel client);
+
+ boolean removeClient(String id, RealmModel realm);
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
index c239fb2..72a0d4c 100755
--- a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -124,6 +124,8 @@ public interface KeycloakSession {
UserProvider users();
+ ClientProvider clientStorageManager();
+
/**
* Un-cached view of all users in system including users loaded by UserStorageProviders
*
@@ -145,6 +147,15 @@ public interface KeycloakSession {
*/
UserProvider userLocalStorage();
+ RealmProvider realmLocalStorage();
+
+ /**
+ * Keycloak specific local storage for clients. No cache in front, this api talks directly to database configured for Keycloak
+ *
+ * @return
+ */
+ ClientProvider clientLocalStorage();
+
/**
* Hybrid storage for UserStorageProviders that can't store a specific piece of keycloak data in their external storage.
* No cache in front.
diff --git a/server-spi/src/main/java/org/keycloak/models/RealmModel.java b/server-spi/src/main/java/org/keycloak/models/RealmModel.java
index 6d48425..5eb18db 100755
--- a/server-spi/src/main/java/org/keycloak/models/RealmModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/RealmModel.java
@@ -22,6 +22,8 @@ import org.keycloak.component.ComponentModel;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.UserStorageProviderModel;
+import org.keycloak.storage.client.ClientStorageProvider;
+import org.keycloak.storage.client.ClientStorageProviderModel;
import java.util.*;
@@ -341,6 +343,16 @@ public interface RealmModel extends RoleContainerModel {
return list;
}
+ default
+ List<ClientStorageProviderModel> getClientStorageProviders() {
+ List<ClientStorageProviderModel> list = new LinkedList<>();
+ for (ComponentModel component : getComponents(getId(), ClientStorageProvider.class.getName())) {
+ list.add(new ClientStorageProviderModel(component));
+ }
+ Collections.sort(list, ClientStorageProviderModel.comparator);
+ return list;
+ }
+
String getLoginTheme();
void setLoginTheme(String name);
diff --git a/server-spi/src/main/java/org/keycloak/models/RealmProvider.java b/server-spi/src/main/java/org/keycloak/models/RealmProvider.java
index d14f2d6..6fed88a 100755
--- a/server-spi/src/main/java/org/keycloak/models/RealmProvider.java
+++ b/server-spi/src/main/java/org/keycloak/models/RealmProvider.java
@@ -19,6 +19,7 @@ package org.keycloak.models;
import org.keycloak.migration.MigrationModel;
import org.keycloak.provider.Provider;
+import org.keycloak.storage.client.ClientLookupProvider;
import java.util.List;
import java.util.Set;
@@ -27,7 +28,7 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public interface RealmProvider extends Provider {
+public interface RealmProvider extends Provider, ClientProvider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
MigrationModel getMigrationModel();
@@ -58,15 +59,6 @@ public interface RealmProvider extends Provider {
void addTopLevelGroup(RealmModel realm, GroupModel subGroup);
- ClientModel addClient(RealmModel realm, String clientId);
-
- ClientModel addClient(RealmModel realm, String id, String clientId);
-
- List<ClientModel> getClients(RealmModel realm);
-
- ClientModel getClientById(String id, RealmModel realm);
- ClientModel getClientByClientId(String clientId, RealmModel realm);
-
RoleModel addRealmRole(RealmModel realm, String name);
@@ -74,22 +66,12 @@ public interface RealmProvider extends Provider {
RoleModel getRealmRole(RealmModel realm, String name);
- RoleModel addClientRole(RealmModel realm, ClientModel client, String name);
-
- RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name);
-
Set<RoleModel> getRealmRoles(RealmModel realm);
- RoleModel getClientRole(RealmModel realm, ClientModel client, String name);
-
- Set<RoleModel> getClientRoles(RealmModel realm, ClientModel client);
-
boolean removeRole(RealmModel realm, RoleModel role);
RoleModel getRoleById(String id, RealmModel realm);
- boolean removeClient(String id, RealmModel realm);
-
ClientTemplateModel getClientTemplateById(String id, RealmModel realm);
GroupModel getGroupById(String id, RealmModel realm);
diff --git a/server-spi/src/main/java/org/keycloak/storage/CacheableStorageProviderModel.java b/server-spi/src/main/java/org/keycloak/storage/CacheableStorageProviderModel.java
new file mode 100644
index 0000000..355821c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/CacheableStorageProviderModel.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.component.PrioritizedComponentModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CacheableStorageProviderModel extends PrioritizedComponentModel {
+ public static final String CACHE_POLICY = "cachePolicy";
+ public static final String MAX_LIFESPAN = "maxLifespan";
+ public static final String EVICTION_HOUR = "evictionHour";
+ public static final String EVICTION_MINUTE = "evictionMinute";
+ public static final String EVICTION_DAY = "evictionDay";
+ public static final String CACHE_INVALID_BEFORE = "cacheInvalidBefore";
+
+ private transient CachePolicy cachePolicy;
+ private transient long maxLifespan = -1;
+ private transient int evictionHour = -1;
+ private transient int evictionMinute = -1;
+ private transient int evictionDay = -1;
+ private transient long cacheInvalidBefore = -1;
+
+ public CacheableStorageProviderModel() {
+ }
+
+ public CacheableStorageProviderModel(ComponentModel copy) {
+ super(copy);
+ }
+
+ public CachePolicy getCachePolicy() {
+ if (cachePolicy == null) {
+ String str = getConfig().getFirst(CACHE_POLICY);
+ if (str == null) return null;
+ cachePolicy = CachePolicy.valueOf(str);
+ }
+ return cachePolicy;
+ }
+
+ public void setCachePolicy(CachePolicy cachePolicy) {
+ this.cachePolicy = cachePolicy;
+ if (cachePolicy == null) {
+ getConfig().remove(CACHE_POLICY);
+
+ } else {
+ getConfig().putSingle(CACHE_POLICY, cachePolicy.name());
+ }
+ }
+
+ public long getMaxLifespan() {
+ if (maxLifespan < 0) {
+ String str = getConfig().getFirst(MAX_LIFESPAN);
+ if (str == null) return -1;
+ maxLifespan = Long.valueOf(str);
+ }
+ return maxLifespan;
+ }
+
+ public void setMaxLifespan(long maxLifespan) {
+ this.maxLifespan = maxLifespan;
+ getConfig().putSingle(MAX_LIFESPAN, Long.toString(maxLifespan));
+ }
+
+ public int getEvictionHour() {
+ if (evictionHour < 0) {
+ String str = getConfig().getFirst(EVICTION_HOUR);
+ if (str == null) return -1;
+ evictionHour = Integer.valueOf(str);
+ }
+ return evictionHour;
+ }
+
+ public void setEvictionHour(int evictionHour) {
+ if (evictionHour > 23 || evictionHour < 0) throw new IllegalArgumentException("Must be between 0 and 23");
+ this.evictionHour = evictionHour;
+ getConfig().putSingle(EVICTION_HOUR, Integer.toString(evictionHour));
+ }
+
+ public int getEvictionMinute() {
+ if (evictionMinute < 0) {
+ String str = getConfig().getFirst(EVICTION_MINUTE);
+ if (str == null) return -1;
+ evictionMinute = Integer.valueOf(str);
+ }
+ return evictionMinute;
+ }
+
+ public void setEvictionMinute(int evictionMinute) {
+ if (evictionMinute > 59 || evictionMinute < 0) throw new IllegalArgumentException("Must be between 0 and 59");
+ this.evictionMinute = evictionMinute;
+ getConfig().putSingle(EVICTION_MINUTE, Integer.toString(evictionMinute));
+ }
+
+ public int getEvictionDay() {
+ if (evictionDay < 0) {
+ String str = getConfig().getFirst(EVICTION_DAY);
+ if (str == null) return -1;
+ evictionDay = Integer.valueOf(str);
+ }
+ return evictionDay;
+ }
+
+ public void setEvictionDay(int evictionDay) {
+ if (evictionDay > 7 || evictionDay < 1) throw new IllegalArgumentException("Must be between 1 and 7");
+ this.evictionDay = evictionDay;
+ getConfig().putSingle(EVICTION_DAY, Integer.toString(evictionDay));
+ }
+
+ public long getCacheInvalidBefore() {
+ if (cacheInvalidBefore < 0) {
+ String str = getConfig().getFirst(CACHE_INVALID_BEFORE);
+ if (str == null) return -1;
+ cacheInvalidBefore = Long.valueOf(str);
+ }
+ return cacheInvalidBefore;
+ }
+
+ public void setCacheInvalidBefore(long cacheInvalidBefore) {
+ this.cacheInvalidBefore = cacheInvalidBefore;
+ getConfig().putSingle(CACHE_INVALID_BEFORE, Long.toString(cacheInvalidBefore));
+ }
+
+ public static enum CachePolicy {
+ NO_CACHE,
+ DEFAULT,
+ EVICT_DAILY,
+ EVICT_WEEKLY,
+ MAX_LIFESPAN
+ }
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/client/ClientLookupProvider.java b/server-spi/src/main/java/org/keycloak/storage/client/ClientLookupProvider.java
new file mode 100644
index 0000000..7f04e5f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/client/ClientLookupProvider.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.client;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.RealmModel;
+
+/**
+ * Abstraction interface for lookoup of clients by id and clientId. These methods required for participating in login flows.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ClientLookupProvider {
+ ClientModel getClientById(String id, RealmModel realm);
+ ClientModel getClientByClientId(String clientId, RealmModel realm);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProvider.java b/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProvider.java
new file mode 100644
index 0000000..6cf80d9
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProvider.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.client;
+
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.provider.Provider;
+import org.keycloak.storage.client.ClientLookupProvider;
+
+/**
+ * Base interface for components that want to provide an alternative storage mechanism for clients
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ClientStorageProvider extends Provider, ClientLookupProvider {
+
+
+ /**
+ * Callback when a realm is removed. Implement this if, for example, you want to do some
+ * cleanup in your user storage when a realm is removed
+ *
+ * @param realm
+ */
+ default
+ void preRemove(RealmModel realm) {
+
+ }
+
+ /**
+ * Callback when a group is removed. Allows you to do things like remove a user
+ * group mapping in your external store if appropriate
+ *
+ * @param realm
+ * @param group
+ */
+ default
+ void preRemove(RealmModel realm, GroupModel group) {
+
+ }
+
+ /**
+ * Callback when a role is removed. Allows you to do things like remove a user
+ * role mapping in your external store if appropriate
+
+ * @param realm
+ * @param role
+ */
+ default
+ void preRemove(RealmModel realm, RoleModel role) {
+
+ }
+}
+
diff --git a/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderFactory.java b/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderFactory.java
new file mode 100755
index 0000000..e9f8ee7
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderFactory.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.client;
+
+import org.keycloak.Config;
+import org.keycloak.component.ComponentFactory;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.component.ComponentValidationException;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ClientStorageProviderFactory<T extends ClientStorageProvider> extends ComponentFactory<T, ClientStorageProvider> {
+
+
+ /**
+ * called per Keycloak transaction.
+ *
+ * @param session
+ * @param model
+ * @return
+ */
+ T create(KeycloakSession session, ComponentModel model);
+
+ /**
+ * This is the name of the provider and will be showed in the admin console as an option.
+ *
+ * @return
+ */
+ @Override
+ String getId();
+
+ @Override
+ default void init(Config.Scope config) {
+
+ }
+
+ @Override
+ default void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ default void close() {
+
+ }
+
+ @Override
+ default String getHelpText() {
+ return "";
+ }
+
+ @Override
+ default List<ProviderConfigProperty> getConfigProperties() {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ default void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException {
+
+ }
+
+ /**
+ * Called when ClientStorageProviderModel is created. This allows you to do initialization of any additional configuration
+ * you need to add.
+ *
+ * @param session
+ * @param realm
+ * @param model
+ */
+ @Override
+ default void onCreate(KeycloakSession session, RealmModel realm, ComponentModel model) {
+
+ }
+
+ /**
+ * configuration properties that are common across all UserStorageProvider implementations
+ *
+ * @return
+ */
+ @Override
+ default
+ List<ProviderConfigProperty> getCommonProviderConfigProperties() {
+ return ClientStorageProviderSpi.commonConfig();
+ }
+
+ @Override
+ default
+ Map<String, Object> getTypeMetadata() {
+ Map<String, Object> metadata = new HashMap<>();
+ return metadata;
+ }
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderModel.java b/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderModel.java
new file mode 100755
index 0000000..54093af
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderModel.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.client;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.storage.CacheableStorageProviderModel;
+
+/**
+ * Stored configuration of a Client Storage provider instance.
+ *
+ * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
+ */
+public class ClientStorageProviderModel extends CacheableStorageProviderModel {
+
+ public static final String ENABLED = "enabled";
+
+ public ClientStorageProviderModel() {
+ setProviderType(ClientStorageProvider.class.getName());
+ }
+
+ public ClientStorageProviderModel(ComponentModel copy) {
+ super(copy);
+ }
+
+ private transient Boolean enabled;
+
+ public void setEnabled(boolean flag) {
+ enabled = flag;
+ getConfig().putSingle(ENABLED, Boolean.toString(flag));
+ }
+
+
+ public boolean isEnabled() {
+ if (enabled == null) {
+ String val = getConfig().getFirst(ENABLED);
+ if (val == null) {
+ enabled = true;
+ } else {
+ enabled = Boolean.valueOf(val);
+ }
+ }
+ return enabled;
+
+ }
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderSpi.java b/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderSpi.java
new file mode 100755
index 0000000..fd0c5a1
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/client/ClientStorageProviderSpi.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.client;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.provider.ProviderConfigurationBuilder;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ClientStorageProviderSpi implements Spi {
+
+ @Override
+ public boolean isInternal() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return "client-storage";
+ }
+
+ @Override
+ public Class<? extends Provider> getProviderClass() {
+ return ClientStorageProvider.class;
+ }
+
+ @Override
+ public Class<? extends ProviderFactory> getProviderFactoryClass() {
+ return ClientStorageProviderFactory.class;
+ }
+
+ private static final List<ProviderConfigProperty> commonConfig;
+
+ static {
+ List<ProviderConfigProperty> config = ProviderConfigurationBuilder.create()
+ .property()
+ .name("enabled").type(ProviderConfigProperty.BOOLEAN_TYPE).add()
+ .property()
+ .name("priority").type(ProviderConfigProperty.STRING_TYPE).add()
+ .property()
+ .name("cachePolicy").type(ProviderConfigProperty.STRING_TYPE).add()
+ .property()
+ .name("maxLifespan").type(ProviderConfigProperty.STRING_TYPE).add()
+ .property()
+ .name("evictionHour").type(ProviderConfigProperty.STRING_TYPE).add()
+ .property()
+ .name("evictionMinute").type(ProviderConfigProperty.STRING_TYPE).add()
+ .property()
+ .name("evictionDay").type(ProviderConfigProperty.STRING_TYPE).add()
+ .property()
+ .name("cacheInvalidBefore").type(ProviderConfigProperty.STRING_TYPE).add()
+ .build();
+ commonConfig = Collections.unmodifiableList(config);
+ }
+
+ public static List<ProviderConfigProperty> commonConfig() {
+ return commonConfig;
+
+ }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/StorageId.java b/server-spi/src/main/java/org/keycloak/storage/StorageId.java
index fbbc406..3a2a141 100644
--- a/server-spi/src/main/java/org/keycloak/storage/StorageId.java
+++ b/server-spi/src/main/java/org/keycloak/storage/StorageId.java
@@ -17,6 +17,7 @@
package org.keycloak.storage;
import org.keycloak.component.ComponentModel;
+import org.keycloak.models.ClientModel;
import org.keycloak.models.UserModel;
import java.io.Serializable;
@@ -75,8 +76,15 @@ public class StorageId implements Serializable {
public static boolean isLocalStorage(UserModel user) {
return new StorageId(user.getId()).getProviderId() == null;
}
- public static boolean isLocalStorage(String userId) {
- return new StorageId(userId).getProviderId() == null;
+ public static boolean isLocalStorage(String id) {
+ return new StorageId(id).getProviderId() == null;
+ }
+
+ public static String resolveProviderId(ClientModel client) {
+ return new StorageId(client.getId()).getProviderId();
+ }
+ public static boolean isLocalStorage(ClientModel client) {
+ return new StorageId(client.getId()).getProviderId() == null;
}
public boolean isLocal() {
return getProviderId() == null;
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java
index 1ec06a6..0b32b94 100755
--- a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java
@@ -26,28 +26,14 @@ import org.keycloak.component.PrioritizedComponentModel;
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
-public class UserStorageProviderModel extends PrioritizedComponentModel {
-
- public static final String CACHE_POLICY = "cachePolicy";
- public static final String MAX_LIFESPAN = "maxLifespan";
- public static final String EVICTION_HOUR = "evictionHour";
- public static final String EVICTION_MINUTE = "evictionMinute";
- public static final String EVICTION_DAY = "evictionDay";
- public static final String CACHE_INVALID_BEFORE = "cacheInvalidBefore";
+public class UserStorageProviderModel extends CacheableStorageProviderModel {
+
public static final String IMPORT_ENABLED = "importEnabled";
public static final String FULL_SYNC_PERIOD = "fullSyncPeriod";
public static final String CHANGED_SYNC_PERIOD = "changedSyncPeriod";
public static final String LAST_SYNC = "lastSync";
public static final String ENABLED = "enabled";
- public static enum CachePolicy {
- NO_CACHE,
- DEFAULT,
- EVICT_DAILY,
- EVICT_WEEKLY,
- MAX_LIFESPAN
- }
-
public UserStorageProviderModel() {
setProviderType(UserStorageProvider.class.getName());
}
@@ -61,104 +47,6 @@ public class UserStorageProviderModel extends PrioritizedComponentModel {
private transient Integer lastSync;
private transient Boolean importEnabled;
private transient Boolean enabled;
- private transient CachePolicy cachePolicy;
- private transient long maxLifespan = -1;
- private transient int evictionHour = -1;
- private transient int evictionMinute = -1;
- private transient int evictionDay = -1;
- private transient long cacheInvalidBefore = -1;
-
- public CachePolicy getCachePolicy() {
- if (cachePolicy == null) {
- String str = getConfig().getFirst(CACHE_POLICY);
- if (str == null) return null;
- cachePolicy = CachePolicy.valueOf(str);
- }
- return cachePolicy;
- }
-
- public void setCachePolicy(CachePolicy cachePolicy) {
- this.cachePolicy = cachePolicy;
- if (cachePolicy == null) {
- getConfig().remove(CACHE_POLICY);
-
- } else {
- getConfig().putSingle(CACHE_POLICY, cachePolicy.name());
- }
- }
-
- public long getMaxLifespan() {
- if (maxLifespan < 0) {
- String str = getConfig().getFirst(MAX_LIFESPAN);
- if (str == null) return -1;
- maxLifespan = Long.valueOf(str);
- }
- return maxLifespan;
- }
-
- public void setMaxLifespan(long maxLifespan) {
- this.maxLifespan = maxLifespan;
- getConfig().putSingle(MAX_LIFESPAN, Long.toString(maxLifespan));
- }
-
- public int getEvictionHour() {
- if (evictionHour < 0) {
- String str = getConfig().getFirst(EVICTION_HOUR);
- if (str == null) return -1;
- evictionHour = Integer.valueOf(str);
- }
- return evictionHour;
- }
-
- public void setEvictionHour(int evictionHour) {
- if (evictionHour > 23 || evictionHour < 0) throw new IllegalArgumentException("Must be between 0 and 23");
- this.evictionHour = evictionHour;
- getConfig().putSingle(EVICTION_HOUR, Integer.toString(evictionHour));
- }
-
- public int getEvictionMinute() {
- if (evictionMinute < 0) {
- String str = getConfig().getFirst(EVICTION_MINUTE);
- if (str == null) return -1;
- evictionMinute = Integer.valueOf(str);
- }
- return evictionMinute;
- }
-
- public void setEvictionMinute(int evictionMinute) {
- if (evictionMinute > 59 || evictionMinute < 0) throw new IllegalArgumentException("Must be between 0 and 59");
- this.evictionMinute = evictionMinute;
- getConfig().putSingle(EVICTION_MINUTE, Integer.toString(evictionMinute));
- }
-
- public int getEvictionDay() {
- if (evictionDay < 0) {
- String str = getConfig().getFirst(EVICTION_DAY);
- if (str == null) return -1;
- evictionDay = Integer.valueOf(str);
- }
- return evictionDay;
- }
-
- public void setEvictionDay(int evictionDay) {
- if (evictionDay > 7 || evictionDay < 1) throw new IllegalArgumentException("Must be between 1 and 7");
- this.evictionDay = evictionDay;
- getConfig().putSingle(EVICTION_DAY, Integer.toString(evictionDay));
- }
-
- public long getCacheInvalidBefore() {
- if (cacheInvalidBefore < 0) {
- String str = getConfig().getFirst(CACHE_INVALID_BEFORE);
- if (str == null) return -1;
- cacheInvalidBefore = Long.valueOf(str);
- }
- return cacheInvalidBefore;
- }
-
- public void setCacheInvalidBefore(long cacheInvalidBefore) {
- this.cacheInvalidBefore = cacheInvalidBefore;
- getConfig().putSingle(CACHE_INVALID_BEFORE, Long.toString(cacheInvalidBefore));
- }
public boolean isImportEnabled() {
if (importEnabled == null) {
diff --git a/server-spi-private/src/main/java/org/keycloak/models/cache/CacheRealmProvider.java b/server-spi-private/src/main/java/org/keycloak/models/cache/CacheRealmProvider.java
index 61ae1be..ce71dee 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/cache/CacheRealmProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/cache/CacheRealmProvider.java
@@ -25,7 +25,7 @@ import org.keycloak.models.RealmProvider;
*/
public interface CacheRealmProvider extends RealmProvider {
void clear();
- RealmProvider getDelegate();
+ RealmProvider getRealmDelegate();
void registerRealmInvalidation(String id, String name);
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
index 0cc81c1..6cabf76 100644
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
@@ -20,6 +20,7 @@ import org.keycloak.component.ComponentFactory;
import org.keycloak.component.ComponentModel;
import org.keycloak.credential.UserCredentialStoreManager;
import org.keycloak.keys.DefaultKeyManager;
+import org.keycloak.models.ClientProvider;
import org.keycloak.models.KeycloakContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
@@ -35,6 +36,7 @@ import org.keycloak.models.cache.UserCache;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.sessions.AuthenticationSessionProvider;
+import org.keycloak.storage.ClientStorageManager;
import org.keycloak.storage.UserStorageManager;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.theme.DefaultThemeManager;
@@ -58,6 +60,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
private final Map<String, Object> attributes = new HashMap<>();
private RealmProvider model;
private UserStorageManager userStorageManager;
+ private ClientStorageManager clientStorageManager;
private UserCredentialStoreManager userCredentialStorageManager;
private UserSessionProvider sessionProvider;
private AuthenticationSessionProvider authenticationSessionProvider;
@@ -136,6 +139,23 @@ public class DefaultKeycloakSession implements KeycloakSession {
}
@Override
+ public RealmProvider realmLocalStorage() {
+ return getProvider(RealmProvider.class);
+ }
+
+ @Override
+ public ClientProvider clientLocalStorage() {
+ return realmLocalStorage();
+ }
+
+ @Override
+ public ClientProvider clientStorageManager() {
+ if (clientStorageManager == null) clientStorageManager = new ClientStorageManager(this);
+ return clientStorageManager;
+ }
+
+
+ @Override
public UserProvider userStorageManager() {
if (userStorageManager == null) userStorageManager = new UserStorageManager(this);
return userStorageManager;
@@ -232,6 +252,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
return model;
}
+
@Override
public UserSessionProvider sessions() {
if (sessionProvider == null) {
diff --git a/services/src/main/java/org/keycloak/storage/ClientStorageManager.java b/services/src/main/java/org/keycloak/storage/ClientStorageManager.java
new file mode 100644
index 0000000..0a4112f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/storage/ClientStorageManager.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage;
+
+import org.jboss.logging.Logger;
+import org.keycloak.common.util.reflections.Types;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.storage.client.ClientLookupProvider;
+import org.keycloak.storage.client.ClientStorageProvider;
+import org.keycloak.storage.client.ClientStorageProviderFactory;
+import org.keycloak.storage.client.ClientStorageProviderModel;
+import org.keycloak.storage.user.UserLookupProvider;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClientStorageManager implements ClientProvider {
+ private static final Logger logger = Logger.getLogger(ClientStorageManager.class);
+
+ protected KeycloakSession session;
+
+ public static boolean isStorageProviderEnabled(RealmModel realm, String providerId) {
+ ClientStorageProviderModel model = getStorageProviderModel(realm, providerId);
+ return model.isEnabled();
+ }
+
+ public static ClientStorageProviderModel getStorageProviderModel(RealmModel realm, String componentId) {
+ ComponentModel model = realm.getComponent(componentId);
+ if (model == null) return null;
+ return new ClientStorageProviderModel(model);
+ }
+
+ public static ClientStorageProvider getStorageProvider(KeycloakSession session, RealmModel realm, String componentId) {
+ ComponentModel model = realm.getComponent(componentId);
+ if (model == null) return null;
+ ClientStorageProviderModel storageModel = new ClientStorageProviderModel(model);
+ ClientStorageProviderFactory factory = (ClientStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(ClientStorageProvider.class, model.getProviderId());
+ if (factory == null) {
+ throw new ModelException("Could not find ClientStorageProviderFactory for: " + model.getProviderId());
+ }
+ return getStorageProviderInstance(session, storageModel, factory);
+ }
+
+
+ public static List<ClientStorageProviderModel> getStorageProviders(RealmModel realm) {
+ return realm.getClientStorageProviders();
+ }
+
+ public static ClientStorageProvider getStorageProviderInstance(KeycloakSession session, ClientStorageProviderModel model, ClientStorageProviderFactory factory) {
+ ClientStorageProvider instance = (ClientStorageProvider)session.getAttribute(model.getId());
+ if (instance != null) return instance;
+ instance = factory.create(session, model);
+ if (instance == null) {
+ throw new IllegalStateException("ClientStorageProvideFactory (of type " + factory.getClass().getName() + ") produced a null instance");
+ }
+ session.enlistForClose(instance);
+ session.setAttribute(model.getId(), instance);
+ return instance;
+ }
+
+
+ public static <T> List<T> getStorageProviders(KeycloakSession session, RealmModel realm, Class<T> type) {
+ List<T> list = new LinkedList<>();
+ for (ClientStorageProviderModel model : getStorageProviders(realm)) {
+ ClientStorageProviderFactory factory = (ClientStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(ClientStorageProvider.class, model.getProviderId());
+ if (factory == null) {
+ logger.warnv("Configured ClientStorageProvider {0} of provider id {1} does not exist in realm {2}", model.getName(), model.getProviderId(), realm.getName());
+ continue;
+ }
+ if (Types.supports(type, factory, ClientStorageProviderFactory.class)) {
+ list.add(type.cast(getStorageProviderInstance(session, model, factory)));
+ }
+
+
+ }
+ return list;
+ }
+
+
+ public static <T> List<T> getEnabledStorageProviders(KeycloakSession session, RealmModel realm, Class<T> type) {
+ List<T> list = new LinkedList<>();
+ for (ClientStorageProviderModel model : getStorageProviders(realm)) {
+ if (!model.isEnabled()) continue;
+ ClientStorageProviderFactory factory = (ClientStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(ClientStorageProvider.class, model.getProviderId());
+ if (factory == null) {
+ logger.warnv("Configured ClientStorageProvider {0} of provider id {1} does not exist in realm {2}", model.getName(), model.getProviderId(), realm.getName());
+ continue;
+ }
+ if (Types.supports(type, factory, ClientStorageProviderFactory.class)) {
+ list.add(type.cast(getStorageProviderInstance(session, model, factory)));
+ }
+
+
+ }
+ return list;
+ }
+
+
+ public ClientStorageManager(KeycloakSession session) {
+ this.session = session;
+ }
+
+ @Override
+ public ClientModel getClientById(String id, RealmModel realm) {
+ StorageId storageId = new StorageId(id);
+ if (storageId.getProviderId() == null) {
+ return session.clientLocalStorage().getClientById(id, realm);
+ }
+ ClientLookupProvider provider = (ClientLookupProvider)getStorageProvider(session, realm, storageId.getProviderId());
+ if (provider == null) return null;
+ if (!isStorageProviderEnabled(realm, storageId.getProviderId())) return null;
+ return provider.getClientById(id, realm);
+ }
+
+ @Override
+ public ClientModel getClientByClientId(String clientId, RealmModel realm) {
+ ClientModel client = session.clientLocalStorage().getClientByClientId(clientId, realm);
+ if (client != null) {
+ return client;
+ }
+ for (ClientLookupProvider provider : getEnabledStorageProviders(session, realm, ClientLookupProvider.class)) {
+ client = provider.getClientByClientId(clientId, realm);
+ if (client != null) return client;
+ }
+ return null;
+ }
+
+
+ @Override
+ public ClientModel addClient(RealmModel realm, String clientId) {
+ return session.clientLocalStorage().addClient(realm, clientId);
+ }
+
+ @Override
+ public ClientModel addClient(RealmModel realm, String id, String clientId) {
+ return session.clientLocalStorage().addClient(realm, id, clientId);
+ }
+
+ @Override
+ public List<ClientModel> getClients(RealmModel realm) {
+ return session.clientLocalStorage().getClients(realm);
+ }
+
+ @Override
+ public RoleModel addClientRole(RealmModel realm, ClientModel client, String name) {
+ if (!StorageId.isLocalStorage(client.getId())) {
+ throw new RuntimeException("Federated clients do not support this operation");
+ }
+ return session.clientLocalStorage().addClientRole(realm, client, name);
+ }
+
+ @Override
+ public RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name) {
+ if (!StorageId.isLocalStorage(client.getId())) {
+ throw new RuntimeException("Federated clients do not support this operation");
+ }
+ return session.clientLocalStorage().addClientRole(realm, client, id, name);
+ }
+
+ @Override
+ public RoleModel getClientRole(RealmModel realm, ClientModel client, String name) {
+ if (!StorageId.isLocalStorage(client.getId())) {
+ throw new RuntimeException("Federated clients do not support this operation");
+ }
+ return session.clientLocalStorage().getClientRole(realm, client, name);
+ }
+
+ @Override
+ public Set<RoleModel> getClientRoles(RealmModel realm, ClientModel client) {
+ if (!StorageId.isLocalStorage(client.getId())) {
+ throw new RuntimeException("Federated clients do not support this operation");
+ }
+ return session.clientLocalStorage().getClientRoles(realm, client);
+ }
+
+ @Override
+ public boolean removeClient(String id, RealmModel realm) {
+ if (!StorageId.isLocalStorage(id)) {
+ throw new RuntimeException("Federated clients do not support this operation");
+ }
+ return session.clientLocalStorage().removeClient(id, realm);
+ }
+
+}