Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BXC-4216 - Patron Role/Permission for accessing reduced quality images #1653

Merged
merged 13 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ plugins:
file: "common-utils/src/main/resources/checkstyle/checkstyle.xml"
sonar-java:
enabled: true
checks:
# Disable enforcement of rule that enum values must be all caps, since we have many that don't adhere
java:S115:
enabled: false
pmd:
enabled: true
# duplication plugin affects similar-code and identical-code
Expand Down
15 changes: 2 additions & 13 deletions auth-api/src/main/java/edu/unc/lib/boxc/auth/api/Permission.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
public enum Permission {
viewMetadata,
viewAccessCopies,
viewReducedResImages,
viewOriginal,
// TODO replaces viewAdminUI and viewEmbargoed
// Staff Permissions
viewHidden,
editDescription,
bulkUpdateDescription,
Expand All @@ -28,16 +29,4 @@ public enum Permission {
editResourceType,
runEnhancements,
reindex;

private Permission() {
}

public static Permission getPermission(String permissionName) {
for (Permission permission: Permission.values()) {
if (permission.name().equals(permissionName)) {
return permission;
}
}
return null;
}
}
99 changes: 25 additions & 74 deletions auth-api/src/main/java/edu/unc/lib/boxc/auth/api/UserRole.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,26 @@
import static edu.unc.lib.boxc.auth.api.Permission.assignStaffRoles;
import static edu.unc.lib.boxc.auth.api.Permission.bulkUpdateDescription;
import static edu.unc.lib.boxc.auth.api.Permission.changePatronAccess;
import static edu.unc.lib.boxc.auth.api.Permission.createAdminUnit;
import static edu.unc.lib.boxc.auth.api.Permission.createCollection;
import static edu.unc.lib.boxc.auth.api.Permission.destroy;
import static edu.unc.lib.boxc.auth.api.Permission.destroyUnit;
import static edu.unc.lib.boxc.auth.api.Permission.editDescription;
import static edu.unc.lib.boxc.auth.api.Permission.editResourceType;
import static edu.unc.lib.boxc.auth.api.Permission.ingest;
import static edu.unc.lib.boxc.auth.api.Permission.markForDeletion;
import static edu.unc.lib.boxc.auth.api.Permission.markForDeletionUnit;
import static edu.unc.lib.boxc.auth.api.Permission.move;
import static edu.unc.lib.boxc.auth.api.Permission.orderMembers;
import static edu.unc.lib.boxc.auth.api.Permission.reindex;
import static edu.unc.lib.boxc.auth.api.Permission.runEnhancements;
import static edu.unc.lib.boxc.auth.api.Permission.viewAccessCopies;
import static edu.unc.lib.boxc.auth.api.Permission.viewHidden;
import static edu.unc.lib.boxc.auth.api.Permission.viewMetadata;
import static edu.unc.lib.boxc.auth.api.Permission.viewOriginal;
import static edu.unc.lib.boxc.auth.api.Permission.viewReducedResImages;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toSet;
import static org.apache.jena.rdf.model.ResourceFactory.createProperty;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.List;
Expand All @@ -48,40 +42,35 @@
*
*/
public enum UserRole {
list("list", new Permission[] {}),
// Patron roles
none("none", false),
canDiscover("canDiscover", false),
canViewMetadata("canViewMetadata", false, viewMetadata),
canViewAccessCopies("canViewAccessCopies", false, viewMetadata, viewAccessCopies),
canViewOriginals("canViewOriginals", false, viewMetadata, viewAccessCopies, viewOriginal),
none("none", false, null),
canDiscover("canDiscover", false, null),
canViewMetadata("canViewMetadata", false, canDiscover, viewMetadata),
canViewAccessCopies("canViewAccessCopies", false, canViewMetadata, viewAccessCopies),
canViewReducedQuality("canViewReducedQuality", false, canViewAccessCopies,
viewReducedResImages),
canViewOriginals("canViewOriginals", false, canViewReducedQuality, viewOriginal),
// Staff roles
canAccess("canAccess", true, viewHidden, viewMetadata, viewAccessCopies, viewOriginal),
canIngest("canIngest", true, viewHidden, viewMetadata, viewAccessCopies, viewOriginal,
ingest),
canDescribe("canDescribe", true, viewHidden, viewMetadata, viewAccessCopies, viewOriginal,
editDescription, bulkUpdateDescription),
canProcess("canProcess", true, viewHidden, viewMetadata, viewAccessCopies, viewOriginal,
editDescription, bulkUpdateDescription, move, orderMembers, markForDeletion, changePatronAccess),
canManage("canManage", true, viewHidden, viewMetadata, viewAccessCopies, viewOriginal,
ingest, editDescription, bulkUpdateDescription, move, orderMembers, markForDeletion,
changePatronAccess, editResourceType, createCollection),
unitOwner("unitOwner", true, viewHidden, viewMetadata, viewAccessCopies, viewOriginal,
ingest, editDescription, bulkUpdateDescription, move, orderMembers, markForDeletion, markForDeletionUnit,
changePatronAccess, editResourceType, destroy, createCollection, assignStaffRoles),
administrator("administrator", true, viewHidden, viewMetadata, viewAccessCopies, viewOriginal,
ingest, editDescription, bulkUpdateDescription, move, orderMembers, markForDeletion, markForDeletionUnit,
changePatronAccess, editResourceType, destroy, destroyUnit, createCollection,
createAdminUnit, assignStaffRoles, runEnhancements, reindex);
canAccess("canAccess", true, canViewOriginals, viewHidden),
canIngest("canIngest", true, canAccess, ingest),
canDescribe("canDescribe", true, canAccess, editDescription, bulkUpdateDescription),
canProcess("canProcess", true, canDescribe,
move, orderMembers, markForDeletion, changePatronAccess),
canManage("canManage", true, canProcess,
ingest, editResourceType, createCollection),
unitOwner("unitOwner", true, canManage,
markForDeletionUnit, destroy, assignStaffRoles),
// Admin role receives all permissions
administrator("administrator", true, null, Permission.values());

public static final List<String> PATRON_ROLE_PRECEDENCE = asList(
UserRole.none.getPropertyString(),
UserRole.canViewMetadata.getPropertyString(),
UserRole.canViewAccessCopies.getPropertyString(),
UserRole.canViewReducedQuality.getPropertyString(),
UserRole.canViewOriginals.getPropertyString()
);

private URI uri;
private String predicate;
private String propertyString;
private Property property;
Expand All @@ -94,56 +83,22 @@ public enum UserRole {

private static Map<Permission, Set<UserRole>> permissionToRoles;

UserRole(String predicate, boolean isStaffRole, Permission... perms) {
UserRole(String predicate, boolean isStaffRole, UserRole inheritPermsFrom, Permission... perms) {
this.predicate = predicate;
this.propertyString = CdrAcl.getURI() + predicate;
this.property = createProperty(propertyString);
this.uri = URI.create(propertyString);
this.isStaffRole = isStaffRole;
this.permissions = new HashSet<>(Arrays.asList(perms));
this.permissionNames = permissions.stream().map(p -> p.name()).collect(toSet());
}

@Deprecated
UserRole(String predicate, Permission[] perms) {
try {
this.predicate = predicate;
this.uri = new URI(CdrAcl.getURI() + predicate);
this.propertyString = "";
HashSet<Permission> mypermissions = new HashSet<>(perms.length);
Collections.addAll(mypermissions, perms);
this.permissions = Collections.unmodifiableSet(mypermissions);
} catch (URISyntaxException e) {
Error x = new ExceptionInInitializerError("Cannot initialize ContentModelHelper");
x.initCause(e);
throw x;
if (inheritPermsFrom != null) {
this.permissions.addAll(inheritPermsFrom.getPermissions());
}
}

@Deprecated
public static boolean matchesMemberURI(String test) {
for (UserRole r : UserRole.values()) {
if (r.getURI().toString().equals(test)) {
return true;
}
}
return false;
}

@Deprecated
public static UserRole getUserRole(String roleUri) {
for (UserRole r : UserRole.values()) {
if (r.propertyString.equals(roleUri)) {
return r;
}
}
return null;
this.permissionNames = permissions.stream().map(p -> p.name()).collect(toSet());
}

/**
* Return a list of all user roles which have the specified permission
*
* @param permission
* @param inPermissions
* @return
*/
public static Set<UserRole> getUserRoles(Collection<Permission> inPermissions) {
Expand Down Expand Up @@ -233,10 +188,6 @@ public Property getProperty() {
return property;
}

public URI getURI() {
return this.uri;
}

public Set<Permission> getPermissions() {
return permissions;
}
Expand Down
141 changes: 141 additions & 0 deletions auth-api/src/test/java/edu/unc/lib/boxc/auth/api/UserRoleTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package edu.unc.lib.boxc.auth.api;

import edu.unc.lib.boxc.model.api.rdf.CdrAcl;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* @author bbpennel
*/
public class UserRoleTest {
@Test
public void canViewReducedQualityPermissionsTest() {
var subject = UserRole.canViewReducedQuality;
var expectedPermissions = Set.of(
Permission.viewMetadata, Permission.viewAccessCopies, Permission.viewReducedResImages);
assertSetMatchesExactly(expectedPermissions, subject.getPermissions());
}

@Test
public void canViewReducedQualityPermissionNamesTest() {
var subject = UserRole.canViewReducedQuality;
var expectedNames = Set.of(Permission.viewMetadata.name(), Permission.viewAccessCopies.name(),
Permission.viewReducedResImages.name());
assertSetMatchesExactly(expectedNames, subject.getPermissionNames());
}

@Test
public void administratorPermissionsTest() {
var subject = UserRole.administrator;
var expectedPermissions = Set.of(Permission.values());
assertSetMatchesExactly(expectedPermissions, subject.getPermissions());
}

@Test
public void getUserRolesWithNoPermissionsTest() {
// Listing no permissions returns all user roles
assertSetMatchesExactly(Set.of(UserRole.values()), UserRole.getUserRoles(Collections.emptyList()));
}

@Test
public void getUserRolesMatchesMultipleRolesTest() {
var expected = Set.of(UserRole.canIngest, UserRole.canManage,
UserRole.unitOwner, UserRole.administrator);
var result = UserRole.getUserRoles(Arrays.asList(Permission.viewAccessCopies, Permission.ingest));
assertSetMatchesExactly(expected, result);
}

@Test
public void getUserRolesWithPermissionOrderMembersTest() {
var expected = Set.of(UserRole.canProcess, UserRole.canManage,
UserRole.unitOwner, UserRole.administrator);
var result = UserRole.getUserRolesWithPermission(Permission.orderMembers);
assertSetMatchesExactly(expected, result);
}

@Test
public void getStaffRolesTest() {
var expected = Arrays.asList(UserRole.canAccess, UserRole.canIngest, UserRole.canDescribe,
UserRole.canProcess, UserRole.canManage, UserRole.unitOwner, UserRole.administrator);
assertIterableEquals(expected, UserRole.getStaffRoles());
}

@Test
public void getPatronRolesTest() {
var expected = Arrays.asList(UserRole.none, UserRole.canDiscover, UserRole.canViewMetadata,
UserRole.canViewAccessCopies, UserRole.canViewReducedQuality, UserRole.canViewOriginals);
assertIterableEquals(expected, UserRole.getPatronRoles());
}

@Test
public void getRoleByPropertyValidTest() {
assertEquals(UserRole.canAccess, UserRole.getRoleByProperty(CdrAcl.canAccess.getURI()));
}

@Test
public void getRoleByPropertyNotFoundTest() {
assertNull(UserRole.getRoleByProperty("http://example.com/ohno"));
}

@Test
public void getPredicateTest() {
assertEquals("canManage", UserRole.canManage.getPredicate());
}

@Test
public void getPropertyTest() {
assertEquals(CdrAcl.canManage, UserRole.canManage.getProperty());
}

@Test
public void getURITest() {
assertEquals(CdrAcl.canManage, UserRole.canManage.getProperty());
}

@Test
public void isStaffRoleTrueTest() {
assertTrue(UserRole.canManage.isStaffRole());
}

@Test
public void isStaffRoleFalseTest() {
assertFalse(UserRole.canViewReducedQuality.isStaffRole());
}

@Test
public void isPatronRoleFalseTest() {
assertFalse(UserRole.canManage.isPatronRole());
}

@Test
public void isPatronRoleTrueTest() {
assertTrue(UserRole.canViewReducedQuality.isPatronRole());
}

@Test
public void equalsTrueTest() {
assertTrue(UserRole.none.equals(CdrAcl.none.getURI()));
}

@Test
public void equalsFalseTest() {
assertFalse(UserRole.none.equals("hello"));
}

// Compare that two sets are exactly equal, order insensitive.
// junits assertIterableEquals is not reliable with sets since it depends on order, and we aren't importing hamcrest
private <T> void assertSetMatchesExactly(Set<T> expected, Set<T> actual) {
var message = "Actual set values did not match expected:\nActual: " + actual + "\nExpected: " + expected;
assertTrue(actual.containsAll(expected), message);
assertEquals(expected.size(), actual.size(), message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static edu.unc.lib.boxc.model.api.rdf.CdrAcl.canViewAccessCopies;
import static edu.unc.lib.boxc.model.api.rdf.CdrAcl.canViewMetadata;
import static edu.unc.lib.boxc.model.api.rdf.CdrAcl.canViewOriginals;
import static edu.unc.lib.boxc.model.api.rdf.CdrAcl.canViewReducedQuality;
import static edu.unc.lib.boxc.model.api.rdf.CdrAcl.embargoUntil;
import static edu.unc.lib.boxc.model.api.rdf.CdrAcl.markedForDeletion;
import static edu.unc.lib.boxc.model.api.rdf.CdrAcl.none;
Expand Down Expand Up @@ -44,6 +45,7 @@ public class ContentObjectAccessRestrictionValidator {
private static final Set<Property> collectionProperties = new HashSet<>(Arrays.asList(
canViewMetadata,
canViewAccessCopies,
canViewReducedQuality,
canViewOriginals,
canAccess,
canDescribe,
Expand All @@ -66,6 +68,7 @@ public class ContentObjectAccessRestrictionValidator {
private static final Set<Property> contentProperties = new HashSet<>(Arrays.asList(
canViewMetadata,
canViewAccessCopies,
canViewReducedQuality,
canViewOriginals,
none,
embargoUntil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ private List<PID> getObjectPath(PID pid) {
private boolean isPatronPermission(Permission permission) {
return permission.equals(Permission.viewMetadata)
|| permission.equals(Permission.viewAccessCopies)
|| permission.equals(Permission.viewReducedResImages)
|| permission.equals(Permission.viewOriginal);
}

Expand Down
Loading
Loading