initial work
This commit is contained in:
parent
64b75d2806
commit
8a17b61f4e
21 changed files with 914 additions and 218 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 class UserStorageProviderModel extends CacheableStorageProviderModel {
|
||||
|
||||
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 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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
@ -135,6 +138,23 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
return getProvider(UserProvider.class);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
@ -232,6 +252,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
return model;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UserSessionProvider sessions() {
|
||||
if (sessionProvider == null) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue