diff --git a/alfa-server/src/main/resources/application.yml b/alfa-server/src/main/resources/application.yml index 521222a6f86965335ce7a54b6387c1d76902649a..7e2109ed1ed9d0638cd233a78efcc2bfb7d32938 100644 --- a/alfa-server/src/main/resources/application.yml +++ b/alfa-server/src/main/resources/application.yml @@ -8,6 +8,8 @@ spring: mvc: pathmatch: matching-strategy: ant-path-matcher + async: + request-timeout: -1 application: name: Alfa jackson: @@ -105,3 +107,5 @@ ozgcloud: search-template: /api/userProfiles/?searchBy={searchBy} dms: enabled: false + domain: + url-pattern: https://*.ozg-cloud.de diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/SecurityConfiguration.java b/alfa-service/src/main/java/de/ozgcloud/alfa/SecurityConfiguration.java index 6b087870a02467be4075bd09bfcb38dae0689c3e..c0036e2317eb30ded804e5196cc62c487b40bf63 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/SecurityConfiguration.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/SecurityConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -74,9 +75,10 @@ public class SecurityConfiguration { .requestMatchers("/*").permitAll() .anyRequest().denyAll()); - http.oauth2ResourceServer(this::setOAuth2ResourceServer); - http.headers(headers -> headers.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))); - http.addFilterBefore(downloadTokenFilter, UsernamePasswordAuthenticationFilter.class); + http.oauth2ResourceServer(this::setOAuth2ResourceServer) + .headers(headers -> headers.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))) + .addFilterBefore(downloadTokenFilter, UsernamePasswordAuthenticationFilter.class) + .cors(Customizer.withDefaults()); return http.build(); } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java index 388dbd757bc6091527ad6c54a1c77c1358dfbe2a..911717902889dfc59197573842a89151a6792c83 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java @@ -28,6 +28,7 @@ import java.util.Optional; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -53,6 +54,7 @@ class OrganisationsEinheitController { return ResponseEntity.of(Optional.of(service.getById(organisationsEinheitId)).map(assembler::toModel)); } + @CrossOrigin(originPatterns = "${ozgcloud.domain.url-pattern:https://*.ozg-cloud.de}") @GetMapping(params = { SEARCH_BY_PARAM }) public CollectionModel<EntityModel<OrganisationsEinheitHeader>> search(@RequestParam String searchBy) { return headerModelAssembler.toCollectionModel(service.searchOrganisationsEinheiten(searchBy).toList()); diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/zipdownload/ZipDownloadService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/zipdownload/ZipDownloadService.java index 11cc784f97b2dc4937fe06b3172fd865fb154466..c03fb379a9592a13027fe788bfa6429db68245e4 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/zipdownload/ZipDownloadService.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/zipdownload/ZipDownloadService.java @@ -28,6 +28,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.nio.file.Files; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -39,15 +40,22 @@ import de.ozgcloud.alfa.common.file.OzgFile; import de.ozgcloud.common.binaryfile.TempFileUtils; import de.ozgcloud.common.errorhandling.TechnicalException; import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; @Service @RequiredArgsConstructor +@Log4j2 public class ZipDownloadService { private final BinaryFileService binaryFileService; public void write(List<OzgFile> ozgFiles, OutputStream out) { - writeZipFileContent(createZipFile(ozgFiles), out); + var file = createZipFile(ozgFiles); + try { + writeZipFileContent(file, out); + } finally { + deleteFile(file); + } } File createZipFile(List<OzgFile> ozgFiles) { @@ -56,6 +64,7 @@ public class ZipDownloadService { ozgFiles.forEach(ozgFile -> addOzgFileToZip(ozgFile, zipOutputStream)); return file; } catch (Exception e) { + deleteFile(file); throw new TechnicalException("Error creating zip file", e); } } @@ -78,4 +87,11 @@ public class ZipDownloadService { } } + void deleteFile(File file) { + try { + Files.deleteIfExists(file.toPath()); + } catch (IOException e) { + LOG.error("Cannot delete file at path %s".formatted(file.toPath()), e); + } + } } diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/zipdownload/ZipDownloadServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/zipdownload/ZipDownloadServiceTest.java index d99563514593561d1d90c7ef96f61cf00c3e3109..f461bf1db6a95a317b8dfa1bd9934ae2fef3e699 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/zipdownload/ZipDownloadServiceTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/zipdownload/ZipDownloadServiceTest.java @@ -33,6 +33,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Path; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -49,6 +50,7 @@ import org.mockito.Spy; import de.ozgcloud.alfa.common.binaryfile.BinaryFileService; import de.ozgcloud.alfa.common.file.OzgFile; import de.ozgcloud.alfa.common.file.OzgFileTestFactory; +import de.ozgcloud.common.binaryfile.TempFileUtils; import de.ozgcloud.common.errorhandling.TechnicalException; import lombok.SneakyThrows; @@ -68,8 +70,16 @@ public class ZipDownloadServiceTest { @Mock private File zipFile; + @BeforeEach + void init() { + doReturn(zipFile).when(service).createZipFile(ozgFiles); + doNothing().when(service).deleteFile(any()); + } + @Test void shouldCreateZipFile() { + doNothing().when(service).writeZipFileContent(zipFile, outputStream); + callService(); verify(service).createZipFile(ozgFiles); @@ -77,7 +87,6 @@ public class ZipDownloadServiceTest { @Test void shouldWriteZipFileContent() { - doReturn(zipFile).when(service).createZipFile(ozgFiles); doNothing().when(service).writeZipFileContent(zipFile, outputStream); callService(); @@ -85,6 +94,25 @@ public class ZipDownloadServiceTest { verify(service).writeZipFileContent(zipFile, outputStream); } + @Test + @SneakyThrows + void shouldDeleteFile() { + doNothing().when(service).writeZipFileContent(zipFile, outputStream); + + callService(); + + verify(service).deleteFile(zipFile); + } + + @Test + void shouldDeleteFileAfterException() { + doThrow(new RuntimeException()).when(service).writeZipFileContent(zipFile, outputStream); + + assertThrows(RuntimeException.class, this::callService); + + verify(service).deleteFile(zipFile); + } + private void callService() { service.write(ozgFiles, outputStream); } @@ -144,11 +172,23 @@ public class ZipDownloadServiceTest { @Test void shouldThrowTechnicalException() { + doNothing().when(service).deleteFile(any()); + doThrow(TechnicalException.class).when(service).addOzgFileToZip(any(), any()); assertThrows(TechnicalException.class, this::callService); } + @Test + void shouldDeleteFileAfterException() { + doThrow(TechnicalException.class).when(service).addOzgFileToZip(any(), any()); + doNothing().when(service).deleteFile(any()); + + assertThrows(TechnicalException.class, this::callService); + + verify(service).deleteFile(file); + } + private File callService() { return service.createZipFile(ozgFiles); } @@ -282,4 +322,25 @@ public class ZipDownloadServiceTest { } } + + @Nested + class TestDeleteFile { + + @Test + void shouldDeleteFile() { + var file = TempFileUtils.createTmpFile().toFile(); + + service.deleteFile(file); + + assertThat(file).doesNotExist(); + } + + @Test + void shouldNotThrowException() { + var file = Path.of("path").toFile(); + + assertThatNoException().isThrownBy(() -> service.deleteFile(file)); + } + + } }