group list caching
This commit is contained in:
parent
9488787986
commit
f10f00ba71
11 changed files with 422 additions and 171 deletions
44
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupListQuery.java
vendored
Executable file
44
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupListQuery.java
vendored
Executable file
|
@ -0,0 +1,44 @@
|
||||||
|
package org.keycloak.models.cache.infinispan;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
|
||||||
|
import org.keycloak.models.cache.infinispan.entities.ClientQuery;
|
||||||
|
import org.keycloak.models.cache.infinispan.entities.GroupQuery;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class GroupListQuery extends AbstractRevisioned implements GroupQuery {
|
||||||
|
private final Set<String> groups;
|
||||||
|
private final String realm;
|
||||||
|
private final String realmName;
|
||||||
|
|
||||||
|
public GroupListQuery(Long revisioned, String id, RealmModel realm, Set<String> groups) {
|
||||||
|
super(revisioned, id);
|
||||||
|
this.realm = realm.getId();
|
||||||
|
this.realmName = realm.getName();
|
||||||
|
this.groups = groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroups() {
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRealm() {
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "GroupListQuery{" +
|
||||||
|
"id='" + getId() + "'" +
|
||||||
|
"realmName='" + realmName + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -1303,67 +1303,45 @@ public class RealmAdapter implements RealmModel {
|
||||||
return cached.getRequiredActionProvidersByAlias().get(alias);
|
return cached.getRequiredActionProvidersByAlias().get(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public GroupModel getGroupById(String id) {
|
|
||||||
if (updated != null) return updated.getGroupById(id);
|
|
||||||
return cacheSession.getGroupById(id, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<GroupModel> getGroups() {
|
|
||||||
if (updated != null) return updated.getGroups();
|
|
||||||
if (cached.getGroups().isEmpty()) return Collections.EMPTY_LIST;
|
|
||||||
List<GroupModel> list = new LinkedList<>();
|
|
||||||
for (String id : cached.getGroups()) {
|
|
||||||
GroupModel group = cacheSession.getGroupById(id, this);
|
|
||||||
if (group == null) continue;
|
|
||||||
list.add(group);
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<GroupModel> getTopLevelGroups() {
|
|
||||||
List<GroupModel> base = getGroups();
|
|
||||||
if (base.isEmpty()) return base;
|
|
||||||
List<GroupModel> copy = new LinkedList<>();
|
|
||||||
for (GroupModel group : base) {
|
|
||||||
if (group.getParent() == null) {
|
|
||||||
copy.add(group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeGroup(GroupModel group) {
|
|
||||||
getDelegateForUpdate();
|
|
||||||
return updated.removeGroup(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GroupModel createGroup(String name) {
|
public GroupModel createGroup(String name) {
|
||||||
getDelegateForUpdate();
|
return cacheSession.createGroup(this, name);
|
||||||
return updated.createGroup(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GroupModel createGroup(String id, String name) {
|
public GroupModel createGroup(String id, String name) {
|
||||||
getDelegateForUpdate();
|
return cacheSession.createGroup(this, id, name);
|
||||||
return updated.createGroup(id, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTopLevelGroup(GroupModel subGroup) {
|
public void addTopLevelGroup(GroupModel subGroup) {
|
||||||
getDelegateForUpdate();
|
cacheSession.addTopLevelGroup(this, subGroup);
|
||||||
updated.addTopLevelGroup(subGroup);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveGroup(GroupModel group, GroupModel toParent) {
|
public void moveGroup(GroupModel group, GroupModel toParent) {
|
||||||
getDelegateForUpdate();
|
cacheSession.moveGroup(this, group, toParent);
|
||||||
updated.moveGroup(group, toParent);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel getGroupById(String id) {
|
||||||
|
return cacheSession.getGroupById(id, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GroupModel> getGroups() {
|
||||||
|
return cacheSession.getGroups(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GroupModel> getTopLevelGroups() {
|
||||||
|
return cacheSession.getTopLevelGroups(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeGroup(GroupModel group) {
|
||||||
|
return cacheSession.removeGroup(this, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -397,6 +397,14 @@ public class StreamCacheRealmProvider implements CacheRealmProvider {
|
||||||
return realm + REALM_CLIENTS_QUERY_SUFFIX;
|
return realm + REALM_CLIENTS_QUERY_SUFFIX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getGroupsQueryCacheKey(String realm) {
|
||||||
|
return realm + ".groups";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTopGroupsQueryCacheKey(String realm) {
|
||||||
|
return realm + ".top.groups";
|
||||||
|
}
|
||||||
|
|
||||||
private String getRolesCacheKey(String container) {
|
private String getRolesCacheKey(String container) {
|
||||||
return container + ROLES_QUERY_SUFFIX;
|
return container + ROLES_QUERY_SUFFIX;
|
||||||
}
|
}
|
||||||
|
@ -687,6 +695,129 @@ public class StreamCacheRealmProvider implements CacheRealmProvider {
|
||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveGroup(RealmModel realm, GroupModel group, GroupModel toParent) {
|
||||||
|
registerGroupInvalidation(group.getId());
|
||||||
|
if (toParent != null) registerGroupInvalidation(toParent.getId());
|
||||||
|
getDelegate().moveGroup(realm, group, toParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GroupModel> getGroups(RealmModel realm) {
|
||||||
|
String cacheKey = getGroupsQueryCacheKey(realm.getId());
|
||||||
|
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
|
||||||
|
if (queryDB) {
|
||||||
|
return getDelegate().getGroups(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
|
||||||
|
if (query != null) {
|
||||||
|
logger.tracev("getGroups cache hit: {0}", realm.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query == null) {
|
||||||
|
Long loaded = cache.getCurrentRevision(cacheKey);
|
||||||
|
List<GroupModel> model = getDelegate().getGroups(realm);
|
||||||
|
if (model == null) return null;
|
||||||
|
Set<String> ids = new HashSet<>();
|
||||||
|
for (GroupModel client : model) ids.add(client.getId());
|
||||||
|
query = new GroupListQuery(loaded, cacheKey, realm, ids);
|
||||||
|
logger.tracev("adding realm getGroups cache miss: realm {0} key {1}", realm.getName(), cacheKey);
|
||||||
|
cache.addRevisioned(query);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
List<GroupModel> list = new LinkedList<>();
|
||||||
|
for (String id : query.getGroups()) {
|
||||||
|
GroupModel group = session.realms().getGroupById(id, realm);
|
||||||
|
if (group == null) {
|
||||||
|
invalidations.add(cacheKey);
|
||||||
|
return getDelegate().getGroups(realm);
|
||||||
|
}
|
||||||
|
list.add(group);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GroupModel> getTopLevelGroups(RealmModel realm) {
|
||||||
|
String cacheKey = getTopGroupsQueryCacheKey(realm.getId());
|
||||||
|
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
|
||||||
|
if (queryDB) {
|
||||||
|
return getDelegate().getTopLevelGroups(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
|
||||||
|
if (query != null) {
|
||||||
|
logger.tracev("getTopLevelGroups cache hit: {0}", realm.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query == null) {
|
||||||
|
Long loaded = cache.getCurrentRevision(cacheKey);
|
||||||
|
List<GroupModel> model = getDelegate().getTopLevelGroups(realm);
|
||||||
|
if (model == null) return null;
|
||||||
|
Set<String> ids = new HashSet<>();
|
||||||
|
for (GroupModel client : model) ids.add(client.getId());
|
||||||
|
query = new GroupListQuery(loaded, cacheKey, realm, ids);
|
||||||
|
logger.tracev("adding realm getTopLevelGroups cache miss: realm {0} key {1}", realm.getName(), cacheKey);
|
||||||
|
cache.addRevisioned(query);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
List<GroupModel> list = new LinkedList<>();
|
||||||
|
for (String id : query.getGroups()) {
|
||||||
|
GroupModel group = session.realms().getGroupById(id, realm);
|
||||||
|
if (group == null) {
|
||||||
|
invalidations.add(cacheKey);
|
||||||
|
return getDelegate().getTopLevelGroups(realm);
|
||||||
|
}
|
||||||
|
list.add(group);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeGroup(RealmModel realm, GroupModel group) {
|
||||||
|
registerGroupInvalidation(group.getId());
|
||||||
|
listInvalidations.add(realm.getId());
|
||||||
|
invalidations.add(getGroupsQueryCacheKey(realm.getId()));
|
||||||
|
if (group.getParentId() == null) {
|
||||||
|
invalidations.add(getTopGroupsQueryCacheKey(realm.getId()));
|
||||||
|
} else {
|
||||||
|
registerGroupInvalidation(group.getParentId());
|
||||||
|
}
|
||||||
|
return getDelegate().removeGroup(realm, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel createGroup(RealmModel realm, String name) {
|
||||||
|
GroupModel group = getDelegate().createGroup(realm, name);
|
||||||
|
return groupAdded(realm, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupModel groupAdded(RealmModel realm, GroupModel group) {
|
||||||
|
listInvalidations.add(realm.getId());
|
||||||
|
invalidations.add(getGroupsQueryCacheKey(realm.getId()));
|
||||||
|
invalidations.add(getTopGroupsQueryCacheKey(realm.getId()));
|
||||||
|
invalidations.add(group.getId());
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel createGroup(RealmModel realm, String id, String name) {
|
||||||
|
GroupModel group = getDelegate().createGroup(realm, id, name);
|
||||||
|
return groupAdded(realm, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTopLevelGroup(RealmModel realm, GroupModel subGroup) {
|
||||||
|
invalidations.add(getTopGroupsQueryCacheKey(realm.getId()));
|
||||||
|
invalidations.add(subGroup.getId());
|
||||||
|
if (subGroup.getParentId() != null) {
|
||||||
|
registerGroupInvalidation(subGroup.getParentId());
|
||||||
|
}
|
||||||
|
getDelegate().addTopLevelGroup(realm, subGroup);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientModel getClientById(String id, RealmModel realm) {
|
public ClientModel getClientById(String id, RealmModel realm) {
|
||||||
CachedClient cached = cache.get(id, CachedClient.class);
|
CachedClient cached = cache.get(id, CachedClient.class);
|
||||||
|
|
|
@ -281,6 +281,96 @@ public class JpaRealmProvider implements RealmProvider {
|
||||||
return new GroupAdapter(realm, em, groupEntity);
|
return new GroupAdapter(realm, em, groupEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveGroup(RealmModel realm, GroupModel group, GroupModel toParent) {
|
||||||
|
if (toParent != null && group.getId().equals(toParent.getId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (group.getParentId() != null) {
|
||||||
|
group.getParent().removeChild(group);
|
||||||
|
}
|
||||||
|
group.setParent(toParent);
|
||||||
|
if (toParent != null) toParent.addChild(group);
|
||||||
|
else session.realms().addTopLevelGroup(realm, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GroupModel> getGroups(RealmModel realm) {
|
||||||
|
List<String> groups = em.createNamedQuery("getAllGroupIdsByRealm", String.class)
|
||||||
|
.setParameter("realm", realm.getId()).getResultList();
|
||||||
|
if (groups == null) return Collections.EMPTY_LIST;
|
||||||
|
List<GroupModel> list = new LinkedList<>();
|
||||||
|
for (String id : groups) {
|
||||||
|
list.add(session.realms().getGroupById(id, realm));
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GroupModel> getTopLevelGroups(RealmModel realm) {
|
||||||
|
List<String> groups = em.createNamedQuery("getTopLevelGroupIds", String.class)
|
||||||
|
.setParameter("realm", realm.getId())
|
||||||
|
.getResultList();
|
||||||
|
if (groups == null) return Collections.EMPTY_LIST;
|
||||||
|
List<GroupModel> list = new LinkedList<>();
|
||||||
|
for (String id : groups) {
|
||||||
|
list.add(session.realms().getGroupById(id, realm));
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeGroup(RealmModel realm, GroupModel group) {
|
||||||
|
if (group == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
session.users().preRemove(realm, group);
|
||||||
|
|
||||||
|
realm.removeDefaultGroup(group);
|
||||||
|
for (GroupModel subGroup : group.getSubGroups()) {
|
||||||
|
session.realms().removeGroup(realm, subGroup);
|
||||||
|
}
|
||||||
|
moveGroup(realm, group, null);
|
||||||
|
GroupEntity groupEntity = em.find(GroupEntity.class, group.getId());
|
||||||
|
if (!groupEntity.getRealm().getId().equals(realm.getId())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// I don't think we need this as GroupEntity has cascade removal. It causes batch errors if you turn this on.
|
||||||
|
// em.createNamedQuery("deleteGroupAttributesByGroup").setParameter("group", groupEntity).executeUpdate();
|
||||||
|
em.createNamedQuery("deleteGroupRoleMappingsByGroup").setParameter("group", groupEntity).executeUpdate();
|
||||||
|
em.remove(groupEntity);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel createGroup(RealmModel realm, String name) {
|
||||||
|
String id = KeycloakModelUtils.generateId();
|
||||||
|
return createGroup(realm, id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel createGroup(RealmModel realm, String id, String name) {
|
||||||
|
if (id == null) id = KeycloakModelUtils.generateId();
|
||||||
|
GroupEntity groupEntity = new GroupEntity();
|
||||||
|
groupEntity.setId(id);
|
||||||
|
groupEntity.setName(name);
|
||||||
|
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
|
||||||
|
groupEntity.setRealm(realmEntity);
|
||||||
|
em.persist(groupEntity);
|
||||||
|
|
||||||
|
return new GroupAdapter(realm, em, groupEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTopLevelGroup(RealmModel realm, GroupModel subGroup) {
|
||||||
|
subGroup.setParent(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientModel addClient(RealmModel realm, String clientId) {
|
public ClientModel addClient(RealmModel realm, String clientId) {
|
||||||
return addClient(realm, KeycloakModelUtils.generateId(), clientId);
|
return addClient(realm, KeycloakModelUtils.generateId(), clientId);
|
||||||
|
|
|
@ -1987,17 +1987,25 @@ public class RealmAdapter implements RealmModel {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel createGroup(String name) {
|
||||||
|
return session.realms().createGroup(this, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel createGroup(String id, String name) {
|
||||||
|
return session.realms().createGroup(this, id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTopLevelGroup(GroupModel subGroup) {
|
||||||
|
session.realms().addTopLevelGroup(this, subGroup);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveGroup(GroupModel group, GroupModel toParent) {
|
public void moveGroup(GroupModel group, GroupModel toParent) {
|
||||||
if (toParent != null && group.getId().equals(toParent.getId())) {
|
session.realms().moveGroup(this, group, toParent);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (group.getParentId() != null) {
|
|
||||||
group.getParent().removeChild(group);
|
|
||||||
}
|
|
||||||
group.setParent(toParent);
|
|
||||||
if (toParent != null) toParent.addChild(group);
|
|
||||||
else addTopLevelGroup(group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2007,75 +2015,17 @@ public class RealmAdapter implements RealmModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getGroups() {
|
public List<GroupModel> getGroups() {
|
||||||
List<String> groups = em.createNamedQuery("getAllGroupIdsByRealm", String.class)
|
return session.realms().getGroups(this);
|
||||||
.setParameter("realm", realm.getId()).getResultList();
|
|
||||||
if (groups == null) return Collections.EMPTY_LIST;
|
|
||||||
List<GroupModel> list = new LinkedList<>();
|
|
||||||
for (String id : groups) {
|
|
||||||
list.add(session.realms().getGroupById(id, this));
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups() {
|
public List<GroupModel> getTopLevelGroups() {
|
||||||
List<GroupModel> base = getGroups();
|
return session.realms().getTopLevelGroups(this);
|
||||||
if (base.isEmpty()) return base;
|
|
||||||
List<GroupModel> copy = new LinkedList<>();
|
|
||||||
for (GroupModel group : base) {
|
|
||||||
if (group.getParent() == null) {
|
|
||||||
copy.add(group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeGroup(GroupModel group) {
|
public boolean removeGroup(GroupModel group) {
|
||||||
if (group == null) {
|
return session.realms().removeGroup(this, group);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
GroupEntity groupEntity = GroupAdapter.toEntity(group, em);
|
|
||||||
if (!groupEntity.getRealm().getId().equals(getId())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
realm.getDefaultGroups().remove(groupEntity);
|
|
||||||
for (GroupModel subGroup : group.getSubGroups()) {
|
|
||||||
removeGroup(subGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
session.users().preRemove(this, group);
|
|
||||||
moveGroup(group, null);
|
|
||||||
em.createNamedQuery("deleteGroupAttributesByGroup").setParameter("group", groupEntity).executeUpdate();
|
|
||||||
em.createNamedQuery("deleteGroupRoleMappingsByGroup").setParameter("group", groupEntity).executeUpdate();
|
|
||||||
em.remove(groupEntity);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GroupModel createGroup(String name) {
|
|
||||||
String id = KeycloakModelUtils.generateId();
|
|
||||||
return createGroup(id, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GroupModel createGroup(String id, String name) {
|
|
||||||
if (id == null) id = KeycloakModelUtils.generateId();
|
|
||||||
GroupEntity groupEntity = new GroupEntity();
|
|
||||||
groupEntity.setId(id);
|
|
||||||
groupEntity.setName(name);
|
|
||||||
groupEntity.setRealm(realm);
|
|
||||||
em.persist(groupEntity);
|
|
||||||
|
|
||||||
return new GroupAdapter(this, em, groupEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addTopLevelGroup(GroupModel subGroup) {
|
|
||||||
subGroup.setParent(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -42,6 +42,7 @@ import java.util.Collection;
|
||||||
@NamedQuery(name="getAllGroupIdsByRealm", query="select u.id from GroupEntity u where u.realm.id = :realm order by u.name"),
|
@NamedQuery(name="getAllGroupIdsByRealm", query="select u.id from GroupEntity u where u.realm.id = :realm order by u.name"),
|
||||||
@NamedQuery(name="getGroupById", query="select u from GroupEntity u where u.id = :id and u.realm = :realm"),
|
@NamedQuery(name="getGroupById", query="select u from GroupEntity u where u.id = :id and u.realm = :realm"),
|
||||||
@NamedQuery(name="getGroupIdsByParent", query="select u.id from GroupEntity u where u.parent = :parent"),
|
@NamedQuery(name="getGroupIdsByParent", query="select u.id from GroupEntity u where u.parent = :parent"),
|
||||||
|
@NamedQuery(name="getTopLevelGroupIds", query="select u.id from GroupEntity u where u.parent is null and u.realm.id = :realm"),
|
||||||
@NamedQuery(name="getGroupCount", query="select count(u) from GroupEntity u where u.realm = :realm"),
|
@NamedQuery(name="getGroupCount", query="select count(u) from GroupEntity u where u.realm = :realm"),
|
||||||
@NamedQuery(name="deleteGroupsByRealm", query="delete from GroupEntity u where u.realm = :realm")
|
@NamedQuery(name="deleteGroupsByRealm", query="delete from GroupEntity u where u.realm = :realm")
|
||||||
})
|
})
|
||||||
|
@ -64,7 +65,9 @@ public class GroupEntity {
|
||||||
@JoinColumn(name = "REALM_ID")
|
@JoinColumn(name = "REALM_ID")
|
||||||
private RealmEntity realm;
|
private RealmEntity realm;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="group")
|
@OneToMany(
|
||||||
|
cascade = CascadeType.REMOVE,
|
||||||
|
orphanRemoval = true, mappedBy="group")
|
||||||
protected Collection<GroupAttributeEntity> attributes = new ArrayList<GroupAttributeEntity>();
|
protected Collection<GroupAttributeEntity> attributes = new ArrayList<GroupAttributeEntity>();
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -154,6 +155,92 @@ public class MongoRealmProvider implements RealmProvider {
|
||||||
return new GroupAdapter(session, realm, group, invocationContext);
|
return new GroupAdapter(session, realm, group, invocationContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveGroup(RealmModel realm, GroupModel group, GroupModel toParent) {
|
||||||
|
if (toParent != null && group.getId().equals(toParent.getId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (group.getParentId() != null) {
|
||||||
|
group.getParent().removeChild(group);
|
||||||
|
}
|
||||||
|
group.setParent(toParent);
|
||||||
|
if (toParent != null) toParent.addChild(group);
|
||||||
|
else session.realms().addTopLevelGroup(realm, group);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GroupModel> getGroups(RealmModel realm) {
|
||||||
|
DBObject query = new QueryBuilder()
|
||||||
|
.and("realmId").is(realm.getId())
|
||||||
|
.get();
|
||||||
|
List<MongoGroupEntity> groups = getMongoStore().loadEntities(MongoGroupEntity.class, query, invocationContext);
|
||||||
|
if (groups == null) return Collections.EMPTY_LIST;
|
||||||
|
|
||||||
|
List<GroupModel> result = new LinkedList<>();
|
||||||
|
|
||||||
|
if (groups == null) return result;
|
||||||
|
for (MongoGroupEntity group : groups) {
|
||||||
|
result.add(getGroupById(group.getId(), realm));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GroupModel> getTopLevelGroups(RealmModel realm) {
|
||||||
|
DBObject query = new QueryBuilder()
|
||||||
|
.and("realmId").is(realm.getId())
|
||||||
|
.and("parentId").is(null)
|
||||||
|
.get();
|
||||||
|
List<MongoGroupEntity> groups = getMongoStore().loadEntities(MongoGroupEntity.class, query, invocationContext);
|
||||||
|
if (groups == null) return Collections.EMPTY_LIST;
|
||||||
|
|
||||||
|
List<GroupModel> result = new LinkedList<>();
|
||||||
|
|
||||||
|
if (groups == null) return result;
|
||||||
|
for (MongoGroupEntity group : groups) {
|
||||||
|
result.add(getGroupById(group.getId(), realm));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeGroup(RealmModel realm, GroupModel group) {
|
||||||
|
session.users().preRemove(realm, group);
|
||||||
|
realm.removeDefaultGroup(group);
|
||||||
|
for (GroupModel subGroup : group.getSubGroups()) {
|
||||||
|
removeGroup(realm, subGroup);
|
||||||
|
}
|
||||||
|
moveGroup(realm, group, null);
|
||||||
|
return getMongoStore().removeEntity(MongoGroupEntity.class, group.getId(), invocationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel createGroup(RealmModel realm, String name) {
|
||||||
|
String id = KeycloakModelUtils.generateId();
|
||||||
|
return createGroup(realm, id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupModel createGroup(RealmModel realm, String id, String name) {
|
||||||
|
if (id == null) id = KeycloakModelUtils.generateId();
|
||||||
|
MongoGroupEntity group = new MongoGroupEntity();
|
||||||
|
group.setId(id);
|
||||||
|
group.setName(name);
|
||||||
|
group.setRealmId(realm.getId());
|
||||||
|
|
||||||
|
getMongoStore().insertEntity(group, invocationContext);
|
||||||
|
|
||||||
|
return new GroupAdapter(session, realm, group, invocationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTopLevelGroup(RealmModel realm, GroupModel subGroup) {
|
||||||
|
subGroup.setParent(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientModel getClientById(String id, RealmModel realm) {
|
public ClientModel getClientById(String id, RealmModel realm) {
|
||||||
MongoClientEntity appData = getMongoStore().loadEntity(MongoClientEntity.class, id, invocationContext);
|
MongoClientEntity appData = getMongoStore().loadEntity(MongoClientEntity.class, id, invocationContext);
|
||||||
|
|
|
@ -645,40 +645,23 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GroupModel createGroup(String name) {
|
public GroupModel createGroup(String name) {
|
||||||
String id = KeycloakModelUtils.generateId();
|
return session.realms().createGroup(this, name);
|
||||||
return createGroup(id, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GroupModel createGroup(String id, String name) {
|
public GroupModel createGroup(String id, String name) {
|
||||||
if (id == null) id = KeycloakModelUtils.generateId();
|
return session.realms().createGroup(this, id, name);
|
||||||
MongoGroupEntity group = new MongoGroupEntity();
|
|
||||||
group.setId(id);
|
|
||||||
group.setName(name);
|
|
||||||
group.setRealmId(getId());
|
|
||||||
|
|
||||||
getMongoStore().insertEntity(group, invocationContext);
|
|
||||||
|
|
||||||
return new GroupAdapter(session, this, group, invocationContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTopLevelGroup(GroupModel subGroup) {
|
public void addTopLevelGroup(GroupModel subGroup) {
|
||||||
subGroup.setParent(null);
|
session.realms().addTopLevelGroup(this, subGroup);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveGroup(GroupModel group, GroupModel toParent) {
|
public void moveGroup(GroupModel group, GroupModel toParent) {
|
||||||
if (toParent != null && group.getId().equals(toParent.getId())) {
|
session.realms().moveGroup(this, group, toParent);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (group.getParentId() != null) {
|
|
||||||
group.getParent().removeChild(group);
|
|
||||||
}
|
|
||||||
group.setParent(toParent);
|
|
||||||
if (toParent != null) toParent.addChild(group);
|
|
||||||
else addTopLevelGroup(group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -688,46 +671,17 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getGroups() {
|
public List<GroupModel> getGroups() {
|
||||||
DBObject query = new QueryBuilder()
|
return session.realms().getGroups(this);
|
||||||
.and("realmId").is(getId())
|
|
||||||
.get();
|
|
||||||
List<MongoGroupEntity> groups = getMongoStore().loadEntities(MongoGroupEntity.class, query, invocationContext);
|
|
||||||
if (groups == null) return Collections.EMPTY_LIST;
|
|
||||||
|
|
||||||
List<GroupModel> result = new LinkedList<>();
|
|
||||||
|
|
||||||
if (groups == null) return result;
|
|
||||||
for (MongoGroupEntity group : groups) {
|
|
||||||
result.add(model.getGroupById(group.getId(), this));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups() {
|
public List<GroupModel> getTopLevelGroups() {
|
||||||
List<GroupModel> base = getGroups();
|
return session.realms().getTopLevelGroups(this);
|
||||||
if (base.isEmpty()) return base;
|
|
||||||
List<GroupModel> copy = new LinkedList<>();
|
|
||||||
for (GroupModel group : base) {
|
|
||||||
if (group.getParent() == null) {
|
|
||||||
copy.add(group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeGroup(GroupModel group) {
|
public boolean removeGroup(GroupModel group) {
|
||||||
if (realm.getDefaultGroups() != null) {
|
return session.realms().removeGroup(this, group);
|
||||||
getMongoStore().pullItemFromList(realm, "defaultGroups", group.getId(), invocationContext);
|
|
||||||
}
|
|
||||||
for (GroupModel subGroup : group.getSubGroups()) {
|
|
||||||
removeGroup(subGroup);
|
|
||||||
}
|
|
||||||
session.users().preRemove(this, group);
|
|
||||||
moveGroup(group, null);
|
|
||||||
return getMongoStore().removeEntity(MongoGroupEntity.class, group.getId(), invocationContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,20 @@ public interface RealmProvider extends Provider {
|
||||||
RealmModel getRealm(String id);
|
RealmModel getRealm(String id);
|
||||||
RealmModel getRealmByName(String name);
|
RealmModel getRealmByName(String name);
|
||||||
|
|
||||||
|
void moveGroup(RealmModel realm, GroupModel group, GroupModel toParent);
|
||||||
|
|
||||||
|
List<GroupModel> getGroups(RealmModel realm);
|
||||||
|
|
||||||
|
List<GroupModel> getTopLevelGroups(RealmModel realm);
|
||||||
|
|
||||||
|
boolean removeGroup(RealmModel realm, GroupModel group);
|
||||||
|
|
||||||
|
GroupModel createGroup(RealmModel realm, String name);
|
||||||
|
|
||||||
|
GroupModel createGroup(RealmModel realm, String id, String name);
|
||||||
|
|
||||||
|
void addTopLevelGroup(RealmModel realm, GroupModel subGroup);
|
||||||
|
|
||||||
ClientModel addClient(RealmModel realm, String clientId);
|
ClientModel addClient(RealmModel realm, String clientId);
|
||||||
|
|
||||||
ClientModel addClient(RealmModel realm, String id, String clientId);
|
ClientModel addClient(RealmModel realm, String id, String clientId);
|
||||||
|
|
0
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/ldap/base/LDAPGroupMapper2WaySyncTest.java
Normal file → Executable file
0
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/ldap/base/LDAPGroupMapper2WaySyncTest.java
Normal file → Executable file
|
@ -62,7 +62,7 @@
|
||||||
"user": "${keycloak.connectionsJpa.user:sa}",
|
"user": "${keycloak.connectionsJpa.user:sa}",
|
||||||
"password": "${keycloak.connectionsJpa.password:}",
|
"password": "${keycloak.connectionsJpa.password:}",
|
||||||
"databaseSchema": "${keycloak.connectionsJpa.databaseSchema:update}",
|
"databaseSchema": "${keycloak.connectionsJpa.databaseSchema:update}",
|
||||||
"showSql": "${keycloak.connectionsJpa.showSql:false}",
|
"showSql": "${keycloak.connectionsJpa.showSql:true}",
|
||||||
"formatSql": "${keycloak.connectionsJpa.formatSql:true}"
|
"formatSql": "${keycloak.connectionsJpa.formatSql:true}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue