From 1db90a596f804b030b0e2615d86e9b5251197095 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Fri, 25 Sep 2020 11:19:01 +0200 Subject: [PATCH 1/6] 73207: Download Permissions in REST Feature Implementation --- .../authorization/impl/DownloadFeature.java | 57 +++++++++++++ .../impl/RequestCopyFeature.java | 84 +++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java new file mode 100644 index 0000000000..f54b8caba9 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java @@ -0,0 +1,57 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.authorization.impl; + +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.dspace.app.rest.authorization.AuthorizationFeature; +import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation; +import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil; +import org.dspace.app.rest.model.BaseObjectRest; +import org.dspace.app.rest.model.BitstreamRest; +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.security.DSpaceRestPermission; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * The create bitstream feature. It can be used to verify if bitstreams can be created in a specific bundle. + * + * Authorization is granted if the current user has ADD & WRITE permissions on the given bundle AND the item + */ +@Component +@AuthorizationFeatureDocumentation(name = DownloadFeature.NAME, + description = "It can be used to verify if the user can download a bitstream") +public class DownloadFeature implements AuthorizationFeature { + + Logger log = Logger.getLogger(DownloadFeature.class); + + public final static String NAME = "canDownload"; + + @Autowired + private AuthorizeServiceRestUtil authorizeServiceRestUtil; + + @Override + public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException { + if (object instanceof BitstreamRest) { + return authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.READ); + } + return false; + } + + @Override + public String[] getSupportedTypes() { + return new String[]{ + BitstreamRest.CATEGORY + "." + BitstreamRest.NAME, + }; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java new file mode 100644 index 0000000000..12aca9f131 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java @@ -0,0 +1,84 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.authorization.impl; + +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import org.apache.log4j.Logger; +import org.dspace.app.rest.authorization.AuthorizationFeature; +import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation; +import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil; +import org.dspace.app.rest.model.BaseObjectRest; +import org.dspace.app.rest.model.BitstreamRest; +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.security.DSpaceRestPermission; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Item; +import org.dspace.content.service.ItemService; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * The create bitstream feature. It can be used to verify if bitstreams can be created in a specific bundle. + * + * Authorization is granted if the current user has ADD & WRITE permissions on the given bundle AND the item + */ +@Component +@AuthorizationFeatureDocumentation(name = RequestCopyFeature.NAME, + description = "It can be used to verify if the user can request a copy of a bitstream") +public class RequestCopyFeature implements AuthorizationFeature { + + Logger log = Logger.getLogger(RequestCopyFeature.class); + + public final static String NAME = "canRequestACopy"; + + @Autowired + private AuthorizeServiceRestUtil authorizeServiceRestUtil; + @Autowired + private AuthorizeService authorizeService; + + @Autowired + private ItemService itemService; + + @Override + public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException { + if (object instanceof ItemRest) { + ItemRest itemRest = (ItemRest) object; + String id = itemRest.getId(); + Item item = itemService.find(context, UUID.fromString(id)); + List bunds = item.getBundles(); + + for (Bundle bund : bunds) { + List bitstreams = bund.getBitstreams(); + for (Bitstream bitstream : bitstreams) { + boolean authorized = authorizeService.authorizeActionBoolean(context, bitstream, Constants.READ); + if (!authorized) { + return true; + } + } + } + } else if (object instanceof BitstreamRest) { + return !authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.READ); + } + return false; + } + + @Override + public String[] getSupportedTypes() { + return new String[]{ + ItemRest.CATEGORY + "." + ItemRest.NAME, + BitstreamRest.CATEGORY + "." + BitstreamRest.NAME, + }; + } +} From f8e32554e6bc2ceb1fbec87d049a25e56e141749 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Fri, 25 Sep 2020 11:44:50 +0200 Subject: [PATCH 2/6] 73207: Download Permissions in REST Feature Implementation --- .../authorization/impl/DownloadFeature.java | 7 ++--- .../impl/RequestCopyFeature.java | 29 ++++++++++++++----- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java index f54b8caba9..4778de263f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java @@ -15,18 +15,15 @@ import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation; import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil; import org.dspace.app.rest.model.BaseObjectRest; import org.dspace.app.rest.model.BitstreamRest; -import org.dspace.app.rest.model.ItemRest; import org.dspace.app.rest.security.DSpaceRestPermission; -import org.dspace.authorize.service.AuthorizeService; -import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** - * The create bitstream feature. It can be used to verify if bitstreams can be created in a specific bundle. + * The download bitstream feature. It can be used to verify if a bitstream can be downloaded. * - * Authorization is granted if the current user has ADD & WRITE permissions on the given bundle AND the item + * Authorization is granted if the current user has READ permissions on the given bitstream. */ @Component @AuthorizationFeatureDocumentation(name = DownloadFeature.NAME, diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java index 12aca9f131..751674be8f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java @@ -14,15 +14,15 @@ import java.util.UUID; import org.apache.log4j.Logger; import org.dspace.app.rest.authorization.AuthorizationFeature; import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation; -import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil; import org.dspace.app.rest.model.BaseObjectRest; import org.dspace.app.rest.model.BitstreamRest; import org.dspace.app.rest.model.ItemRest; -import org.dspace.app.rest.security.DSpaceRestPermission; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; import org.dspace.content.Item; +import org.dspace.content.service.BitstreamService; import org.dspace.content.service.ItemService; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -30,9 +30,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** - * The create bitstream feature. It can be used to verify if bitstreams can be created in a specific bundle. + * The can request a copy feature. It can be used to verify if a copy can be requested of a bitstream or of a bitstream + * in an item. * - * Authorization is granted if the current user has ADD & WRITE permissions on the given bundle AND the item + * Authorization is granted for a bitstream if the user has no access to the bitstream + * and the bistream is part of an archived item. + * Authorization is granted for an item if the user has no access to a bitstream in the item, and the item is archived. */ @Component @AuthorizationFeatureDocumentation(name = RequestCopyFeature.NAME, @@ -43,20 +46,24 @@ public class RequestCopyFeature implements AuthorizationFeature { public final static String NAME = "canRequestACopy"; - @Autowired - private AuthorizeServiceRestUtil authorizeServiceRestUtil; @Autowired private AuthorizeService authorizeService; @Autowired private ItemService itemService; + @Autowired + private BitstreamService bitstreamService; + @Override public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException { if (object instanceof ItemRest) { ItemRest itemRest = (ItemRest) object; String id = itemRest.getId(); Item item = itemService.find(context, UUID.fromString(id)); + if (!item.isArchived()) { + return false; + } List bunds = item.getBundles(); for (Bundle bund : bunds) { @@ -69,7 +76,15 @@ public class RequestCopyFeature implements AuthorizationFeature { } } } else if (object instanceof BitstreamRest) { - return !authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.READ); + BitstreamRest bitstreamRest = (BitstreamRest) object; + Bitstream bitstream = bitstreamService.find(context, UUID.fromString(bitstreamRest.getId())); + + DSpaceObject parentObject = bitstreamService.getParentObject(context, bitstream); + if (parentObject instanceof Item) { + if (((Item) parentObject).isArchived()) { + return !authorizeService.authorizeActionBoolean(context, bitstream, Constants.READ); + } + } } return false; } From c53e211ba52128020b1a27f8ff79637a488a4064 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Fri, 25 Sep 2020 15:18:20 +0200 Subject: [PATCH 3/6] 173207: Implement tests for RequestCopyFeature part 1 --- .../authorization/RequestCopyFeatureIT.java | 358 ++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java new file mode 100644 index 0000000000..25b9454f71 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java @@ -0,0 +1,358 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.authorization; + +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; + +import org.apache.commons.codec.CharEncoding; +import org.apache.commons.io.IOUtils; +import org.dspace.app.rest.authorization.impl.RequestCopyFeature; +import org.dspace.app.rest.converter.BitstreamConverter; +import org.dspace.app.rest.converter.ConverterService; +import org.dspace.app.rest.converter.ItemConverter; +import org.dspace.app.rest.converter.SiteConverter; +import org.dspace.app.rest.model.BitstreamRest; +import org.dspace.app.rest.model.CollectionRest; +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.utils.Utils; +import org.dspace.authorize.service.ResourcePolicyService; +import org.dspace.builder.BitstreamBuilder; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.ItemBuilder; +import org.dspace.builder.WorkspaceItemBuilder; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.Site; +import org.dspace.content.WorkspaceItem; +import org.dspace.content.service.SiteService; +import org.dspace.core.Constants; +import org.dspace.services.ConfigurationService; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { + + @Autowired + private AuthorizationFeatureService authorizationFeatureService; + + @Autowired + private ConverterService converterService; + + @Autowired + private ConfigurationService configurationService; + + @Autowired + private SiteService siteService; + + @Autowired + ResourcePolicyService resourcePolicyService; + + @Autowired + private SiteConverter siteConverter; + + @Autowired + private ItemConverter itemConverter; + + @Autowired + private BitstreamConverter bitstreamConverter; + + + @Autowired + private Utils utils; + + private AuthorizationFeature requestCopyFeature; + + private Collection collectionA; + private Item itemA; + private Bitstream bitstreamA; + private Bitstream bitstreamB; + + private Item itemInWorkSpace; + private Bitstream bitstreamFromWorkSpaceItem; + + private Bitstream bitstreamFromCollection; + + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + context.turnOffAuthorisationSystem(); + requestCopyFeature = authorizationFeatureService.find(RequestCopyFeature.NAME); + + String bitstreamContent = "Dummy content"; + + Community communityA = CommunityBuilder.createCommunity(context).build(); + collectionA = CollectionBuilder.createCollection(context, communityA).withLogo("Blub").build(); + bitstreamFromCollection = collectionA.getLogo(); + + itemA = ItemBuilder.createItem(context, collectionA).build(); + + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstreamA = BitstreamBuilder.createBitstream(context, itemA, is) + .withName("Bitstream") + .withDescription("Description") + .withMimeType("text/plain") + .build(); + bitstreamB = BitstreamBuilder.createBitstream(context, itemA, is) + .withName("Bitstream2") + .withDescription("Description2") + .withMimeType("text/plain") + .build(); + WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, collectionA) + .withFulltext("Test", "source", is) + .build(); + itemInWorkSpace = workspaceItem.getItem(); + bitstreamFromWorkSpaceItem = itemInWorkSpace.getBundles("ORIGINAL").get(0).getBitstreams().get(0); + } + resourcePolicyService.removePolicies(context, bitstreamB, Constants.READ); + + + context.restoreAuthSystemState(); + } + + + @Test + public void requestCopyOnCollectionAAsAdmin() throws Exception { + CollectionRest collectionRest = converterService.toRest(collectionA, Projection.DEFAULT); + String collectionUri = utils.linkToSingleResource(collectionRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", collectionUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + @Test + public void requestCopyOnItemAAsAdmin() throws Exception { + ItemRest itemRest = itemConverter.convert(itemA, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnItemInWorkSpaceAsAdmin() throws Exception { + ItemRest itemRest = itemConverter.convert(itemInWorkSpace, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamAAsAdmin() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamA, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamBAsAdmin() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamFromWorkSpaceItemAsAdmin() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromWorkSpaceItem, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamFromCollectionAsAdmin() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + + // Tests for anonymous user + @Test + public void requestCopyOnCollectionAAsAnonymous() throws Exception { + CollectionRest collectionRest = converterService.toRest(collectionA, Projection.DEFAULT); + String collectionUri = utils.linkToSingleResource(collectionRest, "self").getHref(); + + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", collectionUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + @Test + public void requestCopyOnItemAAsAnonymous() throws Exception { + ItemRest itemRest = itemConverter.convert(itemA, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnItemInWorkSpaceAsAnonymous() throws Exception { + ItemRest itemRest = itemConverter.convert(itemInWorkSpace, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamAAsAnonymous() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamA, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamBAsAnonymous() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamFromWorkSpaceItemAsAnonymous() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromWorkSpaceItem, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamFromCollectionAsAnonymous() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + // Test for Eperson + + + + + + + +} From 61494f42913ad38df47d77f3f5c3f27f3b91cca3 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Mon, 28 Sep 2020 10:14:16 +0200 Subject: [PATCH 4/6] 73210: Finish Its for RequestCopyFeature and DownloadFeature --- .../authorization/impl/DownloadFeature.java | 2 +- .../impl/RequestCopyFeature.java | 4 +- .../rest/authorization/DownloadFeatureIT.java | 305 ++++++++++++++++++ .../authorization/RequestCopyFeatureIT.java | 235 ++++++++++---- 4 files changed, 473 insertions(+), 73 deletions(-) create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/DownloadFeatureIT.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java index 4778de263f..187df3e873 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java @@ -48,7 +48,7 @@ public class DownloadFeature implements AuthorizationFeature { @Override public String[] getSupportedTypes() { return new String[]{ - BitstreamRest.CATEGORY + "." + BitstreamRest.NAME, + BitstreamRest.CATEGORY + "." + BitstreamRest.NAME, }; } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java index 751674be8f..63d350e667 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java @@ -92,8 +92,8 @@ public class RequestCopyFeature implements AuthorizationFeature { @Override public String[] getSupportedTypes() { return new String[]{ - ItemRest.CATEGORY + "." + ItemRest.NAME, - BitstreamRest.CATEGORY + "." + BitstreamRest.NAME, + ItemRest.CATEGORY + "." + ItemRest.NAME, + BitstreamRest.CATEGORY + "." + BitstreamRest.NAME, }; } } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/DownloadFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/DownloadFeatureIT.java new file mode 100644 index 0000000000..dcf1b66383 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/DownloadFeatureIT.java @@ -0,0 +1,305 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.authorization; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; + +import org.apache.commons.codec.CharEncoding; +import org.apache.commons.io.IOUtils; +import org.dspace.app.rest.authorization.impl.DownloadFeature; +import org.dspace.app.rest.converter.BitstreamConverter; +import org.dspace.app.rest.converter.CollectionConverter; +import org.dspace.app.rest.converter.ItemConverter; +import org.dspace.app.rest.matcher.AuthorizationMatcher; +import org.dspace.app.rest.model.BitstreamRest; +import org.dspace.app.rest.model.CollectionRest; +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.utils.Utils; +import org.dspace.authorize.service.ResourcePolicyService; +import org.dspace.builder.BitstreamBuilder; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.ItemBuilder; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.core.Constants; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class DownloadFeatureIT extends AbstractControllerIntegrationTest { + + @Autowired + private AuthorizationFeatureService authorizationFeatureService; + + @Autowired + private ResourcePolicyService resourcePolicyService; + + @Autowired + private CollectionConverter collectionConverter; + + @Autowired + private ItemConverter itemConverter; + + @Autowired + private BitstreamConverter bitstreamConverter; + + + @Autowired + private Utils utils; + + private AuthorizationFeature downloadFeature; + + private Collection collectionA; + private Item itemA; + private Bitstream bitstreamA; + private Bitstream bitstreamB; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + context.turnOffAuthorisationSystem(); + downloadFeature = authorizationFeatureService.find(DownloadFeature.NAME); + + String bitstreamContent = "Dummy content"; + + Community communityA = CommunityBuilder.createCommunity(context).build(); + collectionA = CollectionBuilder.createCollection(context, communityA).withLogo("Blub").build(); + + itemA = ItemBuilder.createItem(context, collectionA).build(); + + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstreamA = BitstreamBuilder.createBitstream(context, itemA, is) + .withName("Bitstream") + .withDescription("Description") + .withMimeType("text/plain") + .build(); + bitstreamB = BitstreamBuilder.createBitstream(context, itemA, is) + .withName("Bitstream2") + .withDescription("Description2") + .withMimeType("text/plain") + .build(); + } + resourcePolicyService.removePolicies(context, bitstreamB, Constants.READ); + + + context.restoreAuthSystemState(); + } + + + @Test + public void downloadOfCollectionAAsAdmin() throws Exception { + CollectionRest collectionRest = collectionConverter.convert(collectionA, Projection.DEFAULT); + String collectionUri = utils.linkToSingleResource(collectionRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", collectionUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + @Test + public void downloadOfItemAAsAdmin() throws Exception { + ItemRest itemRest = itemConverter.convert(itemA, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void downloadOfBitstreamAAsAdmin() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamA, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + Authorization authorizationFeature = new Authorization(admin, downloadFeature, bitstreamRest); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature))))); + + } + + @Test + public void downloadOfBitstreamBAsAdmin() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + Authorization authorizationFeature = new Authorization(admin, downloadFeature, bitstreamRest); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature))))); + + } + + + // Tests for anonymous user + @Test + public void downloadOfCollectionAAsAnonymous() throws Exception { + CollectionRest collectionRest = collectionConverter.convert(collectionA, Projection.DEFAULT); + String collectionUri = utils.linkToSingleResource(collectionRest, "self").getHref(); + + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", collectionUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + @Test + public void downloadOfItemAAsAnonymous() throws Exception { + ItemRest itemRest = itemConverter.convert(itemA, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + + + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void downloadOfBitstreamAAsAnonymous() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamA, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + Authorization authorizationFeature = new Authorization(null, downloadFeature, bitstreamRest); + + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature))))); + + } + + @Test + public void downloadOfBitstreamBAsAnonymous() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + // Test for Eperson + @Test + public void downloadOfCollectionAAsEperson() throws Exception { + CollectionRest collectionRest = collectionConverter.convert(collectionA, Projection.DEFAULT); + String collectionUri = utils.linkToSingleResource(collectionRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", collectionUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + @Test + public void downloadOfItemAAsEperson() throws Exception { + ItemRest itemRest = itemConverter.convert(itemA, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + @Test + public void downloadOfBitstreamAAsEperson() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamA, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + Authorization authorizationFeature = new Authorization(eperson, downloadFeature, bitstreamRest); + + String token = getAuthToken(eperson.getEmail(), password); + + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature))))); + + } + + @Test + public void downloadOfBitstreamBAsEperson() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", downloadFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java index 25b9454f71..2bd50c4455 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java @@ -7,6 +7,7 @@ */ package org.dspace.app.rest.authorization; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -19,9 +20,9 @@ import org.apache.commons.codec.CharEncoding; import org.apache.commons.io.IOUtils; import org.dspace.app.rest.authorization.impl.RequestCopyFeature; import org.dspace.app.rest.converter.BitstreamConverter; -import org.dspace.app.rest.converter.ConverterService; +import org.dspace.app.rest.converter.CollectionConverter; import org.dspace.app.rest.converter.ItemConverter; -import org.dspace.app.rest.converter.SiteConverter; +import org.dspace.app.rest.matcher.AuthorizationMatcher; import org.dspace.app.rest.model.BitstreamRest; import org.dspace.app.rest.model.CollectionRest; import org.dspace.app.rest.model.ItemRest; @@ -38,11 +39,9 @@ import org.dspace.content.Bitstream; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; -import org.dspace.content.Site; import org.dspace.content.WorkspaceItem; -import org.dspace.content.service.SiteService; import org.dspace.core.Constants; -import org.dspace.services.ConfigurationService; +import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -52,20 +51,11 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { @Autowired private AuthorizationFeatureService authorizationFeatureService; - @Autowired - private ConverterService converterService; - - @Autowired - private ConfigurationService configurationService; - - @Autowired - private SiteService siteService; - @Autowired ResourcePolicyService resourcePolicyService; @Autowired - private SiteConverter siteConverter; + private CollectionConverter collectionConverter; @Autowired private ItemConverter itemConverter; @@ -131,7 +121,7 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { @Test public void requestCopyOnCollectionAAsAdmin() throws Exception { - CollectionRest collectionRest = converterService.toRest(collectionA, Projection.DEFAULT); + CollectionRest collectionRest = collectionConverter.convert(collectionA, Projection.DEFAULT); String collectionUri = utils.linkToSingleResource(collectionRest, "self").getHref(); String token = getAuthToken(admin.getEmail(), password); @@ -143,6 +133,7 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { .andExpect(jsonPath("$.page.totalElements", is(0))) .andExpect(jsonPath("$._embedded").doesNotExist()); } + @Test public void requestCopyOnItemAAsAdmin() throws Exception { ItemRest itemRest = itemConverter.convert(itemA, Projection.DEFAULT); @@ -242,30 +233,31 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { // Tests for anonymous user @Test public void requestCopyOnCollectionAAsAnonymous() throws Exception { - CollectionRest collectionRest = converterService.toRest(collectionA, Projection.DEFAULT); + CollectionRest collectionRest = collectionConverter.convert(collectionA, Projection.DEFAULT); String collectionUri = utils.linkToSingleResource(collectionRest, "self").getHref(); getClient().perform(get("/api/authz/authorizations/search/object") - .param("uri", collectionUri) - .param("feature", requestCopyFeature.getName())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.page.totalElements", is(0))) - .andExpect(jsonPath("$._embedded").doesNotExist()); + .param("uri", collectionUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); } + @Test public void requestCopyOnItemAAsAnonymous() throws Exception { ItemRest itemRest = itemConverter.convert(itemA, Projection.DEFAULT); String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + Authorization authorizationFeature = new Authorization(null, requestCopyFeature, itemRest); - String token = getAuthToken(admin.getEmail(), password); - - getClient(token).perform(get("/api/authz/authorizations/search/object") - .param("uri", itemUri) - .param("feature", requestCopyFeature.getName())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) - .andExpect(jsonPath("$._embedded").doesNotExist()); + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature))))); } @Test @@ -273,14 +265,12 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { ItemRest itemRest = itemConverter.convert(itemInWorkSpace, Projection.DEFAULT); String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); - String token = getAuthToken(admin.getEmail(), password); - - getClient(token).perform(get("/api/authz/authorizations/search/object") - .param("uri", itemUri) - .param("feature", requestCopyFeature.getName())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.page.totalElements", is(0))) - .andExpect(jsonPath("$._embedded").doesNotExist()); + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); } @@ -289,14 +279,12 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamA, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); - String token = getAuthToken(admin.getEmail(), password); - - getClient(token).perform(get("/api/authz/authorizations/search/object") - .param("uri", bitstreamUri) - .param("feature", requestCopyFeature.getName())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.page.totalElements", is(0))) - .andExpect(jsonPath("$._embedded").doesNotExist()); + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); } @@ -304,16 +292,17 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { public void requestCopyOnBitstreamBAsAnonymous() throws Exception { BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + Authorization authorizationFeature = new Authorization(null, requestCopyFeature, bitstreamRest); - String token = getAuthToken(admin.getEmail(), password); - - getClient(token).perform(get("/api/authz/authorizations/search/object") - .param("uri", bitstreamUri) - .param("feature", requestCopyFeature.getName())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) - .andExpect(jsonPath("$._embedded").doesNotExist()); + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature)))) + ); } @Test @@ -321,14 +310,12 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromWorkSpaceItem, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); - String token = getAuthToken(admin.getEmail(), password); - - getClient(token).perform(get("/api/authz/authorizations/search/object") - .param("uri", bitstreamUri) - .param("feature", requestCopyFeature.getName())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.page.totalElements", is(0))) - .andExpect(jsonPath("$._embedded").doesNotExist()); + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); } @@ -337,7 +324,122 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); - String token = getAuthToken(admin.getEmail(), password); + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + // Test for Eperson + @Test + public void requestCopyOnCollectionAAsEperson() throws Exception { + CollectionRest collectionRest = collectionConverter.convert(collectionA, Projection.DEFAULT); + String collectionUri = utils.linkToSingleResource(collectionRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", collectionUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + @Test + public void requestCopyOnItemAAsEperson() throws Exception { + ItemRest itemRest = itemConverter.convert(itemA, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + Authorization authorizationFeature = new Authorization(eperson, requestCopyFeature, itemRest); + + String token = getAuthToken(eperson.getEmail(), password); + + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature))))); + } + + @Test + public void requestCopyOnItemInWorkSpaceAsEperson() throws Exception { + ItemRest itemRest = itemConverter.convert(itemInWorkSpace, Projection.DEFAULT); + String itemUri = utils.linkToSingleResource(itemRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", itemUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamAAsEperson() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamA, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamBAsEperson() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + Authorization authorizationFeature = new Authorization(eperson, requestCopyFeature, bitstreamRest); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature)))) + ); + } + + @Test + public void requestCopyOnBitstreamFromWorkSpaceItemAsEperson() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromWorkSpaceItem, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + + } + + @Test + public void requestCopyOnBitstreamFromCollectionAsEperson() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); getClient(token).perform(get("/api/authz/authorizations/search/object") .param("uri", bitstreamUri) @@ -347,12 +449,5 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { .andExpect(jsonPath("$._embedded").doesNotExist()); } - // Test for Eperson - - - - - - } From 6ace62112fdf7f1bd1b6f6352dfb58668d5b63e7 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Fri, 2 Oct 2020 10:43:18 +0200 Subject: [PATCH 5/6] 73914: Features Endpoint - Download Permissions in REST - Feedback --- .../authorization/impl/DownloadFeature.java | 3 - .../impl/RequestCopyFeature.java | 20 +++- .../authorization/RequestCopyFeatureIT.java | 98 +++++++++++++++++++ 3 files changed, 117 insertions(+), 4 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java index 187df3e873..c8f7f77bb7 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DownloadFeature.java @@ -9,7 +9,6 @@ package org.dspace.app.rest.authorization.impl; import java.sql.SQLException; -import org.apache.log4j.Logger; import org.dspace.app.rest.authorization.AuthorizationFeature; import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation; import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil; @@ -30,8 +29,6 @@ import org.springframework.stereotype.Component; description = "It can be used to verify if the user can download a bitstream") public class DownloadFeature implements AuthorizationFeature { - Logger log = Logger.getLogger(DownloadFeature.class); - public final static String NAME = "canDownload"; @Autowired diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java index 63d350e667..1d19a85eeb 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/RequestCopyFeature.java @@ -11,6 +11,7 @@ import java.sql.SQLException; import java.util.List; import java.util.UUID; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.rest.authorization.AuthorizationFeature; import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation; @@ -26,6 +27,8 @@ import org.dspace.content.service.BitstreamService; import org.dspace.content.service.ItemService; import org.dspace.core.Constants; import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -55,8 +58,23 @@ public class RequestCopyFeature implements AuthorizationFeature { @Autowired private BitstreamService bitstreamService; + @Autowired + private ConfigurationService configurationService; + @Override public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException { + String requestType = configurationService.getProperty("request.item.type"); + if (StringUtils.isBlank(requestType)) { + return false; + } else if (StringUtils.equalsIgnoreCase(requestType, "logged")) { + EPerson currentUser = context.getCurrentUser(); + if (currentUser == null) { + return false; + } + } else if (!StringUtils.equalsIgnoreCase(requestType, "all")) { + log.warn("The configuration parameter \"request.item.type\" contains an invalid value."); + return false; + } if (object instanceof ItemRest) { ItemRest itemRest = (ItemRest) object; String id = itemRest.getId(); @@ -64,7 +82,7 @@ public class RequestCopyFeature implements AuthorizationFeature { if (!item.isArchived()) { return false; } - List bunds = item.getBundles(); + List bunds = itemService.getBundles(item, Constants.DEFAULT_BUNDLE_NAME); for (Bundle bund : bunds) { List bitstreams = bund.getBitstreams(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java index 2bd50c4455..ad6d191d26 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java @@ -41,6 +41,7 @@ import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; import org.dspace.core.Constants; +import org.dspace.services.ConfigurationService; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; @@ -63,10 +64,14 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { @Autowired private BitstreamConverter bitstreamConverter; + @Autowired + private ConfigurationService configurationService; + @Autowired private Utils utils; + private AuthorizationFeature requestCopyFeature; private Collection collectionA; @@ -84,6 +89,9 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { @Before public void setUp() throws Exception { super.setUp(); + + configurationService.setProperty("request.item.type", "all"); + context.turnOffAuthorisationSystem(); requestCopyFeature = authorizationFeatureService.find(RequestCopyFeature.NAME); @@ -449,5 +457,95 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { .andExpect(jsonPath("$._embedded").doesNotExist()); } + public void requestACopyItemTypeLoggedAsAnonymous() throws Exception { + configurationService.setProperty("request.item.type", "logged"); + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + @Test + public void requestACopyItemTypeLoggedAsEperson() throws Exception { + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + Authorization authorizationFeature = new Authorization(eperson, requestCopyFeature, bitstreamRest); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) + .andExpect(jsonPath("$._embedded.authorizations", contains( + Matchers.is(AuthorizationMatcher.matchAuthorization(authorizationFeature)))) + ); + } + + public void requestACopyItemTypeEmptyAsAnonymous() throws Exception { + configurationService.setProperty("request.item.type", ""); + + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + public void requestACopyItemTypeEmptyAsEperson() throws Exception { + configurationService.setProperty("request.item.type", ""); + + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + public void requestACopyItemTypeBogusValueAsAnonymous() throws Exception { + configurationService.setProperty("request.item.type", "invalid value"); + + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + getClient().perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + public void requestACopyItemTypeBogusValueAsEperson() throws Exception { + configurationService.setProperty("request.item.type", "invalid value"); + + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authz/authorizations/search/object") + .param("uri", bitstreamUri) + .param("feature", requestCopyFeature.getName())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } } From cd5c89dd68460f3d1023b630eb7e54d2fd037e57 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Mon, 5 Oct 2020 09:34:27 +0200 Subject: [PATCH 6/6] 73914: Implement feedback --- .../app/rest/authorization/RequestCopyFeatureIT.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java index ad6d191d26..6fd5fad35c 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/RequestCopyFeatureIT.java @@ -460,7 +460,7 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { public void requestACopyItemTypeLoggedAsAnonymous() throws Exception { configurationService.setProperty("request.item.type", "logged"); - BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); getClient().perform(get("/api/authz/authorizations/search/object") @@ -473,6 +473,8 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { @Test public void requestACopyItemTypeLoggedAsEperson() throws Exception { + configurationService.setProperty("request.item.type", "logged"); + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); Authorization authorizationFeature = new Authorization(eperson, requestCopyFeature, bitstreamRest); @@ -492,7 +494,7 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { public void requestACopyItemTypeEmptyAsAnonymous() throws Exception { configurationService.setProperty("request.item.type", ""); - BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); getClient().perform(get("/api/authz/authorizations/search/object") @@ -506,7 +508,7 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { public void requestACopyItemTypeEmptyAsEperson() throws Exception { configurationService.setProperty("request.item.type", ""); - BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); String token = getAuthToken(eperson.getEmail(), password); @@ -522,7 +524,7 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { public void requestACopyItemTypeBogusValueAsAnonymous() throws Exception { configurationService.setProperty("request.item.type", "invalid value"); - BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); getClient().perform(get("/api/authz/authorizations/search/object") @@ -536,7 +538,7 @@ public class RequestCopyFeatureIT extends AbstractControllerIntegrationTest { public void requestACopyItemTypeBogusValueAsEperson() throws Exception { configurationService.setProperty("request.item.type", "invalid value"); - BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamFromCollection, Projection.DEFAULT); + BitstreamRest bitstreamRest = bitstreamConverter.convert(bitstreamB, Projection.DEFAULT); String bitstreamUri = utils.linkToSingleResource(bitstreamRest, "self").getHref(); String token = getAuthToken(eperson.getEmail(), password);