This commit is contained in:
anhefti 2019-02-15 12:30:26 +01:00
parent 285290d93d
commit ad374677ee
5 changed files with 163 additions and 55 deletions

View file

@ -15,7 +15,10 @@ import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
/** Defines a Privilege by combining a PrivilegeType for base (overall) rights, /** Defines a Privilege by combining a PrivilegeType for base (overall) rights,
* institutional rights and ownershipRights. */ * institutional rights and ownership rights.
*
* A base-, institutional- and ownership- grant is checked in this exact order and the
* first match fund makes a grant or a denied if none of the three privilege levels has a match */
public final class Privilege { public final class Privilege {
/** The RoleTypeKey defining the UserRole and EntityType for this Privilege */ /** The RoleTypeKey defining the UserRole and EntityType for this Privilege */
@ -75,6 +78,22 @@ public final class Privilege {
return this.ownershipPrivilege.hasImplicit(privilegeType); return this.ownershipPrivilege.hasImplicit(privilegeType);
} }
/** Checks if this Privilege has a grant for a given context.
*
* The privilege grant check function always checks first the base privilege with no institutional or owner grant.
* If user has a grant on base privileges this returns true without checking further institutional or owner grant
* If user has no base privilege grant the function checks further grants, first the institutional grant, where
* the institution id and the users institution id must match and further more the owner grant, where ownerId
* and the users id must match.
*
* @param userId The user identifier of the user to check the grant on
* @param userInstitutionId the users institution identifier. The institution where the user belong to
* @param privilegeType the type of privilege to check (READ_ONLY, MODIFY, WRITE...)
* @param institutionId the institution identifier of an Entity for the institutional grant check,
* may be null in case the institutional grant check should be skipped
* @param ownerId the owner identifier of an Entity for ownership grant check, may be null in case
* the ownership grant check should be skipped
* @return true if there is any grant within the given context or false on deny */
public final boolean hasGrant( public final boolean hasGrant(
final String userId, final String userId,
final Long userInstitutionId, final Long userInstitutionId,

View file

@ -35,62 +35,144 @@ public interface AuthorizationService {
* @return all registered Privileges */ * @return all registered Privileges */
Collection<Privilege> getAllPrivileges(); Collection<Privilege> getAllPrivileges();
boolean hasPrivilege( /** Check grant on privilege type for specified EntityType and for the given user and institution.
*
* This makes a privilege grant check for every UserRole given. The first found successful grant
* will immediately return true
*
* The privilege grant check function always checks first the base privilege with no institutional or owner grant.
* If user has a grant on base privileges this returns true without checking further institutional or owner grant
* If user has no base privilege grant the function checks further grants, first the institutional grant, where
* the institution id and the users institution id must match and further more the owner grant, where ownerId
* and the users id must match.
*
* see Privilege.hasGrant for more information how the overall grant function works
*
* @param privilegeType The privilege type to check
* @param entityType The type of entity to check privilege on
* @param institutionId the institution id (may be null in case the institutional grant check should be skipped)
* @param ownerId the owner identifier (may be null in case the owner grant check should be skipped)
* @param userId the user identifier (UUID)
* @param userInstitutionId the user institution identifier
* @param userRoles the user roles
* @return true if there is any grant within the given context or false on deny */
boolean hasGrant(
PrivilegeType privilegeType, PrivilegeType privilegeType,
EntityType entityType, EntityType entityType,
Long institutionId, Long institutionId,
String ownerId,
String userId, String userId,
Long userInstitutionId, Long userInstitutionId,
Set<UserRole> userRoles); Set<UserRole> userRoles);
boolean hasPrivilege(PrivilegeType privilegeType, GrantEntity grantEntity); /** Check grant for a given privilege type and entity type for the current user.
*
default boolean hasPrivilege(final PrivilegeType privilegeType, final EntityType entityType) { * NOTE: This only checks the base privilege grant because there is no Entity specific information
*
* @param privilegeType the privilege type to check
* @param entityType the type of the entity to check the given privilege type on
* @return true if there is any grant within the given context or false on deny */
default boolean hasGrant(final PrivilegeType privilegeType, final EntityType entityType) {
final SEBServerUser currentUser = getUserService().getCurrentUser(); final SEBServerUser currentUser = getUserService().getCurrentUser();
final UserInfo userInfo = currentUser.getUserInfo(); final UserInfo userInfo = currentUser.getUserInfo();
return hasPrivilege( return hasGrant(
privilegeType, privilegeType,
entityType, entityType,
null, null, null,
userInfo.uuid, userInfo.uuid,
userInfo.institutionId, userInfo.institutionId,
currentUser.getUserRoles()); currentUser.getUserRoles());
} }
default boolean hasPrivilege( /** Check grant for a given privilege type and Entity for the current user.
*
* @param privilegeType the privilege type to check
* @param grantEntity the Entity to check the privilege grant on
* @return true if there is any grant within the given context or false on deny */
default boolean hasGrant(final PrivilegeType privilegeType, final GrantEntity grantEntity) {
final SEBServerUser currentUser = getUserService().getCurrentUser();
final UserInfo userInfo = currentUser.getUserInfo();
return hasGrant(
privilegeType,
grantEntity.entityType(),
grantEntity.getInstitutionId(),
grantEntity.getOwnerId(),
userInfo.uuid,
userInfo.institutionId,
currentUser.getUserRoles());
}
/** Check base privilege grant and institutional privilege grant for a given privilege type
* on a given entity type.
*
* If the question is similar like this:
* "Has the current user that belongs to institution A the right to create an entity of
* type X on institution B", then this is the answer, use:
*
* hasPrivilege(PrivilegeType.WRITE, EntityType.X, B)
*
* @param privilegeType the privilege type to check
* @param entityType the type of the entity to check the given privilege type on
* @param institutionId the institution identifier for institutional privilege grant check
* @return true if there is any grant within the given context or false on deny */
default boolean hasGrant(
final PrivilegeType privilegeType, final PrivilegeType privilegeType,
final EntityType entityType, final EntityType entityType,
final Long institutionId) { final Long institutionId) {
final SEBServerUser currentUser = getUserService().getCurrentUser(); final SEBServerUser currentUser = getUserService().getCurrentUser();
final UserInfo userInfo = currentUser.getUserInfo(); final UserInfo userInfo = currentUser.getUserInfo();
return hasPrivilege( return hasGrant(
privilegeType, privilegeType,
entityType, entityType,
institutionId, institutionId,
null,
userInfo.uuid, userInfo.uuid,
userInfo.institutionId, userInfo.institutionId,
currentUser.getUserRoles()); currentUser.getUserRoles());
} }
default boolean hasReadonlyPrivilege(final GrantEntity grantEntity) { /** Check read-only grant for a given Entity instance and current user.
return hasPrivilege(PrivilegeType.READ_ONLY, grantEntity); *
* @param grantEntity Entity instance
* @return true if the current user has read-only grant on given Entity instance or false on deny */
default boolean hasReadonlyGrant(final GrantEntity grantEntity) {
return hasGrant(PrivilegeType.READ_ONLY, grantEntity);
} }
default boolean hasModifyPrivilege(final GrantEntity grantEntity) { /** Check modify grant for a given Entity instance and current user.
return hasPrivilege(PrivilegeType.MODIFY, grantEntity); *
* @param grantEntity Entity instance
* @return true if the current user has modify grant on given Entity instance or false on deny */
default boolean hasModifyGrant(final GrantEntity grantEntity) {
return hasGrant(PrivilegeType.MODIFY, grantEntity);
} }
default boolean hasWritePrivilege(final GrantEntity grantEntity) { /** Check write grant for a given Entity instance and current user.
return hasPrivilege(PrivilegeType.WRITE, grantEntity); *
* @param grantEntity Entity instance
* @return true if the current user has write grant on given Entity instance or false on deny */
default boolean hasWriteGrant(final GrantEntity grantEntity) {
return hasGrant(PrivilegeType.WRITE, grantEntity);
} }
/** Check grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
* on deny.
*
* @param privilegeType the privilege type to check
* @param entityType the type of the entity to check the given privilege type on */
default void check(final PrivilegeType privilegeType, final EntityType entityType) { default void check(final PrivilegeType privilegeType, final EntityType entityType) {
check(privilegeType, entityType, null); check(privilegeType, entityType, null);
} }
/** Check grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
* on deny.
*
* @param privilegeType the privilege type to check
* @param entityType the type of the entity to check the given privilege type on
* @param institutionId the institution identifier for institutional privilege grant check */
default void check(final PrivilegeType privilegeType, final EntityType entityType, final Long institutionId) { default void check(final PrivilegeType privilegeType, final EntityType entityType, final Long institutionId) {
if (!hasPrivilege(privilegeType, entityType, institutionId)) { if (!hasGrant(privilegeType, entityType, institutionId)) {
throw new PermissionDeniedException( throw new PermissionDeniedException(
entityType, entityType,
privilegeType, privilegeType,
@ -98,8 +180,15 @@ public interface AuthorizationService {
} }
} }
/** Check grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
* on deny or return the given grantEntity within a Result on successful grant.
* This is useful to use with a Result based functional chain.
*
* @param privilegeType the privilege type to check
* @param entityType the type of the entity to check the given privilege type on
* @param institutionId the institution identifier for institutional privilege grant check */
default <E extends GrantEntity> Result<E> check(final PrivilegeType privilegeType, final E grantEntity) { default <E extends GrantEntity> Result<E> check(final PrivilegeType privilegeType, final E grantEntity) {
if (!hasPrivilege(privilegeType, grantEntity)) { if (!hasGrant(privilegeType, grantEntity)) {
throw new PermissionDeniedException( throw new PermissionDeniedException(
grantEntity, grantEntity,
privilegeType, privilegeType,
@ -109,14 +198,32 @@ public interface AuthorizationService {
return Result.of(grantEntity); return Result.of(grantEntity);
} }
/** Check read-only grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
* on deny or returns the given grantEntity within a Result on successful grant.
* This is useful to use with a Result based functional chain.
*
* @param entityType the type of the entity to check the given privilege type on
* @param institutionId the institution identifier for institutional privilege grant check */
default <E extends GrantEntity> Result<E> checkReadonly(final E grantEntity) { default <E extends GrantEntity> Result<E> checkReadonly(final E grantEntity) {
return check(PrivilegeType.READ_ONLY, grantEntity); return check(PrivilegeType.READ_ONLY, grantEntity);
} }
/** Check modify grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
* on deny or returns the given grantEntity within a Result on successful grant.
* This is useful to use with a Result based functional chain.
*
* @param entityType the type of the entity to check the given privilege type on
* @param institutionId the institution identifier for institutional privilege grant check */
default <E extends GrantEntity> Result<E> checkModify(final E grantEntity) { default <E extends GrantEntity> Result<E> checkModify(final E grantEntity) {
return check(PrivilegeType.MODIFY, grantEntity); return check(PrivilegeType.MODIFY, grantEntity);
} }
/** Check write grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
* on deny or returns the given grantEntity within a Result on successful grant.
* This is useful to use with a Result based functional chain.
*
* @param entityType the type of the entity to check the given privilege type on
* @param institutionId the institution identifier for institutional privilege grant check */
default <E extends GrantEntity> Result<E> checkWrite(final E grantEntity) { default <E extends GrantEntity> Result<E> checkWrite(final E grantEntity) {
return check(PrivilegeType.WRITE, grantEntity); return check(PrivilegeType.WRITE, grantEntity);
} }

View file

@ -23,7 +23,6 @@ import ch.ethz.seb.sebserver.gbl.authorization.Privilege;
import ch.ethz.seb.sebserver.gbl.authorization.Privilege.RoleTypeKey; import ch.ethz.seb.sebserver.gbl.authorization.Privilege.RoleTypeKey;
import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType; import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.EntityType; import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@ -115,10 +114,11 @@ public class AuthorizationServiceImpl implements AuthorizationService {
} }
@Override @Override
public boolean hasPrivilege( public boolean hasGrant(
final PrivilegeType privilegeType, final PrivilegeType privilegeType,
final EntityType entityType, final EntityType entityType,
final Long institutionId, final Long institutionId,
final String ownerId,
final String userId, final String userId,
final Long userInstitutionId, final Long userInstitutionId,
final Set<UserRole> userRoles) { final Set<UserRole> userRoles) {
@ -132,25 +132,7 @@ public class AuthorizationServiceImpl implements AuthorizationService {
userInstitutionId, userInstitutionId,
privilegeType, privilegeType,
institutionId, institutionId,
null)) ownerId))
.findFirst()
.isPresent();
}
@Override
public boolean hasPrivilege(final PrivilegeType privilegeType, final GrantEntity grantEntity) {
final UserInfo userInfo = this.userService.getCurrentUser().getUserInfo();
return userInfo.getRoles()
.stream()
.map(roleName -> UserRole.valueOf(roleName))
.map(role -> new RoleTypeKey(grantEntity.entityType(), role))
.map(key -> this.privileges.get(key))
.filter(priv -> (priv != null) && priv.hasGrant(
userInfo.uuid,
userInfo.institutionId,
privilegeType,
grantEntity.getInstitutionId(),
grantEntity.getOwnerId()))
.findFirst() .findFirst()
.isPresent(); .isPresent();
} }

View file

@ -178,7 +178,7 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt
.flatMap(this.entityDAO::loadEntities) .flatMap(this.entityDAO::loadEntities)
.getOrThrow() .getOrThrow()
.stream() .stream()
.filter(this.authorization::hasReadonlyPrivilege) .filter(this.authorization::hasReadonlyGrant)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -296,7 +296,7 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt
protected Result<Collection<T>> getAll(final FilterMap filterMap) { protected Result<Collection<T>> getAll(final FilterMap filterMap) {
return this.entityDAO.allMatching( return this.entityDAO.allMatching(
filterMap, filterMap,
this.authorization::hasReadonlyPrivilege); this.authorization::hasReadonlyGrant);
} }
protected Result<T> notifySaved(final M modifyData, final T entity) { protected Result<T> notifySaved(final M modifyData, final T entity) {

View file

@ -32,36 +32,36 @@ public class AuthorizationServiceTest {
public void testInstitutionGrantForSEB_SERVER_ADMIN() { public void testInstitutionGrantForSEB_SERVER_ADMIN() {
final AuthorizationServiceImpl service = getTestServiceWithUserWithRoles(UserRole.SEB_SERVER_ADMIN); final AuthorizationServiceImpl service = getTestServiceWithUserWithRoles(UserRole.SEB_SERVER_ADMIN);
assertTrue(service.hasPrivilege(PrivilegeType.READ_ONLY, EntityType.INSTITUTION)); assertTrue(service.hasGrant(PrivilegeType.READ_ONLY, EntityType.INSTITUTION));
assertTrue(service.hasPrivilege(PrivilegeType.MODIFY, EntityType.INSTITUTION)); assertTrue(service.hasGrant(PrivilegeType.MODIFY, EntityType.INSTITUTION));
assertTrue(service.hasPrivilege(PrivilegeType.WRITE, EntityType.INSTITUTION)); assertTrue(service.hasGrant(PrivilegeType.WRITE, EntityType.INSTITUTION));
final GrantEntity institution = entityOf(EntityType.INSTITUTION, 2L, ""); final GrantEntity institution = entityOf(EntityType.INSTITUTION, 2L, "");
assertTrue(service.hasReadonlyPrivilege(institution)); assertTrue(service.hasReadonlyGrant(institution));
assertTrue(service.hasModifyPrivilege(institution)); assertTrue(service.hasModifyGrant(institution));
assertTrue(service.hasWritePrivilege(institution)); assertTrue(service.hasWriteGrant(institution));
} }
@Test @Test
public void testInstitutionGrantsForINSTITUTIONAL_ADMIN() { public void testInstitutionGrantsForINSTITUTIONAL_ADMIN() {
final AuthorizationServiceImpl service = getTestServiceWithUserWithRoles(UserRole.INSTITUTIONAL_ADMIN); final AuthorizationServiceImpl service = getTestServiceWithUserWithRoles(UserRole.INSTITUTIONAL_ADMIN);
assertFalse(service.hasPrivilege(PrivilegeType.READ_ONLY, EntityType.INSTITUTION)); assertFalse(service.hasGrant(PrivilegeType.READ_ONLY, EntityType.INSTITUTION));
assertFalse(service.hasPrivilege(PrivilegeType.MODIFY, EntityType.INSTITUTION)); assertFalse(service.hasGrant(PrivilegeType.MODIFY, EntityType.INSTITUTION));
assertFalse(service.hasPrivilege(PrivilegeType.WRITE, EntityType.INSTITUTION)); assertFalse(service.hasGrant(PrivilegeType.WRITE, EntityType.INSTITUTION));
final GrantEntity ownInstitution = entityOf(EntityType.INSTITUTION, 1L, ""); final GrantEntity ownInstitution = entityOf(EntityType.INSTITUTION, 1L, "");
assertTrue(service.hasReadonlyPrivilege(ownInstitution)); assertTrue(service.hasReadonlyGrant(ownInstitution));
assertTrue(service.hasModifyPrivilege(ownInstitution)); assertTrue(service.hasModifyGrant(ownInstitution));
assertFalse(service.hasWritePrivilege(ownInstitution)); assertFalse(service.hasWriteGrant(ownInstitution));
final GrantEntity otherInstitution = entityOf(EntityType.INSTITUTION, 2L, ""); final GrantEntity otherInstitution = entityOf(EntityType.INSTITUTION, 2L, "");
assertFalse(service.hasReadonlyPrivilege(otherInstitution)); assertFalse(service.hasReadonlyGrant(otherInstitution));
assertFalse(service.hasModifyPrivilege(otherInstitution)); assertFalse(service.hasModifyGrant(otherInstitution));
assertFalse(service.hasWritePrivilege(otherInstitution)); assertFalse(service.hasWriteGrant(otherInstitution));
} }
private SEBServerUser getUser(final UserRole... roles) { private SEBServerUser getUser(final UserRole... roles) {