groups initial
This commit is contained in:
parent
0d05d38eb6
commit
d896800ec6
52 changed files with 2406 additions and 2 deletions
81
core/src/main/java/org/keycloak/representations/idm/GroupRepresentation.java
Executable file
81
core/src/main/java/org/keycloak/representations/idm/GroupRepresentation.java
Executable file
|
@ -0,0 +1,81 @@
|
|||
package org.keycloak.representations.idm;
|
||||
|
||||
import org.codehaus.jackson.annotate.JsonIgnore;
|
||||
|
||||
import java.util.Arrays;
|
||||
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 class GroupRepresentation {
|
||||
private String id;
|
||||
private String name;
|
||||
protected Map<String, Object> attributes;
|
||||
protected List<String> realmRoles;
|
||||
protected Map<String, List<String>> clientRoles;
|
||||
protected List<GroupRepresentation> subGroups;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getRealmRoles() {
|
||||
return realmRoles;
|
||||
}
|
||||
|
||||
public void setRealmRoles(List<String> realmRoles) {
|
||||
this.realmRoles = realmRoles;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getClientRoles() {
|
||||
return clientRoles;
|
||||
}
|
||||
|
||||
public void setClientRoles(Map<String, List<String>> clientRoles) {
|
||||
this.clientRoles = clientRoles;
|
||||
}
|
||||
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// This method can be removed once we can remove backwards compatibility with Keycloak 1.3 (then getAttributes() can be changed to return Map<String, List<String>> )
|
||||
@JsonIgnore
|
||||
public Map<String, List<String>> getAttributesAsListValues() {
|
||||
return (Map) attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(Map<String, Object> attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public GroupRepresentation singleAttribute(String name, String value) {
|
||||
if (this.attributes == null) attributes = new HashMap<>();
|
||||
attributes.put(name, Arrays.asList(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<GroupRepresentation> getSubGroups() {
|
||||
return subGroups;
|
||||
}
|
||||
|
||||
public void setSubGroups(List<GroupRepresentation> subGroups) {
|
||||
this.subGroups = subGroups;
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@ public class RealmRepresentation {
|
|||
protected String certificate;
|
||||
protected String codeSecret;
|
||||
protected RolesRepresentation roles;
|
||||
protected List<GroupRepresentation> groups;
|
||||
protected List<String> defaultRoles;
|
||||
@Deprecated
|
||||
protected Set<String> requiredCredentials;
|
||||
|
@ -775,4 +776,12 @@ public class RealmRepresentation {
|
|||
public void setClientAuthenticationFlow(String clientAuthenticationFlow) {
|
||||
this.clientAuthenticationFlow = clientAuthenticationFlow;
|
||||
}
|
||||
|
||||
public List<GroupRepresentation> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
|
||||
public void setGroups(List<GroupRepresentation> groups) {
|
||||
this.groups = groups;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.examples.federation.properties;
|
||||
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
@ -106,6 +107,12 @@ public abstract class BasePropertiesFederationProvider implements UserFederation
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
// complete we dont'care if a role is removed
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the user is still in the properties file
|
||||
*
|
||||
|
|
|
@ -63,4 +63,6 @@ public class ClasspathPropertiesFederationProvider extends BasePropertiesFederat
|
|||
throw new IllegalStateException("Remove not supported");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
6
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java
Normal file → Executable file
6
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java
Normal file → Executable file
|
@ -12,6 +12,7 @@ import org.jboss.logging.Logger;
|
|||
import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
|
||||
import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
@ -105,6 +106,11 @@ public class KerberosFederationProvider implements UserFederationProvider {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(RealmModel realm, UserModel local) {
|
||||
// KerberosUsernamePasswordAuthenticator.isUserAvailable is an overhead, so avoid it for now
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore;
|
|||
import org.keycloak.federation.ldap.kerberos.LDAPProviderKerberosConfig;
|
||||
import org.keycloak.federation.ldap.mappers.LDAPFederationMapper;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.LDAPConstants;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
|
@ -319,6 +320,11 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
|||
// TODO: Maybe mappers callback to ensure role deletion propagated to LDAP by RoleLDAPFederationMapper?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
|
||||
}
|
||||
|
||||
public boolean validPassword(RealmModel realm, UserModel user, String password) {
|
||||
if (kerberosConfig.isAllowKerberosAuthentication() && kerberosConfig.isUseKerberosForPasswordAuthentication()) {
|
||||
// Use Kerberos JAAS (Krb5LoginModule)
|
||||
|
|
|
@ -57,7 +57,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
|
|||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.token.isActive() && this.token.getIssuedAt() > deployment.getNotBefore();
|
||||
return token != null && this.token.isActive() && this.token.getIssuedAt() > deployment.getNotBefore();
|
||||
}
|
||||
|
||||
public KeycloakDeployment getDeployment() {
|
||||
|
@ -111,6 +111,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
|
|||
log.debug("Token Verification succeeded!");
|
||||
} catch (VerificationException e) {
|
||||
log.error("failed verification of token");
|
||||
return false;
|
||||
}
|
||||
if (response.getNotBeforePolicy() > deployment.getNotBefore()) {
|
||||
deployment.setNotBefore(response.getNotBeforePolicy());
|
||||
|
|
74
model/api/src/main/java/org/keycloak/models/GroupModel.java
Executable file
74
model/api/src/main/java/org/keycloak/models/GroupModel.java
Executable file
|
@ -0,0 +1,74 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface GroupModel {
|
||||
String getId();
|
||||
|
||||
String getName();
|
||||
|
||||
void setName(String name);
|
||||
|
||||
/**
|
||||
* Set single value of specified attribute. Remove all other existing values
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
void setSingleAttribute(String name, String value);
|
||||
|
||||
void setAttribute(String name, List<String> values);
|
||||
|
||||
void removeAttribute(String name);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return null if there is not any value of specified attribute or first value otherwise. Don't throw exception if there are more values of the attribute
|
||||
*/
|
||||
String getFirstAttribute(String name);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return list of all attribute values or empty list if there are not any values. Never return null
|
||||
*/
|
||||
List<String> getAttribute(String name);
|
||||
|
||||
Map<String, List<String>> getAttributes();
|
||||
|
||||
Set<RoleModel> getRealmRoleMappings();
|
||||
Set<RoleModel> getClientRoleMappings(ClientModel app);
|
||||
boolean hasRole(RoleModel role);
|
||||
void grantRole(RoleModel role);
|
||||
Set<RoleModel> getRoleMappings();
|
||||
void deleteRoleMapping(RoleModel role);
|
||||
|
||||
GroupModel getParent();
|
||||
Set<GroupModel> getSubGroups();
|
||||
|
||||
/**
|
||||
* You must also call joinGroup on the parent group.
|
||||
*
|
||||
* @param group
|
||||
*/
|
||||
void setParent(GroupModel group);
|
||||
|
||||
/**
|
||||
* Automatically calls setParent() on the subGroup
|
||||
*
|
||||
* @param subGroup
|
||||
*/
|
||||
void addChild(GroupModel subGroup);
|
||||
|
||||
/**
|
||||
* Automatically calls setParent() on the subGroup
|
||||
*
|
||||
* @param subGroup
|
||||
*/
|
||||
void removeChild(GroupModel subGroup);
|
||||
}
|
|
@ -328,4 +328,12 @@ public interface RealmModel extends RoleContainerModel {
|
|||
void setSupportedLocales(Set<String> locales);
|
||||
String getDefaultLocale();
|
||||
void setDefaultLocale(String locale);
|
||||
|
||||
GroupModel getGroupById(String id);
|
||||
List<GroupModel> getGroups();
|
||||
List<GroupModel> getTopLevelGroups();
|
||||
boolean removeGroup(GroupModel group);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -20,8 +20,11 @@ public interface RealmProvider extends Provider {
|
|||
|
||||
RoleModel getRoleById(String id, RealmModel realm);
|
||||
ClientModel getClientById(String id, RealmModel realm);
|
||||
GroupModel getGroupById(String id, RealmModel realm);
|
||||
|
||||
|
||||
|
||||
List<RealmModel> getRealms();
|
||||
boolean removeRealm(String id);
|
||||
|
||||
void close();
|
||||
}
|
||||
|
|
|
@ -165,6 +165,16 @@ public class UserFederationManager implements UserProvider {
|
|||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||
return session.userStorage().getGroupMembers(realm, group, firstResult, maxResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
||||
return getGroupMembers(realm, group, -1, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||
UserModel user = session.userStorage().getUserByUsername(username.toLowerCase(), realm);
|
||||
|
@ -347,6 +357,16 @@ public class UserFederationManager implements UserProvider {
|
|||
session.userStorage().preRemove(realm, model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
||||
UserFederationProvider fed = getFederationProvider(federation);
|
||||
fed.preRemove(realm, group);
|
||||
}
|
||||
session.userStorage().preRemove(realm, group);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, RoleModel role) {
|
||||
for (UserFederationProviderModel federation : realm.getUserFederationProviders()) {
|
||||
|
|
|
@ -119,6 +119,14 @@ public interface UserFederationProvider extends Provider {
|
|||
*/
|
||||
void preRemove(RealmModel realm, RoleModel role);
|
||||
|
||||
/**
|
||||
* called before a role is removed.
|
||||
*
|
||||
* @param realm
|
||||
* @param group
|
||||
*/
|
||||
void preRemove(RealmModel realm, GroupModel group);
|
||||
|
||||
/**
|
||||
* Is the Keycloak UserModel still valid and/or existing in federated storage? Keycloak may call this method
|
||||
* in various user operations. The local storage may be deleted if this method returns false.
|
||||
|
|
|
@ -101,6 +101,11 @@ public interface UserModel {
|
|||
Set<RoleModel> getRoleMappings();
|
||||
void deleteRoleMapping(RoleModel role);
|
||||
|
||||
Set<GroupModel> getGroups();
|
||||
void joinGroup(GroupModel group);
|
||||
void leaveGroup(GroupModel group);
|
||||
boolean isMemberOf(GroupModel group);
|
||||
|
||||
String getFederationLink();
|
||||
void setFederationLink(String link);
|
||||
|
||||
|
|
|
@ -25,12 +25,16 @@ public interface UserProvider extends Provider {
|
|||
UserModel getUserById(String id, RealmModel realm);
|
||||
UserModel getUserByUsername(String username, RealmModel realm);
|
||||
UserModel getUserByEmail(String email, RealmModel realm);
|
||||
|
||||
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults);
|
||||
|
||||
UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
|
||||
UserModel getUserByServiceAccountClient(ClientModel client);
|
||||
List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts);
|
||||
|
||||
// Service account is included for counts
|
||||
int getUsersCount(RealmModel realm);
|
||||
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group);
|
||||
List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts);
|
||||
List<UserModel> searchForUser(String search, RealmModel realm);
|
||||
List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
|
||||
|
@ -48,6 +52,7 @@ public interface UserProvider extends Provider {
|
|||
void preRemove(RealmModel realm, UserFederationProviderModel link);
|
||||
|
||||
void preRemove(RealmModel realm, RoleModel role);
|
||||
void preRemove(RealmModel realm, GroupModel group);
|
||||
|
||||
void preRemove(RealmModel realm, ClientModel client);
|
||||
void preRemove(ClientModel realm, ProtocolMapperModel protocolMapper);
|
||||
|
|
60
model/api/src/main/java/org/keycloak/models/entities/GroupEntity.java
Executable file
60
model/api/src/main/java/org/keycloak/models/entities/GroupEntity.java
Executable file
|
@ -0,0 +1,60 @@
|
|||
package org.keycloak.models.entities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bburke@redhat.com">Bill Burke/a>
|
||||
*/
|
||||
public class GroupEntity extends AbstractIdentifiableEntity {
|
||||
|
||||
private String name;
|
||||
private String realmId;
|
||||
|
||||
private List<String> roleIds;
|
||||
private String parentId;
|
||||
private Map<String, List<String>> attributes;
|
||||
|
||||
public String getRealmId() {
|
||||
return realmId;
|
||||
}
|
||||
|
||||
public void setRealmId(String realmId) {
|
||||
this.realmId = realmId;
|
||||
}
|
||||
|
||||
public List<String> getRoleIds() {
|
||||
return roleIds;
|
||||
}
|
||||
|
||||
public void setRoleIds(List<String> roleIds) {
|
||||
this.roleIds = roleIds;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(Map<String, List<String>> attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(String parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ public class UserEntity extends AbstractIdentifiableEntity {
|
|||
private String realmId;
|
||||
|
||||
private List<String> roleIds;
|
||||
private List<String> groupIds;
|
||||
|
||||
private Map<String, List<String>> attributes;
|
||||
private List<String> requiredActions;
|
||||
|
@ -157,5 +158,13 @@ public class UserEntity extends AbstractIdentifiableEntity {
|
|||
public void setServiceAccountClientLink(String serviceAccountClientLink) {
|
||||
this.serviceAccountClientLink = serviceAccountClientLink;
|
||||
}
|
||||
|
||||
public List<String> getGroupIds() {
|
||||
return groupIds;
|
||||
}
|
||||
|
||||
public void setGroupIds(List<String> groupIds) {
|
||||
this.groupIds = groupIds;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.models.utils;
|
|||
import org.bouncycastle.openssl.PEMWriter;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.KeycloakSessionTask;
|
||||
|
@ -279,6 +280,24 @@ public final class KeycloakModelUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param groups
|
||||
* @param targetGroup
|
||||
* @return true if targetGroup is in groups (directly or indirectly via parent child relationship)
|
||||
*/
|
||||
public static boolean isMember(Set<GroupModel> groups, GroupModel targetGroup) {
|
||||
if (groups.contains(targetGroup)) return true;
|
||||
|
||||
for (GroupModel mapping : groups) {
|
||||
GroupModel child = mapping;
|
||||
while(child.getParent() != null) {
|
||||
if (child.getParent().equals(targetGroup)) return true;
|
||||
child = child.getParent();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// USER FEDERATION RELATED STUFF
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.models.utils;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
|
@ -255,4 +256,26 @@ public class UserModelDelegate implements UserModel {
|
|||
public void setCreatedTimestamp(Long timestamp){
|
||||
delegate.setCreatedTimestamp(timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getGroups() {
|
||||
return delegate.getGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinGroup(GroupModel group) {
|
||||
delegate.joinGroup(group);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveGroup(GroupModel group) {
|
||||
delegate.leaveGroup(group);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMemberOf(GroupModel group) {
|
||||
return delegate.isMemberOf(group);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.keycloak.connections.file.FileConnectionProvider;
|
|||
import org.keycloak.connections.file.InMemoryModel;
|
||||
import org.keycloak.migration.MigrationModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -78,6 +79,11 @@ public class FileRealmProvider implements RealmProvider {
|
|||
return realm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupById(String id, RealmModel realm) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm(String id) {
|
||||
RealmModel model = inMemoryModel.getRealm(id);
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.keycloak.connections.file.InMemoryModel;
|
|||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ModelException;
|
||||
|
@ -80,6 +81,21 @@ public class FileUserProvider implements UserProvider {
|
|||
return inMemoryModel.getUser(realm.getId(), userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||
for (UserModel user : inMemoryModel.getUsers(realm.getId())) {
|
||||
|
|
208
model/file/src/main/java/org/keycloak/models/file/adapter/GroupAdapter.java
Executable file
208
model/file/src/main/java/org/keycloak/models/file/adapter/GroupAdapter.java
Executable file
|
@ -0,0 +1,208 @@
|
|||
package org.keycloak.models.file.adapter;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.entities.GroupEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class GroupAdapter implements GroupModel {
|
||||
|
||||
private final GroupEntity group;
|
||||
private RealmModel realm;
|
||||
private KeycloakSession session;
|
||||
|
||||
public GroupAdapter(KeycloakSession session, RealmModel realm, GroupEntity group) {
|
||||
this.group = group;
|
||||
this.realm = realm;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return group.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return group.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
group.setName(name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || !(o instanceof GroupModel)) return false;
|
||||
|
||||
GroupModel that = (GroupModel) o;
|
||||
return that.getId().equals(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getId().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSingleAttribute(String name, String value) {
|
||||
if (group.getAttributes() == null) {
|
||||
group.setAttributes(new HashMap<String, List<String>>());
|
||||
}
|
||||
|
||||
List<String> attrValues = new ArrayList<>();
|
||||
attrValues.add(value);
|
||||
group.getAttributes().put(name, attrValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, List<String> values) {
|
||||
if (group.getAttributes() == null) {
|
||||
group.setAttributes(new HashMap<String, List<String>>());
|
||||
}
|
||||
|
||||
group.getAttributes().put(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
if (group.getAttributes() == null) return;
|
||||
|
||||
group.getAttributes().remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstAttribute(String name) {
|
||||
if (group.getAttributes()==null) return null;
|
||||
|
||||
List<String> attrValues = group.getAttributes().get(name);
|
||||
return (attrValues==null || attrValues.isEmpty()) ? null : attrValues.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAttribute(String name) {
|
||||
if (group.getAttributes()==null) return Collections.<String>emptyList();
|
||||
List<String> attrValues = group.getAttributes().get(name);
|
||||
return (attrValues == null) ? Collections.<String>emptyList() : Collections.unmodifiableList(attrValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
return group.getAttributes()==null ? Collections.<String, List<String>>emptyMap() : Collections.unmodifiableMap((Map) group.getAttributes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(RoleModel role) {
|
||||
Set<RoleModel> roles = getRoleMappings();
|
||||
return KeycloakModelUtils.hasRole(roles, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grantRole(RoleModel role) {
|
||||
if (group.getRoleIds() == null) {
|
||||
group.setRoleIds(new LinkedList<String>());
|
||||
}
|
||||
if (group.getRoleIds().contains(role.getId())) {
|
||||
return;
|
||||
}
|
||||
group.getRoleIds().add(role.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRoleMappings() {
|
||||
if (group.getRoleIds() == null || group.getRoleIds().isEmpty()) return Collections.EMPTY_SET;
|
||||
Set<RoleModel> roles = new HashSet<>();
|
||||
for (String id : group.getRoleIds()) {
|
||||
roles.add(realm.getRoleById(id));
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRealmRoleMappings() {
|
||||
Set<RoleModel> allRoles = getRoleMappings();
|
||||
|
||||
// Filter to retrieve just realm roles
|
||||
Set<RoleModel> realmRoles = new HashSet<RoleModel>();
|
||||
for (RoleModel role : allRoles) {
|
||||
if (role.getContainer() instanceof RealmModel) {
|
||||
realmRoles.add(role);
|
||||
}
|
||||
}
|
||||
return realmRoles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRoleMapping(RoleModel role) {
|
||||
if (group == null || role == null) return;
|
||||
if (group.getRoleIds() == null) return;
|
||||
group.getRoleIds().remove(role.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getClientRoleMappings(ClientModel app) {
|
||||
Set<RoleModel> result = new HashSet<RoleModel>();
|
||||
Set<RoleModel> roles = getRoleMappings();
|
||||
|
||||
for (RoleModel role : roles) {
|
||||
if (app.equals(role.getContainer())) {
|
||||
result.add(role);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getParent() {
|
||||
if (group.getParentId() == null) return null;
|
||||
return realm.getGroupById(group.getParentId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getSubGroups() {
|
||||
Set<GroupModel> subGroups = new HashSet<>();
|
||||
for (GroupModel groupModel : realm.getGroups()) {
|
||||
if (groupModel.getParent().equals(this)) {
|
||||
subGroups.add(groupModel);
|
||||
}
|
||||
}
|
||||
return subGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(GroupModel group) {
|
||||
this.group.setParentId(group.getId());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChild(GroupModel subGroup) {
|
||||
subGroup.setParent(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChild(GroupModel subGroup) {
|
||||
subGroup.setParent(null);
|
||||
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
|
|||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -88,6 +89,7 @@ public class RealmAdapter implements RealmModel {
|
|||
private final Map<String, ClientModel> allApps = new HashMap<String, ClientModel>();
|
||||
private ClientModel masterAdminApp = null;
|
||||
private final Map<String, RoleAdapter> allRoles = new HashMap<String, RoleAdapter>();
|
||||
private final Map<String, GroupAdapter> allGroups = new HashMap<String, GroupAdapter>();
|
||||
private final Map<String, IdentityProviderModel> allIdProviders = new HashMap<String, IdentityProviderModel>();
|
||||
|
||||
public RealmAdapter(KeycloakSession session, RealmEntity realm, InMemoryModel inMemoryModel) {
|
||||
|
@ -601,6 +603,36 @@ public class RealmAdapter implements RealmModel {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupById(String id) {
|
||||
GroupModel found = allGroups.get(id);
|
||||
if (found != null) return found;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupModel> getGroups() {
|
||||
List<GroupModel> list = new LinkedList<>();
|
||||
for (GroupAdapter group : allGroups.values()) {
|
||||
list.add(group);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupModel> getTopLevelGroups() {
|
||||
List<GroupModel> list = new LinkedList<>();
|
||||
for (GroupAdapter group : allGroups.values()) {
|
||||
if (group.getParent() == null) list.add(group);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGroup(GroupModel group) {
|
||||
return allGroups.remove(group.getId()) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDefaultRoles() {
|
||||
return realm.getDefaultRoles();
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.keycloak.models.ClientModel;
|
|||
|
||||
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
|
||||
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.OTPPolicy;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
|
@ -59,6 +60,7 @@ public class UserAdapter implements UserModel, Comparable {
|
|||
private final RealmModel realm;
|
||||
|
||||
private final Set<RoleModel> allRoles = new HashSet<RoleModel>();
|
||||
private final Set<GroupModel> allGroups = new HashSet<GroupModel>();
|
||||
|
||||
public UserAdapter(RealmModel realm, UserEntity userEntity, InMemoryModel inMemoryModel) {
|
||||
this.user = userEntity;
|
||||
|
@ -467,6 +469,29 @@ public class UserAdapter implements UserModel, Comparable {
|
|||
credentialEntity.setPeriod(credModel.getPeriod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getGroups() {
|
||||
return Collections.unmodifiableSet(allGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinGroup(GroupModel group) {
|
||||
allGroups.add(group);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveGroup(GroupModel group) {
|
||||
if (user == null || group == null) return;
|
||||
allGroups.remove(group);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMemberOf(GroupModel group) {
|
||||
return KeycloakModelUtils.isMember(getGroups(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(RoleModel role) {
|
||||
Set<RoleModel> roles = getRoleMappings();
|
||||
|
|
36
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheRealmProvider.java
vendored
Normal file → Executable file
36
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheRealmProvider.java
vendored
Normal file → Executable file
|
@ -21,9 +21,11 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
protected Set<String> realmInvalidations = new HashSet<String>();
|
||||
protected Set<String> appInvalidations = new HashSet<String>();
|
||||
protected Set<String> roleInvalidations = new HashSet<String>();
|
||||
protected Set<String> groupInvalidations = new HashSet<String>();
|
||||
protected Map<String, RealmModel> managedRealms = new HashMap<String, RealmModel>();
|
||||
protected Map<String, ClientModel> managedApplications = new HashMap<String, ClientModel>();
|
||||
protected Map<String, RoleModel> managedRoles = new HashMap<String, RoleModel>();
|
||||
protected Map<String, GroupModel> managedGroups = new HashMap<String, GroupModel>();
|
||||
|
||||
protected boolean clearAll;
|
||||
|
||||
|
@ -73,6 +75,12 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
roleInvalidations.add(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGroupInvalidation(String id) {
|
||||
groupInvalidations.add(id);
|
||||
|
||||
}
|
||||
|
||||
protected void runInvalidations() {
|
||||
for (String id : realmInvalidations) {
|
||||
cache.invalidateCachedRealmById(id);
|
||||
|
@ -80,6 +88,9 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
for (String id : roleInvalidations) {
|
||||
cache.invalidateRoleById(id);
|
||||
}
|
||||
for (String id : groupInvalidations) {
|
||||
cache.invalidateGroupById(id);
|
||||
}
|
||||
for (String id : appInvalidations) {
|
||||
cache.invalidateCachedApplicationById(id);
|
||||
}
|
||||
|
@ -254,6 +265,31 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
return adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupById(String id, RealmModel realm) {
|
||||
if (!cache.isEnabled()) return getDelegate().getGroupById(id, realm);
|
||||
CachedGroup cached = cache.getGroup(id);
|
||||
if (cached != null && !cached.getRealm().equals(realm.getId())) {
|
||||
cached = null;
|
||||
}
|
||||
|
||||
if (cached == null) {
|
||||
GroupModel model = getDelegate().getGroupById(id, realm);
|
||||
if (model == null) return null;
|
||||
if (groupInvalidations.contains(id)) return model;
|
||||
cached = new CachedGroup(realm, model);
|
||||
cache.addCachedGroup(cached);
|
||||
|
||||
} else if (groupInvalidations.contains(id)) {
|
||||
return getDelegate().getGroupById(id, realm);
|
||||
} else if (managedGroups.containsKey(id)) {
|
||||
return managedGroups.get(id);
|
||||
}
|
||||
GroupAdapter adapter = new GroupAdapter(cached, this, session, realm);
|
||||
managedGroups.put(id, adapter);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientModel getClientById(String id, RealmModel realm) {
|
||||
if (!cache.isEnabled()) return getDelegate().getClientById(id, realm);
|
||||
|
|
15
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java
vendored
Normal file → Executable file
15
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java
vendored
Normal file → Executable file
|
@ -197,6 +197,16 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
|
|||
return getDelegate().getUserByFederatedIdentity(socialLink, realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||
return getDelegate().getGroupMembers(realm, group, firstResult, maxResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
||||
return getDelegate().getGroupMembers(realm, group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserByServiceAccountClient(ClientModel client) {
|
||||
return getDelegate().getUserByServiceAccountClient(client);
|
||||
|
@ -313,6 +323,11 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
|
|||
public void preRemove(RealmModel realm, RoleModel role) {
|
||||
getDelegate().preRemove(realm, role);
|
||||
}
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
getDelegate().preRemove(realm, group);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, UserFederationProviderModel link) {
|
||||
|
|
236
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java
vendored
Executable file
236
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java
vendored
Executable file
|
@ -0,0 +1,236 @@
|
|||
package org.keycloak.models.cache.infinispan;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.cache.CacheRealmProvider;
|
||||
import org.keycloak.models.cache.CacheUserProvider;
|
||||
import org.keycloak.models.cache.entities.CachedGroup;
|
||||
import org.keycloak.models.cache.entities.CachedUser;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class GroupAdapter implements GroupModel {
|
||||
protected GroupModel updated;
|
||||
protected CachedGroup cached;
|
||||
protected CacheRealmProvider cacheSession;
|
||||
protected KeycloakSession keycloakSession;
|
||||
protected RealmModel realm;
|
||||
|
||||
public GroupAdapter(CachedGroup cached, CacheRealmProvider cacheSession, KeycloakSession keycloakSession, RealmModel realm) {
|
||||
this.cached = cached;
|
||||
this.cacheSession = cacheSession;
|
||||
this.keycloakSession = keycloakSession;
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
protected void getDelegateForUpdate() {
|
||||
if (updated == null) {
|
||||
cacheSession.registerGroupInvalidation(getId());
|
||||
updated = cacheSession.getDelegate().getGroupById(getId(), realm);
|
||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || !(o instanceof GroupModel)) return false;
|
||||
|
||||
GroupModel that = (GroupModel) o;
|
||||
|
||||
if (!cached.getId().equals(that.getId())) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return cached.getId().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
if (updated != null) return updated.getId();
|
||||
return cached.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (updated != null) return updated.getName();
|
||||
return cached.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
getDelegateForUpdate();
|
||||
updated.setName(name);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSingleAttribute(String name, String value) {
|
||||
getDelegateForUpdate();
|
||||
updated.setSingleAttribute(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, List<String> values) {
|
||||
getDelegateForUpdate();
|
||||
updated.setAttribute(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
getDelegateForUpdate();
|
||||
updated.removeAttribute(name);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstAttribute(String name) {
|
||||
if (updated != null) return updated.getFirstAttribute(name);
|
||||
return cached.getAttributes().getFirst(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAttribute(String name) {
|
||||
List<String> values = cached.getAttributes().get(name);
|
||||
if (values == null) return null;
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
return cached.getAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRealmRoleMappings() {
|
||||
if (updated != null) return updated.getRealmRoleMappings();
|
||||
Set<RoleModel> roleMappings = getRoleMappings();
|
||||
Set<RoleModel> realmMappings = new HashSet<RoleModel>();
|
||||
for (RoleModel role : roleMappings) {
|
||||
RoleContainerModel container = role.getContainer();
|
||||
if (container instanceof RealmModel) {
|
||||
if (((RealmModel) container).getId().equals(realm.getId())) {
|
||||
realmMappings.add(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
return realmMappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getClientRoleMappings(ClientModel app) {
|
||||
if (updated != null) return updated.getClientRoleMappings(app);
|
||||
Set<RoleModel> roleMappings = getRoleMappings();
|
||||
Set<RoleModel> appMappings = new HashSet<RoleModel>();
|
||||
for (RoleModel role : roleMappings) {
|
||||
RoleContainerModel container = role.getContainer();
|
||||
if (container instanceof ClientModel) {
|
||||
if (((ClientModel) container).getId().equals(app.getId())) {
|
||||
appMappings.add(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
return appMappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(RoleModel role) {
|
||||
if (updated != null) return updated.hasRole(role);
|
||||
if (cached.getRoleMappings().contains(role.getId())) return true;
|
||||
|
||||
Set<RoleModel> mappings = getRoleMappings();
|
||||
for (RoleModel mapping: mappings) {
|
||||
if (mapping.hasRole(role)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grantRole(RoleModel role) {
|
||||
getDelegateForUpdate();
|
||||
updated.grantRole(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRoleMappings() {
|
||||
if (updated != null) return updated.getRoleMappings();
|
||||
Set<RoleModel> roles = new HashSet<RoleModel>();
|
||||
for (String id : cached.getRoleMappings()) {
|
||||
RoleModel roleById = keycloakSession.realms().getRoleById(id, realm);
|
||||
if (roleById == null) {
|
||||
// chance that role was removed, so just delegate to persistence and get user invalidated
|
||||
getDelegateForUpdate();
|
||||
return updated.getRoleMappings();
|
||||
}
|
||||
roles.add(roleById);
|
||||
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRoleMapping(RoleModel role) {
|
||||
getDelegateForUpdate();
|
||||
updated.deleteRoleMapping(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getParent() {
|
||||
if (updated != null) return updated.getParent();
|
||||
if (cached.getParentId() == null) return null;
|
||||
return keycloakSession.realms().getGroupById(cached.getParentId(), realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getSubGroups() {
|
||||
if (updated != null) return updated.getSubGroups();
|
||||
Set<GroupModel> subGroups = new HashSet<>();
|
||||
for (String id : cached.getSubGroups()) {
|
||||
GroupModel subGroup = keycloakSession.realms().getGroupById(id, realm);
|
||||
if (subGroup == null) {
|
||||
// chance that role was removed, so just delegate to persistence and get user invalidated
|
||||
getDelegateForUpdate();
|
||||
return updated.getSubGroups();
|
||||
|
||||
}
|
||||
subGroups.add(subGroup);
|
||||
}
|
||||
return subGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(GroupModel group) {
|
||||
getDelegateForUpdate();
|
||||
updated.setParent(group);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChild(GroupModel subGroup) {
|
||||
getDelegateForUpdate();
|
||||
updated.addChild(subGroup);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChild(GroupModel subGroup) {
|
||||
getDelegateForUpdate();
|
||||
updated.removeChild(subGroup);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import org.infinispan.Cache;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.cache.RealmCache;
|
||||
import org.keycloak.models.cache.entities.CachedClient;
|
||||
import org.keycloak.models.cache.entities.CachedGroup;
|
||||
import org.keycloak.models.cache.entities.CachedRealm;
|
||||
import org.keycloak.models.cache.entities.CachedRole;
|
||||
|
||||
|
@ -101,12 +102,49 @@ public class InfinispanRealmCache implements RealmCache {
|
|||
cache.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedGroup getGroup(String id) {
|
||||
if (!enabled) return null;
|
||||
return get(id, CachedGroup.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateGroup(CachedGroup role) {
|
||||
logger.tracev("Removing group {0}", role.getId());
|
||||
cache.remove(role.getId());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCachedGroup(CachedGroup role) {
|
||||
if (!enabled) return;
|
||||
logger.tracev("Adding group {0}", role.getId());
|
||||
cache.put(role.getId(), role);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCachedGroupById(String id) {
|
||||
logger.tracev("Removing group {0}", id);
|
||||
cache.remove(id);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateGroupById(String id) {
|
||||
logger.tracev("Removing group {0}", id);
|
||||
cache.remove(id);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedRole getRole(String id) {
|
||||
if (!enabled) return null;
|
||||
return get(id, CachedRole.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void invalidateRole(CachedRole role) {
|
||||
logger.tracev("Removing role {0}", role.getId());
|
||||
|
|
|
@ -1262,4 +1262,42 @@ public class RealmAdapter implements RealmModel {
|
|||
if (updated != null) return updated.getRequiredActionProviderByAlias(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 null;
|
||||
List<GroupModel> list = new LinkedList<>();
|
||||
for (String id : cached.getGroups()) {
|
||||
GroupModel group = cacheSession.getGroupById(id, this);
|
||||
if (group == null) continue;
|
||||
list.add(group);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupModel> getTopLevelGroups() {
|
||||
List<GroupModel> all = getGroups();
|
||||
Iterator<GroupModel> it = all.iterator();
|
||||
while (it.hasNext()) {
|
||||
GroupModel group = it.next();
|
||||
if (group.getParent() != null) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGroup(GroupModel group) {
|
||||
getDelegateForUpdate();
|
||||
return updated.removeGroup(group);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -317,6 +317,44 @@ public class UserAdapter implements UserModel {
|
|||
updated.deleteRoleMapping(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getGroups() {
|
||||
if (updated != null) return updated.getGroups();
|
||||
Set<GroupModel> groups = new HashSet<GroupModel>();
|
||||
for (String id : cached.getRoleMappings()) {
|
||||
GroupModel groupModel = keycloakSession.realms().getGroupById(id, realm);
|
||||
if (groupModel == null) {
|
||||
// chance that role was removed, so just delete to persistence and get user invalidated
|
||||
getDelegateForUpdate();
|
||||
return updated.getGroups();
|
||||
}
|
||||
groups.add(groupModel);
|
||||
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinGroup(GroupModel group) {
|
||||
getDelegateForUpdate();
|
||||
updated.joinGroup(group);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveGroup(GroupModel group) {
|
||||
getDelegateForUpdate();
|
||||
updated.leaveGroup(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMemberOf(GroupModel group) {
|
||||
if (updated != null) return updated.isMemberOf(group);
|
||||
if (cached.getGroups().contains(group.getId())) return true;
|
||||
Set<GroupModel> roles = getGroups();
|
||||
return KeycloakModelUtils.isMember(roles, group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConsent(UserConsentModel consent) {
|
||||
getDelegateForUpdate();
|
||||
|
@ -348,4 +386,5 @@ public class UserAdapter implements UserModel {
|
|||
getDelegateForUpdate();
|
||||
return updated.revokeConsentForClient(clientId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,4 +17,6 @@ public interface CacheRealmProvider extends RealmProvider {
|
|||
void registerApplicationInvalidation(String id);
|
||||
|
||||
void registerRoleInvalidation(String id);
|
||||
|
||||
void registerGroupInvalidation(String id);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.models.cache;
|
||||
|
||||
import org.keycloak.models.cache.entities.CachedClient;
|
||||
import org.keycloak.models.cache.entities.CachedGroup;
|
||||
import org.keycloak.models.cache.entities.CachedRealm;
|
||||
import org.keycloak.models.cache.entities.CachedRole;
|
||||
|
||||
|
@ -39,6 +40,16 @@ public interface RealmCache {
|
|||
|
||||
void invalidateRoleById(String id);
|
||||
|
||||
CachedGroup getGroup(String id);
|
||||
|
||||
void invalidateGroup(CachedGroup role);
|
||||
|
||||
void addCachedGroup(CachedGroup role);
|
||||
|
||||
void invalidateCachedGroupById(String id);
|
||||
|
||||
void invalidateGroupById(String id);
|
||||
|
||||
boolean isEnabled();
|
||||
|
||||
void setEnabled(boolean enabled);
|
||||
|
|
74
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedGroup.java
vendored
Executable file
74
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedGroup.java
vendored
Executable file
|
@ -0,0 +1,74 @@
|
|||
package org.keycloak.models.cache.entities;
|
||||
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
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 CachedGroup implements Serializable {
|
||||
private String id;
|
||||
private String realm;
|
||||
private String name;
|
||||
private String parentId;
|
||||
private MultivaluedHashMap<String, String> attributes = new MultivaluedHashMap<>();
|
||||
private Set<String> roleMappings = new HashSet<>();
|
||||
private Set<String> subGroups = new HashSet<>();
|
||||
|
||||
public CachedGroup(RealmModel realm, GroupModel group) {
|
||||
this.id = group.getId();
|
||||
this.realm = realm.getId();
|
||||
this.name = group.getName();
|
||||
if (group.getParent() != null) this.parentId = group.getParent().getId();
|
||||
|
||||
this.attributes.putAll(group.getAttributes());
|
||||
for (RoleModel role : group.getRoleMappings()) {
|
||||
roleMappings.add(role.getId());
|
||||
}
|
||||
Set<GroupModel> subGroups1 = group.getSubGroups();
|
||||
if (subGroups1 != null) {
|
||||
for (GroupModel subGroup : subGroups1) {
|
||||
subGroups.add(subGroup.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public MultivaluedHashMap<String, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public Set<String> getRoleMappings() {
|
||||
return roleMappings;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public Set<String> getSubGroups() {
|
||||
return subGroups;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
|
|||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.OTPPolicy;
|
||||
|
@ -106,6 +107,7 @@ public class CachedRealm implements Serializable {
|
|||
protected Set<String> adminEnabledEventOperations = new HashSet<String>();
|
||||
protected boolean adminEventsDetailsEnabled;
|
||||
private List<String> defaultRoles = new LinkedList<String>();
|
||||
private Set<String> groups = new HashSet<String>();
|
||||
private Map<String, String> realmRoles = new HashMap<String, String>();
|
||||
private Map<String, String> clients = new HashMap<String, String>();
|
||||
private boolean internationalizationEnabled;
|
||||
|
@ -216,6 +218,9 @@ public class CachedRealm implements Serializable {
|
|||
executionsById.put(execution.getId(), execution);
|
||||
}
|
||||
}
|
||||
for (GroupModel group : model.getGroups()) {
|
||||
groups.add(group.getId());
|
||||
}
|
||||
for (AuthenticatorConfigModel authenticator : model.getAuthenticatorConfigs()) {
|
||||
authenticatorConfigs.put(authenticator.getId(), authenticator);
|
||||
}
|
||||
|
@ -507,4 +512,8 @@ public class CachedRealm implements Serializable {
|
|||
public AuthenticationFlowModel getClientAuthenticationFlow() {
|
||||
return clientAuthenticationFlow;
|
||||
}
|
||||
|
||||
public Set<String> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.models.cache.entities;
|
||||
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
|
@ -33,6 +34,7 @@ public class CachedUser implements Serializable {
|
|||
private MultivaluedHashMap<String, String> attributes = new MultivaluedHashMap<>();
|
||||
private Set<String> requiredActions = new HashSet<>();
|
||||
private Set<String> roleMappings = new HashSet<>();
|
||||
private Set<String> groups = new HashSet<>();
|
||||
|
||||
public CachedUser(RealmModel realm, UserModel user) {
|
||||
this.id = user.getId();
|
||||
|
@ -53,6 +55,12 @@ public class CachedUser implements Serializable {
|
|||
for (RoleModel role : user.getRoleMappings()) {
|
||||
roleMappings.add(role.getId());
|
||||
}
|
||||
Set<GroupModel> groupMappings = user.getGroups();
|
||||
if (groupMappings != null) {
|
||||
for (GroupModel group : groupMappings) {
|
||||
groups.add(group.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -118,4 +126,8 @@ public class CachedUser implements Serializable {
|
|||
public String getServiceAccountClientLink() {
|
||||
return serviceAccountClientLink;
|
||||
}
|
||||
|
||||
public Set<String> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
|
320
model/jpa/src/main/java/org/keycloak/models/jpa/GroupAdapter.java
Executable file
320
model/jpa/src/main/java/org/keycloak/models/jpa/GroupAdapter.java
Executable file
|
@ -0,0 +1,320 @@
|
|||
package org.keycloak.models.jpa;
|
||||
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.OTPPolicy;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.jpa.entities.CredentialEntity;
|
||||
import org.keycloak.models.jpa.entities.GroupAttributeEntity;
|
||||
import org.keycloak.models.jpa.entities.GroupEntity;
|
||||
import org.keycloak.models.jpa.entities.GroupRoleMappingEntity;
|
||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||
import org.keycloak.models.jpa.entities.UserAttributeEntity;
|
||||
import org.keycloak.models.jpa.entities.UserConsentEntity;
|
||||
import org.keycloak.models.jpa.entities.UserConsentProtocolMapperEntity;
|
||||
import org.keycloak.models.jpa.entities.UserConsentRoleEntity;
|
||||
import org.keycloak.models.jpa.entities.UserEntity;
|
||||
import org.keycloak.models.jpa.entities.UserRequiredActionEntity;
|
||||
import org.keycloak.models.jpa.entities.UserRoleMappingEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class GroupAdapter implements GroupModel {
|
||||
|
||||
protected GroupEntity group;
|
||||
protected EntityManager em;
|
||||
protected RealmModel realm;
|
||||
|
||||
public GroupAdapter(RealmModel realm, EntityManager em, GroupEntity group) {
|
||||
this.em = em;
|
||||
this.group = group;
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public GroupEntity getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return group.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return group.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
group.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getParent() {
|
||||
GroupEntity parent = group.getParent();
|
||||
if (parent == null) return null;
|
||||
return realm.getGroupById(parent.getId());
|
||||
}
|
||||
|
||||
public static GroupEntity toEntity(GroupModel model, EntityManager em) {
|
||||
if (model instanceof GroupAdapter) {
|
||||
return ((GroupAdapter)model).getGroup();
|
||||
}
|
||||
return em.getReference(GroupEntity.class, model.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(GroupModel group) {
|
||||
GroupEntity parent = toEntity(group, em);
|
||||
group.setParent(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChild(GroupModel subGroup) {
|
||||
subGroup.setParent(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChild(GroupModel subGroup) {
|
||||
subGroup.setParent(null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getSubGroups() {
|
||||
TypedQuery<String> query = em.createNamedQuery("getGroupIdsByParent", String.class);
|
||||
query.setParameter("parent", group);
|
||||
List<String> ids = query.getResultList();
|
||||
Set<GroupModel> set = new HashSet<>();
|
||||
for (String id : ids) {
|
||||
GroupModel subGroup = realm.getGroupById(id);
|
||||
if (subGroup == null) continue;
|
||||
set.add(subGroup);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSingleAttribute(String name, String value) {
|
||||
boolean found = false;
|
||||
List<GroupAttributeEntity> toRemove = new ArrayList<>();
|
||||
for (GroupAttributeEntity attr : group.getAttributes()) {
|
||||
if (attr.getName().equals(name)) {
|
||||
if (!found) {
|
||||
attr.setValue(value);
|
||||
found = true;
|
||||
} else {
|
||||
toRemove.add(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (GroupAttributeEntity attr : toRemove) {
|
||||
em.remove(attr);
|
||||
group.getAttributes().remove(attr);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
return;
|
||||
}
|
||||
|
||||
persistAttributeValue(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, List<String> values) {
|
||||
// Remove all existing
|
||||
removeAttribute(name);
|
||||
|
||||
// Put all new
|
||||
for (String value : values) {
|
||||
persistAttributeValue(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void persistAttributeValue(String name, String value) {
|
||||
GroupAttributeEntity attr = new GroupAttributeEntity();
|
||||
attr.setId(KeycloakModelUtils.generateId());
|
||||
attr.setName(name);
|
||||
attr.setValue(value);
|
||||
attr.setGroup(group);
|
||||
em.persist(attr);
|
||||
group.getAttributes().add(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
Iterator<GroupAttributeEntity> it = group.getAttributes().iterator();
|
||||
while (it.hasNext()) {
|
||||
GroupAttributeEntity attr = it.next();
|
||||
if (attr.getName().equals(name)) {
|
||||
it.remove();
|
||||
em.remove(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstAttribute(String name) {
|
||||
for (GroupAttributeEntity attr : group.getAttributes()) {
|
||||
if (attr.getName().equals(name)) {
|
||||
return attr.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAttribute(String name) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (GroupAttributeEntity attr : group.getAttributes()) {
|
||||
if (attr.getName().equals(name)) {
|
||||
result.add(attr.getValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
MultivaluedHashMap<String, String> result = new MultivaluedHashMap<>();
|
||||
for (GroupAttributeEntity attr : group.getAttributes()) {
|
||||
result.add(attr.getName(), attr.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(RoleModel role) {
|
||||
Set<RoleModel> roles = getRoleMappings();
|
||||
return KeycloakModelUtils.hasRole(roles, role);
|
||||
}
|
||||
|
||||
protected TypedQuery<GroupRoleMappingEntity> getGroupRoleMappingEntityTypedQuery(RoleModel role) {
|
||||
TypedQuery<GroupRoleMappingEntity> query = em.createNamedQuery("groupHasRole", GroupRoleMappingEntity.class);
|
||||
query.setParameter("group", getGroup());
|
||||
query.setParameter("roleId", role.getId());
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grantRole(RoleModel role) {
|
||||
if (hasRole(role)) return;
|
||||
GroupRoleMappingEntity entity = new GroupRoleMappingEntity();
|
||||
entity.setGroup(getGroup());
|
||||
entity.setRoleId(role.getId());
|
||||
em.persist(entity);
|
||||
em.flush();
|
||||
em.detach(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRealmRoleMappings() {
|
||||
Set<RoleModel> roleMappings = getRoleMappings();
|
||||
|
||||
Set<RoleModel> realmRoles = new HashSet<RoleModel>();
|
||||
for (RoleModel role : roleMappings) {
|
||||
RoleContainerModel container = role.getContainer();
|
||||
if (container instanceof RealmModel) {
|
||||
realmRoles.add(role);
|
||||
}
|
||||
}
|
||||
return realmRoles;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRoleMappings() {
|
||||
// we query ids only as the role might be cached and following the @ManyToOne will result in a load
|
||||
// even if we're getting just the id.
|
||||
TypedQuery<String> query = em.createNamedQuery("groupRoleMappingIds", String.class);
|
||||
query.setParameter("group", getGroup());
|
||||
List<String> ids = query.getResultList();
|
||||
Set<RoleModel> roles = new HashSet<RoleModel>();
|
||||
for (String roleId : ids) {
|
||||
RoleModel roleById = realm.getRoleById(roleId);
|
||||
if (roleById == null) continue;
|
||||
roles.add(roleById);
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRoleMapping(RoleModel role) {
|
||||
if (group == null || role == null) return;
|
||||
|
||||
TypedQuery<GroupRoleMappingEntity> query = getGroupRoleMappingEntityTypedQuery(role);
|
||||
List<GroupRoleMappingEntity> results = query.getResultList();
|
||||
if (results.size() == 0) return;
|
||||
for (GroupRoleMappingEntity entity : results) {
|
||||
em.remove(entity);
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getClientRoleMappings(ClientModel app) {
|
||||
Set<RoleModel> roleMappings = getRoleMappings();
|
||||
|
||||
Set<RoleModel> roles = new HashSet<RoleModel>();
|
||||
for (RoleModel role : roleMappings) {
|
||||
RoleContainerModel container = role.getContainer();
|
||||
if (container instanceof ClientModel) {
|
||||
ClientModel appModel = (ClientModel)container;
|
||||
if (appModel.getId().equals(app.getId())) {
|
||||
roles.add(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || !(o instanceof UserModel)) return false;
|
||||
|
||||
UserModel that = (UserModel) o;
|
||||
return that.getId().equals(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getId().hashCode();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -2,11 +2,13 @@ package org.keycloak.models.jpa;
|
|||
|
||||
import org.keycloak.migration.MigrationModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.jpa.entities.ClientEntity;
|
||||
import org.keycloak.models.jpa.entities.GroupEntity;
|
||||
import org.keycloak.models.jpa.entities.RealmEntity;
|
||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
@ -117,6 +119,14 @@ public class JpaRealmProvider implements RealmProvider {
|
|||
return new RoleAdapter(realm, em, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupById(String id, RealmModel realm) {
|
||||
GroupEntity groupEntity = em.find(GroupEntity.class, id);
|
||||
if (groupEntity == null) return null;
|
||||
if (groupEntity.getRealm().getId().equals(realm.getId())) return null;
|
||||
return new GroupAdapter(realm, em, groupEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientModel getClientById(String id, RealmModel realm) {
|
||||
ClientEntity app = em.find(ClientEntity.class, id);
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.models.jpa;
|
|||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -169,6 +170,8 @@ public class JpaUserProvider implements UserProvider {
|
|||
.setParameter("realmId", realm.getId()).executeUpdate();
|
||||
num = em.createNamedQuery("deleteUsersByRealm")
|
||||
.setParameter("realmId", realm.getId()).executeUpdate();
|
||||
num = em.createNamedQuery("deleteUserGroupMembershipByRealm")
|
||||
.setParameter("realmId", realm.getId()).executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -219,6 +222,25 @@ public class JpaUserProvider implements UserProvider {
|
|||
.executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
||||
TypedQuery<UserEntity> query = em.createNamedQuery("groupMembership", UserEntity.class);
|
||||
query.setParameter("groupId", group.getId());
|
||||
List<UserEntity> results = query.getResultList();
|
||||
|
||||
List<UserModel> users = new ArrayList<UserModel>();
|
||||
for (UserEntity user : results) {
|
||||
users.add(new UserAdapter(realm, em, user));
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
em.createNamedQuery("deleteUserGroupMembershipsByGroup").setParameter("groupId", group.getId()).executeUpdate();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserById(String id, RealmModel realm) {
|
||||
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserById", UserEntity.class);
|
||||
|
@ -318,6 +340,25 @@ public class JpaUserProvider implements UserProvider {
|
|||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||
TypedQuery<UserEntity> query = em.createNamedQuery("groupMembership", UserEntity.class);
|
||||
query.setParameter("groupId", group.getId());
|
||||
if (firstResult != -1) {
|
||||
query.setFirstResult(firstResult);
|
||||
}
|
||||
if (maxResults != -1) {
|
||||
query.setMaxResults(maxResults);
|
||||
}
|
||||
List<UserEntity> results = query.getResultList();
|
||||
|
||||
List<UserModel> users = new ArrayList<UserModel>();
|
||||
for (UserEntity user : results) {
|
||||
users.add(new UserAdapter(realm, em, user));
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(String search, RealmModel realm) {
|
||||
return searchForUser(search, realm, -1, -1);
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
|
|||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -24,6 +25,7 @@ import org.keycloak.models.jpa.entities.AuthenticationExecutionEntity;
|
|||
import org.keycloak.models.jpa.entities.AuthenticationFlowEntity;
|
||||
import org.keycloak.models.jpa.entities.AuthenticatorConfigEntity;
|
||||
import org.keycloak.models.jpa.entities.ClientEntity;
|
||||
import org.keycloak.models.jpa.entities.GroupEntity;
|
||||
import org.keycloak.models.jpa.entities.IdentityProviderEntity;
|
||||
import org.keycloak.models.jpa.entities.IdentityProviderMapperEntity;
|
||||
import org.keycloak.models.jpa.entities.RealmAttributeEntity;
|
||||
|
@ -1944,4 +1946,60 @@ public class RealmAdapter implements RealmModel {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupById(String id) {
|
||||
GroupEntity groupEntity = em.find(GroupEntity.class, id);
|
||||
if (groupEntity == null) return null;
|
||||
if (groupEntity.getRealm().getId().equals(getId())) return null;
|
||||
return new GroupAdapter(this, em, groupEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupModel> getGroups() {
|
||||
List<GroupModel> list = new LinkedList<>();
|
||||
Collection<GroupEntity> groups = realm.getGroups();
|
||||
if (groups == null) return list;
|
||||
for (GroupEntity entity : groups) {
|
||||
list.add(new GroupAdapter(this, em, entity));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupModel> getTopLevelGroups() {
|
||||
List<GroupModel> all = getGroups();
|
||||
Iterator<GroupModel> it = all.iterator();
|
||||
while (it.hasNext()) {
|
||||
GroupModel group = it.next();
|
||||
if (group.getParent() != null) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGroup(GroupModel group) {
|
||||
if (group == null) {
|
||||
return false;
|
||||
}
|
||||
GroupEntity groupEntity = GroupAdapter.toEntity(group, em);
|
||||
if (!groupEntity.getRealm().getId().equals(getId())) {
|
||||
return false;
|
||||
}
|
||||
for (GroupModel subGroup : group.getSubGroups()) {
|
||||
removeGroup(subGroup);
|
||||
}
|
||||
|
||||
|
||||
session.users().preRemove(this, group);
|
||||
realm.getGroups().remove(groupEntity);
|
||||
em.createNamedQuery("deleteGroupAttributesByGroup").setParameter("group", group).executeUpdate();
|
||||
em.createNamedQuery("deleteGroupRoleMappingsByGroup").setParameter("group", group).executeUpdate();
|
||||
em.remove(groupEntity);
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.models.jpa;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.OTPPolicy;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
|
@ -19,6 +20,7 @@ import org.keycloak.models.jpa.entities.UserConsentProtocolMapperEntity;
|
|||
import org.keycloak.models.jpa.entities.UserConsentRoleEntity;
|
||||
import org.keycloak.models.jpa.entities.UserAttributeEntity;
|
||||
import org.keycloak.models.jpa.entities.UserEntity;
|
||||
import org.keycloak.models.jpa.entities.UserGroupMembershipEntity;
|
||||
import org.keycloak.models.jpa.entities.UserRequiredActionEntity;
|
||||
import org.keycloak.models.jpa.entities.UserRoleMappingEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
@ -485,6 +487,63 @@ public class UserAdapter implements UserModel {
|
|||
em.flush();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getGroups() {
|
||||
// we query ids only as the group might be cached and following the @ManyToOne will result in a load
|
||||
// even if we're getting just the id.
|
||||
TypedQuery<String> query = em.createNamedQuery("userGroupIds", String.class);
|
||||
query.setParameter("user", getUser());
|
||||
List<String> ids = query.getResultList();
|
||||
Set<GroupModel> groups = new HashSet<>();
|
||||
for (String groupId : ids) {
|
||||
GroupModel group = realm.getGroupById(groupId);
|
||||
if (group == null) continue;
|
||||
groups.add(group);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinGroup(GroupModel group) {
|
||||
if (isMemberOf(group)) return;
|
||||
UserGroupMembershipEntity entity = new UserGroupMembershipEntity();
|
||||
entity.setUser(getUser());
|
||||
entity.setGroupId(group.getId());
|
||||
em.persist(entity);
|
||||
em.flush();
|
||||
em.detach(entity);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveGroup(GroupModel group) {
|
||||
if (user == null || group == null) return;
|
||||
|
||||
TypedQuery<UserGroupMembershipEntity> query = getUserGroupMappingQuery(group);
|
||||
List<UserGroupMembershipEntity> results = query.getResultList();
|
||||
if (results.size() == 0) return;
|
||||
for (UserGroupMembershipEntity entity : results) {
|
||||
em.remove(entity);
|
||||
}
|
||||
em.flush();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMemberOf(GroupModel group) {
|
||||
Set<GroupModel> roles = getGroups();
|
||||
return KeycloakModelUtils.isMember(roles, group);
|
||||
}
|
||||
|
||||
protected TypedQuery<UserGroupMembershipEntity> getUserGroupMappingQuery(GroupModel group) {
|
||||
TypedQuery<UserGroupMembershipEntity> query = em.createNamedQuery("userMemberOf", UserGroupMembershipEntity.class);
|
||||
query.setParameter("user", getUser());
|
||||
query.setParameter("groupId", group.getId());
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasRole(RoleModel role) {
|
||||
Set<RoleModel> roles = getRoleMappings();
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@NamedQueries({
|
||||
@NamedQuery(name="getGroupAttributesByNameAndValue", query="select attr from GroupAttributeEntity attr where attr.name = :name and attr.value = :value"),
|
||||
@NamedQuery(name="deleteGroupAttributesByGroup", query="delete from GroupAttributeEntity attr where attr.group = :group"),
|
||||
@NamedQuery(name="deleteGroupAttributesByRealm", query="delete from GroupAttributeEntity attr where attr.group IN (select u from GroupEntity u where u.realmId=:realmId)")
|
||||
})
|
||||
@Table(name="USER_ATTRIBUTE")
|
||||
@Entity
|
||||
public class GroupAttributeEntity {
|
||||
|
||||
@Id
|
||||
@Column(name="ID", length = 36)
|
||||
protected String id;
|
||||
|
||||
@ManyToOne(fetch= FetchType.LAZY)
|
||||
@JoinColumn(name = "GROUP_ID")
|
||||
protected GroupEntity group;
|
||||
|
||||
@Column(name = "NAME")
|
||||
protected String name;
|
||||
@Column(name = "VALUE")
|
||||
protected String value;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public GroupEntity getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(GroupEntity group) {
|
||||
this.group = group;
|
||||
}
|
||||
}
|
109
model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java
Executable file
109
model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java
Executable file
|
@ -0,0 +1,109 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@NamedQueries({
|
||||
@NamedQuery(name="getAllGroupsByRealm", query="select u from GroupEntity u where u.realmId = :realmId order by u.name"),
|
||||
@NamedQuery(name="getGroupById", query="select u from GroupEntity u where u.id = :id and u.realmId = :realmId"),
|
||||
@NamedQuery(name="getGroupIdsByParent", query="select u.id from GroupEntity u where u.parent = :parent"),
|
||||
@NamedQuery(name="getGroupByName", query="select u from GroupEntity u where u.name = :name and u.realmId = :realmId"),
|
||||
@NamedQuery(name="getGroupCount", query="select count(u) from GroupEntity u where u.realmId = :realmId"),
|
||||
@NamedQuery(name="deleteGroupsByRealm", query="delete from GroupEntity u where u.realmId = :realmId")
|
||||
})
|
||||
@Entity
|
||||
@Table(name="GROUP_ENTITY")
|
||||
public class GroupEntity {
|
||||
@Id
|
||||
@Column(name="ID", length = 36)
|
||||
protected String id;
|
||||
|
||||
@Column(name = "NAME")
|
||||
protected String name;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "PARENT_GROUP")
|
||||
private GroupEntity parent;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "REALM")
|
||||
private RealmEntity realm;
|
||||
|
||||
@OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="group")
|
||||
protected Collection<GroupAttributeEntity> attributes = new ArrayList<GroupAttributeEntity>();
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Collection<GroupAttributeEntity> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(Collection<GroupAttributeEntity> attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public RealmEntity getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public void setRealm(RealmEntity realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public GroupEntity getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(GroupEntity parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GroupEntity that = (GroupEntity) o;
|
||||
|
||||
if (!id.equals(that.id)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@NamedQueries({
|
||||
@NamedQuery(name="groupHasRole", query="select m from GroupRoleMappingEntity m where m.group = :group and m.roleId = :roleId"),
|
||||
@NamedQuery(name="groupRoleMappings", query="select m from GroupRoleMappingEntity m where m.group = :group"),
|
||||
@NamedQuery(name="groupRoleMappingIds", query="select m.roleId from GroupRoleMappingEntity m where m.group = :group"),
|
||||
@NamedQuery(name="deleteGroupRoleMappingsByRealm", query="delete from GroupRoleMappingEntity mapping where mapping.group IN (select u from GroupEntity u where u.realmId=:realmId)"),
|
||||
@NamedQuery(name="deleteGroupRoleMappingsByRole", query="delete from GroupRoleMappingEntity m where m.roleId = :roleId"),
|
||||
@NamedQuery(name="deleteGroupRoleMappingsByGroup", query="delete from GroupRoleMappingEntity m where m.group = :group")
|
||||
|
||||
})
|
||||
@Table(name="GROUP_ROLE_MAPPING")
|
||||
@Entity
|
||||
@IdClass(GroupRoleMappingEntity.Key.class)
|
||||
public class GroupRoleMappingEntity {
|
||||
|
||||
@Id
|
||||
@ManyToOne(fetch= FetchType.LAZY)
|
||||
@JoinColumn(name="GROUP_ID")
|
||||
protected GroupEntity group;
|
||||
|
||||
@Id
|
||||
@Column(name = "ROLE_ID")
|
||||
protected String roleId;
|
||||
|
||||
public GroupEntity getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(GroupEntity group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public String getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(String roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
|
||||
public static class Key implements Serializable {
|
||||
|
||||
protected GroupEntity group;
|
||||
|
||||
protected String roleId;
|
||||
|
||||
public Key() {
|
||||
}
|
||||
|
||||
public Key(GroupEntity group, String roleId) {
|
||||
this.group = group;
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
public GroupEntity getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public String getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Key key = (Key) o;
|
||||
|
||||
if (!roleId.equals(key.roleId)) return false;
|
||||
if (!group.equals(key.group)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = group.hashCode();
|
||||
result = 31 * result + roleId.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -133,6 +133,9 @@ public class RealmEntity {
|
|||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
|
||||
Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
|
||||
Collection<GroupEntity> groups = new ArrayList<GroupEntity>();
|
||||
|
||||
@ElementCollection
|
||||
@MapKeyColumn(name="NAME")
|
||||
@Column(name="VALUE")
|
||||
|
@ -718,5 +721,21 @@ public class RealmEntity {
|
|||
public void setClientAuthenticationFlow(String clientAuthenticationFlow) {
|
||||
this.clientAuthenticationFlow = clientAuthenticationFlow;
|
||||
}
|
||||
|
||||
public Collection<GroupEntity> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
|
||||
public void setGroups(Collection<GroupEntity> groups) {
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
public void addGroup(GroupEntity group) {
|
||||
if (groups == null) {
|
||||
groups = new ArrayList<GroupEntity>();
|
||||
}
|
||||
groups.add(group);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@NamedQueries({
|
||||
@NamedQuery(name="userMemberOf", query="select m from UserGroupMembershipEntity m where m.user = :user and m.groupId = :groupId"),
|
||||
@NamedQuery(name="userGroupMembership", query="select m from UserGroupMembershipEntity m where m.user = :user"),
|
||||
@NamedQuery(name="groupMembership", query="select g.user from UserGroupMembershipEntity g where g.groupId = :groupId"),
|
||||
@NamedQuery(name="userGroupIds", query="select m.groupId from UserGroupMembershipEntity m where m.user = :user"),
|
||||
@NamedQuery(name="deleteUserGroupMembershipByRealm", query="delete from UserGroupMembershipEntity mapping where mapping.user IN (select u from UserEntity u where u.realmId=:realmId)"),
|
||||
@NamedQuery(name="deleteUserGroupMembershipsByRealmAndLink", query="delete from UserGroupMembershipEntity mapping where mapping.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link)"),
|
||||
@NamedQuery(name="deleteUserGroupMembershipsByGroup", query="delete from UserGroupMembershipEntity m where m.groupId = :groupId"),
|
||||
@NamedQuery(name="deleteUserGroupMembershipsByUser", query="delete from UserGroupMembershipEntity m where m.user = :user")
|
||||
|
||||
})
|
||||
@Table(name="USER_GROUP_MEMBERSHIP")
|
||||
@Entity
|
||||
@IdClass(UserGroupMembershipEntity.Key.class)
|
||||
public class UserGroupMembershipEntity {
|
||||
|
||||
@Id
|
||||
@ManyToOne(fetch= FetchType.LAZY)
|
||||
@JoinColumn(name="USER_ID")
|
||||
protected UserEntity user;
|
||||
|
||||
@Id
|
||||
@Column(name = "GROUP_ID")
|
||||
protected String groupId;
|
||||
|
||||
public UserEntity getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(UserEntity user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public static class Key implements Serializable {
|
||||
|
||||
protected UserEntity user;
|
||||
|
||||
protected String groupId;
|
||||
|
||||
public Key() {
|
||||
}
|
||||
|
||||
public Key(UserEntity user, String groupId) {
|
||||
this.user = user;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public UserEntity getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Key key = (Key) o;
|
||||
|
||||
if (!groupId.equals(key.groupId)) return false;
|
||||
if (!user.equals(key.user)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = user.hashCode();
|
||||
result = 31 * result + groupId.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
package org.keycloak.models.mongo.keycloak.adapters;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.QueryBuilder;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||
import org.keycloak.models.mongo.utils.MongoModelUtils;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class GroupAdapter extends AbstractMongoAdapter<MongoGroupEntity> implements GroupModel {
|
||||
|
||||
private final MongoGroupEntity group;
|
||||
private RealmModel realm;
|
||||
private KeycloakSession session;
|
||||
|
||||
public GroupAdapter(KeycloakSession session, RealmModel realm, MongoGroupEntity group, MongoStoreInvocationContext invContext) {
|
||||
super(invContext);
|
||||
this.group = group;
|
||||
this.realm = realm;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return group.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return group.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
group.setName(name);
|
||||
updateGroup();
|
||||
}
|
||||
|
||||
protected void updateGroup() {
|
||||
super.updateMongoEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MongoGroupEntity getMongoEntity() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || !(o instanceof GroupModel)) return false;
|
||||
|
||||
GroupModel that = (GroupModel) o;
|
||||
return that.getId().equals(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getId().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSingleAttribute(String name, String value) {
|
||||
if (group.getAttributes() == null) {
|
||||
group.setAttributes(new HashMap<String, List<String>>());
|
||||
}
|
||||
|
||||
List<String> attrValues = new ArrayList<>();
|
||||
attrValues.add(value);
|
||||
group.getAttributes().put(name, attrValues);
|
||||
updateGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, List<String> values) {
|
||||
if (group.getAttributes() == null) {
|
||||
group.setAttributes(new HashMap<String, List<String>>());
|
||||
}
|
||||
|
||||
group.getAttributes().put(name, values);
|
||||
updateGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
if (group.getAttributes() == null) return;
|
||||
|
||||
group.getAttributes().remove(name);
|
||||
updateGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstAttribute(String name) {
|
||||
if (group.getAttributes()==null) return null;
|
||||
|
||||
List<String> attrValues = group.getAttributes().get(name);
|
||||
return (attrValues==null || attrValues.isEmpty()) ? null : attrValues.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAttribute(String name) {
|
||||
if (group.getAttributes()==null) return Collections.<String>emptyList();
|
||||
List<String> attrValues = group.getAttributes().get(name);
|
||||
return (attrValues == null) ? Collections.<String>emptyList() : Collections.unmodifiableList(attrValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
return group.getAttributes()==null ? Collections.<String, List<String>>emptyMap() : Collections.unmodifiableMap((Map) group.getAttributes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(RoleModel role) {
|
||||
Set<RoleModel> roles = getRoleMappings();
|
||||
return KeycloakModelUtils.hasRole(roles, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grantRole(RoleModel role) {
|
||||
getMongoStore().pushItemToList(group, "roleIds", role.getId(), true, invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRoleMappings() {
|
||||
if (group.getRoleIds() == null || group.getRoleIds().isEmpty()) return Collections.EMPTY_SET;
|
||||
Set<RoleModel> roles = new HashSet<>();
|
||||
for (String id : group.getRoleIds()) {
|
||||
roles.add(realm.getRoleById(id));
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRealmRoleMappings() {
|
||||
Set<RoleModel> allRoles = getRoleMappings();
|
||||
|
||||
// Filter to retrieve just realm roles
|
||||
Set<RoleModel> realmRoles = new HashSet<RoleModel>();
|
||||
for (RoleModel role : allRoles) {
|
||||
if (role.getContainer() instanceof RealmModel) {
|
||||
realmRoles.add(role);
|
||||
}
|
||||
}
|
||||
return realmRoles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRoleMapping(RoleModel role) {
|
||||
if (group == null || role == null) return;
|
||||
|
||||
getMongoStore().pullItemFromList(group, "roleIds", role.getId(), invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getClientRoleMappings(ClientModel app) {
|
||||
Set<RoleModel> result = new HashSet<RoleModel>();
|
||||
Set<RoleModel> roles = getRoleMappings();
|
||||
|
||||
for (RoleModel role : roles) {
|
||||
if (app.equals(role.getContainer())) {
|
||||
result.add(role);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getParent() {
|
||||
if (group.getParentId() == null) return null;
|
||||
return realm.getGroupById(group.getParentId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getSubGroups() {
|
||||
Set<GroupModel> subGroups = new HashSet<>();
|
||||
for (GroupModel groupModel : realm.getGroups()) {
|
||||
if (groupModel.getParent().equals(this)) {
|
||||
subGroups.add(groupModel);
|
||||
}
|
||||
}
|
||||
return subGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(GroupModel group) {
|
||||
this.group.setParentId(group.getId());
|
||||
updateGroup();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChild(GroupModel subGroup) {
|
||||
subGroup.setParent(this);
|
||||
updateGroup();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChild(GroupModel subGroup) {
|
||||
subGroup.setParent(null);
|
||||
updateGroup();
|
||||
|
||||
}
|
||||
}
|
|
@ -7,11 +7,13 @@ import org.keycloak.connections.mongo.api.MongoStore;
|
|||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.migration.MigrationModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||
|
@ -121,6 +123,14 @@ public class MongoRealmProvider implements RealmProvider {
|
|||
return new RoleAdapter(session, realm, role, null, invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupById(String id, RealmModel realm) {
|
||||
MongoGroupEntity group = getMongoStore().loadEntity(MongoGroupEntity.class, id, invocationContext);
|
||||
if (group == null) return null;
|
||||
if (group.getRealmId() != null && !group.getRealmId().equals(realm.getId())) return null;
|
||||
return new GroupAdapter(session, realm, group, invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientModel getClientById(String id, RealmModel realm) {
|
||||
MongoClientEntity appData = getMongoStore().loadEntity(MongoClientEntity.class, id, invocationContext);
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
|||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -90,10 +91,26 @@ public class MongoUserProvider implements UserProvider {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||
QueryBuilder queryBuilder = new QueryBuilder()
|
||||
.and("realmId").is(realm.getId());
|
||||
queryBuilder.and("groupIds").is(group.getId());
|
||||
DBObject sort = new BasicDBObject("username", 1);
|
||||
|
||||
List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, queryBuilder.get(), sort, firstResult, maxResults, invocationContext);
|
||||
return convertUserEntities(realm, users);
|
||||
}
|
||||
|
||||
protected MongoStore getMongoStore() {
|
||||
return invocationContext.getMongoStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
||||
return getGroupMembers(realm, group, -1, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
|
||||
DBObject query = new QueryBuilder()
|
||||
|
@ -411,6 +428,17 @@ public class MongoUserProvider implements UserProvider {
|
|||
getMongoStore().updateEntities(MongoUserConsentEntity.class, query, pull, invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
// Remove this role from all users, which has it
|
||||
DBObject query = new QueryBuilder()
|
||||
.and("groupIds").is(group.getId())
|
||||
.get();
|
||||
|
||||
DBObject pull = new BasicDBObject("$pull", query);
|
||||
getMongoStore().updateEntities(MongoUserEntity.class, query, pull, invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, RoleModel role) {
|
||||
// Remove this role from all users, which has it
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
|
|||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -34,6 +35,7 @@ import org.keycloak.models.entities.RequiredCredentialEntity;
|
|||
import org.keycloak.models.entities.UserFederationMapperEntity;
|
||||
import org.keycloak.models.entities.UserFederationProviderEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
@ -607,6 +609,47 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
return model.getRoleById(id, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupById(String id) {
|
||||
return model.getGroupById(id, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupModel> getGroups() {
|
||||
DBObject query = new QueryBuilder()
|
||||
.and("realmId").is(getId())
|
||||
.get();
|
||||
List<MongoGroupEntity> groups = getMongoStore().loadEntities(MongoGroupEntity.class, query, invocationContext);
|
||||
|
||||
List<GroupModel> result = new LinkedList<>();
|
||||
|
||||
if (groups == null) return result;
|
||||
for (MongoGroupEntity group : groups) {
|
||||
result.add(new GroupAdapter(session, this, group, invocationContext));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupModel> getTopLevelGroups() {
|
||||
List<GroupModel> all = getGroups();
|
||||
Iterator<GroupModel> it = all.iterator();
|
||||
while (it.hasNext()) {
|
||||
GroupModel group = it.next();
|
||||
if (group.getParent() != null) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGroup(GroupModel group) {
|
||||
session.users().preRemove(this, group);
|
||||
return getMongoStore().removeEntity(MongoGroupEntity.class, group.getId(), invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDefaultRoles() {
|
||||
return realm.getDefaultRoles();
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.mongodb.QueryBuilder;
|
|||
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.OTPPolicy;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
|
@ -450,6 +451,37 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
|
|||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<GroupModel> getGroups() {
|
||||
if (user.getGroupIds() == null && user.getGroupIds().size() == 0) return Collections.EMPTY_SET;
|
||||
Set<GroupModel> groups = new HashSet<>();
|
||||
for (String id : user.getGroupIds()) {
|
||||
groups.add(realm.getGroupById(id));
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinGroup(GroupModel group) {
|
||||
getMongoStore().pushItemToList(getUser(), "groupIds", group.getId(), true, invocationContext);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveGroup(GroupModel group) {
|
||||
if (user == null || group == null) return;
|
||||
|
||||
getMongoStore().pullItemFromList(getUser(), "groupIds", group.getId(), invocationContext);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMemberOf(GroupModel group) {
|
||||
if (user.getGroupIds().contains(group.getId())) return true;
|
||||
Set<GroupModel> groups = getGroups();
|
||||
return KeycloakModelUtils.isMember(groups, group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(RoleModel role) {
|
||||
Set<RoleModel> roles = getRoleMappings();
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package org.keycloak.models.mongo.keycloak.entities;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.QueryBuilder;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.connections.mongo.api.MongoCollection;
|
||||
import org.keycloak.connections.mongo.api.MongoField;
|
||||
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.connections.mongo.api.MongoStore;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.entities.GroupEntity;
|
||||
import org.keycloak.models.entities.RoleEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*/
|
||||
@MongoCollection(collectionName = "groups")
|
||||
public class MongoGroupEntity extends GroupEntity implements MongoIdentifiableEntity {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MongoGroupEntity.class);
|
||||
|
||||
@Override
|
||||
public void afterRemove(MongoStoreInvocationContext invContext) {
|
||||
}
|
||||
}
|
|
@ -4,11 +4,13 @@ import com.mongodb.DBObject;
|
|||
import com.mongodb.QueryBuilder;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.entities.ClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.adapters.ClientAdapter;
|
||||
import org.keycloak.models.mongo.keycloak.adapters.GroupAdapter;
|
||||
import org.keycloak.models.mongo.keycloak.adapters.UserAdapter;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.testsuite;
|
||||
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
|
@ -67,6 +68,11 @@ public class DummyUserFederationProvider implements UserFederationProvider {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(RealmModel realm, UserModel local) {
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue