diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java index 01596ad28..c87ce4590 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java @@ -11,6 +11,7 @@ import eu.eudat.data.query.items.table.dmp.DataManagementPlanTableRequest; import eu.eudat.data.query.items.table.dmp.DataManagmentPlanPublicTableRequest; import eu.eudat.exceptions.datamanagementplan.DMPNewVersionException; import eu.eudat.exceptions.datamanagementplan.DMPWithDatasetsDeleteException; +import eu.eudat.exceptions.security.UnauthorisedException; import eu.eudat.logic.managers.DataManagementPlanManager; import eu.eudat.logic.managers.DatasetManager; import eu.eudat.logic.proxy.config.configloaders.ConfigLoader; @@ -123,7 +124,11 @@ public class DMPs extends BaseController { DataManagementPlanOverviewModel dataManagementPlan = this.dataManagementPlanManager.getOverviewSingle(id, principal); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(dataManagementPlan)); } catch (Exception e) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE)); + if (e instanceof UnauthorisedException) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE)); + } else { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE)); + } } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java index 17573e46a..b5967aa67 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java @@ -4,6 +4,7 @@ import eu.eudat.data.entities.Dataset; import eu.eudat.data.query.items.item.dataset.DatasetWizardAutocompleteRequest; import eu.eudat.data.query.items.item.datasetprofile.DatasetProfileWizardAutocompleteRequest; import eu.eudat.exceptions.datasetwizard.DatasetWizardCannotUnlockException; +import eu.eudat.exceptions.security.UnauthorisedException; import eu.eudat.logic.managers.DatasetManager; import eu.eudat.logic.managers.DatasetWizardManager; import eu.eudat.logic.managers.UserManager; @@ -15,6 +16,7 @@ import eu.eudat.models.data.datasetwizard.DataManagentPlanListingModel; import eu.eudat.models.data.datasetwizard.DatasetWizardModel; import eu.eudat.models.data.dmp.AssociatedProfile; import eu.eudat.models.data.helpers.responses.ResponseItem; +import eu.eudat.models.data.listingmodels.DataManagementPlanOverviewModel; import eu.eudat.models.data.security.Principal; import eu.eudat.models.data.user.composite.PagedDatasetProfile; import eu.eudat.types.ApiMessageCode; @@ -30,6 +32,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import javax.persistence.NoResultException; import javax.transaction.Transactional; import java.io.File; import java.io.FileInputStream; @@ -79,32 +82,43 @@ public class DatasetWizardController extends BaseController { @Transactional @RequestMapping(method = RequestMethod.GET, value = {"{id}"}, produces = "application/json") public @ResponseBody - ResponseEntity getSingle(@PathVariable String id, @RequestHeader("Content-Type") String contentType, @ClaimedAuthorities(claims = {ANONYMOUS}) Principal principal) throws IllegalAccessException, IOException, InstantiationException { - if(contentType.equals("application/xml")) { - VisibilityRuleService visibilityRuleService = this.getApiContext().getUtilitiesService().getVisibilityRuleService(); - return this.datasetManager.getDocument(id, visibilityRuleService, contentType); - } - else if (contentType.equals("application/msword")) { - File file = datasetManager.getWordDocument(this.configLoader, id, this.getApiContext().getUtilitiesService().getVisibilityRuleService()); - InputStream resource = new FileInputStream(file); - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentLength(file.length()); - responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); - responseHeaders.set("Content-Disposition", "attachment;filename=" + file.getName()); - responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); - responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); + ResponseEntity getSingle(@PathVariable String id, @RequestHeader("Content-Type") String contentType, Principal principal) throws IllegalAccessException, IOException, InstantiationException { + try { + if (contentType.equals("application/xml")) { + VisibilityRuleService visibilityRuleService = this.getApiContext().getUtilitiesService().getVisibilityRuleService(); + return this.datasetManager.getDocument(id, visibilityRuleService, contentType, principal); + } else if (contentType.equals("application/msword")) { + File file = datasetManager.getWordDocument(this.configLoader, id, this.getApiContext().getUtilitiesService().getVisibilityRuleService(), principal); + InputStream resource = new FileInputStream(file); + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentLength(file.length()); + responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); + responseHeaders.set("Content-Disposition", "attachment;filename=" + file.getName()); + responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); + responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); - byte[] content = IOUtils.toByteArray(resource); - resource.close(); - Files.deleteIfExists(file.toPath()); - return new ResponseEntity<>(content, - responseHeaders, - HttpStatus.OK); - } - else { - DatasetWizardModel dataset = this.datasetManager.getSingle(id); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(dataset)); + byte[] content = IOUtils.toByteArray(resource); + resource.close(); + Files.deleteIfExists(file.toPath()); + return new ResponseEntity<>(content, + responseHeaders, + HttpStatus.OK); + } else { + DatasetWizardModel dataset = this.datasetManager.getSingle(id, principal); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(dataset)); + } + } catch (Exception e) { + if (e instanceof UnauthorisedException) { + if (e instanceof UnauthorisedException) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE)); + } else if (e instanceof NoResultException) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE)); + } else { + throw e; + } + } } + return null; // ???? } @RequestMapping(method = RequestMethod.GET, value = {"/public/{id}"}, produces = "application/json") @@ -137,8 +151,8 @@ public class DatasetWizardController extends BaseController { @RequestMapping(method = RequestMethod.GET, value = {"/getPDF/{id}"}) public @ResponseBody - ResponseEntity getPDFDocument(@PathVariable String id) throws IllegalAccessException, IOException, InstantiationException, InterruptedException { - File file = datasetManager.getWordDocument(this.configLoader, id, this.getApiContext().getUtilitiesService().getVisibilityRuleService()); + ResponseEntity getPDFDocument(@PathVariable String id, Principal principal) throws IllegalAccessException, IOException, InstantiationException, InterruptedException { + File file = datasetManager.getWordDocument(this.configLoader, id, this.getApiContext().getUtilitiesService().getVisibilityRuleService(), principal); String fileName = file.getName(); if (fileName.endsWith(".docx")){ fileName = fileName.substring(0, fileName.length() - 5); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 254e43710..24ce41df1 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -1035,7 +1035,7 @@ public class DataManagementPlanManager { eu.eudat.data.entities.DMP dmp = databaseRepository.getDmpDao().find(UUID.fromString(id)); if (!dmp.isPublic() && dmp.getUsers().stream().noneMatch(userInfo -> userInfo.getUser().getId() == principal.getId())) throw new UnauthorisedException(); - RDAExportModel rdaExportModel = new RDAExportModel().fromDataModel(dmp, datasetManager); + RDAExportModel rdaExportModel = new RDAExportModel().fromDataModel(dmp, datasetManager, principal); ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java index f9b72232c..2d42c5015 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java @@ -14,6 +14,7 @@ import eu.eudat.data.query.items.table.dataset.DatasetTableRequest; import eu.eudat.data.query.items.table.datasetprofile.DatasetProfileTableRequestItem; import eu.eudat.elastic.criteria.DatasetCriteria; import eu.eudat.elastic.repository.DatasetRepository; +import eu.eudat.exceptions.security.UnauthorisedException; import eu.eudat.logic.builders.BuilderFactory; import eu.eudat.logic.builders.entity.UserInfoBuilder; import eu.eudat.logic.proxy.config.configloaders.ConfigLoader; @@ -186,9 +187,13 @@ public class DatasetManager { return dataTable; } - public DatasetWizardModel getSingle(String id) { + public DatasetWizardModel getSingle(String id, Principal principal) { DatasetWizardModel dataset = new DatasetWizardModel(); eu.eudat.data.entities.Dataset datasetEntity = databaseRepository.getDatasetDao().find(UUID.fromString(id), HintedModelFactory.getHint(DatasetWizardModel.class)); + if (datasetEntity.getDmp().getUsers() + .stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()) + .collect(Collectors.toList()).size() == 0) + throw new UnauthorisedException(); eu.eudat.elastic.entities.Dataset datasetElastic; try { datasetElastic = datasetRepository.exists() ? @@ -261,11 +266,15 @@ public class DatasetManager { return pagedDatasetProfile; } - public File getWordDocument(ConfigLoader configLoader, String id, VisibilityRuleService visibilityRuleService) throws IOException { + public File getWordDocument(ConfigLoader configLoader, String id, VisibilityRuleService visibilityRuleService, Principal principal) throws IOException { WordBuilder wordBuilder = new WordBuilder(); DatasetWizardModel dataset = new DatasetWizardModel(); XWPFDocument document = configLoader.getDocument(); eu.eudat.data.entities.Dataset datasetEntity = databaseRepository.getDatasetDao().find(UUID.fromString(id), HintedModelFactory.getHint(DatasetWizardModel.class)); + if (!datasetEntity.getDmp().isPublic() && datasetEntity.getDmp().getUsers() + .stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()) + .collect(Collectors.toList()).size() == 0) + throw new UnauthorisedException(); wordBuilder.addParagraphContent(datasetEntity.getLabel(), document, ParagraphStyle.HEADER1, BigInteger.ZERO); // Space below Dataset title. @@ -342,10 +351,14 @@ public class DatasetManager { return exportFile; } - public FileEnvelope getXmlDocument(String id, VisibilityRuleService visibilityRuleService) throws InstantiationException, IllegalAccessException, IOException { + public FileEnvelope getXmlDocument(String id, VisibilityRuleService visibilityRuleService, Principal principal) throws InstantiationException, IllegalAccessException, IOException { ExportXmlBuilder xmlBuilder = new ExportXmlBuilder(); DatasetWizardModel dataset = new DatasetWizardModel(); eu.eudat.data.entities.Dataset datasetEntity = databaseRepository.getDatasetDao().find(UUID.fromString(id), HintedModelFactory.getHint(DatasetWizardModel.class)); + if (!datasetEntity.getDmp().isPublic() && datasetEntity.getDmp().getUsers() + .stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()) + .collect(Collectors.toList()).size() == 0) + throw new UnauthorisedException(); Map properties = new HashMap<>(); if (datasetEntity.getProperties() != null) { JSONObject jobject = new JSONObject(datasetEntity.getProperties()); @@ -595,8 +608,8 @@ public class DatasetManager { datasetDao.createOrUpdate(dataset); } - public ResponseEntity getDocument(String id, VisibilityRuleService visibilityRuleService, String contentType) throws IllegalAccessException, IOException, InstantiationException { - FileEnvelope envelope = getXmlDocument(id, visibilityRuleService); + public ResponseEntity getDocument(String id, VisibilityRuleService visibilityRuleService, String contentType, Principal principal) throws IllegalAccessException, IOException, InstantiationException { + FileEnvelope envelope = getXmlDocument(id, visibilityRuleService, principal); InputStream resource = new FileInputStream(envelope.getFile()); logger.info("Mime Type of " + envelope.getFilename() + " is " + new MimetypesFileTypeMap().getContentType(envelope.getFile())); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java index 396e66286..0418feca3 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java @@ -7,6 +7,7 @@ import com.jayway.jsonpath.JsonPath; import eu.eudat.data.entities.Dataset; import eu.eudat.logic.managers.DatasetManager; import eu.eudat.logic.utilities.builders.XmlBuilder; +import eu.eudat.models.data.security.Principal; import org.json.JSONArray; import org.json.JSONObject; import org.slf4j.Logger; @@ -149,7 +150,7 @@ public class DatasetRDAExportModel { } - public DatasetRDAExportModel fromDataModel(Dataset dataset, DatasetManager datasetManager) { + public DatasetRDAExportModel fromDataModel(Dataset dataset, DatasetManager datasetManager, Principal principal) { // Map of template Ids to rda values. JSONObject jObject = new JSONObject(dataset.getProperties()); Map templateIdsToValues = jObject.toMap(); @@ -165,7 +166,7 @@ public class DatasetRDAExportModel { // Transform the answered dataset description to json so we can parse it and fill the rda model. JSONObject datasetDescriptionJson = null; try { - String jsonResult = mapper.writeValueAsString(datasetManager.getSingle(dataset.getId().toString()).getDatasetProfileDefinition()); + String jsonResult = mapper.writeValueAsString(datasetManager.getSingle(dataset.getId().toString(), principal).getDatasetProfileDefinition()); datasetDescriptionJson = new JSONObject(jsonResult); } catch (JsonProcessingException e) { logger.error(e.getMessage(), e); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java index 53fda76d0..47147fc4e 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java @@ -5,6 +5,7 @@ import eu.eudat.data.entities.Dataset; import eu.eudat.data.entities.UserDMP; import eu.eudat.data.entities.UserInfo; import eu.eudat.logic.managers.DatasetManager; +import eu.eudat.models.data.security.Principal; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -127,7 +128,7 @@ public class DmpRDAExportModel { this.title = title; } - public DmpRDAExportModel fromDataModel(DMP entity, DatasetManager datasetManager) { + public DmpRDAExportModel fromDataModel(DMP entity, DatasetManager datasetManager, Principal principal) { DmpRDAExportModel dmpRda = new DmpRDAExportModel(); dmpRda.contact = new ContactRDAExportModel().fromDataModel(entity.getUsers().stream().filter(x -> x.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())).findFirst().get().getUser()); if (entity.getUsers().stream().anyMatch(x -> x.getRole().equals(UserDMP.UserDMPRoles.USER.getValue()))) { @@ -142,7 +143,7 @@ public class DmpRDAExportModel { dmpRda.dataset = new LinkedList<>(); for (Dataset dataset : entity.getDataset()) { if (dataset.getStatus() != Dataset.Status.DELETED.getValue() && dataset.getStatus() != Dataset.Status.CANCELED.getValue()) - dmpRda.dataset.add(new DatasetRDAExportModel().fromDataModel(dataset, datasetManager)); + dmpRda.dataset.add(new DatasetRDAExportModel().fromDataModel(dataset, datasetManager, principal)); } dmpRda.description = entity.getDescription().replace("\n", " "); if (entity.getDoi() != null) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java index ad3d3c16b..98bb5627d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java @@ -3,6 +3,7 @@ package eu.eudat.models.data.rda; import eu.eudat.data.entities.DMP; import eu.eudat.data.entities.Dataset; import eu.eudat.logic.managers.DatasetManager; +import eu.eudat.models.data.security.Principal; import java.util.LinkedList; import java.util.List; @@ -17,8 +18,8 @@ public class RDAExportModel { this.dmp = dmp; } - public RDAExportModel fromDataModel(DMP dmp, DatasetManager datasetManager) { - this.dmp = new DmpRDAExportModel().fromDataModel(dmp, datasetManager); + public RDAExportModel fromDataModel(DMP dmp, DatasetManager datasetManager, Principal principal) { + this.dmp = new DmpRDAExportModel().fromDataModel(dmp, datasetManager, principal); return this; } } diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index e19f588bf..f7832f157 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -162,8 +162,17 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr }) }, error => { - this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-FOUND'), SnackBarNotificationLevel.Error); - this.router.navigate(['/datasets/edit/' + this.itemId]); + switch (error.status) { + case 403: + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-ALLOWED'), SnackBarNotificationLevel.Error); + break; + case 404: + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-FOUND'), SnackBarNotificationLevel.Error); + break; + default: + this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.ERRORS.HTTP-REQUEST-ERROR'), SnackBarNotificationLevel.Error); + } + this.router.navigate(['/datasets/']); return observableOf(null); }); } else if (dmpId != null) { diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index e02c04059..93c9afbc4 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -74,6 +74,9 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { if (error.status === 404) { return this.onFetchingDeletedCallbackError('/plans/'); } + if (error.status === 403) { + return this.onFetchingForbiddenCallbackError('/plans/'); + } }); } else if (publicId != null) { @@ -93,6 +96,9 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { if (error.status === 404) { return this.onFetchingDeletedCallbackError('/plans/'); } + if (error.status === 403) { + return this.onFetchingForbiddenCallbackError('/plans/'); + } }); } }); @@ -103,6 +109,11 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { this.router.navigate([redirectRoot]); } + onFetchingForbiddenCallbackError(redirectRoot: string) { + this.uiNotificationService.snackBarNotification(this.language.instant('DMP-OVERVIEW.ERROR.FORBIDEN-DMP'), SnackBarNotificationLevel.Error); + this.router.navigate([redirectRoot]); + } + setIsUserOwner() { if (this.dmp) { const principal: Principal = this.authentication.current(); diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index a48bb153a..ce44af4cd 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -491,6 +491,7 @@ }, "MESSAGES": { "DATASET-NOT-FOUND": "Dataset Description does not exist", + "DATASET-NOT-ALLOWED": "You have no access to this Dataset Description", "SUCCESS-UPDATE-DATASET-PROFILE": "Dataset Description Template updated successfully" }, "UPLOAD": { @@ -519,7 +520,8 @@ "TEMPLATES-INVOLVED": "Dataset Description Templates Involved" }, "ERROR": { - "DELETED-DMP": "The requested DMP is deleted" + "DELETED-DMP": "The requested DMP is deleted", + "FORBIDEN-DMP": "You are not allowed to access this DMP" } }, "DATASET-LISTING": { diff --git a/dmp-frontend/src/assets/i18n/es.json b/dmp-frontend/src/assets/i18n/es.json index 0b5ddf215..ab171f90f 100644 --- a/dmp-frontend/src/assets/i18n/es.json +++ b/dmp-frontend/src/assets/i18n/es.json @@ -489,6 +489,7 @@ }, "MESSAGES": { "DATASET-NOT-FOUND": "No existe la descripción del Dataset", + "DATASET-NOT-ALLOWED": "You have no access to this Dataset Description", "SUCCESS-UPDATE-DATASET-PROFILE": "Plantilla de descripción del Dataset actualizada correctamente" }, "UPLOAD": { @@ -517,7 +518,8 @@ "TEMPLATES-INVOLVED": "Plantillas de descripción del Dataset implicadas" }, "ERROR": { - "DELETED-DMP": "El PGD solicitado está borrado" + "DELETED-DMP": "El PGD solicitado está borrado", + "FORBIDEN-DMP": "You are not allowed to access this DMP" } }, "DATASET-LISTING": {