authz changes

This commit is contained in:
Efstratios Giannopoulos 2024-03-13 17:04:17 +02:00
parent cf5acb2656
commit cbfe4ec4f2
20 changed files with 565 additions and 16 deletions

View File

@ -0,0 +1,40 @@
package eu.eudat.authorization;
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class AffiliatedAuthorizationRequirement implements AuthorizationRequirement {
private final Set<String> requiredPermissions;
private final boolean matchAll;
public AffiliatedAuthorizationRequirement(Set<String> requiredPermissions) {
this(false, requiredPermissions);
}
public AffiliatedAuthorizationRequirement(String... requiredPermissions) {
this(false, requiredPermissions);
}
public AffiliatedAuthorizationRequirement(boolean matchAll, Set<String> requiredPermissions) {
this.matchAll = matchAll;
this.requiredPermissions = requiredPermissions;
}
public AffiliatedAuthorizationRequirement(boolean matchAll, String... requiredPermissions) {
this.requiredPermissions = new HashSet<>();
this.matchAll = matchAll;
this.requiredPermissions.addAll(Arrays.stream(requiredPermissions).distinct().toList());
}
public Set<String> getRequiredPermissions() {
return requiredPermissions;
}
public boolean getMatchAll() {
return matchAll;
}
}

View File

@ -0,0 +1,31 @@
package eu.eudat.authorization;
import eu.eudat.commons.enums.DmpUserRole;
import gr.cite.commons.web.authz.policy.AuthorizationResource;
import java.util.HashSet;
import java.util.List;
public class AffiliatedResource extends AuthorizationResource {
private HashSet<DmpUserRole> dmpUserRoles;
public AffiliatedResource() {
dmpUserRoles = new HashSet<>();
}
public AffiliatedResource(DmpUserRole dmpUserRole) {
this(List.of(dmpUserRole));
}
public AffiliatedResource(List<DmpUserRole> dmpUserRoles) {
this.dmpUserRoles = new HashSet<>(dmpUserRoles);
}
public HashSet<DmpUserRole> getDmpUserRoles() {
return dmpUserRoles;
}
public void setDmpUserRoles(HashSet<DmpUserRole> dmpUserRoles) {
this.dmpUserRoles = dmpUserRoles;
}
}

View File

@ -0,0 +1,40 @@
package eu.eudat.authorization;
import eu.eudat.convention.ConventionService;
import eu.eudat.service.deposit.DepositServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class PermissionNameProvider {
private static final Logger logger = LoggerFactory.getLogger(DepositServiceImpl.class);
private final List<String> permissions;
public PermissionNameProvider(ConventionService conventionService) {
this.permissions = new ArrayList<>();
Class<Permission> clazz = Permission.class;
for (Field f : clazz.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers())) {
try {
Object value = f.get(null);
if (value != null && !conventionService.isNullOrEmpty((String)value)) this.permissions.add((String)value);
} catch (Exception e) {
logger.error("Can not load permission " + f.getName() + " " + e.getMessage());
}
}
}
}
public List<String> getPermissions() {
return permissions;
}
}

View File

@ -0,0 +1,10 @@
package eu.eudat.authorization.authorizationcontentresolver;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.affiliation")
public class AffiliationCacheOptions extends CacheOptions {
}

View File

@ -0,0 +1,97 @@
package eu.eudat.authorization.authorizationcontentresolver;
import eu.eudat.authorization.AffiliatedResource;
import eu.eudat.convention.ConventionService;
import gr.cite.tools.cache.CacheService;
import gr.cite.tools.exception.MyApplicationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
@Service
public class AffiliationCacheService extends CacheService<AffiliationCacheService.AffiliationCacheValue> {
public static class AffiliationCacheValue {
public AffiliationCacheValue() {
}
public AffiliationCacheValue(UUID userId, UUID entityId, String entityType, AffiliatedResource affiliatedResource) {
this.userId = userId;
this.entityId = entityId;
this.entityType = entityType;
this.affiliatedResource = affiliatedResource;
}
private UUID userId;
private UUID entityId;
private String entityType;
private AffiliatedResource affiliatedResource;
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
public UUID getEntityId() {
return entityId;
}
public void setEntityId(UUID entityId) {
this.entityId = entityId;
}
public String getEntityType() {
return entityType;
}
public void setEntityType(String entityType) {
this.entityType = entityType;
}
public AffiliatedResource getAffiliatedResource() {
return affiliatedResource;
}
public void setAffiliatedResource(AffiliatedResource affiliatedResource) {
this.affiliatedResource = affiliatedResource;
}
}
private final ConventionService conventionService;
@Autowired
public AffiliationCacheService(AffiliationCacheOptions options, ConventionService conventionService) {
super(options);
this.conventionService = conventionService;
}
@Override
protected Class<AffiliationCacheValue> valueClass() {
return AffiliationCacheValue.class;
}
@Override
public String keyOf(AffiliationCacheValue value) {
return this.buildKey(value.getUserId(), value.getEntityId(), value.getEntityType());
}
public String buildKey(UUID userId, UUID entityId, String entityType) {
if (userId == null) throw new IllegalArgumentException("userId id is required");
if (entityId == null) throw new IllegalArgumentException("entityId id is required");
if (this.conventionService.isNullOrEmpty(entityType)) throw new IllegalArgumentException("entityType id is required");
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$user$", userId.toString().replace("-", "").toLowerCase(Locale.ROOT));
keyParts.put("$entity$", entityId.toString().replace("-", "").toLowerCase(Locale.ROOT));
keyParts.put("$type$", entityType);
return this.generateKey(keyParts);
}
}

View File

@ -0,0 +1,13 @@
package eu.eudat.authorization.authorizationcontentresolver;
import eu.eudat.authorization.AffiliatedResource;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public interface AuthorizationContentResolver {
List<String> getPermissionNames();
Map<UUID, AffiliatedResource> dmpAffiliation(List<UUID> ids);
}

View File

@ -0,0 +1,77 @@
package eu.eudat.authorization.authorizationcontentresolver;
import eu.eudat.authorization.AffiliatedResource;
import eu.eudat.authorization.PermissionNameProvider;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.data.DmpEntity;
import eu.eudat.data.DmpUserEntity;
import eu.eudat.model.DmpUser;
import eu.eudat.query.DmpUserQuery;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.fieldset.BaseFieldSet;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.RequestScope;
import java.util.*;
@Service
@RequestScope
public class AuthorizationContentResolverImpl implements AuthorizationContentResolver {
private final QueryFactory queryFactory;
private final UserScope userScope;
private final AffiliationCacheService affiliationCacheService;
private final PermissionNameProvider permissionNameProvider;
public AuthorizationContentResolverImpl(QueryFactory queryFactory, UserScope userScope, AffiliationCacheService affiliationCacheService, PermissionNameProvider permissionNameProvider) {
this.queryFactory = queryFactory;
this.userScope = userScope;
this.affiliationCacheService = affiliationCacheService;
this.permissionNameProvider = permissionNameProvider;
}
@Override
public List<String> getPermissionNames() {
return permissionNameProvider.getPermissions();
}
@Override
public Map<UUID, AffiliatedResource> dmpAffiliation(List<UUID> ids){
UUID userId = this.userScope.getUserIdSafe();
Map<UUID, AffiliatedResource> affiliatedResources = new HashMap<>();
for (UUID id : ids){
affiliatedResources.put(id, new AffiliatedResource());
}
if (userId == null || !userScope.isSet()) return affiliatedResources;
List<UUID> idsToResolve = this.getAffiliatedFromCache(ids, userId, affiliatedResources, DmpEntity.class.getSimpleName());
if (idsToResolve.isEmpty()) return affiliatedResources;
List<DmpUserEntity> dmpUsers = this.queryFactory.query(DmpUserQuery.class).dmpIds(ids).userIds(userId).isActives(IsActive.Active).collectAs(new BaseFieldSet().ensure(DmpUser._role).ensure(DmpUser._dmp));
for (DmpUserEntity dmpUser : dmpUsers){
affiliatedResources.get(dmpUser.getDmpId()).getDmpUserRoles().add(dmpUser.getRole());
}
this.ensureAffiliatedInCache(idsToResolve, userId, affiliatedResources, DmpEntity.class.getSimpleName());
return affiliatedResources;
}
private List<UUID> getAffiliatedFromCache(List<UUID> ids, UUID userId, Map<UUID, AffiliatedResource> affiliatedResources, String entityType){
List<UUID> idsToResolve = new ArrayList<>();
for (UUID id : ids){
AffiliationCacheService.AffiliationCacheValue cacheValue = this.affiliationCacheService.lookup(this.affiliationCacheService.buildKey(userId, id, entityType));
if (cacheValue != null) affiliatedResources.put(id, cacheValue.getAffiliatedResource());
else idsToResolve.add(id);
}
return idsToResolve;
}
private void ensureAffiliatedInCache(List<UUID> idsToResolve, UUID userId, Map<UUID, AffiliatedResource> affiliatedResources, String entityType){
for (UUID id : idsToResolve){
AffiliatedResource affiliatedResource = affiliatedResources.getOrDefault(id, null);
if (affiliatedResource != null) {
AffiliationCacheService.AffiliationCacheValue cacheValue = new AffiliationCacheService.AffiliationCacheValue(userId, id, entityType, affiliatedResource);
this.affiliationCacheService.put(cacheValue);
}
}
}
}

View File

@ -84,6 +84,9 @@ public class Dmp {
private List<EntityDoi> entityDois; private List<EntityDoi> entityDois;
public static final String _entityDois = "entityDois"; public static final String _entityDois = "entityDois";
private List<String> authorizationFlags;
public static final String _authorizationFlags = "authorizationFlags";
public UUID getId() { public UUID getId() {
return id; return id;
} }
@ -275,4 +278,12 @@ public class Dmp {
public void setEntityDois(List<EntityDoi> entityDois) { public void setEntityDois(List<EntityDoi> entityDois) {
this.entityDois = entityDois; this.entityDois = entityDois;
} }
public List<String> getAuthorizationFlags() {
return authorizationFlags;
}
public void setAuthorizationFlags(List<String> authorizationFlags) {
this.authorizationFlags = authorizationFlags;
}
} }

View File

@ -1,12 +1,18 @@
package eu.eudat.model.builder; package eu.eudat.model.builder;
import eu.eudat.authorization.AffiliatedResource;
import eu.eudat.authorization.Permission;
import eu.eudat.authorization.PermissionNameProvider;
import eu.eudat.convention.ConventionService; import eu.eudat.convention.ConventionService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.builder.Builder; import gr.cite.tools.data.builder.Builder;
import gr.cite.tools.data.query.QueryBase; import gr.cite.tools.data.query.QueryBase;
import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
@ -92,5 +98,28 @@ public abstract class BaseBuilder<M, D> implements Builder {
return this.conventionService.asIndexer(names); return this.conventionService.asIndexer(names);
} }
protected Set<String> extractAuthorizationFlags(FieldSet fields, String propertyName, List<String> permissionNames){
if (fields == null) return new HashSet<>();
if (permissionNames == null) return new HashSet<>();
FieldSet authorizationFlags = fields.extractPrefixed(this.asPrefix(propertyName));
List<String> permissions = new ArrayList<>();
for (String fieldValue : authorizationFlags.getFields()) permissions.addAll(permissionNames.stream().filter(x-> x.equalsIgnoreCase(fieldValue)).toList());
return new HashSet<>(permissions);
}
protected List<String> evaluateAuthorizationFlags(AuthorizationService authorizationService, Set<String> authorizationFlags, AffiliatedResource affiliatedResource) {
List<String> allowed = new ArrayList<>();
if (authorizationFlags == null) return allowed;
if (authorizationService == null) return allowed;
for (String permission : authorizationFlags) {
Boolean isAllowed = affiliatedResource == null ? authorizationService.authorize(permission) : authorizationService.authorizeAtLeastOne(List.of(affiliatedResource), permission);
if (isAllowed) allowed.add(permission);
}
return allowed;
}
} }

View File

@ -1,6 +1,9 @@
package eu.eudat.model.builder; package eu.eudat.model.builder;
import eu.eudat.authorization.AffiliatedResource;
import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission;
import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver;
import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.enums.EntityType; import eu.eudat.commons.enums.EntityType;
import eu.eudat.commons.types.description.PropertyDefinitionEntity; import eu.eudat.commons.types.description.PropertyDefinitionEntity;
@ -12,6 +15,7 @@ import eu.eudat.model.*;
import eu.eudat.model.builder.descriptionpropertiesdefinition.PropertyDefinitionBuilder; import eu.eudat.model.builder.descriptionpropertiesdefinition.PropertyDefinitionBuilder;
import eu.eudat.model.builder.dmpproperties.DmpPropertiesBuilder; import eu.eudat.model.builder.dmpproperties.DmpPropertiesBuilder;
import eu.eudat.query.*; import eu.eudat.query.*;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyApplicationException;
@ -36,17 +40,21 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
private final JsonHandlingService jsonHandlingService; private final JsonHandlingService jsonHandlingService;
private final AuthorizationService authorizationService;
private final AuthorizationContentResolver authorizationContentResolver;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None); private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
@Autowired @Autowired
public DmpBuilder(ConventionService conventionService, public DmpBuilder(ConventionService conventionService,
QueryFactory queryFactory, QueryFactory queryFactory,
BuilderFactory builderFactory, JsonHandlingService jsonHandlingService) { BuilderFactory builderFactory, JsonHandlingService jsonHandlingService, AuthorizationService authorizationService, AuthorizationContentResolver authorizationContentResolver) {
super(conventionService, new LoggerService(LoggerFactory.getLogger(DmpBuilder.class))); super(conventionService, new LoggerService(LoggerFactory.getLogger(DmpBuilder.class)));
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.builderFactory = builderFactory; this.builderFactory = builderFactory;
this.jsonHandlingService = jsonHandlingService; this.jsonHandlingService = jsonHandlingService;
this.authorizationService = authorizationService;
this.authorizationContentResolver = authorizationContentResolver;
} }
public DmpBuilder authorize(EnumSet<AuthorizationFlags> values) { public DmpBuilder authorize(EnumSet<AuthorizationFlags> values) {
@ -84,6 +92,10 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
FieldSet dmpDescriptionTemplatesFields = fields.extractPrefixed(this.asPrefix(Dmp._dmpDescriptionTemplates)); FieldSet dmpDescriptionTemplatesFields = fields.extractPrefixed(this.asPrefix(Dmp._dmpDescriptionTemplates));
Map<UUID, List<DmpDescriptionTemplate>> dmpDescriptionTemplatesMap = this.collectDmpDescriptionTemplates(dmpDescriptionTemplatesFields, data); Map<UUID, List<DmpDescriptionTemplate>> dmpDescriptionTemplatesMap = this.collectDmpDescriptionTemplates(dmpDescriptionTemplatesFields, data);
Set<String> authorizationFlags = this.extractAuthorizationFlags(fields, Dmp._authorizationFlags, this.authorizationContentResolver.getPermissionNames());
Map<UUID, AffiliatedResource> affiliatedResourceMap = authorizationFlags == null || authorizationFlags.isEmpty() ? null : this.authorizationContentResolver.dmpAffiliation(data.stream().map(DmpEntity::getId).collect(Collectors.toList()));
FieldSet propertiesFields = fields.extractPrefixed(this.asPrefix(Dmp._properties)); FieldSet propertiesFields = fields.extractPrefixed(this.asPrefix(Dmp._properties));
for (DmpEntity d : data) { for (DmpEntity d : data) {
Dmp m = new Dmp(); Dmp m = new Dmp();
@ -113,6 +125,7 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
DmpPropertiesEntity propertyDefinition = this.jsonHandlingService.fromJsonSafe(DmpPropertiesEntity.class, d.getProperties()); DmpPropertiesEntity propertyDefinition = this.jsonHandlingService.fromJsonSafe(DmpPropertiesEntity.class, d.getProperties());
m.setProperties(this.builderFactory.builder(DmpPropertiesBuilder.class).authorize(this.authorize).build(propertiesFields, propertyDefinition)); m.setProperties(this.builderFactory.builder(DmpPropertiesBuilder.class).authorize(this.authorize).build(propertiesFields, propertyDefinition));
} }
if (authorizationFlags != null && !authorizationFlags.isEmpty()) m.setAuthorizationFlags(this.evaluateAuthorizationFlags(this.authorizationService, authorizationFlags, affiliatedResourceMap.getOrDefault(d.getId(), null)));
models.add(m); models.add(m);
} }
this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0)); this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0));

View File

@ -38,7 +38,7 @@ public class ReferenceCensor extends BaseCensor {
if (fields == null || fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseReference); this.authService.authorizeForce(Permission.BrowseReference, Permission.DeferredAffiliation);
FieldSet definitionFields = fields.extractPrefixed(this.asIndexerPrefix(Reference._definition)); FieldSet definitionFields = fields.extractPrefixed(this.asIndexerPrefix(Reference._definition));
this.censorFactory.censor(DefinitionCensor.class).censor(definitionFields, userId); this.censorFactory.censor(DefinitionCensor.class).censor(definitionFields, userId);
FieldSet dmpReferencesFields = fields.extractPrefixed(this.asIndexerPrefix(Reference._dmpReferences)); FieldSet dmpReferencesFields = fields.extractPrefixed(this.asIndexerPrefix(Reference._dmpReferences));

View File

@ -259,6 +259,8 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
else if (item.match(DmpUser._updatedAt)) return DmpUserEntity._updatedAt; else if (item.match(DmpUser._updatedAt)) return DmpUserEntity._updatedAt;
else if (item.match(DmpUser._isActive)) return DmpUserEntity._isActive; else if (item.match(DmpUser._isActive)) return DmpUserEntity._isActive;
else if (item.match(DmpUser._hash)) return DmpUserEntity._updatedAt; else if (item.match(DmpUser._hash)) return DmpUserEntity._updatedAt;
else if (item.match(DmpUser._dmp)) return DmpUserEntity._dmpId;
else if (item.match(DmpUser._user)) return DmpUserEntity._userId;
else return null; else return null;
} }

View File

@ -0,0 +1,69 @@
package eu.eudat.authorization;
import eu.eudat.commons.enums.DmpUserRole;
import gr.cite.commons.web.authz.handler.AuthorizationHandler;
import gr.cite.commons.web.authz.handler.AuthorizationHandlerContext;
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
import gr.cite.commons.web.oidc.principal.MyPrincipal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
@Component("affiliatedAuthorizationHandler")
public class AffiliatedAuthorizationHandler extends AuthorizationHandler<AffiliatedAuthorizationRequirement> {
private final CustomPermissionAttributesConfiguration myConfiguration;
@Autowired
public AffiliatedAuthorizationHandler(CustomPermissionAttributesConfiguration myConfiguration) {
this.myConfiguration = myConfiguration;
}
@Override
public int handleRequirement(AuthorizationHandlerContext context, Object resource, AuthorizationRequirement requirement) {
AffiliatedAuthorizationRequirement req = (AffiliatedAuthorizationRequirement) requirement;
if (req.getRequiredPermissions() == null)
return ACCESS_NOT_DETERMINED;
AffiliatedResource rs = (AffiliatedResource) resource;
boolean isAuthenticated = ((MyPrincipal) context.getPrincipal()).isAuthenticated();
if (!isAuthenticated)
return ACCESS_NOT_DETERMINED;
if (myConfiguration.getMyPolicies() == null)
return ACCESS_NOT_DETERMINED;
int hits = 0;
HashSet<DmpUserRole> roles = rs != null && rs.getDmpUserRoles() != null ? rs.getDmpUserRoles() : null;
for (String permission : req.getRequiredPermissions()) {
CustomPermissionAttributesProperties.MyPermission policy = myConfiguration.getMyPolicies().get(permission);
boolean hasPermission = policy != null && hasPermission(policy.getDmp(), roles);
if (hasPermission) hits += 1;
}
if ((req.getMatchAll() && req.getRequiredPermissions().size() == hits) || (!req.getMatchAll() && hits > 0))
return ACCESS_GRANTED;
return ACCESS_NOT_DETERMINED;
}
private Boolean hasPermission(DmpRole dmpRole, HashSet<DmpUserRole> roles) {
if (roles == null)
return Boolean.FALSE;
if (dmpRole == null || dmpRole.getRoles() == null)
return Boolean.FALSE;
for (DmpUserRole role : dmpRole.getRoles()) {
if (roles.contains(role))
return Boolean.TRUE;
}
return Boolean.FALSE;
}
@Override
public Class<? extends AuthorizationRequirement> supporting() {
return AffiliatedAuthorizationRequirement.class;
}
}

View File

@ -0,0 +1,24 @@
package eu.eudat.authorization;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
@Configuration
@EnableConfigurationProperties(CustomPermissionAttributesProperties.class)
public class CustomPermissionAttributesConfiguration {
private final CustomPermissionAttributesProperties properties;
@Autowired
public CustomPermissionAttributesConfiguration(CustomPermissionAttributesProperties properties) {
this.properties = properties;
}
public HashMap<String, CustomPermissionAttributesProperties.MyPermission> getMyPolicies() {
return properties.getPolicies();
}
}

View File

@ -0,0 +1,39 @@
package eu.eudat.authorization;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.ConstructorBinding;
import java.util.HashMap;
@ConfigurationProperties(prefix = "permissions")
@ConditionalOnProperty(prefix = "permissions", name = "enabled", havingValue = "true")
public class CustomPermissionAttributesProperties {
private final HashMap<String, MyPermission> policies;
@ConstructorBinding
public CustomPermissionAttributesProperties(HashMap<String, MyPermission> policies) {
this.policies = policies;
}
public HashMap<String, MyPermission> getPolicies() {
return policies;
}
public static class MyPermission {
private final DmpRole dmp;
@ConstructorBinding
public MyPermission(DmpRole dmp) {
this.dmp = dmp;
}
public DmpRole getDmp() {
return dmp;
}
}
}

View File

@ -0,0 +1,21 @@
package eu.eudat.authorization;
import eu.eudat.commons.enums.DmpUserRole;
import org.springframework.boot.context.properties.bind.ConstructorBinding;
import java.util.Set;
public class DmpRole {
private final Set<DmpUserRole> roles;
@ConstructorBinding
public DmpRole(Set<DmpUserRole> roles) {
this.roles = roles;
}
public Set<DmpUserRole> getRoles() {
return roles;
}
}

View File

@ -1,5 +1,6 @@
package eu.eudat.authorization; package eu.eudat.authorization;
import eu.eudat.commons.enums.DmpUserRole;
import eu.eudat.commons.scope.user.UserScope; import eu.eudat.commons.scope.user.UserScope;
import gr.cite.commons.web.authz.handler.AuthorizationHandler; import gr.cite.commons.web.authz.handler.AuthorizationHandler;
import gr.cite.commons.web.authz.handler.AuthorizationHandlerContext; import gr.cite.commons.web.authz.handler.AuthorizationHandlerContext;
@ -8,6 +9,9 @@ import gr.cite.commons.web.oidc.principal.MyPrincipal;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.List;
@Component("ownedAuthorizationHandler") @Component("ownedAuthorizationHandler")
public class OwnedAuthorizationHandler extends AuthorizationHandler<OwnedAuthorizationRequirement> { public class OwnedAuthorizationHandler extends AuthorizationHandler<OwnedAuthorizationRequirement> {
@ -40,3 +44,4 @@ public class OwnedAuthorizationHandler extends AuthorizationHandler<OwnedAuthori
} }
} }

View File

@ -1,9 +1,7 @@
package eu.eudat.configurations; package eu.eudat.configurations;
import eu.eudat.authorization.OwnedAuthorizationHandler; import eu.eudat.authorization.*;
import eu.eudat.authorization.OwnedAuthorizationRequirement;
import eu.eudat.authorization.OwnedResource;
import gr.cite.commons.web.authz.handler.AuthorizationHandler; import gr.cite.commons.web.authz.handler.AuthorizationHandler;
import gr.cite.commons.web.authz.handler.PermissionClientAuthorizationHandler; import gr.cite.commons.web.authz.handler.PermissionClientAuthorizationHandler;
import gr.cite.commons.web.authz.policy.AuthorizationRequirement; import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
@ -39,16 +37,19 @@ public class SecurityConfiguration {
private final AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver; private final AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
private final Filter apiKeyFilter; private final Filter apiKeyFilter;
private final OwnedAuthorizationHandler ownedAuthorizationHandler; private final OwnedAuthorizationHandler ownedAuthorizationHandler;
private final AffiliatedAuthorizationHandler affiliatedAuthorizationHandler;
@Autowired @Autowired
public SecurityConfiguration(WebSecurityProperties webSecurityProperties, public SecurityConfiguration(WebSecurityProperties webSecurityProperties,
@Qualifier("tokenAuthenticationResolver") AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver, @Qualifier("tokenAuthenticationResolver") AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver,
@Qualifier("apiKeyFilter") Filter apiKeyFilter, @Qualifier("apiKeyFilter") Filter apiKeyFilter,
@Qualifier("ownedAuthorizationHandler") OwnedAuthorizationHandler ownedAuthorizationHandler) { @Qualifier("ownedAuthorizationHandler") OwnedAuthorizationHandler ownedAuthorizationHandler,
@Qualifier("affiliatedAuthorizationHandler") AffiliatedAuthorizationHandler affiliatedAuthorizationHandler) {
this.webSecurityProperties = webSecurityProperties; this.webSecurityProperties = webSecurityProperties;
this.authenticationManagerResolver = authenticationManagerResolver; this.authenticationManagerResolver = authenticationManagerResolver;
this.apiKeyFilter = apiKeyFilter; this.apiKeyFilter = apiKeyFilter;
this.ownedAuthorizationHandler = ownedAuthorizationHandler; this.ownedAuthorizationHandler = ownedAuthorizationHandler;
this.affiliatedAuthorizationHandler = affiliatedAuthorizationHandler;
} }
@Bean @Bean
@ -80,7 +81,7 @@ public class SecurityConfiguration {
//If not set / set to null, only the default authorization handlers will be used //If not set / set to null, only the default authorization handlers will be used
@Override @Override
public List<AuthorizationHandler<? extends AuthorizationRequirement>> addCustomHandlers() { public List<AuthorizationHandler<? extends AuthorizationRequirement>> addCustomHandlers() {
return List.of( ownedAuthorizationHandler); return List.of(affiliatedAuthorizationHandler, ownedAuthorizationHandler);
} }
//Here you can register your custom authorization requirements (if any) //Here you can register your custom authorization requirements (if any)
@ -116,6 +117,9 @@ public class SecurityConfiguration {
if (OwnedResource.class.equals(type)) { if (OwnedResource.class.equals(type)) {
return new OwnedAuthorizationRequirement(); return new OwnedAuthorizationRequirement();
} }
if (AffiliatedResource.class.equals(type)) {
return new AffiliatedAuthorizationRequirement(matchAll, permissions);
}
throw new IllegalArgumentException("resource"); throw new IllegalArgumentException("resource");
} }
}; };

View File

@ -34,6 +34,14 @@ cache:
expireAfterWriteMinutes: 10 expireAfterWriteMinutes: 10
expireAfterAccessMinutes: 10 expireAfterAccessMinutes: 10
refreshAfterWriteMinutes: 10 refreshAfterWriteMinutes: 10
- names: [ "affiliation" ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
enableRecordStats: false
expireAfterWriteMinutes: 1
expireAfterAccessMinutes: 1
refreshAfterWriteMinutes: 1
- names: [ "dashboardStatisticsByUserId" ] - names: [ "dashboardStatisticsByUserId" ]
allowNullValues: true allowNullValues: true
initialCapacity: 100 initialCapacity: 100
@ -80,3 +88,6 @@ cache:
token-exchange-key: token-exchange-key:
name: tokenExchangeKey name: tokenExchangeKey
keyPattern: resolve_$keyhash$:v0 keyPattern: resolve_$keyhash$:v0
affiliation:
name: affiliation
keyPattern: affiliation_$entity$_$user$_$type$:v0

View File

@ -206,9 +206,6 @@ permissions:
BrowseDmpAssociatedUser: BrowseDmpAssociatedUser:
roles: roles:
- Admin - Admin
- DescriptionTemplateEditor
- Manager
- User
claims: [ ] claims: [ ]
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
@ -217,6 +214,9 @@ permissions:
BrowseDescriptionTemplateType: BrowseDescriptionTemplateType:
roles: roles:
- Admin - Admin
- User
- Manager
- DescriptionTemplateEditor
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
@ -321,6 +321,12 @@ permissions:
EditDmp: EditDmp:
roles: roles:
- Admin - Admin
dmp:
roles:
- Owner
- User
- DescriptionContributor
- Reviewer
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
@ -463,7 +469,6 @@ permissions:
BrowseReference: BrowseReference:
roles: roles:
- Admin - Admin
- User
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
@ -527,6 +532,9 @@ permissions:
BrowseSupportiveMaterial: BrowseSupportiveMaterial:
roles: roles:
- Admin - Admin
- User
- Manager
- DescriptionTemplateEditor
clients: [ ] clients: [ ]
allowAnonymous: yes allowAnonymous: yes
allowAuthenticated: yes allowAuthenticated: yes
@ -548,6 +556,9 @@ permissions:
BrowseReferenceType: BrowseReferenceType:
roles: roles:
- Admin - Admin
- User
- Manager
- DescriptionTemplateEditor
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
@ -691,25 +702,24 @@ permissions:
# Lock Permissions # Lock Permissions
BrowseLock: BrowseLock:
roles: roles:
- User
- Admin - Admin
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
EditLock: EditLock:
roles: roles:
- User - Admin
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
DeleteLock: DeleteLock:
roles: roles:
- User - Admin
claims: [ ] claims: [ ]
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
# Lock Permissions # Contact Permissions
SendContactSupport: SendContactSupport:
roles: [] roles: []
clients: [ ] clients: [ ]
@ -740,6 +750,9 @@ permissions:
BrowsePrefillingSource: BrowsePrefillingSource:
roles: roles:
- Admin - Admin
- DescriptionTemplateEditor
- Manager
- User
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false