package eu.europeana.cloud.service.mcs.rest; import eu.europeana.cloud.common.model.File; import eu.europeana.cloud.common.model.Permission; import eu.europeana.cloud.common.model.Representation; import eu.europeana.cloud.service.mcs.RecordService; import eu.europeana.cloud.service.mcs.exception.*; import eu.europeana.cloud.test.AbstractSecurityTest; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.acls.domain.BasePermission; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.validation.constraints.NotNull; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.io.InputStream; import java.net.URI; import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @RunWith(SpringJUnit4ClassRunner.class) public class RepresentationAuthorizationResourceAATest extends AbstractSecurityTest { @Autowired @NotNull private FileResource fileResource; @Autowired @NotNull private FilesResource filesResource; @Autowired @NotNull private RecordService recordService; @Autowired @NotNull private RepresentationAuthorizationResource fileAuthorizationResource; @Autowired @NotNull private RepresentationResource representationResource; private static final String GLOBAL_ID = "GLOBAL_ID"; private static final String SCHEMA = "CIRCLE"; private static final String VERSION = "KIT_KAT"; private static final String PROVIDER_ID = "provider"; private static final String REPRESENTATION_NAME = "REPRESENTATION_NAME"; private static final String COPIED_REPRESENTATION_VERSION = "KIT_KAT_COPIED"; private static final String FILE_NAME = "FILE_NAME"; private static final String MIME_TYPE = APPLICATION_OCTET_STREAM_TYPE.toString(); private static final String READ_PERMISSION = "read"; private static final String WRITE_PERMISSION = "write"; private static final String BROKEN_PERMISSION = "sdfas"; private UriInfo URI_INFO; private InputStream INPUT_STREAM; private Representation representation; /** * Pre-defined users */ private final static String RANDOM_PERSON = "admin"; private final static String RANDOM_PASSWORD = "admin"; private final static String VAN_PERSIE = "Robin_Van_Persie"; private final static String VAN_PERSIE_PASSWORD = "Feyenoord"; private final static String RONALDO = "Cristiano"; private final static String RONALD_PASSWORD = "Ronaldo"; private final static String ANONYMOUS = "Anonymous"; private final static String ANONYMOUS_PASSWORD = "Anonymous"; private final static String ADMIN = "admin"; private final static String ADMIN_PASSWORD = "admin"; @Before public void mockUp() throws Exception { URI_INFO = Mockito.mock(UriInfo.class); UriBuilder uriBuilder = Mockito.mock(UriBuilder.class); representation = new Representation(); representation.setCloudId(GLOBAL_ID); representation.setRepresentationName(SCHEMA); representation.setVersion(VERSION); Mockito.doReturn(representation).when(recordService).createRepresentation(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); Mockito.doReturn(uriBuilder).when(URI_INFO).getBaseUriBuilder(); Mockito.doReturn(uriBuilder).when(uriBuilder).path((Class) Mockito.anyObject()); Mockito.doReturn(new URI("")).when(uriBuilder).buildFromMap(Mockito.anyMap()); Mockito.doReturn(new URI("")).when(uriBuilder).buildFromMap(Mockito.anyMap()); Mockito.doReturn(new URI("")).when(URI_INFO).resolve((URI) Mockito.anyObject()); INPUT_STREAM = new InputStream() { @Override public int read() throws IOException { // TODO Auto-generated method stub return 0; } }; } @Test public void testSpringPermissionStrings() { assertEquals(READ_PERMISSION, Permission.READ.getValue()); assertEquals(WRITE_PERMISSION, Permission.WRITE.getValue()); } /** * Tests giving read access to specific user. */ @Test public void vanPersieShouldBeAbleToGetRonaldosFilesAfterAccessWasGivenToHim() throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException, FileAlreadyExistsException, FileNotExistsException, WrongContentRangeException, RecordNotExistsException, ProviderNotExistsException { Mockito.doThrow(new FileNotExistsException()).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); login(RONALDO, RONALD_PASSWORD); representationResource.createRepresentation(URI_INFO, GLOBAL_ID, SCHEMA, PROVIDER_ID); filesResource.sendFile(URI_INFO, GLOBAL_ID, SCHEMA, VERSION, MIME_TYPE, INPUT_STREAM, FILE_NAME); File f = new File(); f.setFileName(FILE_NAME); f.setMimeType(APPLICATION_OCTET_STREAM_TYPE.toString()); Mockito.doReturn(f).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); Response response = fileAuthorizationResource.updateAuthorization(GLOBAL_ID, SCHEMA, VERSION, VAN_PERSIE, READ_PERMISSION + ""); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); login(VAN_PERSIE, VAN_PERSIE_PASSWORD); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); } /** * Tests giving write access to specific user. */ @Test public void vanPersieShouldBeAbleToModifyRonaldosFilesAfterAccessWasGivenToHim() throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException, FileAlreadyExistsException, FileNotExistsException, WrongContentRangeException, RecordNotExistsException, ProviderNotExistsException { Mockito.doThrow(new FileNotExistsException()).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); login(RONALDO, RONALD_PASSWORD); representationResource.createRepresentation(URI_INFO, GLOBAL_ID, SCHEMA, PROVIDER_ID); filesResource.sendFile(URI_INFO, GLOBAL_ID, SCHEMA, VERSION, MIME_TYPE, INPUT_STREAM, FILE_NAME); File f = new File(); f.setFileName(FILE_NAME); f.setMimeType(APPLICATION_OCTET_STREAM_TYPE.toString()); Mockito.doReturn(f).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); Response response = fileAuthorizationResource.updateAuthorization(GLOBAL_ID, SCHEMA, VERSION, VAN_PERSIE, WRITE_PERMISSION + ""); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); login(VAN_PERSIE, VAN_PERSIE_PASSWORD); fileResource.sendFile(URI_INFO, GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, MIME_TYPE, INPUT_STREAM); } /** * Tests giving write access to specific user. */ @Test public void updateAuthorization_throwsMCSException() throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException, FileAlreadyExistsException, FileNotExistsException, WrongContentRangeException, RecordNotExistsException, ProviderNotExistsException { //given Mockito.doThrow(new FileNotExistsException()).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); login(RONALDO, RONALD_PASSWORD); representationResource.createRepresentation(URI_INFO, GLOBAL_ID, SCHEMA, PROVIDER_ID); filesResource.sendFile(URI_INFO, GLOBAL_ID, SCHEMA, VERSION, MIME_TYPE, INPUT_STREAM, FILE_NAME); File f = new File(); f.setFileName(FILE_NAME); f.setMimeType(APPLICATION_OCTET_STREAM_TYPE.toString()); Mockito.doReturn(f).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); try { //when fileAuthorizationResource.updateAuthorization(GLOBAL_ID, SCHEMA, VERSION, VAN_PERSIE, BROKEN_PERMISSION + ""); fail("Expected WebApplicationException"); } catch (WebApplicationException e) { //then Assert.assertThat(e.getResponse().getStatus(), is(Response.Status.BAD_REQUEST.getStatusCode())); } login(VAN_PERSIE, VAN_PERSIE_PASSWORD); assertUserDontHaveAccessToFile(); } private void assertUserDontHaveAccessToFile() throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException, FileNotExistsException { try { fileResource.sendFile(URI_INFO, GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, MIME_TYPE, INPUT_STREAM); fail("Expected AccessDeniedException"); } catch (AccessDeniedException e) { } } // TEST giving access to everyone + anonymous users // @Test public void randomPersonShouldBeAbleToGetRonaldosFilesAfterAccessWasGivenForEveryone() throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException, FileAlreadyExistsException, FileNotExistsException, WrongContentRangeException, RecordNotExistsException, ProviderNotExistsException { Mockito.doThrow(new FileNotExistsException()).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); login(RONALDO, RONALD_PASSWORD); representationResource.createRepresentation(URI_INFO, GLOBAL_ID, SCHEMA, PROVIDER_ID); filesResource.sendFile(URI_INFO, GLOBAL_ID, SCHEMA, VERSION, MIME_TYPE, INPUT_STREAM, FILE_NAME); File f = new File(); f.setFileName(FILE_NAME); f.setMimeType(APPLICATION_OCTET_STREAM_TYPE.toString()); Mockito.doReturn(f).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); fileAuthorizationResource.giveReadAccessToEveryone(GLOBAL_ID, SCHEMA, VERSION); login(RANDOM_PERSON, RANDOM_PASSWORD); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); } @Test public void unknownUserShouldBeAbleToGetFileAfterAccessWasGivenForEveryone() throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException, FileAlreadyExistsException, FileNotExistsException, WrongContentRangeException, RecordNotExistsException, ProviderNotExistsException { Mockito.doThrow(new FileNotExistsException()).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); login(RONALDO, RONALD_PASSWORD); representationResource.createRepresentation(URI_INFO, GLOBAL_ID, SCHEMA, PROVIDER_ID); filesResource.sendFile(URI_INFO, GLOBAL_ID, SCHEMA, VERSION, MIME_TYPE, INPUT_STREAM, FILE_NAME); File f = new File(); f.setFileName(FILE_NAME); f.setMimeType(APPLICATION_OCTET_STREAM_TYPE.toString()); Mockito.doReturn(f).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); fileAuthorizationResource.giveReadAccessToEveryone(GLOBAL_ID, SCHEMA, VERSION); login(ANONYMOUS, ANONYMOUS_PASSWORD); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); } /* * Removing permissions */ @Test(expected = AuthenticationCredentialsNotFoundException.class) public void notLoggedInUserShouldNotBeAbleToRemovePrivilegesFromAnyResource() { fileAuthorizationResource.removePermissions("someID", "someSchema", "someVersion", "userName", READ_PERMISSION + ""); } @Test(expected = AccessDeniedException.class) public void anonymousUserShouldNotBeAbleToRemovePrivilegesFromAnyResource() { login(ANONYMOUS, ANONYMOUS_PASSWORD); fileAuthorizationResource.removePermissions(GLOBAL_ID, SCHEMA, VERSION, "userName", READ_PERMISSION + ""); } @Test(expected = AccessDeniedException.class) public void userWithoutSufficientRightsShouldNotBeAbleToRemovePrivilegesFromAnyResource() { login(RONALDO, RONALD_PASSWORD); fileAuthorizationResource.removePermissions(GLOBAL_ID, SCHEMA, VERSION, "userName", READ_PERMISSION + ""); } @Test(expected = AccessDeniedException.class) public void ronaldoShouldBeAbleToDeletePermissionsForVanPersieToHisFile() throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException, FileAlreadyExistsException, FileNotExistsException, WrongContentRangeException, RecordNotExistsException, ProviderNotExistsException { /* Add file to eCloud */ login(RONALDO, RONALD_PASSWORD); representationResource.createRepresentation(URI_INFO, GLOBAL_ID, SCHEMA, PROVIDER_ID); filesResource.sendFile(URI_INFO, GLOBAL_ID, SCHEMA, VERSION, MIME_TYPE, INPUT_STREAM, FILE_NAME); /* Grant access to this file for Van Persie */ Response response = fileAuthorizationResource.updateAuthorization(GLOBAL_ID, SCHEMA, VERSION, VAN_PERSIE, READ_PERMISSION + ""); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); File f = new File(); f.setFileName(FILE_NAME); f.setMimeType(APPLICATION_OCTET_STREAM_TYPE.toString()); Mockito.doReturn(f).when(recordService).getFile(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); login(VAN_PERSIE, VAN_PERSIE_PASSWORD); /* Check if Van Persie has access to file */ fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); /* Delete permissions for Var Persie */ login(RONALDO, RONALD_PASSWORD); response = fileAuthorizationResource.removePermissions(GLOBAL_ID, SCHEMA, VERSION, VAN_PERSIE, READ_PERMISSION + ""); Assert.assertEquals(response.getStatus(), Response.Status.NO_CONTENT.getStatusCode()); /* VAn Persie should not be able to access file */ login(VAN_PERSIE, VAN_PERSIE_PASSWORD); fileResource.getFile(GLOBAL_ID, SCHEMA, VERSION, FILE_NAME, null); } }