Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block downloading unpublished objectid. #135

Merged
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
*/
package bio.overture.score.server.repository.s3;

import static bio.overture.score.server.metadata.MetadataService.getAnalysisId;
import static com.google.common.base.Preconditions.checkArgument;

import bio.overture.score.server.metadata.MetadataEntity;
import bio.overture.score.server.metadata.MetadataService;
import lombok.Cleanup;
import lombok.Setter;
import lombok.val;
Expand Down Expand Up @@ -69,6 +72,7 @@ public class S3DownloadService implements DownloadService {
* Constants.
*/
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final String PUBLISHED_ANALYSIS_STATE = "PUBLISHED";

/**
* Configuration.
Expand All @@ -79,6 +83,8 @@ public class S3DownloadService implements DownloadService {
private int expiration;
@Value("${object.sentinel}")
private String sentinelObjectId;
@Value("${metadata.useLegacyMode:false}")
private boolean useLegacyMode;

/**
* Dependencies.
Expand All @@ -91,10 +97,14 @@ public class S3DownloadService implements DownloadService {
private URLGenerator urlGenerator;
@Autowired
private PartCalculator partCalculator;
@Autowired
private MetadataService metadataService;

@Override
public ObjectSpecification download(String objectId, long offset, long length, boolean forExternalUse) {
try {
checkPublishedAnalysisState(metadataService.getEntity(objectId));

checkArgument(offset > -1L);

// Retrieve our meta file for object id
Expand Down Expand Up @@ -142,6 +152,21 @@ public ObjectSpecification download(String objectId, long offset, long length, b
}
}

void checkPublishedAnalysisState(MetadataEntity entity){
if(!useLegacyMode){
val objectId = entity.getId();
val analysisState = metadataService.getAnalysisStateForMetadata(entity);
if (!analysisState.equals(PUBLISHED_ANALYSIS_STATE)){
val message = String.format("Critical Error: cannot complete download for objectId '%s' with "
+ "analysisState '%s' and analysisId '%s'. "
+ "Can only download objects that have the analysisState '%s'. Update the file metadata and retry.",
objectId, analysisState, getAnalysisId(entity), PUBLISHED_ANALYSIS_STATE);
log.error(message); // Log to audit log file
throw new NotRetryableException(new IllegalStateException(message));
}
}
}

// This really is a misleading method name - should be retrieveMetaFile() or something
public ObjectSpecification getSpecification(String objectId) {
val objectKey = ObjectKeys.getObjectKey(dataDir, objectId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,11 +409,11 @@ void checkRegistered(String objectId) {
}

if (!useLegacyMode){
checkAnalysisState(entity);
checkUnpublishedAnalysisState(entity);
}
}

void checkAnalysisState(MetadataEntity entity){
void checkUnpublishedAnalysisState(MetadataEntity entity){
val objectId = entity.getId();
val analysisState = metadataClient.getAnalysisStateForMetadata(entity);
if (!analysisState.equals(UNPUBLISHED_ANALYSIS_STATE)){
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package bio.overture.score.server.repository.s3;

import bio.overture.score.server.exception.NotRetryableException;
import bio.overture.score.server.metadata.MetadataEntity;
import bio.overture.score.server.metadata.MetadataService;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class S3DownloadServiceTest {

private final String objectId = "45dfcd17-8e80-53fc-b400-cc8b583dae05";

private S3DownloadService s3DownloadService = new S3DownloadService();

private MetadataService mockService;

private MetadataEntity metadataEntity;

@Before
public void set_up(){
mockService = mock(MetadataService.class);
s3DownloadService.setMetadataService(mockService);
metadataEntity = MetadataEntity.builder()
.id(objectId)
.fileName("file_1")
.access("open")
.gnosId("an1")
.projectCode("project")
.build();

when(mockService.getAnalysisStateForMetadata(metadataEntity)).thenReturn("UNPUBLISHED");
}

@Test
public void test_if_unpublished_file_triggers_error() {
val throwable = catchThrowable(() -> s3DownloadService.checkPublishedAnalysisState(metadataEntity));
assertThat(throwable)
.hasMessageContaining(
format("Critical Error: cannot complete download for objectId '%s' with ", objectId));
}

@Test
public void verify_if_download_unpublished_objectId_is_blocked() {
when(mockService.getAnalysisStateForMetadata(metadataEntity)).thenReturn("UNPUBLISHED");
when(mockService.getEntity(objectId)).thenReturn(metadataEntity);

val throwable = catchThrowable(() -> s3DownloadService.download(objectId, 0, -1, false));
assertThat(throwable).isExactlyInstanceOf(NotRetryableException.class);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;

import java.net.URL;
import java.util.regex.Pattern;
Expand All @@ -30,13 +28,14 @@
import bio.overture.score.server.config.ServerConfig;
import bio.overture.score.server.exception.IdNotFoundException;
import bio.overture.score.core.util.SimplePartCalculator;
import bio.overture.score.server.metadata.MetadataEntity;
import bio.overture.score.server.metadata.MetadataService;
import bio.overture.score.server.repository.s3.S3BucketNamingService;
import bio.overture.score.server.repository.s3.S3DownloadService;
import bio.overture.score.server.repository.s3.S3URLGenerator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
Expand Down Expand Up @@ -69,28 +68,43 @@ public class ObjectDownloadServiceTest extends S3DownloadService {
/**
* SUT
*/
@InjectMocks
S3DownloadService service;
S3DownloadService service = new S3DownloadService();

S3BucketNamingService namingService = new S3BucketNamingService();

MetadataService mockService;

MetadataEntity metadataEntity;

@Before
public void setUp() {
namingService.setObjectBucketName(objectBucketName);
namingService.setStateBucketName(stateBucketName);
namingService.setBucketPoolSize(16);
namingService.setBucketKeySize(3);
service.setBucketNamingService(namingService);
service.setS3Client(s3Client);

// ReflectionTestUtils.setField(service, "dataBucketName", dataBucketName);
// ReflectionTestUtils.setField(service, "stateBucketName", stateBucketName);
ReflectionTestUtils.setField(service, "dataDir", dataDir);
// ReflectionTestUtils.setField(service, "bucketPoolSize", 5);
// ReflectionTestUtils.setField(service, "bucketKeySize", 2);
ReflectionTestUtils.setField(service, "expiration", 7);

ReflectionTestUtils.setField(service, "urlGenerator", new S3URLGenerator());
ReflectionTestUtils.setField(service, "partCalculator", new SimplePartCalculator(20000));

setUpMockService();
}

public void setUpMockService(){
mockService = mock(MetadataService.class);
Buwujiu marked this conversation as resolved.
Show resolved Hide resolved
service.setMetadataService(mockService);
metadataEntity = MetadataEntity.builder()
.id(objectId)
.fileName("file_1")
.access("open")
.gnosId("an1")
.projectCode("project")
.build();
when(mockService.getAnalysisStateForMetadata(metadataEntity)).thenReturn("PUBLISHED");
when(mockService.getEntity(objectId)).thenReturn(metadataEntity);
}

@Test(expected = IdNotFoundException.class)
Expand Down