From ea733c12878ae5f22cfb589fcaea56b1af79a4ac Mon Sep 17 00:00:00 2001 From: "Gantner, Florian Klaus" Date: Wed, 28 Feb 2024 10:28:10 +0100 Subject: [PATCH] implement authorized check for xlscollectionCrosswalk implement interface method for fine granular check to export these issues only to Administrator group. Configured crosswalk to stay to the current behaviour (export to all) https://github.com/4Science/DSpace/issues/422 --- .../crosswalks/XlsCollectionCrosswalk.java | 46 ++++++++ .../crosswalks/XlsCollectionCrosswalkIT.java | 111 ++++++++++++++++++ dspace/config/spring/api/crosswalks.xml | 9 +- 3 files changed, 165 insertions(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/integration/crosswalks/XlsCollectionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/integration/crosswalks/XlsCollectionCrosswalk.java index 986d7b0e8b71..02c35b083806 100644 --- a/dspace-api/src/main/java/org/dspace/content/integration/crosswalks/XlsCollectionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/integration/crosswalks/XlsCollectionCrosswalk.java @@ -14,7 +14,9 @@ import java.io.OutputStream; import java.sql.SQLException; import java.util.Iterator; +import java.util.List; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections4.IteratorUtils; import org.apache.poi.ss.usermodel.Workbook; import org.dspace.app.bulkedit.BulkImport; @@ -31,6 +33,9 @@ import org.dspace.content.service.ItemService; import org.dspace.core.Constants; import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; +import org.dspace.eperson.service.GroupService; import org.springframework.beans.factory.annotation.Autowired; /** @@ -52,6 +57,9 @@ public class XlsCollectionCrosswalk implements ItemExportCrosswalk { @Autowired private BulkImportWorkbookBuilder bulkImportWorkbookBuilder; + @Autowired + private GroupService groupService; + @Override public boolean canDisseminate(Context context, DSpaceObject dso) { return dso.getType() == Constants.COLLECTION; @@ -71,6 +79,16 @@ public CrosswalkMode getCrosswalkMode() { return CrosswalkMode.MULTIPLE; } + private List allowedGroups; + + public List getAllowedGroups() { + return allowedGroups; + } + + public void setAllowedGroups(List allowedGroups) { + this.allowedGroups = allowedGroups; + } + @Override public void disseminate(Context context, DSpaceObject dso, OutputStream out) throws CrosswalkException, IOException, SQLException, AuthorizeException { @@ -79,6 +97,10 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out) throw new CrosswalkObjectNotSupported("Can only crosswalk a Collection"); } + if (!isAuthorized(context)) { + throw new AuthorizeException("The current user is not allowed to perform a xls collection export"); + } + Collection collection = (Collection) dso; Iterator itemIterator = itemService.findByCollection(context, collection); @@ -133,4 +155,28 @@ private Collection findCollection(Context context, Item item) throws SQLExceptio return collection; } + @Override + public boolean isAuthorized(Context context) { + if (CollectionUtils.isEmpty(getAllowedGroups())) { + return true; + } + + EPerson ePerson = context.getCurrentUser(); + if (ePerson == null) { + return getAllowedGroups().contains(Group.ANONYMOUS); + } + + return getAllowedGroups().stream() + .anyMatch(groupName -> isMemberOfGroupNamed(context, ePerson, groupName)); + } + + private boolean isMemberOfGroupNamed(Context context, EPerson ePerson, String groupName) { + try { + Group group = groupService.findByName(context, groupName); + return groupService.isMember(context, ePerson, group); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } diff --git a/dspace-api/src/test/java/org/dspace/content/integration/crosswalks/XlsCollectionCrosswalkIT.java b/dspace-api/src/test/java/org/dspace/content/integration/crosswalks/XlsCollectionCrosswalkIT.java index 6ed7d8ba3aa7..e47d76686d53 100644 --- a/dspace-api/src/test/java/org/dspace/content/integration/crosswalks/XlsCollectionCrosswalkIT.java +++ b/dspace-api/src/test/java/org/dspace/content/integration/crosswalks/XlsCollectionCrosswalkIT.java @@ -63,6 +63,9 @@ import org.dspace.content.WorkspaceItem; import org.dspace.core.Constants; import org.dspace.core.CrisConstants; +import org.dspace.eperson.Group; +import org.dspace.eperson.factory.EPersonServiceFactory; +import org.dspace.eperson.service.GroupService; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.utils.DSpace; @@ -86,6 +89,8 @@ public class XlsCollectionCrosswalkIT extends AbstractIntegrationTestWithDatabas private ConfigurationService configurationService; + private GroupService groupService; + private Community community; private static final String BITSTREAM_URL_FORMAT = "%s/api/core/bitstreams/%s/content"; @@ -103,6 +108,9 @@ public void setup() throws SQLException, AuthorizeException { .getServicesByType(BulkImportWorkbookBuilderImpl.class).get(0); configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + + groupService = EPersonServiceFactory.getInstance().getGroupService(); context.turnOffAuthorisationSystem(); community = createCommunity(context).build(); @@ -332,6 +340,109 @@ public void testCollectionDisseminateWithEmptyCollection() throws Exception { assertThat(getRowValues(mainSheet.getRow(0), mainSheetHeader.length), contains(mainSheetHeader)); } + @Test + public void testCollectionIsNotAuthorized() throws Exception { + + context.turnOffAuthorisationSystem(); + Collection collection = createCollection(context, community) + .withAdminGroup(eperson) + .build(); + context.restoreAuthSystemState(); + + List groups = new ArrayList<>(); + groups.add("Test1"); + xlsCollectionCrosswalk.setAllowedGroups(groups); + context.commit(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + assertThat(xlsCollectionCrosswalk.isAuthorized(context), equalTo(false)); + + AuthorizeException authorizeException = Assert.assertThrows(AuthorizeException.class, + () -> xlsCollectionCrosswalk.disseminate(context, collection, baos)); + + assertThat(authorizeException.getMessage(), + is("The current user is not allowed to perform a xls collection export")); + + + } + + @Test + public void testCollectionIsAuthorizedEmptyCollection() throws Exception { + + context.turnOffAuthorisationSystem(); + Collection collection = createCollection(context, community) + .withAdminGroup(eperson) + .build(); + + Group group = groupService.create(context); + groupService.setName(group, "Test"); + groupService.addMember(context, group, eperson); + context.commit(); + + context.restoreAuthSystemState(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + List groups = new ArrayList<>(); + groups.add("Test"); + + xlsCollectionCrosswalk.setAllowedGroups(groups); + + assertThat(xlsCollectionCrosswalk.isAuthorized(context), equalTo(true)); + + xlsCollectionCrosswalk.disseminate(context, collection, baos); + + Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(baos.toByteArray())); + assertThat(workbook.getNumberOfSheets(), equalTo(2)); + + Sheet mainSheet = workbook.getSheetAt(0); + String[] mainSheetHeader = { "ID", "DISCOVERABLE", "dc.contributor.author", "dc.title", "dc.title.alternative", + "dc.date.issued", "dc.publisher", "dc.identifier.citation", "dc.relation.ispartofseries", + "dc.identifier.doi", "dc.identifier.scopus", "dc.identifier.isi", "dc.identifier.adsbibcode", + "dc.identifier.pmid", "dc.identifier.arxiv", "dc.identifier.issn", "dc.identifier.other", + "dc.identifier.ismn", "dc.identifier.govdoc", "dc.identifier.uri", "dc.identifier.isbn", + "dc.type", "dc.language.iso", "dc.subject", "dc.description.abstract", "dc.description.sponsorship", + "dc.description" }; + assertThat(mainSheet.getPhysicalNumberOfRows(), equalTo(1)); + assertThat(getRowValues(mainSheet.getRow(0), mainSheetHeader.length), contains(mainSheetHeader)); + } + + @Test + public void testCollectionIsAuthorizedAnonymousEmptyCollection() throws Exception { + + context.turnOffAuthorisationSystem(); + Collection collection = createCollection(context, community) + .withAdminGroup(eperson) + .build(); + context.restoreAuthSystemState(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + List groups = new ArrayList<>(); + groups.add("Anonymous"); + + xlsCollectionCrosswalk.setAllowedGroups(groups); + + assertThat(xlsCollectionCrosswalk.isAuthorized(context), equalTo(true)); + + xlsCollectionCrosswalk.disseminate(context, collection, baos); + + Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(baos.toByteArray())); + assertThat(workbook.getNumberOfSheets(), equalTo(2)); + + Sheet mainSheet = workbook.getSheetAt(0); + String[] mainSheetHeader = { "ID", "DISCOVERABLE", "dc.contributor.author", "dc.title", "dc.title.alternative", + "dc.date.issued", "dc.publisher", "dc.identifier.citation", "dc.relation.ispartofseries", + "dc.identifier.doi", "dc.identifier.scopus", "dc.identifier.isi", "dc.identifier.adsbibcode", + "dc.identifier.pmid", "dc.identifier.arxiv", "dc.identifier.issn", "dc.identifier.other", + "dc.identifier.ismn", "dc.identifier.govdoc", "dc.identifier.uri", "dc.identifier.isbn", + "dc.type", "dc.language.iso", "dc.subject", "dc.description.abstract", "dc.description.sponsorship", + "dc.description" }; + assertThat(mainSheet.getPhysicalNumberOfRows(), equalTo(1)); + assertThat(getRowValues(mainSheet.getRow(0), mainSheetHeader.length), contains(mainSheetHeader)); + } + @Test public void testCollectionDisseminateWithMockSubmissionFormConfiguration() throws Exception { diff --git a/dspace/config/spring/api/crosswalks.xml b/dspace/config/spring/api/crosswalks.xml index 9184a56482da..c3000df5ec94 100644 --- a/dspace/config/spring/api/crosswalks.xml +++ b/dspace/config/spring/api/crosswalks.xml @@ -509,7 +509,14 @@ - + + + + Administrator + Anonymous + + +