auto create keycloak tenant groups
This commit is contained in:
parent
3e4316a627
commit
2e083df185
|
@ -9,6 +9,25 @@ import java.util.List;
|
||||||
@ConfigurationProperties(prefix = "authorization")
|
@ConfigurationProperties(prefix = "authorization")
|
||||||
public class AuthorizationProperties {
|
public class AuthorizationProperties {
|
||||||
|
|
||||||
|
private String globalAdminRole;
|
||||||
|
|
||||||
|
public String getGlobalAdminRole() {
|
||||||
|
return globalAdminRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGlobalAdminRole(String globalAdminRole) {
|
||||||
|
this.globalAdminRole = globalAdminRole;
|
||||||
|
}
|
||||||
|
private Boolean autoAssignGlobalAdminToNewTenants;
|
||||||
|
|
||||||
|
public Boolean getAutoAssignGlobalAdminToNewTenants() {
|
||||||
|
return autoAssignGlobalAdminToNewTenants;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoAssignGlobalAdminToNewTenants(Boolean autoAssignGlobalAdminToNewTenants) {
|
||||||
|
this.autoAssignGlobalAdminToNewTenants = autoAssignGlobalAdminToNewTenants;
|
||||||
|
}
|
||||||
|
|
||||||
private List<String> allowedTenantRoles;
|
private List<String> allowedTenantRoles;
|
||||||
|
|
||||||
public List<String> getAllowedTenantRoles() {
|
public List<String> getAllowedTenantRoles() {
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
package eu.eudat.service.keycloak;
|
package eu.eudat.service.keycloak;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.bind.ConstructorBinding;
|
|
||||||
|
|
||||||
public class KeycloakAuthorityProperties {
|
public class KeycloakAuthorityProperties {
|
||||||
|
|
||||||
private final String groupId, groupTitle;
|
private String groupId;
|
||||||
|
|
||||||
@ConstructorBinding
|
public KeycloakAuthorityProperties() {
|
||||||
public KeycloakAuthorityProperties(String groupId, String groupTitle) {
|
|
||||||
this.groupId = groupId;
|
|
||||||
this.groupTitle = groupTitle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGroupId() {
|
public String getGroupId() {
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGroupTitle() {
|
public void setGroupId(String groupId) {
|
||||||
return groupTitle;
|
this.groupId = groupId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,4 +19,14 @@ public class KeycloakResourcesConfiguration {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTenantGroupName(String tenantCode) {
|
||||||
|
return properties.getTenantGroupsNamingStrategy()
|
||||||
|
.replace("{tenantCode}", tenantCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTenantRoleAttributeValue(String tenantCode, String key) {
|
||||||
|
return properties.getTenantAuthorities().get(key).getRoleAttributeValueStrategy()
|
||||||
|
.replace("{tenantCode}", tenantCode);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,41 @@ import java.util.HashMap;
|
||||||
@ConditionalOnProperty(prefix = "keycloak-resources", name = "enabled", havingValue = "true")
|
@ConditionalOnProperty(prefix = "keycloak-resources", name = "enabled", havingValue = "true")
|
||||||
public class KeycloakResourcesProperties {
|
public class KeycloakResourcesProperties {
|
||||||
|
|
||||||
private final HashMap<String, KeycloakAuthorityProperties> authorities;
|
private HashMap<String, KeycloakAuthorityProperties> authorities;
|
||||||
|
private HashMap<String, KeycloakTenantAuthorityProperties> tenantAuthorities;
|
||||||
@ConstructorBinding
|
|
||||||
public KeycloakResourcesProperties(HashMap<String, KeycloakAuthorityProperties> authorities) {
|
private String tenantGroupsNamingStrategy;
|
||||||
this.authorities = authorities;
|
private String tenantRoleAttributeName;
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String, KeycloakAuthorityProperties> getAuthorities() {
|
public HashMap<String, KeycloakAuthorityProperties> getAuthorities() {
|
||||||
return authorities;
|
return authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAuthorities(HashMap<String, KeycloakAuthorityProperties> authorities) {
|
||||||
|
this.authorities = authorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, KeycloakTenantAuthorityProperties> getTenantAuthorities() {
|
||||||
|
return tenantAuthorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantAuthorities(HashMap<String, KeycloakTenantAuthorityProperties> tenantAuthorities) {
|
||||||
|
this.tenantAuthorities = tenantAuthorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTenantGroupsNamingStrategy() {
|
||||||
|
return tenantGroupsNamingStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantGroupsNamingStrategy(String tenantGroupsNamingStrategy) {
|
||||||
|
this.tenantGroupsNamingStrategy = tenantGroupsNamingStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTenantRoleAttributeName() {
|
||||||
|
return tenantRoleAttributeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantRoleAttributeName(String tenantRoleAttributeName) {
|
||||||
|
this.tenantRoleAttributeName = tenantRoleAttributeName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
package eu.eudat.service.keycloak;
|
package eu.eudat.service.keycloak;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.keycloak.representations.idm.GroupRepresentation;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface KeycloakService {
|
public interface KeycloakService {
|
||||||
|
|
||||||
void addUserToGroup(UUID subjectId, String groupId);
|
void addUserToGroup(@NotNull String subjectId, String groupId);
|
||||||
void removeUserFromGroup(@NotNull UUID subjectId, String groupId);
|
|
||||||
void addUserToGroup(UUID subjectId, KeycloakRole role);
|
|
||||||
void removeUserFromGroup(@NotNull UUID subjectId, KeycloakRole role);
|
|
||||||
void assignClientRoleToUser(UUID subjectId, String clientId, KeycloakRole role);
|
|
||||||
void removeClientRoleFromUser(UUID subjectId, String clientId, KeycloakRole role);
|
|
||||||
|
|
||||||
|
void removeUserFromGroup(@NotNull String subjectId, String groupId);
|
||||||
|
|
||||||
|
void addUserToGlobalRoleGroup(String subjectId, String role);
|
||||||
|
void removeUserGlobalRoleGroup(@NotNull String subjectId, String role);
|
||||||
|
|
||||||
|
void addUserToTenantRoleGroup(String subjectId, String tenantCode, String tenantRole);
|
||||||
|
|
||||||
|
void removeUserTenantRoleGroup(String subjectId, String tenantCode, String tenantRole);
|
||||||
|
|
||||||
|
void createTenantGroups(String tenantCode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import gr.cite.commons.web.keycloak.api.configuration.KeycloakClientConfiguratio
|
||||||
import gr.cite.tools.logging.LoggerService;
|
import gr.cite.tools.logging.LoggerService;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.keycloak.representations.idm.GroupRepresentation;
|
import org.keycloak.representations.idm.GroupRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -27,56 +26,83 @@ public class KeycloakServiceImpl implements KeycloakService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addUserToGroup(@NotNull UUID subjectId, String groupId) {
|
public void addUserToGroup(@NotNull String subjectId, String groupId) {
|
||||||
api.users().addUserToGroup(subjectId.toString(), groupId);
|
api.users().addUserToGroup(subjectId, groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeUserFromGroup(@NotNull UUID subjectId, String groupId) {
|
public void removeUserFromGroup(@NotNull String subjectId, String groupId) {
|
||||||
api.users().removeUserFromGroup(subjectId.toString(), groupId);
|
api.users().removeUserFromGroup(subjectId, groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addUserToGroup(UUID subjectId, KeycloakRole role) {
|
public void addUserToGlobalRoleGroup(String subjectId, String role) {
|
||||||
KeycloakAuthorityProperties properties = this.configuration.getProperties().getAuthorities().get(role.name());
|
KeycloakAuthorityProperties properties = this.configuration.getProperties().getAuthorities().get(role);
|
||||||
if (properties != null)
|
if (properties != null) addUserToGroup(subjectId, properties.getGroupId());
|
||||||
addUserToGroup(subjectId, properties.getGroupId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeUserFromGroup(@NotNull UUID subjectId, KeycloakRole role) {
|
public void removeUserGlobalRoleGroup(@NotNull String subjectId, String role) {
|
||||||
KeycloakAuthorityProperties properties = this.configuration.getProperties().getAuthorities().get(role.name());
|
KeycloakAuthorityProperties properties = this.configuration.getProperties().getAuthorities().get(role);
|
||||||
if (properties != null)
|
if (properties != null)
|
||||||
removeUserFromGroup(subjectId, properties.getGroupId());
|
removeUserFromGroup(subjectId, properties.getGroupId());
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void assignClientRoleToUser(UUID subjectId, String clientId, KeycloakRole role) {
|
||||||
|
// if (clientId == null)
|
||||||
|
// clientId = clientConfiguration.getProperties().getClientId();
|
||||||
|
// UserRepresentation user = api.users().findUserById(subjectId.toString());
|
||||||
|
// user.getClientRoles().computeIfAbsent(clientId, k -> new ArrayList<>());
|
||||||
|
// Set<String> clientRoles = new HashSet<>(Set.copyOf(user.getClientRoles().get(clientId)));
|
||||||
|
// clientRoles.add(role.name());
|
||||||
|
// user.getClientRoles().get(clientId).clear();
|
||||||
|
// user.getClientRoles().get(clientId).addAll(clientRoles);
|
||||||
|
// api.users().updateUser(subjectId.toString(), user);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void removeClientRoleFromUser(UUID subjectId, String clientId, KeycloakRole role) {
|
||||||
|
// if (clientId == null) clientId = clientConfiguration.getProperties().getClientId();
|
||||||
|
// UserRepresentation user = api.users().findUserById(subjectId.toString());
|
||||||
|
// user.getClientRoles().computeIfAbsent(clientId, k -> new ArrayList<>());
|
||||||
|
// Set<String> clientRoles = new HashSet<>(Set.copyOf(user.getClientRoles().get(clientId)));
|
||||||
|
// clientRoles.remove(role.name());
|
||||||
|
// user.getClientRoles().get(clientId).clear();
|
||||||
|
// user.getClientRoles().get(clientId).addAll(clientRoles);
|
||||||
|
// api.users().updateUser(subjectId.toString(), user);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public List<GroupRepresentation> getUserGroups(UUID subjectId) {
|
||||||
|
// return api.users().getGroups(subjectId.toString());
|
||||||
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void assignClientRoleToUser(UUID subjectId, String clientId, KeycloakRole role) {
|
public void addUserToTenantRoleGroup(String subjectId, String tenantCode, String tenantRole) {
|
||||||
if (clientId == null)
|
GroupRepresentation group = api.groups().findGroupByPath(getTenantAuthorityParentPath(tenantRole) + "/" + configuration.getTenantGroupName(tenantCode));
|
||||||
clientId = clientConfiguration.getProperties().getClientId();
|
addUserToGroup(subjectId, group.getId());
|
||||||
UserRepresentation user = api.users().findUserById(subjectId.toString());
|
|
||||||
user.getClientRoles().computeIfAbsent(clientId, k -> new ArrayList<>());
|
|
||||||
Set<String> clientRoles = new HashSet<>(Set.copyOf(user.getClientRoles().get(clientId)));
|
|
||||||
clientRoles.add(role.name());
|
|
||||||
user.getClientRoles().get(clientId).clear();
|
|
||||||
user.getClientRoles().get(clientId).addAll(clientRoles);
|
|
||||||
api.users().updateUser(subjectId.toString(), user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeClientRoleFromUser(UUID subjectId, String clientId, KeycloakRole role) {
|
public void removeUserTenantRoleGroup(String subjectId, String tenantCode, String tenantRole) {
|
||||||
if (clientId == null) clientId = clientConfiguration.getProperties().getClientId();
|
GroupRepresentation group = api.groups().findGroupByPath(getTenantAuthorityParentPath(tenantRole) + "/" + configuration.getTenantGroupName(tenantCode));
|
||||||
UserRepresentation user = api.users().findUserById(subjectId.toString());
|
removeUserFromGroup(subjectId, group.getId());
|
||||||
user.getClientRoles().computeIfAbsent(clientId, k -> new ArrayList<>());
|
}
|
||||||
Set<String> clientRoles = new HashSet<>(Set.copyOf(user.getClientRoles().get(clientId)));
|
|
||||||
clientRoles.remove(role.name());
|
private String getTenantAuthorityParentPath(String tenantRole) {
|
||||||
user.getClientRoles().get(clientId).clear();
|
GroupRepresentation parent = api.groups().findGroupById(configuration.getProperties().getTenantAuthorities().get(tenantRole).getParent());
|
||||||
user.getClientRoles().get(clientId).addAll(clientRoles);
|
return parent.getPath();
|
||||||
api.users().updateUser(subjectId.toString(), user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GroupRepresentation> getUserGroups(UUID subjectId) {
|
@Override
|
||||||
return api.users().getGroups(subjectId.toString());
|
public void createTenantGroups(String tenantCode) {
|
||||||
|
for (Map.Entry<String,KeycloakTenantAuthorityProperties> entry :configuration.getProperties().getTenantAuthorities().entrySet()){
|
||||||
|
GroupRepresentation group = new GroupRepresentation();
|
||||||
|
group.setName(configuration.getTenantGroupName(tenantCode));
|
||||||
|
HashMap<String, List<String>> user_attributes = new HashMap<>();
|
||||||
|
user_attributes.put(this.configuration.getProperties().getTenantRoleAttributeName(), List.of(configuration.getTenantRoleAttributeValue(tenantCode, entry.getKey())));
|
||||||
|
group.setAttributes(user_attributes);
|
||||||
|
api.groups().addGroupWithParent(group, configuration.getProperties().getTenantAuthorities().get(entry.getKey()).getParent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package eu.eudat.service.keycloak;
|
||||||
|
|
||||||
|
public class KeycloakTenantAuthorityProperties {
|
||||||
|
|
||||||
|
private String parent;
|
||||||
|
private String roleAttributeValueStrategy;
|
||||||
|
|
||||||
|
public KeycloakTenantAuthorityProperties() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(String parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoleAttributeValueStrategy() {
|
||||||
|
return roleAttributeValueStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoleAttributeValueStrategy(String roleAttributeValueStrategy) {
|
||||||
|
this.roleAttributeValueStrategy = roleAttributeValueStrategy;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,34 @@
|
||||||
package eu.eudat.service.tenant;
|
package eu.eudat.service.tenant;
|
||||||
|
|
||||||
import eu.eudat.authorization.AuthorizationFlags;
|
import eu.eudat.authorization.AuthorizationFlags;
|
||||||
|
import eu.eudat.authorization.AuthorizationProperties;
|
||||||
import eu.eudat.authorization.Permission;
|
import eu.eudat.authorization.Permission;
|
||||||
import eu.eudat.commons.XmlHandlingService;
|
import eu.eudat.commons.XmlHandlingService;
|
||||||
import eu.eudat.commons.enums.IsActive;
|
import eu.eudat.commons.enums.IsActive;
|
||||||
|
import eu.eudat.commons.scope.tenant.TenantScope;
|
||||||
import eu.eudat.commons.types.tenant.*;
|
import eu.eudat.commons.types.tenant.*;
|
||||||
import eu.eudat.convention.ConventionService;
|
import eu.eudat.convention.ConventionService;
|
||||||
import eu.eudat.data.TenantEntity;
|
import eu.eudat.data.TenantEntity;
|
||||||
import eu.eudat.data.TenantEntityManager;
|
import eu.eudat.data.TenantEntityManager;
|
||||||
|
import eu.eudat.data.UserCredentialEntity;
|
||||||
|
import eu.eudat.data.UserRoleEntity;
|
||||||
import eu.eudat.errorcode.ErrorThesaurusProperties;
|
import eu.eudat.errorcode.ErrorThesaurusProperties;
|
||||||
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEvent;
|
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEvent;
|
||||||
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEventHandler;
|
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEventHandler;
|
||||||
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEvent;
|
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEvent;
|
||||||
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEventHandler;
|
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEventHandler;
|
||||||
import eu.eudat.model.Tenant;
|
import eu.eudat.model.Tenant;
|
||||||
|
import eu.eudat.model.UserCredential;
|
||||||
import eu.eudat.model.builder.TenantBuilder;
|
import eu.eudat.model.builder.TenantBuilder;
|
||||||
import eu.eudat.model.deleter.TenantDeleter;
|
import eu.eudat.model.deleter.TenantDeleter;
|
||||||
|
import eu.eudat.model.deleter.UserRoleDeleter;
|
||||||
import eu.eudat.model.persist.TenantPersist;
|
import eu.eudat.model.persist.TenantPersist;
|
||||||
import eu.eudat.model.persist.tenantconfig.*;
|
import eu.eudat.model.persist.tenantconfig.*;
|
||||||
import eu.eudat.model.tenantconfig.TenantSource;
|
import eu.eudat.model.tenantconfig.TenantSource;
|
||||||
|
import eu.eudat.query.UserCredentialQuery;
|
||||||
|
import eu.eudat.query.UserRoleQuery;
|
||||||
import eu.eudat.service.encryption.EncryptionService;
|
import eu.eudat.service.encryption.EncryptionService;
|
||||||
|
import eu.eudat.service.keycloak.KeycloakService;
|
||||||
import eu.eudat.service.responseutils.ResponseUtilsService;
|
import eu.eudat.service.responseutils.ResponseUtilsService;
|
||||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||||
import gr.cite.tools.data.builder.BuilderFactory;
|
import gr.cite.tools.data.builder.BuilderFactory;
|
||||||
|
@ -73,6 +82,11 @@ public class TenantServiceImpl implements TenantService {
|
||||||
private final TenantProperties properties;
|
private final TenantProperties properties;
|
||||||
private final TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler;
|
private final TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler;
|
||||||
private final TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler;
|
private final TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler;
|
||||||
|
private final KeycloakService keycloakService;
|
||||||
|
private final AuthorizationProperties authorizationProperties;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
private final QueryFactory queryFactory;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public TenantServiceImpl(
|
public TenantServiceImpl(
|
||||||
|
@ -84,7 +98,7 @@ public class TenantServiceImpl implements TenantService {
|
||||||
MessageSource messageSource,
|
MessageSource messageSource,
|
||||||
XmlHandlingService xmlHandlingService,
|
XmlHandlingService xmlHandlingService,
|
||||||
ErrorThesaurusProperties errors,
|
ErrorThesaurusProperties errors,
|
||||||
EncryptionService encryptionService, TenantProperties properties, TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler, TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler) {
|
EncryptionService encryptionService, TenantProperties properties, TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler, TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler, KeycloakService keycloakService, AuthorizationProperties authorizationProperties, TenantScope tenantScope, QueryFactory queryFactory) {
|
||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
this.authorizationService = authorizationService;
|
this.authorizationService = authorizationService;
|
||||||
this.deleterFactory = deleterFactory;
|
this.deleterFactory = deleterFactory;
|
||||||
|
@ -97,6 +111,10 @@ public class TenantServiceImpl implements TenantService {
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
this.tenantTouchedIntegrationEventHandler = tenantTouchedIntegrationEventHandler;
|
this.tenantTouchedIntegrationEventHandler = tenantTouchedIntegrationEventHandler;
|
||||||
this.tenantRemovalIntegrationEventHandler = tenantRemovalIntegrationEventHandler;
|
this.tenantRemovalIntegrationEventHandler = tenantRemovalIntegrationEventHandler;
|
||||||
|
this.keycloakService = keycloakService;
|
||||||
|
this.authorizationProperties = authorizationProperties;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
|
this.queryFactory = queryFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,6 +149,11 @@ public class TenantServiceImpl implements TenantService {
|
||||||
else this.entityManager.persist(data);
|
else this.entityManager.persist(data);
|
||||||
|
|
||||||
this.entityManager.flush();
|
this.entityManager.flush();
|
||||||
|
|
||||||
|
if (!isUpdate) {
|
||||||
|
this.keycloakService.createTenantGroups(data.getCode());
|
||||||
|
this.autoAssignGlobalAdminsToNewTenant(data);
|
||||||
|
}
|
||||||
|
|
||||||
TenantTouchedIntegrationEvent tenantTouchedIntegrationEvent = new TenantTouchedIntegrationEvent();
|
TenantTouchedIntegrationEvent tenantTouchedIntegrationEvent = new TenantTouchedIntegrationEvent();
|
||||||
tenantTouchedIntegrationEvent.setId(data.getId());
|
tenantTouchedIntegrationEvent.setId(data.getId());
|
||||||
|
@ -139,6 +162,39 @@ public class TenantServiceImpl implements TenantService {
|
||||||
|
|
||||||
return this.builderFactory.builder(TenantBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Tenant._id), data);
|
return this.builderFactory.builder(TenantBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Tenant._id), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void autoAssignGlobalAdminsToNewTenant(TenantEntity tenant){
|
||||||
|
if (!this.authorizationProperties.getAutoAssignGlobalAdminToNewTenants()) return;
|
||||||
|
List<UserRoleEntity> existingItems;
|
||||||
|
List<UserCredentialEntity> userCredentialEntities;
|
||||||
|
try {
|
||||||
|
this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
|
|
||||||
|
existingItems = this.queryFactory.query(UserRoleQuery.class).tenantIsSet(false).roles(this.authorizationProperties.getGlobalAdminRole()).collect();
|
||||||
|
userCredentialEntities = this.queryFactory.query(UserCredentialQuery.class).userIds(existingItems.stream().map(UserRoleEntity::getUserId).distinct().toList()).collect();
|
||||||
|
} finally {
|
||||||
|
this.tenantScope.removeTempTenant(this.entityManager.getEntityManager());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), tenant.getId(), tenant.getCode());
|
||||||
|
for (UUID userId : existingItems.stream().map(UserRoleEntity::getUserId).distinct().toList()) {
|
||||||
|
UserCredentialEntity userCredential = userCredentialEntities.stream().filter(x-> !this.conventionService.isNullOrEmpty(x.getExternalId()) && x.getUserId().equals(userId)).findFirst().orElse(null);
|
||||||
|
if (userCredential == null) continue;
|
||||||
|
UserRoleEntity item = new UserRoleEntity();
|
||||||
|
item.setId(UUID.randomUUID());
|
||||||
|
item.setUserId(userId);
|
||||||
|
item.setRole(this.authorizationProperties.getGlobalAdminRole());
|
||||||
|
item.setCreatedAt(Instant.now());
|
||||||
|
this.entityManager.persist(item);
|
||||||
|
this.keycloakService.addUserToGlobalRoleGroup(userCredential.getExternalId(), this.authorizationProperties.getGlobalAdminRole());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.tenantScope.removeTempTenant(this.entityManager.getEntityManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entityManager.flush();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private @NotNull TenantConfigEntity buildConfigEntity(TenantConfigPersist persist) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
|
private @NotNull TenantConfigEntity buildConfigEntity(TenantConfigPersist persist) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
|
||||||
TenantConfigEntity data = new TenantConfigEntity();
|
TenantConfigEntity data = new TenantConfigEntity();
|
||||||
|
|
|
@ -29,7 +29,6 @@ import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEvent;
|
||||||
import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEventHandler;
|
import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEventHandler;
|
||||||
import eu.eudat.integrationevent.outbox.userremoval.UserRemovalIntegrationEventHandler;
|
import eu.eudat.integrationevent.outbox.userremoval.UserRemovalIntegrationEventHandler;
|
||||||
import eu.eudat.integrationevent.outbox.usertouched.UserTouchedIntegrationEventHandler;
|
import eu.eudat.integrationevent.outbox.usertouched.UserTouchedIntegrationEventHandler;
|
||||||
import eu.eudat.model.Tenant;
|
|
||||||
import eu.eudat.model.User;
|
import eu.eudat.model.User;
|
||||||
import eu.eudat.model.UserContactInfo;
|
import eu.eudat.model.UserContactInfo;
|
||||||
import eu.eudat.model.UserCredential;
|
import eu.eudat.model.UserCredential;
|
||||||
|
@ -41,7 +40,6 @@ import eu.eudat.model.persist.actionconfirmation.RemoveCredentialRequestPersist;
|
||||||
import eu.eudat.query.*;
|
import eu.eudat.query.*;
|
||||||
import eu.eudat.service.actionconfirmation.ActionConfirmationService;
|
import eu.eudat.service.actionconfirmation.ActionConfirmationService;
|
||||||
import eu.eudat.service.elastic.ElasticService;
|
import eu.eudat.service.elastic.ElasticService;
|
||||||
import eu.eudat.service.keycloak.KeycloakRole;
|
|
||||||
import eu.eudat.service.keycloak.KeycloakService;
|
import eu.eudat.service.keycloak.KeycloakService;
|
||||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||||
import gr.cite.tools.data.builder.BuilderFactory;
|
import gr.cite.tools.data.builder.BuilderFactory;
|
||||||
|
@ -252,7 +250,7 @@ public class UserServiceImpl implements UserService {
|
||||||
throw new MyApplicationException("Currently cannot update roles for this user");
|
throw new MyApplicationException("Currently cannot update roles for this user");
|
||||||
if (userCredentials.getFirst().getExternalId() == null)
|
if (userCredentials.getFirst().getExternalId() == null)
|
||||||
throw new MyApplicationException("Currently cannot update roles for this user");
|
throw new MyApplicationException("Currently cannot update roles for this user");
|
||||||
UUID subjectId = UUID.fromString(userCredentials.getFirst().getExternalId());
|
String subjectId = userCredentials.getFirst().getExternalId();
|
||||||
|
|
||||||
this.applyGlobalRoles(data.getId(), subjectId, model);
|
this.applyGlobalRoles(data.getId(), subjectId, model);
|
||||||
|
|
||||||
|
@ -266,33 +264,39 @@ public class UserServiceImpl implements UserService {
|
||||||
return this.builderFactory.builder(UserBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, User._id), data);
|
return this.builderFactory.builder(UserBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, User._id), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyGlobalRoles(UUID userId, UUID subjectId, UserRolePatchPersist model) throws InvalidApplicationException {
|
private void applyGlobalRoles(UUID userId, String subjectId, UserRolePatchPersist model) throws InvalidApplicationException {
|
||||||
List<UserRoleEntity> existingItems = this.queryFactory.query(UserRoleQuery.class).userIds(userId).tenantIsSet(false).roles(this.authorizationProperties.getAllowedGlobalRoles()).collect();
|
try {
|
||||||
List<UUID> foundIds = new ArrayList<>();
|
this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
|
||||||
for (String roleName : model.getRoles().stream().filter(x-> x != null && !x.isBlank() && this.authorizationProperties.getAllowedGlobalRoles().contains(x)).distinct().toList()) {
|
|
||||||
UserRoleEntity item = existingItems.stream().filter(x-> x.getRole().equals(roleName)).findFirst().orElse(null);
|
List<UserRoleEntity> existingItems = this.queryFactory.query(UserRoleQuery.class).userIds(userId).tenantIsSet(false).roles(this.authorizationProperties.getAllowedGlobalRoles()).collect();
|
||||||
if (item == null) {
|
List<UUID> foundIds = new ArrayList<>();
|
||||||
item = new UserRoleEntity();
|
for (String roleName : model.getRoles().stream().filter(x -> x != null && !x.isBlank() && this.authorizationProperties.getAllowedGlobalRoles().contains(x)).distinct().toList()) {
|
||||||
item.setId(UUID.randomUUID());
|
UserRoleEntity item = existingItems.stream().filter(x -> x.getRole().equals(roleName)).findFirst().orElse(null);
|
||||||
item.setUserId(userId);
|
if (item == null) {
|
||||||
item.setRole(roleName);
|
item = new UserRoleEntity();
|
||||||
item.setCreatedAt(Instant.now());
|
item.setId(UUID.randomUUID());
|
||||||
this.entityManager.persist(item);
|
item.setUserId(userId);
|
||||||
this.keycloakService.addUserToGroup(subjectId, KeycloakRole.valueOf(roleName));
|
item.setRole(roleName);
|
||||||
|
item.setCreatedAt(Instant.now());
|
||||||
|
this.entityManager.persist(item);
|
||||||
|
this.keycloakService.addUserToGlobalRoleGroup(subjectId, roleName);
|
||||||
|
}
|
||||||
|
foundIds.add(item.getId());
|
||||||
}
|
}
|
||||||
foundIds.add(item.getId());
|
|
||||||
|
this.entityManager.flush();
|
||||||
|
|
||||||
|
List<UserRoleEntity> toDelete = existingItems.stream().filter(x -> foundIds.stream().noneMatch(y -> y.equals(x.getId()))).collect(Collectors.toList());
|
||||||
|
toDelete.forEach(x -> this.keycloakService.removeUserGlobalRoleGroup(subjectId, x.getRole()));
|
||||||
|
this.deleterFactory.deleter(UserRoleDeleter.class).deleteAndSave(toDelete);
|
||||||
|
|
||||||
|
this.entityManager.flush();
|
||||||
|
} finally {
|
||||||
|
this.tenantScope.removeTempTenant(this.entityManager.getEntityManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.entityManager.flush();
|
|
||||||
|
|
||||||
List<UserRoleEntity> toDelete = existingItems.stream().filter(x-> foundIds.stream().noneMatch(y-> y.equals(x.getId()))).collect(Collectors.toList());
|
|
||||||
toDelete.forEach(x -> this.keycloakService.removeUserFromGroup(subjectId, KeycloakRole.valueOf(x.getRole())));
|
|
||||||
this.deleterFactory.deleter(UserRoleDeleter.class).deleteAndSave(toDelete);
|
|
||||||
|
|
||||||
this.entityManager.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyTenantRoles(UUID userId, UUID subjectId, UserRolePatchPersist model) throws InvalidApplicationException {
|
private void applyTenantRoles(UUID userId, String subjectId, UserRolePatchPersist model) throws InvalidApplicationException {
|
||||||
if (!tenantScope.isSet()) throw new MyForbiddenException("tenant scope required");
|
if (!tenantScope.isSet()) throw new MyForbiddenException("tenant scope required");
|
||||||
|
|
||||||
UserRoleQuery userRoleQuery = this.queryFactory.query(UserRoleQuery.class).userIds(userId).roles(this.authorizationProperties.getAllowedTenantRoles());
|
UserRoleQuery userRoleQuery = this.queryFactory.query(UserRoleQuery.class).userIds(userId).roles(this.authorizationProperties.getAllowedTenantRoles());
|
||||||
|
@ -311,7 +315,7 @@ public class UserServiceImpl implements UserService {
|
||||||
item.setCreatedAt(Instant.now());
|
item.setCreatedAt(Instant.now());
|
||||||
item.setTenantId(this.tenantScope.getTenant());
|
item.setTenantId(this.tenantScope.getTenant());
|
||||||
this.entityManager.persist(item);
|
this.entityManager.persist(item);
|
||||||
this.keycloakService.addUserToGroup(subjectId, KeycloakRole.valueOf(roleName));
|
this.keycloakService.addUserToTenantRoleGroup(subjectId, this.tenantScope.getTenantCode(), roleName);
|
||||||
}
|
}
|
||||||
foundIds.add(item.getId());
|
foundIds.add(item.getId());
|
||||||
}
|
}
|
||||||
|
@ -319,7 +323,13 @@ public class UserServiceImpl implements UserService {
|
||||||
this.entityManager.flush();
|
this.entityManager.flush();
|
||||||
|
|
||||||
List<UserRoleEntity> toDelete = existingItems.stream().filter(x-> foundIds.stream().noneMatch(y-> y.equals(x.getId()))).collect(Collectors.toList());
|
List<UserRoleEntity> toDelete = existingItems.stream().filter(x-> foundIds.stream().noneMatch(y-> y.equals(x.getId()))).collect(Collectors.toList());
|
||||||
toDelete.forEach(x -> this.keycloakService.removeUserFromGroup(subjectId, KeycloakRole.valueOf(x.getRole())));
|
toDelete.forEach(x -> {
|
||||||
|
try {
|
||||||
|
this.keycloakService.removeUserTenantRoleGroup(subjectId, this.tenantScope.getTenantCode(), x.getRole());
|
||||||
|
} catch (InvalidApplicationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
this.deleterFactory.deleter(UserRoleDeleter.class).deleteAndSave(toDelete);
|
this.deleterFactory.deleter(UserRoleDeleter.class).deleteAndSave(toDelete);
|
||||||
|
|
||||||
this.entityManager.flush();
|
this.entityManager.flush();
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
authorization:
|
authorization:
|
||||||
|
globalAdminRole: Admin
|
||||||
|
autoAssignGlobalAdminToNewTenants: true
|
||||||
allowedTenantRoles:
|
allowedTenantRoles:
|
||||||
- TenantAdmin
|
- TenantAdmin
|
||||||
- TenantUser
|
- TenantUser
|
||||||
|
|
|
@ -1,14 +1,21 @@
|
||||||
keycloak-resources:
|
keycloak-resources:
|
||||||
|
tenantGroupsNamingStrategy: 'tenant-{tenantCode}'
|
||||||
|
tenantRoleAttributeName: 'tenant_role'
|
||||||
authorities:
|
authorities:
|
||||||
User:
|
User:
|
||||||
groupId: a04fd333-f127-449e-8fc2-0626570a3899
|
groupId: a04fd333-f127-449e-8fc2-0626570a3899
|
||||||
groupTitle: role-user
|
|
||||||
Admin:
|
Admin:
|
||||||
groupId: 299f18fe-e271-4625-a4c1-9c3eb313b2ea
|
groupId: 299f18fe-e271-4625-a4c1-9c3eb313b2ea
|
||||||
groupTitle: role-admin
|
tenantAuthorities:
|
||||||
Manager:
|
TenantAdmin:
|
||||||
groupId: 1753f7a7-cedb-4ad4-ae5f-96fe9bdabe3e
|
parent: 1e650f57-8b7c-4f32-bf5b-e1a9147c597b
|
||||||
groupTitle: role-manager
|
roleAttributeValueStrategy: 'TenantAdmin:{tenantCode}'
|
||||||
DescriptionTemplateEditor:
|
TenantUser:
|
||||||
groupId: b0ea3cf3-21b0-4c6b-9c42-fb09f0e09dbb
|
parent: c7057c4d-e7dc-49ef-aa5d-02ad3a22bff8
|
||||||
groupTitle: role-description-template-editor
|
roleAttributeValueStrategy: 'TenantUser:{tenantCode}'
|
||||||
|
TenantManager:
|
||||||
|
parent: d111bb2f-b4a6-4de7-ad22-5151ee1a508b
|
||||||
|
roleAttributeValueStrategy: 'TenantManager:{tenantCode}'
|
||||||
|
TenantDescriptionTemplateEditor:
|
||||||
|
parent: 55cf7b17-c025-4065-8906-49f9f430f038
|
||||||
|
roleAttributeValueStrategy: 'TenantDescriptionTemplateEditor:{tenantCode}'
|
|
@ -1,10 +1,10 @@
|
||||||
keycloak-client:
|
keycloak-client:
|
||||||
serverUrl: ${KEYCLOAK_API_SERVER_URL:}
|
serverUrl: ${KEYCLOAK_API_SERVER_URL}
|
||||||
realm: ${KEYCLOAK_API_REALM:}
|
realm: ${KEYCLOAK_API_REALM}
|
||||||
username: ${KEYCLOAK_API_USERNAME:}
|
username: ${KEYCLOAK_API_USERNAME}
|
||||||
password: ${KEYCLOAK_API_PASSWORD:}
|
password: ${KEYCLOAK_API_PASSWORD}
|
||||||
clientId: ${KEYCLOAK_API_CLIENT_ID:}
|
clientId: ${KEYCLOAK_API_CLIENT_ID}
|
||||||
clientSecret: ${KEYCLOAK_API_CLIENT_SECRET:}
|
clientSecret: ${KEYCLOAK_API_CLIENT_SECRET}
|
||||||
|
|
||||||
keycloak-resources:
|
keycloak-resources:
|
||||||
authorities: null
|
authorities: null
|
Loading…
Reference in New Issue