Loading src/main/java/it/inaf/ia2/transfer/controller/ArchiveFileController.java +13 −6 Original line number Original line Diff line number Diff line Loading @@ -6,12 +6,12 @@ package it.inaf.ia2.transfer.controller; package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.exception.PermissionDeniedException; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveJob.Type; import it.inaf.ia2.transfer.service.ArchiveJob.Type; import it.inaf.ia2.transfer.service.ArchiveService; import it.inaf.ia2.transfer.service.ArchiveService; import java.io.File; import java.io.File; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders; Loading @@ -30,9 +30,6 @@ public class ArchiveFileController extends FileController { @Autowired @Autowired private ArchiveService archiveService; private ArchiveService archiveService; @Autowired private HttpServletRequest request; @Autowired @Autowired private HttpServletResponse response; private HttpServletResponse response; Loading @@ -42,7 +39,7 @@ public class ArchiveFileController extends FileController { Type type = Type.valueOf(archiveRequest.getType()); Type type = Type.valueOf(archiveRequest.getType()); ArchiveJob job = new ArchiveJob(); ArchiveJob job = new ArchiveJob(); job.setPrincipal((TokenPrincipal) request.getUserPrincipal()); job.setPrincipal(getPrincipal()); job.setJobId(archiveRequest.getJobId()); job.setJobId(archiveRequest.getJobId()); job.setType(type); job.setType(type); job.setVosPaths(archiveRequest.getPaths()); job.setVosPaths(archiveRequest.getPaths()); Loading @@ -59,10 +56,20 @@ public class ArchiveFileController extends FileController { @GetMapping(value = "/archive/{fileName}") @GetMapping(value = "/archive/{fileName}") public void getArchiveFile(@PathVariable("fileName") String fileName) { public void getArchiveFile(@PathVariable("fileName") String fileName) { TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); TokenPrincipal principal = getPrincipal(); File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile(); File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile(); FileResponseUtil.getFileResponse(response, file); FileResponseUtil.getFileResponse(response, file); } } private TokenPrincipal getPrincipal() { TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); if ("anonymous".equals(principal.getName())) { throw new PermissionDeniedException("Tar/Zip archive generation not allowed to anonymous users"); } return principal; } } } src/main/java/it/inaf/ia2/transfer/controller/GetFileController.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -65,7 +65,7 @@ public class GetFileController extends FileController { FileInfo fileInfo = optFileInfo.get(); FileInfo fileInfo = optFileInfo.get(); if (!authorizationService.isDownloadable(fileInfo, (TokenPrincipal) request.getUserPrincipal())) { if (!authorizationService.isDownloadable(fileInfo, (TokenPrincipal) request.getUserPrincipal())) { throw new PermissionDeniedException(path); throw new PermissionDeniedException("PermissionDenied Path: " + path); } } File file = new File(fileInfo.getOsPath()); File file = new File(fileInfo.getOsPath()); Loading src/main/java/it/inaf/ia2/transfer/exception/PermissionDeniedException.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -11,8 +11,8 @@ import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(value = HttpStatus.FORBIDDEN) @ResponseStatus(value = HttpStatus.FORBIDDEN) public class PermissionDeniedException extends JobException { public class PermissionDeniedException extends JobException { public PermissionDeniedException(String path) { public PermissionDeniedException(String errorDetail) { super(Type.FATAL, "Permission Denied"); super(Type.FATAL, "Permission Denied"); setErrorDetail("PermissionDenied Path: " + path); setErrorDetail(errorDetail); } } } } src/test/java/it/inaf/ia2/transfer/controller/ArchiveFileControllerTest.java +62 −2 Original line number Original line Diff line number Diff line Loading @@ -6,26 +6,34 @@ package it.inaf.ia2.transfer.controller; package it.inaf.ia2.transfer.controller; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveService; import it.inaf.ia2.transfer.service.ArchiveService; import java.io.File; import java.nio.file.Files; import java.util.Arrays; import java.util.Arrays; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.util.FileSystemUtils; @SpringBootTest @SpringBootTest @AutoConfigureMockMvc @AutoConfigureMockMvc(addFilters = false) public class ArchiveFileControllerTest { public class ArchiveFileControllerTest { private static final ObjectMapper MAPPER = new ObjectMapper(); private static final ObjectMapper MAPPER = new ObjectMapper(); Loading @@ -45,6 +53,7 @@ public class ArchiveFileControllerTest { request.setPaths(Arrays.asList("/path/to/file1", "/path/to/file2")); request.setPaths(Arrays.asList("/path/to/file1", "/path/to/file2")); mockMvc.perform(post("/archive") mockMvc.perform(post("/archive") .principal(fakePrincipal("user1")) .contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .content(MAPPER.writeValueAsString(request))) .content(MAPPER.writeValueAsString(request))) .andDo(print()) .andDo(print()) Loading @@ -53,9 +62,60 @@ public class ArchiveFileControllerTest { verify(archiveService, times(1)).createArchive(argThat(job -> { verify(archiveService, times(1)).createArchive(argThat(job -> { assertEquals("123", job.getJobId()); assertEquals("123", job.getJobId()); assertEquals(ArchiveJob.Type.TAR, job.getType()); assertEquals(ArchiveJob.Type.TAR, job.getType()); assertEquals("anonymous", job.getPrincipal().getName()); assertEquals("user1", job.getPrincipal().getName()); assertEquals(2, job.getVosPaths().size()); assertEquals(2, job.getVosPaths().size()); return true; return true; })); })); } } @Test public void testGetArchive() throws Exception { File tmpDir = Files.createTempDirectory("tmp").toFile(); try { tmpDir.toPath().resolve("123.zip").toFile().createNewFile(); when(archiveService.getArchiveParentDir(any())).thenReturn(tmpDir); mockMvc.perform(get("/archive/123.zip") .principal(fakePrincipal("user1"))) .andDo(print()) .andExpect(status().isOk()); } finally { FileSystemUtils.deleteRecursively(tmpDir); } } @Test public void testAnonymousCantCreateArchive() throws Exception { ArchiveRequest request = new ArchiveRequest(); request.setJobId("123"); request.setType("ZIP"); request.setPaths(Arrays.asList("/ignore")); mockMvc.perform(post("/archive") .principal(fakePrincipal("anonymous")) .contentType(MediaType.APPLICATION_JSON) .content(MAPPER.writeValueAsString(request))) .andDo(print()) .andExpect(status().isForbidden()); } @Test public void testAnonymousCantGetArchive() throws Exception { mockMvc.perform(get("/archive/123.zip") .principal(fakePrincipal("anonymous"))) .andDo(print()) .andExpect(status().isForbidden()); } private TokenPrincipal fakePrincipal(String name) { TokenPrincipal principal = mock(TokenPrincipal.class); when(principal.getName()).thenReturn(name); return principal; } } } Loading
src/main/java/it/inaf/ia2/transfer/controller/ArchiveFileController.java +13 −6 Original line number Original line Diff line number Diff line Loading @@ -6,12 +6,12 @@ package it.inaf.ia2.transfer.controller; package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.exception.PermissionDeniedException; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveJob.Type; import it.inaf.ia2.transfer.service.ArchiveJob.Type; import it.inaf.ia2.transfer.service.ArchiveService; import it.inaf.ia2.transfer.service.ArchiveService; import java.io.File; import java.io.File; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders; Loading @@ -30,9 +30,6 @@ public class ArchiveFileController extends FileController { @Autowired @Autowired private ArchiveService archiveService; private ArchiveService archiveService; @Autowired private HttpServletRequest request; @Autowired @Autowired private HttpServletResponse response; private HttpServletResponse response; Loading @@ -42,7 +39,7 @@ public class ArchiveFileController extends FileController { Type type = Type.valueOf(archiveRequest.getType()); Type type = Type.valueOf(archiveRequest.getType()); ArchiveJob job = new ArchiveJob(); ArchiveJob job = new ArchiveJob(); job.setPrincipal((TokenPrincipal) request.getUserPrincipal()); job.setPrincipal(getPrincipal()); job.setJobId(archiveRequest.getJobId()); job.setJobId(archiveRequest.getJobId()); job.setType(type); job.setType(type); job.setVosPaths(archiveRequest.getPaths()); job.setVosPaths(archiveRequest.getPaths()); Loading @@ -59,10 +56,20 @@ public class ArchiveFileController extends FileController { @GetMapping(value = "/archive/{fileName}") @GetMapping(value = "/archive/{fileName}") public void getArchiveFile(@PathVariable("fileName") String fileName) { public void getArchiveFile(@PathVariable("fileName") String fileName) { TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); TokenPrincipal principal = getPrincipal(); File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile(); File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile(); FileResponseUtil.getFileResponse(response, file); FileResponseUtil.getFileResponse(response, file); } } private TokenPrincipal getPrincipal() { TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); if ("anonymous".equals(principal.getName())) { throw new PermissionDeniedException("Tar/Zip archive generation not allowed to anonymous users"); } return principal; } } }
src/main/java/it/inaf/ia2/transfer/controller/GetFileController.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -65,7 +65,7 @@ public class GetFileController extends FileController { FileInfo fileInfo = optFileInfo.get(); FileInfo fileInfo = optFileInfo.get(); if (!authorizationService.isDownloadable(fileInfo, (TokenPrincipal) request.getUserPrincipal())) { if (!authorizationService.isDownloadable(fileInfo, (TokenPrincipal) request.getUserPrincipal())) { throw new PermissionDeniedException(path); throw new PermissionDeniedException("PermissionDenied Path: " + path); } } File file = new File(fileInfo.getOsPath()); File file = new File(fileInfo.getOsPath()); Loading
src/main/java/it/inaf/ia2/transfer/exception/PermissionDeniedException.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -11,8 +11,8 @@ import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(value = HttpStatus.FORBIDDEN) @ResponseStatus(value = HttpStatus.FORBIDDEN) public class PermissionDeniedException extends JobException { public class PermissionDeniedException extends JobException { public PermissionDeniedException(String path) { public PermissionDeniedException(String errorDetail) { super(Type.FATAL, "Permission Denied"); super(Type.FATAL, "Permission Denied"); setErrorDetail("PermissionDenied Path: " + path); setErrorDetail(errorDetail); } } } }
src/test/java/it/inaf/ia2/transfer/controller/ArchiveFileControllerTest.java +62 −2 Original line number Original line Diff line number Diff line Loading @@ -6,26 +6,34 @@ package it.inaf.ia2.transfer.controller; package it.inaf.ia2.transfer.controller; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveService; import it.inaf.ia2.transfer.service.ArchiveService; import java.io.File; import java.nio.file.Files; import java.util.Arrays; import java.util.Arrays; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.util.FileSystemUtils; @SpringBootTest @SpringBootTest @AutoConfigureMockMvc @AutoConfigureMockMvc(addFilters = false) public class ArchiveFileControllerTest { public class ArchiveFileControllerTest { private static final ObjectMapper MAPPER = new ObjectMapper(); private static final ObjectMapper MAPPER = new ObjectMapper(); Loading @@ -45,6 +53,7 @@ public class ArchiveFileControllerTest { request.setPaths(Arrays.asList("/path/to/file1", "/path/to/file2")); request.setPaths(Arrays.asList("/path/to/file1", "/path/to/file2")); mockMvc.perform(post("/archive") mockMvc.perform(post("/archive") .principal(fakePrincipal("user1")) .contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .content(MAPPER.writeValueAsString(request))) .content(MAPPER.writeValueAsString(request))) .andDo(print()) .andDo(print()) Loading @@ -53,9 +62,60 @@ public class ArchiveFileControllerTest { verify(archiveService, times(1)).createArchive(argThat(job -> { verify(archiveService, times(1)).createArchive(argThat(job -> { assertEquals("123", job.getJobId()); assertEquals("123", job.getJobId()); assertEquals(ArchiveJob.Type.TAR, job.getType()); assertEquals(ArchiveJob.Type.TAR, job.getType()); assertEquals("anonymous", job.getPrincipal().getName()); assertEquals("user1", job.getPrincipal().getName()); assertEquals(2, job.getVosPaths().size()); assertEquals(2, job.getVosPaths().size()); return true; return true; })); })); } } @Test public void testGetArchive() throws Exception { File tmpDir = Files.createTempDirectory("tmp").toFile(); try { tmpDir.toPath().resolve("123.zip").toFile().createNewFile(); when(archiveService.getArchiveParentDir(any())).thenReturn(tmpDir); mockMvc.perform(get("/archive/123.zip") .principal(fakePrincipal("user1"))) .andDo(print()) .andExpect(status().isOk()); } finally { FileSystemUtils.deleteRecursively(tmpDir); } } @Test public void testAnonymousCantCreateArchive() throws Exception { ArchiveRequest request = new ArchiveRequest(); request.setJobId("123"); request.setType("ZIP"); request.setPaths(Arrays.asList("/ignore")); mockMvc.perform(post("/archive") .principal(fakePrincipal("anonymous")) .contentType(MediaType.APPLICATION_JSON) .content(MAPPER.writeValueAsString(request))) .andDo(print()) .andExpect(status().isForbidden()); } @Test public void testAnonymousCantGetArchive() throws Exception { mockMvc.perform(get("/archive/123.zip") .principal(fakePrincipal("anonymous"))) .andDo(print()) .andExpect(status().isForbidden()); } private TokenPrincipal fakePrincipal(String name) { TokenPrincipal principal = mock(TokenPrincipal.class); when(principal.getName()).thenReturn(name); return principal; } } }