Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions server/catgenome/profiles/dev/catgenome.properties
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,6 @@ item.path.update.notification.cc=${ITEM_PATH_UPDATE_NOTIFICATION_CC:}
#CLOUD PIPELINE
cloud.pipeline.server.url=${CLOUD_PIPELINE_SERVER_URL:}
cloud.pipeline.server.token=${CLOUD_PIPELINE_SERVER_TOKEN:}

# flag determines if file download is allowed
file.download.allowed=true
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public enum MessageCode {
ERROR_GENE_PRED_FILE_READING("error.genepred.file.reading"),
ERROR_NO_QUALIFIERS("error.no.qualifiers"),

URL_FILE_BROWSING_NOT_ALLOWED("error.url.file.browsing.not.allowed");
URL_FILE_BROWSING_NOT_ALLOWED("error.url.file.browsing.not.allowed"),
FILES_DOWNLOAD_NOT_ALLOWED("error.files.download.not.allowed");

private final String code;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* MIT License
*
* Copyright (c) 2016 EPAM Systems
* Copyright (c) 2016-2022 EPAM Systems
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -27,6 +27,7 @@
import static com.epam.catgenome.component.MessageHelper.getMessage;

import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -71,7 +72,7 @@ public class DataItemController extends AbstractRESTController {
private DataItemManager dataItemManager;

@ResponseBody
@RequestMapping(value = "/dataitem/search", method = RequestMethod.GET)
@GetMapping(value = "/dataitem/search")
@ApiOperation(
value = "Finds all files registered on the server by a specified file name",
notes = "Finds all files registered on the server by a specified file name</br>" +
Expand All @@ -89,7 +90,7 @@ public final Result<List<BiologicalDataItem>> findFilesByName(@RequestParam(valu
}

@ResponseBody
@RequestMapping(value = "/dataitem/formats", method = RequestMethod.GET)
@GetMapping(value = "/dataitem/formats")
@ApiOperation(
value = "Get all available bed formats.",
produces = MediaType.APPLICATION_JSON_VALUE)
Expand All @@ -101,7 +102,7 @@ public Result<Map<String, BiologicalDataItemFormat>> getBedFormats() {
}

@ResponseBody
@RequestMapping(value = "/dataitem/delete", method = RequestMethod.DELETE)
@DeleteMapping(value = "/dataitem/delete")
@ApiOperation(
value = "Deletes a file, specified by biological item id from the database",
notes = "Deletes a file, specified by biological item id from the database",
Expand All @@ -116,7 +117,7 @@ public final Result<Boolean> deleteFileBiBioItemId(@RequestParam(value = "id")
}

@ResponseBody
@RequestMapping(value = "/dataitem/find", method = RequestMethod.GET)
@GetMapping(value = "/dataitem/find")
@ApiOperation(
value = "Finds a file, specified by biological item id from the database",
notes = "Finds a file, specified by biological item id from the database",
Expand Down Expand Up @@ -146,32 +147,46 @@ public final Result<Boolean> rename(
return Result.success(null);
}

@GetMapping("/dataitem/{id}/download")
@GetMapping("/dataitem/{id}/download/{projectId}")
@ApiOperation(
value = "Downloads a file specified by biological item id",
notes = "Downloads a file specified by biological item id",
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void downloadFileByBiologicalItemId(
@PathVariable(value = "id") final Long id,
@PathVariable(value = "projectId") final Long projectId,
@RequestParam(value = "source", defaultValue = "true") final Boolean source,
final HttpServletResponse response) throws IOException {
final BiologicalDataItem biologicalDataItem = dataItemManager.findFileByBioItemId(id);
final BiologicalDataItemFile biologicalDataItemFile =
dataItemSecurityService.loadItemFile(biologicalDataItem, source);
writeStreamToResponse(response, biologicalDataItemFile.getContent(), biologicalDataItemFile.getFileName());
final BiologicalDataItemFile itemFile = dataItemSecurityService.loadItemFile(id, projectId, source);
writeStreamToResponse(response, itemFile.getContent(), itemFile.getFileName());
}

@ResponseBody
@GetMapping("/dataitem/{id}/downloadUrl")
@GetMapping("/dataitem/{id}/downloadUrl/{projectId}")
@ApiOperation(
value = "Generates download url for file specified by biological item id",
notes = "Generates download url for file specified by biological item id",
produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(
value = {@ApiResponse(code = HTTP_STATUS_OK, message = API_STATUS_DESCRIPTION)
})
public final Result<BiologicalDataItemDownloadUrl> generateDownloadUrl(@PathVariable(value = "id") final Long id) {
final BiologicalDataItem biologicalDataItem = dataItemManager.findFileByBioItemId(id);
return Result.success(dataItemSecurityService.generateDownloadUrl(id, biologicalDataItem));
public final Result<BiologicalDataItemDownloadUrl> generateDownloadUrl(
@PathVariable(value = "id") final Long id,
@PathVariable(value = "projectId") final Long projectId)
throws AccessDeniedException {
return Result.success(dataItemSecurityService.generateDownloadUrl(id, projectId));
}

@ResponseBody
@GetMapping(value = "/dataitem/download/allowed")
@ApiOperation(
value = "Checks if files download is allowed",
notes = "Returns true if files download is allowed and false if not",
produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(
value = {@ApiResponse(code = HTTP_STATUS_OK, message = API_STATUS_DESCRIPTION)
})
public Result<Boolean> isFileDownloadAllowed() {
return Result.success(dataItemManager.isFileDownloadAllowed());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

package com.epam.catgenome.manager.dataitem;

import static com.epam.catgenome.component.MessageCode.FILES_DOWNLOAD_NOT_ALLOWED;
import static com.epam.catgenome.component.MessageHelper.getMessage;
import static com.epam.catgenome.constant.MessagesConstants.ERROR_BIO_ID_NOT_FOUND;
import static com.epam.catgenome.constant.MessagesConstants.ERROR_BIO_NAME_NOT_FOUND;
Expand All @@ -32,6 +33,7 @@
import static com.epam.catgenome.constant.MessagesConstants.ERROR_UNSUPPORTED_FILE_FORMAT;

import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -72,7 +74,7 @@
*/
@Service
public class DataItemManager {
private static final String DOWNLOAD_LOCAL_FILE_URL_FORMAT = "%s/restapi/dataitem/%d/download";
private static final String DOWNLOAD_LOCAL_FILE_URL_FORMAT = "%s/restapi/dataitem/%d/download/%d";

@Autowired
private BiologicalDataItemDao biologicalDataItemDao;
Expand Down Expand Up @@ -104,6 +106,9 @@ public class DataItemManager {
@Value("${base.external.url:}")
private String baseExternalUrl;

@Value("#{catgenome['file.download.allowed'] ?: false}")
private boolean fileDownloadAllowed;

/**
* Method finds all files registered in the system by an input search query
* @param name to find
Expand Down Expand Up @@ -213,6 +218,9 @@ public Map<String, BiologicalDataItemFormat> getFormats() {

public BiologicalDataItemFile loadItemFile(final BiologicalDataItem biologicalDataItem,
final Boolean source) throws IOException {
if (!isFileDownloadAllowed()) {
throw new AccessDeniedException(getMessage(FILES_DOWNLOAD_NOT_ALLOWED));
}
final String dataItemPath = source ? biologicalDataItem.getSource() : biologicalDataItem.getPath();
if (BiologicalDataItemResourceType.FILE.equals(biologicalDataItem.getType())) {
return loadLocalFileItem(biologicalDataItem, dataItemPath);
Expand All @@ -221,11 +229,16 @@ public BiologicalDataItemFile loadItemFile(final BiologicalDataItem biologicalDa
}

public BiologicalDataItemDownloadUrl generateDownloadUrl(final Long id,
final BiologicalDataItem biologicalDataItem) {
final Long projectId,
final BiologicalDataItem biologicalDataItem)
throws AccessDeniedException {
if (!isFileDownloadAllowed()) {
throw new AccessDeniedException(getMessage(FILES_DOWNLOAD_NOT_ALLOWED));
}
final BiologicalDataItemResourceType type = determineType(biologicalDataItem);
switch (type) {
case FILE:
return generateDownloadUrlForLocalFile(id, biologicalDataItem);
return generateDownloadUrlForLocalFile(id, projectId, biologicalDataItem);
case S3:
return S3Client.getInstance().generatePresignedUrl(biologicalDataItem.getSource());
case AZ:
Expand All @@ -236,6 +249,10 @@ public BiologicalDataItemDownloadUrl generateDownloadUrl(final Long id,
}
}

public boolean isFileDownloadAllowed() {
return fileDownloadAllowed;
}

private BiologicalDataItemResourceType determineType(final BiologicalDataItem biologicalDataItem) {
if (S3Client.isS3Source(biologicalDataItem.getSource())) {
return BiologicalDataItemResourceType.S3;
Expand All @@ -247,14 +264,15 @@ private BiologicalDataItemResourceType determineType(final BiologicalDataItem bi
}

private BiologicalDataItemDownloadUrl generateDownloadUrlForLocalFile(final Long id,
final Long projectId,
final BiologicalDataItem biologicalDataItem) {
final Path dataItemPath = Paths.get(biologicalDataItem.getSource());
try {
Assert.state(Files.exists(dataItemPath),
getMessage(ERROR_BIO_ID_NOT_FOUND, biologicalDataItem.getId()));
return BiologicalDataItemDownloadUrl.builder()
.url(String.format(DOWNLOAD_LOCAL_FILE_URL_FORMAT,
StringUtils.removeEnd(baseExternalUrl, "/"), id))
StringUtils.removeEnd(baseExternalUrl, "/"), id, projectId))
.type(BiologicalDataItemResourceType.FILE)
.size(Files.size(dataItemPath))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* * MIT License
* *
* * Copyright (c) 2018 EPAM Systems
* * Copyright (c) 2018-2022 EPAM Systems
* *
* * Permission is hereby granted, free of charge, to any person obtaining a copy
* * of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -39,6 +39,7 @@
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -83,15 +84,17 @@ public Map<String, BiologicalDataItemFormat> getFormats() {
return dataItemManager.getFormats();
}

@PreAuthorize(ROLE_USER)
public BiologicalDataItemFile loadItemFile(final BiologicalDataItem biologicalDataItem,
final Boolean source) throws IOException {
@PreAuthorize("isDownloadFileAllowed(#id, #projectId)")
public BiologicalDataItemFile loadItemFile(final Long id, final Long projectId, final Boolean source)
throws IOException {
final BiologicalDataItem biologicalDataItem = dataItemManager.findFileByBioItemId(id);
return dataItemManager.loadItemFile(biologicalDataItem, source);
}

@PreAuthorize(ROLE_USER)
public BiologicalDataItemDownloadUrl generateDownloadUrl(final Long generateDownloadUrl,
final BiologicalDataItem biologicalDataItem) {
return dataItemManager.generateDownloadUrl(generateDownloadUrl, biologicalDataItem);
@PreAuthorize("isDownloadFileAllowed(#id, #projectId)")
public BiologicalDataItemDownloadUrl generateDownloadUrl(final Long id, final Long projectId)
throws AccessDeniedException {
final BiologicalDataItem biologicalDataItem = dataItemManager.findFileByBioItemId(id);
return dataItemManager.generateDownloadUrl(id, projectId, biologicalDataItem);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* MIT License
*
* Copyright (c) 2018 EPAM Systems
* Copyright (c) 2018-2022 EPAM Systems
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -73,6 +73,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

Expand Down Expand Up @@ -165,6 +166,32 @@ public boolean isAllowedByBioItemId(String permissionName, Long bioItemId) {
permissionName);
}

public boolean isDownloadFileAllowed(final Long bioItemId, final Long projectId) {
if (isAdmin(getSids())){
return true;
}
final Project project = projectManager.load(projectId);
final boolean projectContainsItem = project.getItems().stream()
.map(i -> BiologicalDataItem.getBioDataItemId(i.getBioDataItem()))
.collect(Collectors.toSet())
.contains(bioItemId);
if (projectContainsItem && (isAllowed(READ, project) || isOwner(project))) {
return true;
}
final BiologicalDataItem bioItem = dataItemManager.findFileByBioItemId(bioItemId);
if (1 == bioItem.getFormat().getId() || isOwner(bioItem) || isAnnotation(bioItemId)) {
return true;
}
return permissionEvaluator
.hasPermission(SecurityContextHolder.getContext().getAuthentication(),
bioItem,
READ);
}

public boolean isAnnotation(final Long id) {
return CollectionUtils.isNotEmpty(referenceGenomeManager.loadReferenceIdsByAnnotationFileId(id));
}

public boolean projectCanBeMoved(Long projectId, Long newParentId) {
Project project = projectManager.load(projectId);
boolean isAllowed = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ public boolean hasPermissionByBioItemId(Long bioItemId, String permission) {
return permissionHelper.isAllowedByBioItemId(permission, bioItemId);
}

public boolean isDownloadFileAllowed(Long bioItemId, Long projectId) {
return permissionHelper.isDownloadFileAllowed(bioItemId, projectId);
}

@Override
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,3 +316,4 @@ error.cloud.pipeline.not.available=Cloud Pipeline server is not available. Notif
error.genepred.file.reading=Failed to read GenePred file

error.url.file.browsing.not.allowed=Url file browsing is not allowed
error.files.download.not.allowed=Files download is not allowed