mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-16 14:33:09 +00:00
84100: Admin only files rights issue IT
This commit is contained in:
@@ -1072,7 +1072,7 @@ prevent the generation of resource policy entry values with null dspace_object a
|
|||||||
private boolean isNotAlreadyACustomRPOfThisTypeOnDSO(Context context, DSpaceObject dso) throws SQLException {
|
private boolean isNotAlreadyACustomRPOfThisTypeOnDSO(Context context, DSpaceObject dso) throws SQLException {
|
||||||
List<ResourcePolicy> readRPs = resourcePolicyService.find(context, dso, Constants.READ);
|
List<ResourcePolicy> readRPs = resourcePolicyService.find(context, dso, Constants.READ);
|
||||||
for (ResourcePolicy readRP : readRPs) {
|
for (ResourcePolicy readRP : readRPs) {
|
||||||
if (readRP.getRpType().equals(ResourcePolicy.TYPE_CUSTOM)) {
|
if (readRP.getRpType() != null && readRP.getRpType().equals(ResourcePolicy.TYPE_CUSTOM)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,12 +43,16 @@ import org.apache.commons.lang3.time.DateUtils;
|
|||||||
import org.dspace.app.rest.matcher.CollectionMatcher;
|
import org.dspace.app.rest.matcher.CollectionMatcher;
|
||||||
import org.dspace.app.rest.matcher.ItemMatcher;
|
import org.dspace.app.rest.matcher.ItemMatcher;
|
||||||
import org.dspace.app.rest.matcher.MetadataMatcher;
|
import org.dspace.app.rest.matcher.MetadataMatcher;
|
||||||
|
import org.dspace.app.rest.matcher.ResourcePolicyMatcher;
|
||||||
import org.dspace.app.rest.matcher.WorkspaceItemMatcher;
|
import org.dspace.app.rest.matcher.WorkspaceItemMatcher;
|
||||||
import org.dspace.app.rest.model.patch.AddOperation;
|
import org.dspace.app.rest.model.patch.AddOperation;
|
||||||
import org.dspace.app.rest.model.patch.Operation;
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
import org.dspace.app.rest.model.patch.RemoveOperation;
|
import org.dspace.app.rest.model.patch.RemoveOperation;
|
||||||
import org.dspace.app.rest.model.patch.ReplaceOperation;
|
import org.dspace.app.rest.model.patch.ReplaceOperation;
|
||||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||||
|
import org.dspace.authorize.ResourcePolicy;
|
||||||
|
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||||
|
import org.dspace.authorize.service.ResourcePolicyService;
|
||||||
import org.dspace.builder.BitstreamBuilder;
|
import org.dspace.builder.BitstreamBuilder;
|
||||||
import org.dspace.builder.CollectionBuilder;
|
import org.dspace.builder.CollectionBuilder;
|
||||||
import org.dspace.builder.CommunityBuilder;
|
import org.dspace.builder.CommunityBuilder;
|
||||||
@@ -67,9 +71,11 @@ import org.dspace.content.Item;
|
|||||||
import org.dspace.content.Relationship;
|
import org.dspace.content.Relationship;
|
||||||
import org.dspace.content.RelationshipType;
|
import org.dspace.content.RelationshipType;
|
||||||
import org.dspace.content.WorkspaceItem;
|
import org.dspace.content.WorkspaceItem;
|
||||||
|
import org.dspace.core.Constants;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||||
|
import org.dspace.eperson.service.GroupService;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -88,6 +94,10 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationService configurationService;
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
|
private GroupService groupService;
|
||||||
|
|
||||||
|
private ResourcePolicyService resourcePolicyService;
|
||||||
|
|
||||||
private Group embargoedGroups;
|
private Group embargoedGroups;
|
||||||
private Group embargoedGroup1;
|
private Group embargoedGroup1;
|
||||||
private Group embargoedGroup2;
|
private Group embargoedGroup2;
|
||||||
@@ -98,6 +108,8 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
this.groupService = EPersonServiceFactory.getInstance().getGroupService();
|
||||||
|
this.resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService();
|
||||||
|
|
||||||
embargoedGroups = GroupBuilder.createGroup(context)
|
embargoedGroups = GroupBuilder.createGroup(context)
|
||||||
.withName("Embargoed Groups")
|
.withName("Embargoed Groups")
|
||||||
@@ -5299,4 +5311,232 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void patchUploadAddAdminRPInstallAndVerifyOnlyAdminCanView() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
Community community = CommunityBuilder.createCommunity(context).withName("Com").build();
|
||||||
|
Collection collection = CollectionBuilder.createCollection(context, community).withName("Col").build();
|
||||||
|
InputStream pdf = getClass().getResourceAsStream("simple-article.pdf");
|
||||||
|
WorkspaceItem wItem = WorkspaceItemBuilder.createWorkspaceItem(context, collection)
|
||||||
|
.withSubmitter(eperson)
|
||||||
|
.withTitle(
|
||||||
|
"Test Item patchUploadAddAdminRPInstallAndVerifyOnlyAdminCanView")
|
||||||
|
.withIssueDate("2019-03-06")
|
||||||
|
.withFulltext("upload2.pdf", "/local/path/simple-article.pdf", pdf)
|
||||||
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// auth
|
||||||
|
String epersonToken = getAuthToken(eperson.getEmail(), password);
|
||||||
|
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
// prepare patch body
|
||||||
|
Map<String, String> accessCondition = new HashMap<>();
|
||||||
|
accessCondition.put("name", "administrator");
|
||||||
|
List<Operation> ops = new ArrayList<>();
|
||||||
|
ops.add(new AddOperation("/sections/upload/files/0/accessConditions/-", accessCondition));
|
||||||
|
String patchBody = getPatchContent(ops);
|
||||||
|
|
||||||
|
// submit patch and verify response
|
||||||
|
getClient(epersonToken)
|
||||||
|
.perform(
|
||||||
|
patch("/api/submission/workspaceitems/" + wItem.getID())
|
||||||
|
.content(patchBody)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON)
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
Bitstream bitstream = wItem.getItem().getBundles().get(0).getBitstreams().get(0);
|
||||||
|
Group adminGroup = groupService.findByName(context, Group.ADMIN);
|
||||||
|
|
||||||
|
// verify that bitstream of workspace item has this admin RP
|
||||||
|
getClient(adminToken).perform(get("/api/authz/resourcepolicies/search/resource")
|
||||||
|
.param("uuid", bitstream.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.resourcepolicies", Matchers.hasItems(
|
||||||
|
ResourcePolicyMatcher.matchResourcePolicyProperties(adminGroup, null, bitstream,
|
||||||
|
ResourcePolicy.TYPE_CUSTOM, Constants.READ, "administrator")
|
||||||
|
)));
|
||||||
|
|
||||||
|
// submit the workspaceitem to complete the deposit (as there is no workflow configured)
|
||||||
|
getClient(epersonToken)
|
||||||
|
.perform(post(BASE_REST_SERVER_URL + "/api/workflow/workflowitems")
|
||||||
|
.content("/api/submission/workspaceitems/" + wItem.getID())
|
||||||
|
.contentType(textUriContentType))
|
||||||
|
.andExpect(status().isCreated());
|
||||||
|
|
||||||
|
Group anonGroup = groupService.findByName(context, Group.ANONYMOUS);
|
||||||
|
|
||||||
|
// verify that bitstream of workspace item still has this admin RP and no Anon READ inherited policy
|
||||||
|
getClient(adminToken).perform(get("/api/authz/resourcepolicies/search/resource")
|
||||||
|
.param("uuid", bitstream.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.resourcepolicies", Matchers.hasItems(
|
||||||
|
ResourcePolicyMatcher.matchResourcePolicyProperties(adminGroup, null, bitstream,
|
||||||
|
ResourcePolicy.TYPE_CUSTOM, Constants.READ, "administrator")
|
||||||
|
)))
|
||||||
|
.andExpect(jsonPath("$._embedded.resourcepolicies", Matchers.not(Matchers.hasItems(
|
||||||
|
ResourcePolicyMatcher
|
||||||
|
.matchResourcePolicyProperties(anonGroup, null, bitstream, null, Constants.READ,
|
||||||
|
null)
|
||||||
|
))));
|
||||||
|
|
||||||
|
// Bitstream should NOT be accessible to anon or eperson user, only to admin
|
||||||
|
getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isUnauthorized());
|
||||||
|
getClient(epersonToken).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
getClient(adminToken).perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void patchUploadAddOpenAccessRPInstallAndVerifyAnonCanView() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
Community community = CommunityBuilder.createCommunity(context).withName("Com").build();
|
||||||
|
Collection collection = CollectionBuilder.createCollection(context, community).withName("Col").build();
|
||||||
|
InputStream pdf = getClass().getResourceAsStream("simple-article.pdf");
|
||||||
|
WorkspaceItem wItem =
|
||||||
|
WorkspaceItemBuilder.createWorkspaceItem(context, collection).withSubmitter(eperson)
|
||||||
|
.withTitle("Test Item patchUploadAddOpenAccessRPInstallAndVerifyOnlyAdminCanView")
|
||||||
|
.withIssueDate("2019-03-06")
|
||||||
|
.withFulltext("upload2.pdf", "/local/path/simple-article.pdf", pdf)
|
||||||
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// auth
|
||||||
|
String epersonToken = getAuthToken(eperson.getEmail(), password);
|
||||||
|
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
// prepare patch body
|
||||||
|
Map<String, String> accessCondition = new HashMap<>();
|
||||||
|
accessCondition.put("name", "openaccess");
|
||||||
|
List<Operation> ops = new ArrayList<>();
|
||||||
|
ops.add(new AddOperation("/sections/upload/files/0/accessConditions/-", accessCondition));
|
||||||
|
String patchBody = getPatchContent(ops);
|
||||||
|
|
||||||
|
// submit patch and verify response
|
||||||
|
getClient(epersonToken)
|
||||||
|
.perform(
|
||||||
|
patch("/api/submission/workspaceitems/" + wItem.getID())
|
||||||
|
.content(patchBody)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON)
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
Bitstream bitstream = wItem.getItem().getBundles().get(0).getBitstreams().get(0);
|
||||||
|
|
||||||
|
// verify that bitstream of workspace item has this open access RP
|
||||||
|
getClient(adminToken).perform(get("/api/authz/resourcepolicies/search/resource")
|
||||||
|
.param("uuid", bitstream.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.resourcepolicies", Matchers.hasItems(
|
||||||
|
ResourcePolicyMatcher.matchResourcePolicyProperties(anonymousGroup, null, bitstream,
|
||||||
|
ResourcePolicy.TYPE_CUSTOM, Constants.READ, "openaccess")
|
||||||
|
)));
|
||||||
|
|
||||||
|
// submit the workspaceitem to complete the deposit (as there is no workflow configured)
|
||||||
|
getClient(epersonToken)
|
||||||
|
.perform(post(BASE_REST_SERVER_URL + "/api/workflow/workflowitems")
|
||||||
|
.content("/api/submission/workspaceitems/" + wItem.getID())
|
||||||
|
.contentType(textUriContentType))
|
||||||
|
.andExpect(status().isCreated());
|
||||||
|
|
||||||
|
// verify that bitstream of workspace item still has this open access RP
|
||||||
|
getClient(adminToken).perform(get("/api/authz/resourcepolicies/search/resource")
|
||||||
|
.param("uuid", bitstream.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.resourcepolicies", Matchers.hasItems(
|
||||||
|
ResourcePolicyMatcher.matchResourcePolicyProperties(anonymousGroup, null, bitstream,
|
||||||
|
ResourcePolicy.TYPE_CUSTOM, Constants.READ, "openaccess")
|
||||||
|
)));
|
||||||
|
|
||||||
|
// Bitstream should be accessible to anon
|
||||||
|
getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void patchUploadAddAdminThenOpenAccessRPInstallAndVerifyAnonCanView() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
Community community = CommunityBuilder.createCommunity(context).withName("Com").build();
|
||||||
|
Collection collection = CollectionBuilder.createCollection(context, community).withName("Col").build();
|
||||||
|
InputStream pdf = getClass().getResourceAsStream("simple-article.pdf");
|
||||||
|
WorkspaceItem wItem =
|
||||||
|
WorkspaceItemBuilder.createWorkspaceItem(context, collection).withSubmitter(eperson)
|
||||||
|
.withTitle("Test Item patchUploadAddOpenAccessRPInstallAndVerifyOnlyAdminCanView")
|
||||||
|
.withIssueDate("2019-03-06")
|
||||||
|
.withFulltext("upload2.pdf", "/local/path/simple-article.pdf", pdf)
|
||||||
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
// auth
|
||||||
|
String epersonToken = getAuthToken(eperson.getEmail(), password);
|
||||||
|
String adminToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
// prepare patch body
|
||||||
|
Map<String, String> accessCondition = new HashMap<>();
|
||||||
|
accessCondition.put("name", "administrator");
|
||||||
|
List<Operation> ops = new ArrayList<>();
|
||||||
|
ops.add(new AddOperation("/sections/upload/files/0/accessConditions/-", accessCondition));
|
||||||
|
String patchBody = getPatchContent(ops);
|
||||||
|
|
||||||
|
// submit patch and verify response
|
||||||
|
getClient(epersonToken)
|
||||||
|
.perform(
|
||||||
|
patch("/api/submission/workspaceitems/" + wItem.getID())
|
||||||
|
.content(patchBody)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON)
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
Bitstream bitstream = wItem.getItem().getBundles().get(0).getBitstreams().get(0);
|
||||||
|
Group adminGroup = groupService.findByName(context, Group.ADMIN);
|
||||||
|
|
||||||
|
// verify that bitstream of workspace item has this admin RP
|
||||||
|
getClient(adminToken).perform(get("/api/authz/resourcepolicies/search/resource")
|
||||||
|
.param("uuid", bitstream.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.resourcepolicies", Matchers.hasItems(
|
||||||
|
ResourcePolicyMatcher.matchResourcePolicyProperties(adminGroup, null, bitstream,
|
||||||
|
ResourcePolicy.TYPE_CUSTOM, Constants.READ, "administrator")
|
||||||
|
)));
|
||||||
|
|
||||||
|
// prepare patch body
|
||||||
|
Map<String, String> accessCondition2 = new HashMap<>();
|
||||||
|
accessCondition2.put("name", "openaccess");
|
||||||
|
List<Operation> ops2 = new ArrayList<>();
|
||||||
|
ops2.add(new AddOperation("/sections/upload/files/0/accessConditions/-", accessCondition2));
|
||||||
|
String patchBody2 = getPatchContent(ops2);
|
||||||
|
|
||||||
|
// submit patch and verify response
|
||||||
|
getClient(epersonToken)
|
||||||
|
.perform(
|
||||||
|
patch("/api/submission/workspaceitems/" + wItem.getID())
|
||||||
|
.content(patchBody2)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON)
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
// verify that bitstream of workspace item has this open access RP
|
||||||
|
getClient(adminToken).perform(get("/api/authz/resourcepolicies/search/resource")
|
||||||
|
.param("uuid", bitstream.getID().toString()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$._embedded.resourcepolicies", Matchers.hasItems(
|
||||||
|
ResourcePolicyMatcher.matchResourcePolicyProperties(anonymousGroup, null, bitstream,
|
||||||
|
ResourcePolicy.TYPE_CUSTOM, Constants.READ, "openaccess")
|
||||||
|
)));
|
||||||
|
|
||||||
|
// submit the workspaceitem to complete the deposit (as there is no workflow configured)
|
||||||
|
getClient(epersonToken)
|
||||||
|
.perform(post(BASE_REST_SERVER_URL + "/api/workflow/workflowitems")
|
||||||
|
.content("/api/submission/workspaceitems/" + wItem.getID())
|
||||||
|
.contentType(textUriContentType))
|
||||||
|
.andExpect(status().isCreated());
|
||||||
|
|
||||||
|
// Bitstream should be accessible to anon
|
||||||
|
getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,13 @@ import static org.hamcrest.Matchers.allOf;
|
|||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.dspace.authorize.ResourcePolicy;
|
import org.dspace.authorize.ResourcePolicy;
|
||||||
|
import org.dspace.content.DSpaceObject;
|
||||||
import org.dspace.core.Constants;
|
import org.dspace.core.Constants;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.eperson.Group;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,6 +34,27 @@ public class ResourcePolicyMatcher {
|
|||||||
private ResourcePolicyMatcher() {
|
private ResourcePolicyMatcher() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Matcher<? super Object> matchResourcePolicyProperties(@Nullable Group group,
|
||||||
|
@Nullable EPerson eperson, DSpaceObject dso, @Nullable String rpType, int action, @Nullable String name) {
|
||||||
|
return allOf(
|
||||||
|
hasJsonPath("$.name", is(name)),
|
||||||
|
hasJsonPath("$.action", is(Constants.actionText[action])),
|
||||||
|
rpType != null ?
|
||||||
|
hasJsonPath("$.policyType", is(rpType)) :
|
||||||
|
hasNoJsonPath("$.policyType"),
|
||||||
|
hasJsonPath("$.type", is("resourcepolicy")),
|
||||||
|
hasJsonPath("$._embedded.resource.id", is(dso.getID().toString())),
|
||||||
|
eperson != null ?
|
||||||
|
hasJsonPath("$._embedded.eperson.id",
|
||||||
|
is(eperson.getID().toString())) :
|
||||||
|
hasJsonPath("$._embedded.eperson", nullValue()),
|
||||||
|
group != null ?
|
||||||
|
hasJsonPath("$._embedded.group.id",
|
||||||
|
is(group.getID().toString())) :
|
||||||
|
hasJsonPath("$._embedded.group", nullValue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static Matcher<? super Object> matchResourcePolicy(ResourcePolicy resourcePolicy) {
|
public static Matcher<? super Object> matchResourcePolicy(ResourcePolicy resourcePolicy) {
|
||||||
return allOf(hasJsonPath("$.id", is(resourcePolicy.getID())),
|
return allOf(hasJsonPath("$.id", is(resourcePolicy.getID())),
|
||||||
hasJsonPath("$.name", is(resourcePolicy.getRpName())),
|
hasJsonPath("$.name", is(resourcePolicy.getRpName())),
|
||||||
|
Reference in New Issue
Block a user