Merge branch 'dmp-refactoring' of https://code-repo.d4science.org/MaDgiK-CITE/argos into dmp-refactoring

This commit is contained in:
Sofia Papacharalampous 2024-04-16 13:29:50 +03:00
commit cf9a65ae53
17 changed files with 326 additions and 110 deletions

View File

@ -9,6 +9,25 @@ import java.util.List;
@ConfigurationProperties(prefix = "authorization")
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;
public List<String> getAllowedTenantRoles() {

View File

@ -67,6 +67,13 @@ public class TenantScope {
this.tenant.set(tenant);
this.tenantCode.set(tenantCode);
entityManager
.unwrap(Session.class)
.disableFilter(TenantScopedBaseEntity.TENANT_FILTER);
entityManager
.unwrap(Session.class)
.disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
if (this.tenant.get() != null || this.isDefaultTenant()) {
if(!this.isDefaultTenant()) {
entityManager
@ -84,6 +91,15 @@ public class TenantScope {
public void removeTempTenant(EntityManager entityManager) {
this.tenant.set(this.initialTenant.get());
this.tenantCode.set(this.initialTenantCode.get());
entityManager
.unwrap(Session.class)
.disableFilter(TenantScopedBaseEntity.TENANT_FILTER);
entityManager
.unwrap(Session.class)
.disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
if (this.initialTenant.get() != null || this.isDefaultTenant()) {
if(!this.isDefaultTenant()) {
entityManager

View File

@ -9,6 +9,7 @@ import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.data.DescriptionTemplateEntity;
import eu.eudat.data.DmpDescriptionTemplateEntity;
import eu.eudat.data.DmpEntity;
import eu.eudat.data.EntityDoiEntity;
import eu.eudat.model.DescriptionTemplate;
import eu.eudat.query.utils.BuildSubQueryInput;
import eu.eudat.query.utils.QueryUtilsService;
@ -53,6 +54,8 @@ public class DescriptionTemplateQuery extends QueryBase<DescriptionTemplateEntit
private Instant after;
private DmpDescriptionTemplateQuery dmpDescriptionTemplateQuery;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
public DescriptionTemplateQuery like(String value) {
@ -200,6 +203,11 @@ public class DescriptionTemplateQuery extends QueryBase<DescriptionTemplateEntit
return this;
}
public DescriptionTemplateQuery dmpDescriptionTemplateSubQuery(DmpDescriptionTemplateQuery value) {
this.dmpDescriptionTemplateQuery = value;
return this;
}
public DescriptionTemplateQuery authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values;
return this;
@ -327,6 +335,11 @@ public class DescriptionTemplateQuery extends QueryBase<DescriptionTemplateEntit
predicates.add(afterClause);
}
if (this.dmpDescriptionTemplateQuery != null) {
QueryContext<DmpDescriptionTemplateEntity, UUID> subQuery = this.applySubQuery(this.dmpDescriptionTemplateQuery, queryContext, UUID.class, dmpDescriptionTemplateEntityRoot -> dmpDescriptionTemplateEntityRoot.get(DmpDescriptionTemplateEntity._descriptionTemplateGroupId));
predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionTemplateEntity._groupId)).value(subQuery.Query));
}
if (!predicates.isEmpty()) {
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
return queryContext.CriteriaBuilder.and(predicatesArray);

View File

@ -1,22 +1,18 @@
package eu.eudat.service.keycloak;
import org.springframework.boot.context.properties.bind.ConstructorBinding;
public class KeycloakAuthorityProperties {
private final String groupId, groupTitle;
private String groupId;
@ConstructorBinding
public KeycloakAuthorityProperties(String groupId, String groupTitle) {
this.groupId = groupId;
this.groupTitle = groupTitle;
public KeycloakAuthorityProperties() {
}
public String getGroupId() {
return groupId;
}
public String getGroupTitle() {
return groupTitle;
public void setGroupId(String groupId) {
this.groupId = groupId;
}
}

View File

@ -19,4 +19,14 @@ public class KeycloakResourcesConfiguration {
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);
}
}

View File

@ -10,15 +10,41 @@ import java.util.HashMap;
@ConditionalOnProperty(prefix = "keycloak-resources", name = "enabled", havingValue = "true")
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) {
this.authorities = authorities;
}
private String tenantGroupsNamingStrategy;
private String tenantRoleAttributeName;
public HashMap<String, KeycloakAuthorityProperties> getAuthorities() {
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;
}
}

View File

@ -1,7 +0,0 @@
package eu.eudat.service.keycloak;
public enum KeycloakRole {
Admin, User
}

View File

@ -1,17 +1,23 @@
package eu.eudat.service.keycloak;
import org.jetbrains.annotations.NotNull;
import org.keycloak.representations.idm.GroupRepresentation;
import java.util.HashMap;
import java.util.UUID;
public interface KeycloakService {
void addUserToGroup(UUID 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 addUserToGroup(@NotNull String subjectId, String groupId);
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);
}

View File

@ -4,7 +4,6 @@ import gr.cite.commons.web.keycloak.api.configuration.KeycloakClientConfiguratio
import gr.cite.tools.logging.LoggerService;
import org.jetbrains.annotations.NotNull;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -27,56 +26,83 @@ public class KeycloakServiceImpl implements KeycloakService {
}
@Override
public void addUserToGroup(@NotNull UUID subjectId, String groupId) {
api.users().addUserToGroup(subjectId.toString(), groupId);
public void addUserToGroup(@NotNull String subjectId, String groupId) {
api.users().addUserToGroup(subjectId, groupId);
}
@Override
public void removeUserFromGroup(@NotNull UUID subjectId, String groupId) {
api.users().removeUserFromGroup(subjectId.toString(), groupId);
public void removeUserFromGroup(@NotNull String subjectId, String groupId) {
api.users().removeUserFromGroup(subjectId, groupId);
}
@Override
public void addUserToGroup(UUID subjectId, KeycloakRole role) {
KeycloakAuthorityProperties properties = this.configuration.getProperties().getAuthorities().get(role.name());
if (properties != null)
addUserToGroup(subjectId, properties.getGroupId());
public void addUserToGlobalRoleGroup(String subjectId, String role) {
KeycloakAuthorityProperties properties = this.configuration.getProperties().getAuthorities().get(role);
if (properties != null) addUserToGroup(subjectId, properties.getGroupId());
}
@Override
public void removeUserFromGroup(@NotNull UUID subjectId, KeycloakRole role) {
KeycloakAuthorityProperties properties = this.configuration.getProperties().getAuthorities().get(role.name());
public void removeUserGlobalRoleGroup(@NotNull String subjectId, String role) {
KeycloakAuthorityProperties properties = this.configuration.getProperties().getAuthorities().get(role);
if (properties != null)
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
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);
public void addUserToTenantRoleGroup(String subjectId, String tenantCode, String tenantRole) {
GroupRepresentation group = api.groups().findGroupByPath(getTenantAuthorityParentPath(tenantRole) + "/" + configuration.getTenantGroupName(tenantCode));
addUserToGroup(subjectId, group.getId());
}
@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 void removeUserTenantRoleGroup(String subjectId, String tenantCode, String tenantRole) {
GroupRepresentation group = api.groups().findGroupByPath(getTenantAuthorityParentPath(tenantRole) + "/" + configuration.getTenantGroupName(tenantCode));
removeUserFromGroup(subjectId, group.getId());
}
public List<GroupRepresentation> getUserGroups(UUID subjectId) {
return api.users().getGroups(subjectId.toString());
private String getTenantAuthorityParentPath(String tenantRole) {
GroupRepresentation parent = api.groups().findGroupById(configuration.getProperties().getTenantAuthorities().get(tenantRole).getParent());
return parent.getPath();
}
@Override
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());
}
}
}

View File

@ -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;
}
}

View File

@ -279,7 +279,15 @@ public class MetricsServiceImpl implements MetricsService {
}
private double calculateDoiedDatasets(boolean forNexus) {
return 0;
DescriptionQuery descriptionQuery = this.queryFactory.query(DescriptionQuery.class).statuses(DescriptionStatus.Finalized).isActive(IsActive.Active);
if (forNexus)
descriptionQuery.createdAfter(_config.getNexusDate());
DmpQuery dmpQuery = this.queryFactory.query(DmpQuery.class).isActive(IsActive.Active);
EntityDoiQuery entityDoiQuery = this.queryFactory.query(EntityDoiQuery.class).types(EntityType.DMP).isActive(IsActive.Active);
dmpQuery.entityDoiSubQuery(entityDoiQuery);
descriptionQuery.dmpSubQuery(dmpQuery);
descriptionQuery.setDistinct(true);
return descriptionQuery.count();
}
private double calculateDraftTemplates(boolean forNexus) {
@ -297,11 +305,13 @@ public class MetricsServiceImpl implements MetricsService {
}
private double calculateUsedTemplates(boolean forNexus) {
DmpDescriptionTemplateQuery dmpDescriptionTemplateQuery = this.queryFactory.query(DmpDescriptionTemplateQuery.class).isActive(IsActive.Active);
dmpDescriptionTemplateQuery.setDistinct(true);
DescriptionTemplateQuery descriptionTemplateQuery = this.queryFactory.query(DescriptionTemplateQuery.class).isActive(IsActive.Active);
descriptionTemplateQuery.setDistinct(true);
if (forNexus)
dmpDescriptionTemplateQuery.after(_config.getNexusDate());
return dmpDescriptionTemplateQuery.count();
descriptionTemplateQuery.after(_config.getNexusDate());
DmpDescriptionTemplateQuery dmpDescriptionTemplateQuery = this.queryFactory.query(DmpDescriptionTemplateQuery.class);
descriptionTemplateQuery.dmpDescriptionTemplateSubQuery(dmpDescriptionTemplateQuery);
return descriptionTemplateQuery.count();
}
private double calculateActiveUsers() {

View File

@ -1,25 +1,34 @@
package eu.eudat.service.tenant;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.AuthorizationProperties;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.XmlHandlingService;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.commons.types.tenant.*;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.TenantEntity;
import eu.eudat.data.TenantEntityManager;
import eu.eudat.data.UserCredentialEntity;
import eu.eudat.data.UserRoleEntity;
import eu.eudat.errorcode.ErrorThesaurusProperties;
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEvent;
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEventHandler;
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEvent;
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEventHandler;
import eu.eudat.model.Tenant;
import eu.eudat.model.UserCredential;
import eu.eudat.model.builder.TenantBuilder;
import eu.eudat.model.deleter.TenantDeleter;
import eu.eudat.model.deleter.UserRoleDeleter;
import eu.eudat.model.persist.TenantPersist;
import eu.eudat.model.persist.tenantconfig.*;
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.keycloak.KeycloakService;
import eu.eudat.service.responseutils.ResponseUtilsService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.builder.BuilderFactory;
@ -73,6 +82,11 @@ public class TenantServiceImpl implements TenantService {
private final TenantProperties properties;
private final TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler;
private final TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler;
private final KeycloakService keycloakService;
private final AuthorizationProperties authorizationProperties;
private final TenantScope tenantScope;
private final QueryFactory queryFactory;
@Autowired
public TenantServiceImpl(
@ -84,7 +98,7 @@ public class TenantServiceImpl implements TenantService {
MessageSource messageSource,
XmlHandlingService xmlHandlingService,
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.authorizationService = authorizationService;
this.deleterFactory = deleterFactory;
@ -97,6 +111,10 @@ public class TenantServiceImpl implements TenantService {
this.properties = properties;
this.tenantTouchedIntegrationEventHandler = tenantTouchedIntegrationEventHandler;
this.tenantRemovalIntegrationEventHandler = tenantRemovalIntegrationEventHandler;
this.keycloakService = keycloakService;
this.authorizationProperties = authorizationProperties;
this.tenantScope = tenantScope;
this.queryFactory = queryFactory;
}
@Override
@ -132,6 +150,11 @@ public class TenantServiceImpl implements TenantService {
this.entityManager.flush();
if (!isUpdate) {
this.keycloakService.createTenantGroups(data.getCode());
this.autoAssignGlobalAdminsToNewTenant(data);
}
TenantTouchedIntegrationEvent tenantTouchedIntegrationEvent = new TenantTouchedIntegrationEvent();
tenantTouchedIntegrationEvent.setId(data.getId());
tenantTouchedIntegrationEvent.setCode(data.getCode());
@ -140,6 +163,39 @@ public class TenantServiceImpl implements TenantService {
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 {
TenantConfigEntity data = new TenantConfigEntity();
if (persist == null) return data;

View File

@ -29,7 +29,6 @@ import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEvent;
import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEventHandler;
import eu.eudat.integrationevent.outbox.userremoval.UserRemovalIntegrationEventHandler;
import eu.eudat.integrationevent.outbox.usertouched.UserTouchedIntegrationEventHandler;
import eu.eudat.model.Tenant;
import eu.eudat.model.User;
import eu.eudat.model.UserContactInfo;
import eu.eudat.model.UserCredential;
@ -41,7 +40,6 @@ import eu.eudat.model.persist.actionconfirmation.RemoveCredentialRequestPersist;
import eu.eudat.query.*;
import eu.eudat.service.actionconfirmation.ActionConfirmationService;
import eu.eudat.service.elastic.ElasticService;
import eu.eudat.service.keycloak.KeycloakRole;
import eu.eudat.service.keycloak.KeycloakService;
import gr.cite.commons.web.authz.service.AuthorizationService;
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");
if (userCredentials.getFirst().getExternalId() == null)
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);
@ -266,7 +264,10 @@ public class UserServiceImpl implements UserService {
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 {
try {
this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
List<UserRoleEntity> existingItems = this.queryFactory.query(UserRoleQuery.class).userIds(userId).tenantIsSet(false).roles(this.authorizationProperties.getAllowedGlobalRoles()).collect();
List<UUID> foundIds = new ArrayList<>();
for (String roleName : model.getRoles().stream().filter(x -> x != null && !x.isBlank() && this.authorizationProperties.getAllowedGlobalRoles().contains(x)).distinct().toList()) {
@ -278,7 +279,7 @@ public class UserServiceImpl implements UserService {
item.setRole(roleName);
item.setCreatedAt(Instant.now());
this.entityManager.persist(item);
this.keycloakService.addUserToGroup(subjectId, KeycloakRole.valueOf(roleName));
this.keycloakService.addUserToGlobalRoleGroup(subjectId, roleName);
}
foundIds.add(item.getId());
}
@ -286,13 +287,16 @@ public class UserServiceImpl implements UserService {
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())));
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());
}
}
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");
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.setTenantId(this.tenantScope.getTenant());
this.entityManager.persist(item);
this.keycloakService.addUserToGroup(subjectId, KeycloakRole.valueOf(roleName));
this.keycloakService.addUserToTenantRoleGroup(subjectId, this.tenantScope.getTenantCode(), roleName);
}
foundIds.add(item.getId());
}
@ -319,7 +323,13 @@ public class UserServiceImpl implements UserService {
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())));
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.entityManager.flush();

View File

@ -1,4 +1,6 @@
authorization:
globalAdminRole: Admin
autoAssignGlobalAdminToNewTenants: true
allowedTenantRoles:
- TenantAdmin
- TenantUser

View File

@ -1,14 +1,21 @@
keycloak-resources:
tenantGroupsNamingStrategy: 'tenant-{tenantCode}'
tenantRoleAttributeName: 'tenant_role'
authorities:
User:
groupId: a04fd333-f127-449e-8fc2-0626570a3899
groupTitle: role-user
Admin:
groupId: 299f18fe-e271-4625-a4c1-9c3eb313b2ea
groupTitle: role-admin
Manager:
groupId: 1753f7a7-cedb-4ad4-ae5f-96fe9bdabe3e
groupTitle: role-manager
DescriptionTemplateEditor:
groupId: b0ea3cf3-21b0-4c6b-9c42-fb09f0e09dbb
groupTitle: role-description-template-editor
tenantAuthorities:
TenantAdmin:
parent: 1e650f57-8b7c-4f32-bf5b-e1a9147c597b
roleAttributeValueStrategy: 'TenantAdmin:{tenantCode}'
TenantUser:
parent: c7057c4d-e7dc-49ef-aa5d-02ad3a22bff8
roleAttributeValueStrategy: 'TenantUser:{tenantCode}'
TenantManager:
parent: d111bb2f-b4a6-4de7-ad22-5151ee1a508b
roleAttributeValueStrategy: 'TenantManager:{tenantCode}'
TenantDescriptionTemplateEditor:
parent: 55cf7b17-c025-4065-8906-49f9f430f038
roleAttributeValueStrategy: 'TenantDescriptionTemplateEditor:{tenantCode}'

View File

@ -1,10 +1,10 @@
keycloak-client:
serverUrl: ${KEYCLOAK_API_SERVER_URL:}
realm: ${KEYCLOAK_API_REALM:}
username: ${KEYCLOAK_API_USERNAME:}
password: ${KEYCLOAK_API_PASSWORD:}
clientId: ${KEYCLOAK_API_CLIENT_ID:}
clientSecret: ${KEYCLOAK_API_CLIENT_SECRET:}
serverUrl: ${KEYCLOAK_API_SERVER_URL}
realm: ${KEYCLOAK_API_REALM}
username: ${KEYCLOAK_API_USERNAME}
password: ${KEYCLOAK_API_PASSWORD}
clientId: ${KEYCLOAK_API_CLIENT_ID}
clientSecret: ${KEYCLOAK_API_CLIENT_SECRET}
keycloak-resources:
authorities: null

View File

@ -11,7 +11,7 @@ CREATE TABLE IF NOT EXISTS public."ant_Annotation"
"entity_type" character varying(512) COLLATE pg_catalog."default" NOT NULL,
"anchor" character varying(512) COLLATE pg_catalog."default",
"payload" text COLLATE pg_catalog."default",
"tenant" uuid NOT NULL,
"tenant" uuid NULL,
"created_at" timestamp without time zone NOT NULL,
"updated_at" timestamp without time zone NOT NULL,
"is_active" smallint NOT NULL,