From 3a251f5e88daa755a3efaf7176698cb48d39a8d7 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Fri, 1 Sep 2023 16:01:31 +0200 Subject: [PATCH 01/18] #36 Add issue id to fixme tags Signed-off-by: Sven Strittmatter --- .../defectdojo/service/DefaultImportScanService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java index 83f74a9e..62b9ea37 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java @@ -85,7 +85,7 @@ private ImportScanResponse createFindings(ScanFile scanFile, String endpoint, lo // 2. the raw scan result as file headers.setContentType(MediaType.MULTIPART_FORM_DATA); - // FIXME: Why do we use a multi value map here? Do we need multiple values for any given key? + // FIXME: #36 Why do we use a multi value map here? Do we need multiple values for any given key? final var body = new LinkedMultiValueMap(); body.add("lead", Long.toString(lead)); @@ -100,7 +100,7 @@ private ImportScanResponse createFindings(ScanFile scanFile, String endpoint, lo body.remove(optionName); } - // FIXME: Workaround due to type incompatibility of MultiValueMap and MultiValueMap. + // FIXME: #36 Workaround due to type incompatibility of MultiValueMap and MultiValueMap. for (final var option : options.entrySet()) { body.add(option.getKey(), option.getValue()); } @@ -114,7 +114,7 @@ public String getFilename() { } }; - // FIXME: Why do we add the whole byte array resource here as object? Is not simply the file name sufficient here? Then we could use + // FIXME: #36 Why do we add the whole byte array resource here as object? Is not simply the file name sufficient here? Then we could use // We send the whole file content, so DefectDojo can parse the finding by itself. body.add("file", contentsAsResource); From 83caaa8adf881738dd7b22ece70587e65ede141e Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Fri, 1 Sep 2023 16:34:45 +0200 Subject: [PATCH 02/18] #36 Make the default name a constant Signed-off-by: Sven Strittmatter --- .../persistence/defectdojo/model/ScanFile.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/ScanFile.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/ScanFile.java index 38047538..6eb8b511 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/ScanFile.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/ScanFile.java @@ -8,18 +8,24 @@ @Data public class ScanFile { + /** + * A default name must be set + *

+ * It does not matter however unless the parser pays attention to file endings like json or xml. + *

+ */ + static final String DEFAULT_NAME = "default-name.txt"; String content; - // a default name must be set, it does not matter however - // unless the parser pays attention to file endings like json or xml - String name = "default-name.txt"; + String name; - public ScanFile(String content){ - this.content = content; + public ScanFile(String content) { + this(content, DEFAULT_NAME); } - public ScanFile(String content, String name){ + public ScanFile(String content, String name) { + super(); this.content = content; this.name = name; } From 5fe20e9aade2838d812cb113110d49cb19aa806b Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Fri, 1 Sep 2023 17:26:56 +0200 Subject: [PATCH 03/18] #36 Remove obsolete comment Signed-off-by: Sven Strittmatter --- .../persistence/defectdojo/service/DefaultImportScanService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java index 62b9ea37..9183233b 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java @@ -114,7 +114,6 @@ public String getFilename() { } }; - // FIXME: #36 Why do we add the whole byte array resource here as object? Is not simply the file name sufficient here? Then we could use // We send the whole file content, so DefectDojo can parse the finding by itself. body.add("file", contentsAsResource); From 68e93a9725794ac3cc7e2cc1413c2b2fa84ba632 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Fri, 1 Sep 2023 17:40:22 +0200 Subject: [PATCH 04/18] Revert "#36 Extract network side effect into interface so we can mock this out in the tests" This reverts commit 99b039f9e9b6573b399c0f32e8687da1af3b8283. Signed-off-by: Sven Strittmatter --- .../service/DefaultImportScanService.java | 203 ++++++++---------- .../service/DefaultHttpRequesterTest.java | 137 ------------ .../service/DefaultImportScanServiceTest.java | 143 +++++++++++- 3 files changed, 234 insertions(+), 249 deletions(-) delete mode 100644 src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultHttpRequesterTest.java diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java index 9183233b..07a557f9 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java @@ -44,7 +44,7 @@ class DefaultImportScanService implements ImportScanService { new FormHttpMessageConverter(), new ResourceHttpMessageConverter(), new MappingJackson2HttpMessageConverter()); - private final HttpRequester requester = new DefaultHttpRequester(); + private final SystemPropertyFinder properties = new SystemPropertyFinder(); @Getter private final String defectDojoUrl; @Getter @@ -118,12 +118,26 @@ public String getFilename() { body.add("file", contentsAsResource); final var payload = new HttpEntity>(body, headers); - return requester.exchange(generateApiUrl(endpoint), payload); + return exchangeRequest(endpoint, payload); } catch (HttpClientErrorException e) { throw new PersistenceException("Failed to attach findings to engagement."); } } + ImportScanResponse exchangeRequest(String endpoint, HttpEntity payload) { + final var restTemplate = this.createRestTemplate(); + return restTemplate.exchange( + generateApiUrl(endpoint), + HttpMethod.POST, + payload, + ImportScanResponse.class) + .getBody(); + } + + String generateApiUrl(final String endpoint) { + return String.format("%s/api/v2/%s/", getDefectDojoUrl(), endpoint); + } + /** * The DefectDojo Authentication Header * @@ -135,133 +149,104 @@ HttpHeaders createDefectDojoAuthorizationHeaders() { return authorizationHeader; } - String generateApiUrl(final String endpoint) { - return String.format("%s/api/v2/%s/", getDefectDojoUrl(), endpoint); - } + private RestTemplate createRestTemplate() { + final var template = new RestTemplate(); - private static class SystemPropertyFinder { - private boolean hasProperty(@NonNull final ProxyConfigNames name) { - return System.getProperty(name.getLiterat()) != null; + if (shouldConfigureProxySettings()) { + template.setRequestFactory(createRequestFactoryWithProxyAuthConfig()); } - private boolean notHasProperty(@NonNull final ProxyConfigNames name) { - return !hasProperty(name); - } + template.setMessageConverters(HTTP_MESSAGE_CONVERTERS); - private String getProperty(@NonNull final ProxyConfigNames name) { - return System.getProperty(name.getLiterat()); - } + return template; } - final static class MissingProxyAuthenticationConfig extends RuntimeException { - MissingProxyAuthenticationConfig(ProxyConfigNames name) { - super(String.format("Expected System property '%s' not set!", name.getLiterat())); - } + boolean shouldConfigureProxySettings() { + return properties.hasProperty(ProxyConfigNames.HTTP_PROXY_USER) + && properties.hasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD); } /** - * This interface abstracts the network side effect done by the underlying HTTP + * Configuring proxy authentication explicitly + * + *

+ * This isn't done by default for spring rest templates.This method expects these four system properties (Java flag + * {@literal -DpropertyName}) to be set: + *

+ *
    + *
  • http.proxyUser
  • + *
  • http.proxyPassword
  • + *
  • http.proxyHost
  • + *
  • http.proxyPort
  • + *
+ * + * @return never {@code null} */ - interface HttpRequester { - ImportScanResponse exchange(String endpoint, HttpEntity payload); - } + ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() { + if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_USER)) { + throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_USER); + } - /** - * Default implementation which utilizes {@link RestTemplate} - */ - static final class DefaultHttpRequester implements HttpRequester { - private final SystemPropertyFinder properties = new SystemPropertyFinder(); - - @Override - public ImportScanResponse exchange(final String url, final HttpEntity payload) { - final var restTemplate = this.createRestTemplate(); - return restTemplate.exchange( - url, - HttpMethod.POST, - payload, - ImportScanResponse.class) - .getBody(); + if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) { + throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PASSWORD); + } + + if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_HOST)) { + throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_HOST); + } + + if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PORT)) { + throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PORT); } - private RestTemplate createRestTemplate() { - final var template = new RestTemplate(); + final var proxyHost = properties.getProperty(ProxyConfigNames.HTTP_PROXY_HOST); + final int proxyPort; + try { + proxyPort = Integer.parseInt(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PORT)); + } catch (final NumberFormatException e) { + throw new IllegalArgumentException( + String.format("Given port for proxy authentication configuration (property '%s') is not a valid number! Given value wa '%s'.", + ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), + System.getProperty("http.proxyPort")), + e); + } - if (shouldConfigureProxySettings()) { - template.setRequestFactory(createRequestFactoryWithProxyAuthConfig()); - } + final var credentials = new BasicCredentialsProvider(); + credentials.setCredentials( + new AuthScope(proxyHost, proxyPort), + new UsernamePasswordCredentials( + properties.getProperty(ProxyConfigNames.HTTP_PROXY_USER), + properties.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) + ); + + final var clientBuilder = HttpClientBuilder.create(); + clientBuilder.useSystemProperties(); + clientBuilder.setProxy(new HttpHost(proxyHost, proxyPort)); + clientBuilder.setDefaultCredentialsProvider(credentials); + clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()); + + final var factory = new HttpComponentsClientHttpRequestFactory(); + factory.setHttpClient(clientBuilder.build()); + return factory; + } - template.setMessageConverters(HTTP_MESSAGE_CONVERTERS); + private static class SystemPropertyFinder { + private boolean hasProperty(@NonNull final ProxyConfigNames name) { + return System.getProperty(name.getLiterat()) != null; + } - return template; + private boolean notHasProperty(@NonNull final ProxyConfigNames name) { + return !hasProperty(name); } - boolean shouldConfigureProxySettings() { - return properties.hasProperty(ProxyConfigNames.HTTP_PROXY_USER) - && properties.hasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD); + private String getProperty(@NonNull final ProxyConfigNames name) { + return System.getProperty(name.getLiterat()); } + } - /** - * Configuring proxy authentication explicitly - * - *

- * This isn't done by default for spring rest templates.This method expects these four system properties (Java flag - * {@literal -DpropertyName}) to be set: - *

- *
    - *
  • http.proxyUser
  • - *
  • http.proxyPassword
  • - *
  • http.proxyHost
  • - *
  • http.proxyPort
  • - *
- * - * @return never {@code null} - */ - ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() { - if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_USER)) { - throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_USER); - } - - if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) { - throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PASSWORD); - } - - if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_HOST)) { - throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_HOST); - } - - if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PORT)) { - throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PORT); - } - - final var proxyHost = properties.getProperty(ProxyConfigNames.HTTP_PROXY_HOST); - final int proxyPort; - try { - proxyPort = Integer.parseInt(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PORT)); - } catch (final NumberFormatException e) { - throw new IllegalArgumentException( - String.format("Given port for proxy authentication configuration (property '%s') is not a valid number! Given value wa '%s'.", - ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), - System.getProperty("http.proxyPort")), - e); - } - - final var credentials = new BasicCredentialsProvider(); - credentials.setCredentials( - new AuthScope(proxyHost, proxyPort), - new UsernamePasswordCredentials( - properties.getProperty(ProxyConfigNames.HTTP_PROXY_USER), - properties.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) - ); - - final var clientBuilder = HttpClientBuilder.create(); - clientBuilder.useSystemProperties(); - clientBuilder.setProxy(new HttpHost(proxyHost, proxyPort)); - clientBuilder.setDefaultCredentialsProvider(credentials); - clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()); - - final var factory = new HttpComponentsClientHttpRequestFactory(); - factory.setHttpClient(clientBuilder.build()); - return factory; + final static class MissingProxyAuthenticationConfig extends RuntimeException { + MissingProxyAuthenticationConfig(ProxyConfigNames name) { + super(String.format("Expected System property '%s' not set!", name.getLiterat())); } } } diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultHttpRequesterTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultHttpRequesterTest.java deleted file mode 100644 index 84be4edb..00000000 --- a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultHttpRequesterTest.java +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-FileCopyrightText: the secureCodeBox authors -// -// SPDX-License-Identifier: Apache-2.0 - -package io.securecodebox.persistence.defectdojo.service; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import uk.org.webcompere.systemstubs.jupiter.SystemStub; -import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; -import uk.org.webcompere.systemstubs.properties.SystemProperties; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * Tests for {@link DefaultHttpRequesterTest} - */ -@ExtendWith(SystemStubsExtension.class) -final class DefaultHttpRequesterTest { - @SystemStub - - private SystemProperties systemProperties; - private final DefaultImportScanService.DefaultHttpRequester sut = new DefaultImportScanService.DefaultHttpRequester(); - - @Test - void shouldConfigureProxySettings_falseIfNeitherUserNorPasswordIsSet() { - assertThat(sut.shouldConfigureProxySettings(), is(false)); - } - - @Test - void shouldConfigureProxySettings_falseIfUserSetButPasswordNot() throws Exception { - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - - systemProperties.execute(() -> { - assertThat(sut.shouldConfigureProxySettings(), is(false)); - }); - } - - @Test - void shouldConfigureProxySettings_falseIfPasswordSetButUserNot() throws Exception { - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - - systemProperties.execute(() -> { - assertThat(sut.shouldConfigureProxySettings(), is(false)); - }); - } - - @Test - void shouldConfigureProxySettings_trueIfUserAndPasswordSet() throws Exception { - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - - systemProperties.execute(() -> { - assertThat(sut.shouldConfigureProxySettings(), is(true)); - }); - } - - @Test - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfUserNotSet() throws Exception { - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); - - systemProperties.execute(() -> { - final var thrown = assertThrows( - DefaultImportScanService.MissingProxyAuthenticationConfig.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyUser' not set!")); - }); - } - - @Test - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPasswordNotSet() throws Exception { - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); - - systemProperties.execute(() -> { - final var thrown = assertThrows( - DefaultImportScanService.MissingProxyAuthenticationConfig.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPassword' not set!")); - }); - } - - @Test - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfHostNotSet() throws Exception { - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); - - systemProperties.execute(() -> { - final var thrown = assertThrows( - DefaultImportScanService.MissingProxyAuthenticationConfig.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyHost' not set!")); - }); - } - - @Test - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortNotSet() throws Exception { - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - - systemProperties.execute(() -> { - final var thrown = assertThrows( - DefaultImportScanService.MissingProxyAuthenticationConfig.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPort' not set!")); - }); - } - - @Test - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortIsNotInteger() throws Exception { - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - systemProperties.set(ImportScanService.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "FUBAR"); - - systemProperties.execute(() -> { - final var thrown = assertThrows( - IllegalArgumentException.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat( - thrown.getMessage(), - is("Given port for proxy authentication configuration (property 'http.proxyPort') is not a valid number! Given value wa 'FUBAR'.")); - }); - } -} diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java index 538eaff7..63e64549 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java @@ -5,13 +5,21 @@ package io.securecodebox.persistence.defectdojo.service; import io.securecodebox.persistence.defectdojo.config.Config; +import io.securecodebox.persistence.defectdojo.service.DefaultImportScanService.MissingProxyAuthenticationConfig; +import io.securecodebox.persistence.defectdojo.service.ImportScanService.ProxyConfigNames; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; +import java.util.HashMap; +import java.util.Map; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Tests for {@link DefaultImportScanService} @@ -23,6 +31,32 @@ class DefaultImportScanServiceTest { 23 ); private final DefaultImportScanService sut = new DefaultImportScanService(config); + /** + * Since System.getProperty() is an side effect we need to back up and restore it to isolate test cases. + */ + private final Map backup = new HashMap<>(); + + @BeforeEach + void backupSystemProperties() { + backup.clear(); + backup.put(ProxyConfigNames.HTTP_PROXY_HOST, System.getProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat())); + backup.put(ProxyConfigNames.HTTP_PROXY_PORT, System.getProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat())); + backup.put(ProxyConfigNames.HTTP_PROXY_USER, System.getProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat())); + backup.put(ProxyConfigNames.HTTP_PROXY_PASSWORD, System.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat())); + } + + @AfterEach + void restoreSystemProperties() { + for (final var entry : backup.entrySet()) { + final var name = entry.getKey().getLiterat(); + + if (null == entry.getValue()) { + System.clearProperty(name); + } else { + System.setProperty(name, entry.getValue()); + } + } + } @Test void constructorShouldThrowExceptionOnNullConfig() { @@ -32,15 +66,118 @@ void constructorShouldThrowExceptionOnNullConfig() { } @Test - void createDefectDojoAuthorizationHeaders_apiKeyFromConfigShouldBePresentAsAuthHeader() { + void createDefectDojoAuthorizationHeaders_apiKeyFromConfigShouldBePresentAsAuthHEader() { final var authorizationHeaders = sut.createDefectDojoAuthorizationHeaders(); - assertAll( () -> assertThat(authorizationHeaders.size(), is(1)), () -> assertThat(authorizationHeaders.get(HttpHeaders.AUTHORIZATION).get(0), is("Token apiKey")) ); } + @Test + void shouldConfigureProxySettings_falseIfNeitherUserNorPasswordIsSet() { + System.clearProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); + + assertThat(sut.shouldConfigureProxySettings(), is(false)); + } + + @Test + void shouldConfigureProxySettings_falseIfUserSetButPasswordNot() { + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); + + assertThat(sut.shouldConfigureProxySettings(), is(false)); + } + + @Test + void shouldConfigureProxySettings_falseIfPasswordSetButUserNot() { + System.clearProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + + assertThat(sut.shouldConfigureProxySettings(), is(false)); + } + + @Test + void shouldConfigureProxySettings_trueIfUserAndPasswordSet() { + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + + assertThat(sut.shouldConfigureProxySettings(), is(true)); + } + + @Test + void createRequestFactoryWithProxyAuthConfig_throesExceptionIfUserNotSet() { + System.clearProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + + final var thrown = assertThrows( + MissingProxyAuthenticationConfig.class, + sut::createRequestFactoryWithProxyAuthConfig); + + assertThat(thrown.getMessage(), is("Expected System property 'http.proxyUser' not set!")); + } + + @Test + void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPasswordNotSet() { + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); + System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + + final var thrown = assertThrows( + MissingProxyAuthenticationConfig.class, + sut::createRequestFactoryWithProxyAuthConfig); + + assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPassword' not set!")); + } + + @Test + void createRequestFactoryWithProxyAuthConfig_throesExceptionIfHostNotSet() { + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat()); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + + final var thrown = assertThrows( + MissingProxyAuthenticationConfig.class, + sut::createRequestFactoryWithProxyAuthConfig); + + assertThat(thrown.getMessage(), is("Expected System property 'http.proxyHost' not set!")); + } + + @Test + void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortNotSet() { + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat()); + + final var thrown = assertThrows( + MissingProxyAuthenticationConfig.class, + sut::createRequestFactoryWithProxyAuthConfig); + + assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPort' not set!")); + } + + @Test + void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortIsNotInteger() { + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "FUBAR"); + + final var thrown = assertThrows( + IllegalArgumentException.class, + sut::createRequestFactoryWithProxyAuthConfig); + + assertThat( + thrown.getMessage(), + is("Given port for proxy authentication configuration (property 'http.proxyPort') is not a valid number! Given value wa 'FUBAR'.")); + } + @Test void generateApiUrl() { assertThat(sut.generateApiUrl("foo"), is("http://localhost/api/v2/foo/")); From fe5d64938a5e4ad8bccd0191ba13343f470a70e7 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sat, 2 Sep 2023 14:07:42 +0200 Subject: [PATCH 05/18] #36 Add class to hold proxy configuration will be used later to remove code duplication in the services. Signed-off-by: Sven Strittmatter --- .../defectdojo/http/ProxyConfig.java | 84 +++++++++++++++++++ .../defectdojo/http/ProxyConfigTest.java | 83 ++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java create mode 100644 src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java new file mode 100644 index 00000000..54050a5e --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java @@ -0,0 +1,84 @@ +package io.securecodebox.persistence.defectdojo.http; + +import lombok.Builder; +import lombok.Value; + +/** + * Holds HTTP proxy configuration + *

+ * This class is immutable by design and therefor thread safe. As defaults it does not use |{@code null} to prevent null + * pointer exceptions. It utilizes sane defaults (empty string or 0) to indicate a not set value. Also it introduces a + * null-object to indicate a not-existing configuration. + *

+ */ +@Value +@Builder +class ProxyConfig { + /** + * Null pattern object. + */ + static final ProxyConfig NULL = ProxyConfig.builder().build(); + private static final String DEFAULT_STRING = ""; + private static final int DEFAULT_INT = 0; + + /** + * Username to authenticate on a proxy. + *

+ * Defaults to empty string. + *

+ */ + @Builder.Default + String user = DEFAULT_STRING; + + /** + * Password to authenticate on a proxy. + *

+ * Defaults to empty string. + *

+ */ + @Builder.Default + String password = DEFAULT_STRING; + + /** + * Host name of the proxy. + *

+ * Defaults to empty string. + *

+ */ + @Builder.Default + String host = DEFAULT_STRING; + + /** + * Port of the proxy. + *

+ * Defaults to 0 (zero). + *

+ */ + @Builder.Default + int port = DEFAULT_INT; + + /** + * configuration is considered complete if all values are not default values + * + * @return {@code true} if all values are set else {@code false} + */ + boolean isComplete() { + if (getUser().equals(DEFAULT_STRING)) { + return false; + } + + if (getPassword().equals(DEFAULT_STRING)) { + return false; + } + + if (getHost().equals(DEFAULT_STRING)) { + return false; + } + + if (getPort() == DEFAULT_INT) { + return false; + } + + return true; + } +} diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java new file mode 100644 index 00000000..4663561e --- /dev/null +++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java @@ -0,0 +1,83 @@ +package io.securecodebox.persistence.defectdojo.http; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +/** + * Tests for {@link ProxyConfig} + */ +class ProxyConfigTest { + @Test + void equalsAndHashCode() { + EqualsVerifier.forClass(ProxyConfig.class).verify(); + } + + @Test + void builderCreatesDefault() { + final var sut = ProxyConfig.builder().build(); + + assertAll( + () -> assertThat(sut.getUser(), is(emptyString())), + () -> assertThat(sut.getPassword(), is(emptyString())), + () -> assertThat(sut.getHost(), is(emptyString())), + () -> assertThat(sut.getPort(), is(0)) + ); + } + + @Test + void buildersDefaultIsEqualToNullObject() { + assertThat(ProxyConfig.builder().build(), is(ProxyConfig.NULL)); + } + + @Test + void isComplete_falseForNullObject() { + assertThat(ProxyConfig.NULL.isComplete(), is(false)); + } + + @Test + void isComplete_falseForDefault() { + assertThat(ProxyConfig.builder().build().isComplete(), is(false)); + } + + @ParameterizedTest + @MethodSource("incompleteConfigs") + void isComplete_falseUnlessAllFieldsAreSet(final ProxyConfig sut) { + + } + + private static Stream incompleteConfigs() { + return Stream.of( + // Only one is set: + Arguments.of(ProxyConfig.builder().user("user").build()), + Arguments.of(ProxyConfig.builder().password("pw").build()), + Arguments.of(ProxyConfig.builder().host("host").build()), + Arguments.of(ProxyConfig.builder().port(42).build()), + // All but one is set: + Arguments.of(ProxyConfig.builder().password("pwd").host("host").port(42).build()), + Arguments.of(ProxyConfig.builder().user("user").host("host").port(42).build()), + Arguments.of(ProxyConfig.builder().user("user").password("pwd").port(42).build()), + Arguments.of(ProxyConfig.builder().user("user").password("pwd").host("host").build()) + ); + } + + @Test + void isComplete_trueIfAllFieldsAreNonDefaults() { + final var sut = ProxyConfig.builder() + .user("user") + .password("pw") + .host("host") + .port(42) + .build(); + + assertThat(sut.isComplete(), is(true)); + } +} From 79108cbe81350385f4350a7cb27c068ce55cd3f5 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 14:34:16 +0200 Subject: [PATCH 06/18] #36 Fix robert's lastname Signed-off-by: Sven Strittmatter --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 8ce11f6a..8e897012 100644 --- a/pom.xml +++ b/pom.xml @@ -42,9 +42,9 @@ jannik.hollenbach@iteratec.com - robert.seedorff - Robert Seedorff - robert.seedorff@iteratec.com + robert.felber + Robert Felber + robert.felber@iteratec.com johannes.zahn From 185028f2330e836b62e437831e8e28ca461629be Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 14:44:03 +0200 Subject: [PATCH 07/18] #36 Add facotry to create proxy config from system properties Signed-off-by: Sven Strittmatter --- .../defectdojo/http/ProxyConfigFactory.java | 116 ++++++++++++++++++ .../http/ProxyConfigFactoryTest.java | 93 ++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java create mode 100644 src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java new file mode 100644 index 00000000..25f38e94 --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java @@ -0,0 +1,116 @@ +package io.securecodebox.persistence.defectdojo.http; + +import lombok.Getter; +import lombok.NonNull; + +/** + * This class is responsible to create a proxy configuration + *

+ * This implementation collects the configuration values from Java system properties. It also treats the + * cases of non-present values ot values of incorrect type. + *

+ *

+ * This class does not validate for semantic errors of the values, e.g. malformed hostnames or invalid + * port numbers. + *

+ */ +final class ProxyConfigFactory { + private final SystemPropertyFinder properties = new SystemPropertyFinder(); + + ProxyConfig create() { + final var builder = ProxyConfig.builder(); + + if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_USER)) { + throw new MissingProxyConfigValue(ProxyConfigNames.HTTP_PROXY_USER); + } + + builder.user(properties.getProperty(ProxyConfigNames.HTTP_PROXY_USER)); + + if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) { + throw new MissingProxyConfigValue(ProxyConfigNames.HTTP_PROXY_PASSWORD); + } + + builder.password(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)); + + if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_HOST)) { + throw new MissingProxyConfigValue(ProxyConfigNames.HTTP_PROXY_HOST); + } + + builder.host(properties.getProperty(ProxyConfigNames.HTTP_PROXY_HOST)); + + if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PORT)) { + throw new MissingProxyConfigValue(ProxyConfigNames.HTTP_PROXY_PORT); + } + + try { + builder.port(Integer.parseInt(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PORT))); + } catch (final NumberFormatException e) { + throw new IllegalArgumentException( + String.format("Given port for proxy authentication configuration (property '%s') is not a valid number! Given value wa '%s'.", + ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), + System.getProperty("http.proxyPort")), + e); + } + + return builder.build(); + } + + /** + * These properties can be configured by passing them to the running Java process w/ flag {@literal -D} + *

+ * Example: {@literal java -Dhttp.proxyHost=... -D... -jar ...} + *

+ *

+ * Important: All four parameters are mandatory. You must set them all + * or none of them! + *

+ */ + @Getter + enum ProxyConfigNames { + /** + * System property name for the proxy username + */ + HTTP_PROXY_USER("http.proxyUser"), + /** + * System property name for the proxy user's password + */ + HTTP_PROXY_PASSWORD("http.proxyPassword"), + /** + * System property name for the proxy's hostname + */ + HTTP_PROXY_HOST("http.proxyHost"), + /** + * System property for the proxy's port number + */ + HTTP_PROXY_PORT("http.proxyPort"); + + private final String literat; + + ProxyConfigNames(String literat) { + this.literat = literat; + } + } + + private static class SystemPropertyFinder { + private boolean hasProperty(@NonNull final ProxyConfigNames name) { + return System.getProperty(name.getLiterat()) != null; + } + + private boolean notHasProperty(@NonNull final ProxyConfigNames name) { + return !hasProperty(name); + } + + private String getProperty(@NonNull final ProxyConfigNames name) { + return System.getProperty(name.getLiterat()); + } + } + + /** + * This exception indicates a missing proxy config value + */ + final static class MissingProxyConfigValue extends RuntimeException { + MissingProxyConfigValue(ProxyConfigNames name) { + super(String.format("Expected System property '%s' not set!", name.getLiterat())); + } + } +} diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java new file mode 100644 index 00000000..5f2af793 --- /dev/null +++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java @@ -0,0 +1,93 @@ +package io.securecodebox.persistence.defectdojo.http; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; +import uk.org.webcompere.systemstubs.properties.SystemProperties; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * Tests for {@link ProxyConfigFactory} + */ +@ExtendWith(SystemStubsExtension.class) +class ProxyConfigFactoryTest { + @SystemStub + private SystemProperties restoreSystemProperties; + private final ProxyConfigFactory sut = new ProxyConfigFactory(); + + @Test + void create_throesExceptionIfUserNotSet() { + System.clearProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + + final var thrown = assertThrows( + ProxyConfigFactory.MissingProxyConfigValue.class, + sut::create); + + assertThat(thrown.getMessage(), is("Expected System property 'http.proxyUser' not set!")); + } + + @Test + void create_throesExceptionIfPasswordNotSet() { + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.clearProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + + final var thrown = assertThrows( + ProxyConfigFactory.MissingProxyConfigValue.class, + sut::create); + + assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPassword' not set!")); + } + + @Test + void create_throesExceptionIfHostNotSet() { + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.clearProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat()); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + + final var thrown = assertThrows( + ProxyConfigFactory.MissingProxyConfigValue.class, + sut::create); + + assertThat(thrown.getMessage(), is("Expected System property 'http.proxyHost' not set!")); + } + + @Test + void create_throesExceptionIfPortNotSet() { + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.clearProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat()); + + final var thrown = assertThrows( + ProxyConfigFactory.MissingProxyConfigValue.class, + sut::create); + + assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPort' not set!")); + } + + @Test + void create_throesExceptionIfPortIsNotInteger() { + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "FUBAR"); + + final var thrown = assertThrows( + IllegalArgumentException.class, + sut::create); + + assertThat( + thrown.getMessage(), + is("Given port for proxy authentication configuration (property 'http.proxyPort') is not a valid number! Given value wa 'FUBAR'.")); + } +} From 35d185675c1f83cec40b6ddefda61a3bd132edf6 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 14:44:29 +0200 Subject: [PATCH 08/18] #36 Marke methods deprecated which will be removed after code refactoring Signed-off-by: Sven Strittmatter --- .../defectdojo/service/DefaultImportScanService.java | 3 +++ .../persistence/defectdojo/service/ImportScanService.java | 1 + .../defectdojo/service/DefaultImportScanServiceTest.java | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java index 07a557f9..5aa46ea7 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java @@ -44,6 +44,7 @@ class DefaultImportScanService implements ImportScanService { new FormHttpMessageConverter(), new ResourceHttpMessageConverter(), new MappingJackson2HttpMessageConverter()); + @Deprecated private final SystemPropertyFinder properties = new SystemPropertyFinder(); @Getter private final String defectDojoUrl; @@ -230,6 +231,7 @@ ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() { return factory; } + @Deprecated private static class SystemPropertyFinder { private boolean hasProperty(@NonNull final ProxyConfigNames name) { return System.getProperty(name.getLiterat()) != null; @@ -244,6 +246,7 @@ private String getProperty(@NonNull final ProxyConfigNames name) { } } + @Deprecated final static class MissingProxyAuthenticationConfig extends RuntimeException { MissingProxyAuthenticationConfig(ProxyConfigNames name) { super(String.format("Expected System property '%s' not set!", name.getLiterat())); diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java index 437c32fc..bae02b3f 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java @@ -62,6 +62,7 @@ class ImportScanResponse { * or none of them! *

*/ + @Deprecated enum ProxyConfigNames { HTTP_PROXY_HOST("http.proxyHost"), HTTP_PROXY_PORT("http.proxyPort"), diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java index 63e64549..1d0b586f 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java @@ -107,6 +107,7 @@ void shouldConfigureProxySettings_trueIfUserAndPasswordSet() { } @Test + @Deprecated void createRequestFactoryWithProxyAuthConfig_throesExceptionIfUserNotSet() { System.clearProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); @@ -121,6 +122,7 @@ void createRequestFactoryWithProxyAuthConfig_throesExceptionIfUserNotSet() { } @Test + @Deprecated void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPasswordNotSet() { System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); System.clearProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); @@ -135,6 +137,7 @@ void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPasswordNotSet() { } @Test + @Deprecated void createRequestFactoryWithProxyAuthConfig_throesExceptionIfHostNotSet() { System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); @@ -149,6 +152,7 @@ void createRequestFactoryWithProxyAuthConfig_throesExceptionIfHostNotSet() { } @Test + @Deprecated void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortNotSet() { System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); @@ -163,6 +167,7 @@ void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortNotSet() { } @Test + @Deprecated void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortIsNotInteger() { System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); From d87455eca6b77c9eddd6506fce14121cde1f2f70 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 15:15:05 +0200 Subject: [PATCH 09/18] #36 Use new proxy config in import scan service Signed-off-by: Sven Strittmatter --- .../persistence/defectdojo/config/Config.java | 4 + .../defectdojo/http/ProxyConfig.java | 6 +- .../defectdojo/http/ProxyConfigFactory.java | 6 +- .../service/DefaultImportScanService.java | 71 ++------ .../defectdojo/service/ImportScanService.java | 42 ++--- .../service/DefaultImportScanServiceTest.java | 158 +++--------------- .../service/ImportScanServiceTest.java | 14 +- 7 files changed, 70 insertions(+), 231 deletions(-) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/config/Config.java b/src/main/java/io/securecodebox/persistence/defectdojo/config/Config.java index 3a54ce56..1ba06f6c 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/config/Config.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/config/Config.java @@ -20,6 +20,10 @@ public final class Config { * Default for {@link #maxPageCountForGets} */ static final int DEFAULT_MAX_PAGE_COUNT_FOR_GETS = 100; + /** + * Null pattern object. + */ + public static final Config NULL = new Config("", "", DEFAULT_MAX_PAGE_COUNT_FOR_GETS); /** * URL of the host which serves the DefectDojo API. diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java index 54050a5e..9c8e09da 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java @@ -13,11 +13,11 @@ */ @Value @Builder -class ProxyConfig { +public class ProxyConfig { /** * Null pattern object. */ - static final ProxyConfig NULL = ProxyConfig.builder().build(); + public static final ProxyConfig NULL = ProxyConfig.builder().build(); private static final String DEFAULT_STRING = ""; private static final int DEFAULT_INT = 0; @@ -62,7 +62,7 @@ class ProxyConfig { * * @return {@code true} if all values are set else {@code false} */ - boolean isComplete() { + public boolean isComplete() { if (getUser().equals(DEFAULT_STRING)) { return false; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java index 25f38e94..a2b92122 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java @@ -14,10 +14,10 @@ * port numbers. *

*/ -final class ProxyConfigFactory { +public final class ProxyConfigFactory { private final SystemPropertyFinder properties = new SystemPropertyFinder(); - ProxyConfig create() { + public ProxyConfig create() { final var builder = ProxyConfig.builder(); if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_USER)) { @@ -66,7 +66,7 @@ ProxyConfig create() { *

*/ @Getter - enum ProxyConfigNames { + public enum ProxyConfigNames { /** * System property name for the proxy username */ diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java index 5aa46ea7..0b92bec7 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java @@ -7,6 +7,7 @@ import io.securecodebox.persistence.defectdojo.ScanType; import io.securecodebox.persistence.defectdojo.config.Config; import io.securecodebox.persistence.defectdojo.exception.PersistenceException; +import io.securecodebox.persistence.defectdojo.http.ProxyConfig; import io.securecodebox.persistence.defectdojo.model.ScanFile; import lombok.Getter; import lombok.NonNull; @@ -44,22 +45,23 @@ class DefaultImportScanService implements ImportScanService { new FormHttpMessageConverter(), new ResourceHttpMessageConverter(), new MappingJackson2HttpMessageConverter()); - @Deprecated - private final SystemPropertyFinder properties = new SystemPropertyFinder(); @Getter private final String defectDojoUrl; @Getter private final String defectDojoApiKey; + private final ProxyConfig proxyConfig; /** * Dedicated constructor. * - * @param config not {@code null} + * @param config not {@code null} + * @param proxyConfig not {@code null} */ - DefaultImportScanService(final @NonNull Config config) { + DefaultImportScanService(final @NonNull Config config, @NonNull ProxyConfig proxyConfig) { super(); this.defectDojoUrl = config.getUrl(); this.defectDojoApiKey = config.getApiKey(); + this.proxyConfig = proxyConfig; } @Override @@ -163,8 +165,7 @@ private RestTemplate createRestTemplate() { } boolean shouldConfigureProxySettings() { - return properties.hasProperty(ProxyConfigNames.HTTP_PROXY_USER) - && properties.hasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD); + return proxyConfig.isComplete(); } /** @@ -184,45 +185,17 @@ boolean shouldConfigureProxySettings() { * @return never {@code null} */ ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() { - if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_USER)) { - throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_USER); - } - - if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) { - throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PASSWORD); - } - - if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_HOST)) { - throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_HOST); - } - - if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PORT)) { - throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PORT); - } - - final var proxyHost = properties.getProperty(ProxyConfigNames.HTTP_PROXY_HOST); - final int proxyPort; - try { - proxyPort = Integer.parseInt(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PORT)); - } catch (final NumberFormatException e) { - throw new IllegalArgumentException( - String.format("Given port for proxy authentication configuration (property '%s') is not a valid number! Given value wa '%s'.", - ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), - System.getProperty("http.proxyPort")), - e); - } - final var credentials = new BasicCredentialsProvider(); credentials.setCredentials( - new AuthScope(proxyHost, proxyPort), + new AuthScope(proxyConfig.getHost(), proxyConfig.getPort()), new UsernamePasswordCredentials( - properties.getProperty(ProxyConfigNames.HTTP_PROXY_USER), - properties.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) + proxyConfig.getUser(), + proxyConfig.getPassword()) ); final var clientBuilder = HttpClientBuilder.create(); clientBuilder.useSystemProperties(); - clientBuilder.setProxy(new HttpHost(proxyHost, proxyPort)); + clientBuilder.setProxy(new HttpHost(proxyConfig.getHost(), proxyConfig.getPort())); clientBuilder.setDefaultCredentialsProvider(credentials); clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()); @@ -230,26 +203,4 @@ ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() { factory.setHttpClient(clientBuilder.build()); return factory; } - - @Deprecated - private static class SystemPropertyFinder { - private boolean hasProperty(@NonNull final ProxyConfigNames name) { - return System.getProperty(name.getLiterat()) != null; - } - - private boolean notHasProperty(@NonNull final ProxyConfigNames name) { - return !hasProperty(name); - } - - private String getProperty(@NonNull final ProxyConfigNames name) { - return System.getProperty(name.getLiterat()); - } - } - - @Deprecated - final static class MissingProxyAuthenticationConfig extends RuntimeException { - MissingProxyAuthenticationConfig(ProxyConfigNames name) { - super(String.format("Expected System property '%s' not set!", name.getLiterat())); - } - } } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java index bae02b3f..808c2995 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java @@ -7,9 +7,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.securecodebox.persistence.defectdojo.ScanType; import io.securecodebox.persistence.defectdojo.config.Config; +import io.securecodebox.persistence.defectdojo.http.ProxyConfig; +import io.securecodebox.persistence.defectdojo.http.ProxyConfigFactory; import io.securecodebox.persistence.defectdojo.model.ScanFile; import lombok.Data; -import lombok.Getter; +import lombok.NonNull; import java.util.HashMap; import java.util.Map; @@ -25,7 +27,18 @@ public interface ImportScanService { * @return never {@code null} */ static ImportScanService createDefault(final Config config) { - return new DefaultImportScanService(config); + return createDefault(config, new ProxyConfigFactory().create()); + } + + /** + * Factory method to create new instance of service default implementation + * + * @param config must not be {@code null} + * @param proxyConfig must not be {@code null} + * @return never {@code null} + */ + static ImportScanService createDefault(@NonNull final Config config, @NonNull final ProxyConfig proxyConfig) { + return new DefaultImportScanService(config, proxyConfig); } default ImportScanResponse importScan(ScanFile scanFile, long engagementId, long lead, String currentDate, ScanType scanType, long testType) { @@ -51,29 +64,4 @@ class ImportScanResponse { @JsonProperty("test") protected long testId; } - - /** - * These properties can be configured by passing them to the running Java process w/ flag {@literal -D} - *

- * Example: {@literal java -Dhttp.proxyHost=... -D... -jar ...} - *

- *

- * Important: All four parameters are mandatory. You must set them all - * or none of them! - *

- */ - @Deprecated - enum ProxyConfigNames { - HTTP_PROXY_HOST("http.proxyHost"), - HTTP_PROXY_PORT("http.proxyPort"), - HTTP_PROXY_USER("http.proxyUser"), - HTTP_PROXY_PASSWORD("http.proxyPassword"); - - @Getter - private final String literat; - - ProxyConfigNames(String literat) { - this.literat = literat; - } - } } diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java index 1d0b586f..902e4d22 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java @@ -5,17 +5,11 @@ package io.securecodebox.persistence.defectdojo.service; import io.securecodebox.persistence.defectdojo.config.Config; -import io.securecodebox.persistence.defectdojo.service.DefaultImportScanService.MissingProxyAuthenticationConfig; -import io.securecodebox.persistence.defectdojo.service.ImportScanService.ProxyConfigNames; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import io.securecodebox.persistence.defectdojo.http.ProxyConfig; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; -import java.util.HashMap; -import java.util.Map; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertAll; @@ -30,38 +24,19 @@ class DefaultImportScanServiceTest { "apiKey", 23 ); - private final DefaultImportScanService sut = new DefaultImportScanService(config); - /** - * Since System.getProperty() is an side effect we need to back up and restore it to isolate test cases. - */ - private final Map backup = new HashMap<>(); - - @BeforeEach - void backupSystemProperties() { - backup.clear(); - backup.put(ProxyConfigNames.HTTP_PROXY_HOST, System.getProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat())); - backup.put(ProxyConfigNames.HTTP_PROXY_PORT, System.getProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat())); - backup.put(ProxyConfigNames.HTTP_PROXY_USER, System.getProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat())); - backup.put(ProxyConfigNames.HTTP_PROXY_PASSWORD, System.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat())); - } + private final DefaultImportScanService sut = new DefaultImportScanService(config, ProxyConfig.NULL); - @AfterEach - void restoreSystemProperties() { - for (final var entry : backup.entrySet()) { - final var name = entry.getKey().getLiterat(); - - if (null == entry.getValue()) { - System.clearProperty(name); - } else { - System.setProperty(name, entry.getValue()); - } - } + @Test + void constructorShouldThrowExceptionOnNullConfig() { + assertThrows(NullPointerException.class, () -> { + new DefaultImportScanService(null, ProxyConfig.NULL); + }); } @Test - void constructorShouldThrowExceptionOnNullConfig() { + void constructorShouldThrowExceptionOnNullProxyConfig() { assertThrows(NullPointerException.class, () -> { - new DefaultImportScanService(null); + new DefaultImportScanService(Config.NULL, null); }); } @@ -75,112 +50,25 @@ void createDefectDojoAuthorizationHeaders_apiKeyFromConfigShouldBePresentAsAuthH } @Test - void shouldConfigureProxySettings_falseIfNeitherUserNorPasswordIsSet() { - System.clearProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); - System.clearProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); - - assertThat(sut.shouldConfigureProxySettings(), is(false)); - } - - @Test - void shouldConfigureProxySettings_falseIfUserSetButPasswordNot() { - System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.clearProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); - - assertThat(sut.shouldConfigureProxySettings(), is(false)); - } - - @Test - void shouldConfigureProxySettings_falseIfPasswordSetButUserNot() { - System.clearProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + void shouldConfigureProxySettings_trueIfProxyConfigIsComplete() { + final var proxyConfig = ProxyConfig.builder() + .user("user") + .password("pw") + .host("host") + .port(42) + .build(); + final var innerSut = new DefaultImportScanService(config, proxyConfig); - assertThat(sut.shouldConfigureProxySettings(), is(false)); + assertThat(innerSut.shouldConfigureProxySettings(), is(true)); } @Test - void shouldConfigureProxySettings_trueIfUserAndPasswordSet() { - System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + void shouldConfigureProxySettings_falseIfProxyConfigIsIncomplete() { + final var proxyConfig = ProxyConfig.builder() + .build(); + final var innerSut = new DefaultImportScanService(config, proxyConfig); - assertThat(sut.shouldConfigureProxySettings(), is(true)); - } - - @Test - @Deprecated - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfUserNotSet() { - System.clearProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); - - final var thrown = assertThrows( - MissingProxyAuthenticationConfig.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyUser' not set!")); - } - - @Test - @Deprecated - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPasswordNotSet() { - System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.clearProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); - System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); - - final var thrown = assertThrows( - MissingProxyAuthenticationConfig.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPassword' not set!")); - } - - @Test - @Deprecated - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfHostNotSet() { - System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - System.clearProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat()); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); - - final var thrown = assertThrows( - MissingProxyAuthenticationConfig.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyHost' not set!")); - } - - @Test - @Deprecated - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortNotSet() { - System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - System.clearProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat()); - - final var thrown = assertThrows( - MissingProxyAuthenticationConfig.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPort' not set!")); - } - - @Test - @Deprecated - void createRequestFactoryWithProxyAuthConfig_throesExceptionIfPortIsNotInteger() { - System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "FUBAR"); - - final var thrown = assertThrows( - IllegalArgumentException.class, - sut::createRequestFactoryWithProxyAuthConfig); - - assertThat( - thrown.getMessage(), - is("Given port for proxy authentication configuration (property 'http.proxyPort') is not a valid number! Given value wa 'FUBAR'.")); + assertThat(innerSut.shouldConfigureProxySettings(), is(false)); } @Test diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/ImportScanServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/ImportScanServiceTest.java index 6263cf7c..d49f1ce6 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/service/ImportScanServiceTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/ImportScanServiceTest.java @@ -6,6 +6,7 @@ import io.securecodebox.persistence.defectdojo.ScanType; import io.securecodebox.persistence.defectdojo.config.Config; +import io.securecodebox.persistence.defectdojo.http.ProxyConfig; import io.securecodebox.persistence.defectdojo.model.ScanFile; import lombok.Getter; import org.junit.jupiter.api.Test; @@ -25,9 +26,16 @@ class ImportScanServiceTest { private final ImportScanServiceStub sut = new ImportScanServiceStub(); @Test - void createDefault_throwsExceptionIfNullPassedIn() { + void createDefault_throwsExceptionIfNullPassedInAsConfig() { assertThrows(NullPointerException.class, () -> { - ImportScanService.createDefault(null); + ImportScanService.createDefault(null, ProxyConfig.NULL); + }); + } + + @Test + void createDefault_throwsExceptionIfNullPassedInAsProxyConfig() { + assertThrows(NullPointerException.class, () -> { + ImportScanService.createDefault(Config.NULL, null); }); } @@ -39,7 +47,7 @@ void createDefault_passesConfig() { 23 ); - final var sut = (DefaultImportScanService) ImportScanService.createDefault(config); + final var sut = (DefaultImportScanService) ImportScanService.createDefault(config, ProxyConfig.NULL); assertAll( () -> assertThat(sut.getDefectDojoUrl(), is(config.getUrl())), From 4fa891dc9d76912a38dc8e53b4fef4c778412a72 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 15:23:07 +0200 Subject: [PATCH 10/18] #36 Extract config name enum in own file forbetter readability Signed-off-by: Sven Strittmatter --- .../defectdojo/http/ProxyConfigFactory.java | 37 ----------------- .../defectdojo/http/ProxyConfigNames.java | 39 ++++++++++++++++++ .../http/ProxyConfigFactoryTest.java | 40 +++++++++---------- 3 files changed, 59 insertions(+), 57 deletions(-) create mode 100644 src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java index a2b92122..73177ada 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java @@ -1,6 +1,5 @@ package io.securecodebox.persistence.defectdojo.http; -import lombok.Getter; import lombok.NonNull; /** @@ -55,42 +54,6 @@ public ProxyConfig create() { return builder.build(); } - /** - * These properties can be configured by passing them to the running Java process w/ flag {@literal -D} - *

- * Example: {@literal java -Dhttp.proxyHost=... -D... -jar ...} - *

- *

- * Important: All four parameters are mandatory. You must set them all - * or none of them! - *

- */ - @Getter - public enum ProxyConfigNames { - /** - * System property name for the proxy username - */ - HTTP_PROXY_USER("http.proxyUser"), - /** - * System property name for the proxy user's password - */ - HTTP_PROXY_PASSWORD("http.proxyPassword"), - /** - * System property name for the proxy's hostname - */ - HTTP_PROXY_HOST("http.proxyHost"), - /** - * System property for the proxy's port number - */ - HTTP_PROXY_PORT("http.proxyPort"); - - private final String literat; - - ProxyConfigNames(String literat) { - this.literat = literat; - } - } - private static class SystemPropertyFinder { private boolean hasProperty(@NonNull final ProxyConfigNames name) { return System.getProperty(name.getLiterat()) != null; diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java new file mode 100644 index 00000000..04a0db04 --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java @@ -0,0 +1,39 @@ +package io.securecodebox.persistence.defectdojo.http; + +import lombok.Getter; + +/** + * These properties can be configured by passing them to the running Java process w/ flag {@literal -D} + *

+ * Example: {@literal java -Dhttp.proxyHost=... -D... -jar ...} + *

+ *

+ * Important: All four parameters are mandatory. You must set them all + * or none of them! + *

+ */ +@Getter +public enum ProxyConfigNames { + /** + * System property name for the proxy username + */ + HTTP_PROXY_USER("http.proxyUser"), + /** + * System property name for the proxy user's password + */ + HTTP_PROXY_PASSWORD("http.proxyPassword"), + /** + * System property name for the proxy's hostname + */ + HTTP_PROXY_HOST("http.proxyHost"), + /** + * System property for the proxy's port number + */ + HTTP_PROXY_PORT("http.proxyPort"); + + private final String literat; + + ProxyConfigNames(String literat) { + this.literat = literat; + } +} diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java index 5f2af793..48ad1f20 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java @@ -21,10 +21,10 @@ class ProxyConfigFactoryTest { @Test void create_throesExceptionIfUserNotSet() { - System.clearProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat()); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); final var thrown = assertThrows( ProxyConfigFactory.MissingProxyConfigValue.class, @@ -35,10 +35,10 @@ void create_throesExceptionIfUserNotSet() { @Test void create_throesExceptionIfPasswordNotSet() { - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.clearProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat()); + System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); final var thrown = assertThrows( ProxyConfigFactory.MissingProxyConfigValue.class, @@ -49,10 +49,10 @@ void create_throesExceptionIfPasswordNotSet() { @Test void create_throesExceptionIfHostNotSet() { - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - System.clearProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat()); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat()); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); final var thrown = assertThrows( ProxyConfigFactory.MissingProxyConfigValue.class, @@ -63,10 +63,10 @@ void create_throesExceptionIfHostNotSet() { @Test void create_throesExceptionIfPortNotSet() { - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - System.clearProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat()); + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.clearProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat()); final var thrown = assertThrows( ProxyConfigFactory.MissingProxyConfigValue.class, @@ -77,10 +77,10 @@ void create_throesExceptionIfPortNotSet() { @Test void create_throesExceptionIfPortIsNotInteger() { - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); - System.setProperty(ProxyConfigFactory.ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "FUBAR"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_USER.getLiterat(), "user"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD.getLiterat(), "password"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_HOST.getLiterat(), "host"); + System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "FUBAR"); final var thrown = assertThrows( IllegalArgumentException.class, From c7bc27755132e84e265097495bc2e26fa44e9020 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 15:26:24 +0200 Subject: [PATCH 11/18] #36 Extract exception for missingproxy config in own file forbetter readability Signed-off-by: Sven Strittmatter --- .../http/MissingProxyConfigValue.java | 12 ++++++++++++ .../defectdojo/http/ProxyConfigFactory.java | 8 -------- .../http/MissingProxyConfigValueTest.java | 19 +++++++++++++++++++ .../http/ProxyConfigFactoryTest.java | 18 +++++++++--------- 4 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java create mode 100644 src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java new file mode 100644 index 00000000..dfbbe424 --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java @@ -0,0 +1,12 @@ +package io.securecodebox.persistence.defectdojo.http; + +import lombok.NonNull; + +/** + * This exception indicates a missing proxy config value + */ +public final class MissingProxyConfigValue extends RuntimeException { + MissingProxyConfigValue(@NonNull final ProxyConfigNames name) { + super(String.format("Expected system property '%s' not set!", name.getLiterat())); + } +} diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java index 73177ada..2de68fff 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java @@ -68,12 +68,4 @@ private String getProperty(@NonNull final ProxyConfigNames name) { } } - /** - * This exception indicates a missing proxy config value - */ - final static class MissingProxyConfigValue extends RuntimeException { - MissingProxyConfigValue(ProxyConfigNames name) { - super(String.format("Expected System property '%s' not set!", name.getLiterat())); - } - } } diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java new file mode 100644 index 00000000..50493b7f --- /dev/null +++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java @@ -0,0 +1,19 @@ +package io.securecodebox.persistence.defectdojo.http; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +/** + * Tests for {@link MissingProxyConfigValue} + */ +class MissingProxyConfigValueTest { + @Test + void rendersMessageFromProxyConfigName() { + final var sut = new MissingProxyConfigValue(ProxyConfigNames.HTTP_PROXY_HOST); + + assertThat(sut.getMessage(), is("Expected system property 'http.proxyHost' not set!")); + } +} diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java index 48ad1f20..f02d3741 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java @@ -7,7 +7,7 @@ import uk.org.webcompere.systemstubs.properties.SystemProperties; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertThrows; /** @@ -27,10 +27,10 @@ void create_throesExceptionIfUserNotSet() { System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); final var thrown = assertThrows( - ProxyConfigFactory.MissingProxyConfigValue.class, + MissingProxyConfigValue.class, sut::create); - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyUser' not set!")); + assertThat(thrown.getMessage(), containsString("'http.proxyUser'")); } @Test @@ -41,10 +41,10 @@ void create_throesExceptionIfPasswordNotSet() { System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); final var thrown = assertThrows( - ProxyConfigFactory.MissingProxyConfigValue.class, + MissingProxyConfigValue.class, sut::create); - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPassword' not set!")); + assertThat(thrown.getMessage(), containsString("'http.proxyPassword'")); } @Test @@ -55,10 +55,10 @@ void create_throesExceptionIfHostNotSet() { System.setProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(), "4242"); final var thrown = assertThrows( - ProxyConfigFactory.MissingProxyConfigValue.class, + MissingProxyConfigValue.class, sut::create); - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyHost' not set!")); + assertThat(thrown.getMessage(), containsString("'http.proxyHost'")); } @Test @@ -69,10 +69,10 @@ void create_throesExceptionIfPortNotSet() { System.clearProperty(ProxyConfigNames.HTTP_PROXY_PORT.getLiterat()); final var thrown = assertThrows( - ProxyConfigFactory.MissingProxyConfigValue.class, + MissingProxyConfigValue.class, sut::create); - assertThat(thrown.getMessage(), is("Expected System property 'http.proxyPort' not set!")); + assertThat(thrown.getMessage(), containsString("'http.proxyPort'")); } @Test From 482662bb5c49c2e015b8295e63c92813bb5f16c8 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 23:08:54 +0200 Subject: [PATCH 12/18] #36 Start to extract duplicated code Signed-off-by: Sven Strittmatter --- .../persistence/defectdojo/http/Foo.java | 35 +++++++++++++++++++ .../service/GenericDefectDojoService.java | 14 ++------ 2 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java new file mode 100644 index 00000000..090194c2 --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java @@ -0,0 +1,35 @@ +package io.securecodebox.persistence.defectdojo.http; + +import io.securecodebox.persistence.defectdojo.config.Config; +import lombok.NonNull; +import org.springframework.http.HttpHeaders; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * Placeholder to move duplicated code, will be named better later + */ +public final class Foo { + private final Config config; + + public Foo(@NonNull final Config config) { + super(); + this.config = config; + } + + public HttpHeaders getDefectDojoAuthorizationHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", "Token " + this.config.getApiKey()); + + String username = System.getProperty("http.proxyUser", ""); + String password = System.getProperty("http.proxyPassword", ""); + + if (!username.isEmpty() || !password.isEmpty()) { + System.out.println("Setting Proxy Auth Header..."); + headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((username + ':' + password).getBytes(StandardCharsets.UTF_8))); + } + + return headers; + } +} diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java index 1858b851..40b6f3e4 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.databind.cfg.CoercionInputShape; import io.securecodebox.persistence.defectdojo.config.Config; import io.securecodebox.persistence.defectdojo.exception.LoopException; +import io.securecodebox.persistence.defectdojo.http.Foo; import io.securecodebox.persistence.defectdojo.model.BaseModel; import io.securecodebox.persistence.defectdojo.model.Response; import io.securecodebox.persistence.defectdojo.model.Engagement; @@ -75,18 +76,7 @@ public GenericDefectDojoService(Config config) { * @return The DefectDojo Authentication Header */ private HttpHeaders getDefectDojoAuthorizationHeaders() { - HttpHeaders headers = new HttpHeaders(); - headers.set("Authorization", "Token " + this.config.getApiKey()); - - String username = System.getProperty("http.proxyUser", ""); - String password = System.getProperty("http.proxyPassword", ""); - - if (!username.isEmpty() || !password.isEmpty()) { - System.out.println("Setting Proxy Auth Header..."); - headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((username + ':' + password).getBytes(StandardCharsets.UTF_8))); - } - - return headers; + return new Foo(config).getDefectDojoAuthorizationHeaders(); } private RestTemplate setupRestTemplate() { From dc255d6671e2abb9dce8346c743f7277b8aff260 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 23:10:13 +0200 Subject: [PATCH 13/18] #36 Add a old version because did to many refactorings so that's hard to see the code duplication Signed-off-by: Sven Strittmatter --- .../service/ImportScanService2.java | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java new file mode 100644 index 00000000..d250e77d --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java @@ -0,0 +1,186 @@ +/* + * secureCodeBox (SCB) + * Copyright 2021 iteratec GmbH + * https://www.iteratec.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.securecodebox.persistence.defectdojo.service; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.securecodebox.persistence.defectdojo.ScanType; +import io.securecodebox.persistence.defectdojo.config.Config; +import io.securecodebox.persistence.defectdojo.exception.PersistenceException; +import io.securecodebox.persistence.defectdojo.http.Foo; +import io.securecodebox.persistence.defectdojo.model.ScanFile; +import lombok.Data; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.ProxyAuthenticationStrategy; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.http.converter.ResourceHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * Copied the version before I did refactoring for easier compare of duplicated code + */ +public class ImportScanService2 { + + private final Config config; + @Deprecated + protected String defectDojoUrl; + @Deprecated + protected String defectDojoApiKey; + + public ImportScanService2(Config config) { + super(); + this.config = config; + this.defectDojoUrl = config.getUrl(); + this.defectDojoApiKey = config.getApiKey(); + } + + /** + * @return The DefectDojo Authentication Header + */ + private HttpHeaders getDefectDojoAuthorizationHeaders() { + return new Foo(config).getDefectDojoAuthorizationHeaders(); + } + + protected RestTemplate getRestTemplate() { + if (System.getProperty("http.proxyUser") != null && System.getProperty("http.proxyPassword") != null) { + // Configuring Proxy Authentication explicitly as it isn't done by default for spring rest templates :( + CredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials( + new AuthScope(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))), + new UsernamePasswordCredentials(System.getProperty("http.proxyUser"), System.getProperty("http.proxyPassword")) + ); + HttpClientBuilder clientBuilder = HttpClientBuilder.create(); + + clientBuilder.useSystemProperties(); + clientBuilder.setProxy(new HttpHost(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort")))); + clientBuilder.setDefaultCredentialsProvider(credsProvider); + clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()); + + CloseableHttpClient client = clientBuilder.build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setHttpClient(client); + return new RestTemplate(factory); + } else { + return new RestTemplate(); + } + } + + /** + * Before version 1.5.4. testName (in DefectDojo _test_type_) must be defectDojoScanName, afterwards, you can have somethings else + */ + protected ImportScanResponse createFindings(ScanFile scanFile, String endpoint, long lead, String currentDate, ScanType scanType, long testType, MultiValueMap options) { + var restTemplate = this.getRestTemplate(); + HttpHeaders headers = getDefectDojoAuthorizationHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + restTemplate.setMessageConverters(List.of( + new FormHttpMessageConverter(), + new ResourceHttpMessageConverter(), + new MappingJackson2HttpMessageConverter()) + ); + + MultiValueMap mvn = new LinkedMultiValueMap<>(); + + mvn.add("lead", Long.toString(lead)); + mvn.add("scan_date", currentDate); + mvn.add("scan_type", scanType.getTestType()); + mvn.add("close_old_findings", "true"); + mvn.add("skip_duplicates", "false"); + mvn.add("test_type", String.valueOf(testType)); + + for (String theKey : options.keySet()) { + mvn.remove(theKey); + } + mvn.addAll(options); + + try { + ByteArrayResource contentsAsResource = new ByteArrayResource(scanFile.getContent().getBytes(StandardCharsets.UTF_8)) { + @Override + public String getFilename() { + return scanFile.getName(); + } + }; + + mvn.add("file", contentsAsResource); + + var payload = new HttpEntity<>(mvn, headers); + + return restTemplate.exchange(defectDojoUrl + "/api/v2/" + endpoint + "/", HttpMethod.POST, payload, ImportScanResponse.class).getBody(); + } catch (HttpClientErrorException e) { + throw new PersistenceException("Failed to attach findings to engagement."); + } + } + + + public ImportScanResponse importScan(ScanFile scanFile, long engagementId, long lead, String currentDate, ScanType scanType, long testType) { + var additionalValues = new LinkedMultiValueMap(); + additionalValues.add("engagement", Long.toString(engagementId)); + + return this.importScan(scanFile, engagementId, lead, currentDate, scanType, testType, additionalValues); + } + + public ImportScanResponse reimportScan(ScanFile scanFile, long testId, long lead, String currentDate, ScanType scanType, long testType) { + var additionalValues = new LinkedMultiValueMap(); + additionalValues.add("test", Long.toString(testId)); + + return this.reimportScan(scanFile, testId, lead, currentDate, scanType, testType, additionalValues); + } + + //overloading with optional parameter + public ImportScanResponse importScan(ScanFile scanFile, long engagementId, long lead, String currentDate, ScanType scanType, long testType, LinkedMultiValueMap additionalValues) { + additionalValues.add("engagement", Long.toString(engagementId)); + + return this.createFindings(scanFile, "import-scan", lead, currentDate, scanType, testType, additionalValues); + } + + public ImportScanResponse reimportScan(ScanFile scanFile, long testId, long lead, String currentDate, ScanType scanType, long testType, LinkedMultiValueMap additionalValues) { + additionalValues.add("test", Long.toString(testId)); + + return this.createFindings(scanFile, "reimport-scan", lead, currentDate, scanType, testType, additionalValues); + } + + @Data + public static class ImportScanResponse { + @JsonProperty + protected Boolean verified; + + @JsonProperty + protected Boolean active; + + @JsonProperty("test") + protected long testId; + } +} From bd237d28a2cf2a1a1b8d46e25576933b49cde6d3 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 23:15:05 +0200 Subject: [PATCH 14/18] #36 Make the code identical to duplicated one Signed-off-by: Sven Strittmatter --- .../defectdojo/service/ImportScanService2.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java index d250e77d..ba6ff5b9 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java @@ -74,7 +74,9 @@ private HttpHeaders getDefectDojoAuthorizationHeaders() { return new Foo(config).getDefectDojoAuthorizationHeaders(); } - protected RestTemplate getRestTemplate() { + protected RestTemplate setupRestTemplate() { + RestTemplate restTemplate; + if (System.getProperty("http.proxyUser") != null && System.getProperty("http.proxyPassword") != null) { // Configuring Proxy Authentication explicitly as it isn't done by default for spring rest templates :( CredentialsProvider credsProvider = new BasicCredentialsProvider(); @@ -93,17 +95,19 @@ protected RestTemplate getRestTemplate() { HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); factory.setHttpClient(client); - return new RestTemplate(factory); + restTemplate = new RestTemplate(factory); } else { - return new RestTemplate(); + restTemplate = new RestTemplate(); } + + return restTemplate; } /** * Before version 1.5.4. testName (in DefectDojo _test_type_) must be defectDojoScanName, afterwards, you can have somethings else */ protected ImportScanResponse createFindings(ScanFile scanFile, String endpoint, long lead, String currentDate, ScanType scanType, long testType, MultiValueMap options) { - var restTemplate = this.getRestTemplate(); + var restTemplate = this.setupRestTemplate(); HttpHeaders headers = getDefectDojoAuthorizationHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); restTemplate.setMessageConverters(List.of( From d3ea3e64cece6fe432c74f9eb5967b3876936e7a Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Sun, 3 Sep 2023 23:20:07 +0200 Subject: [PATCH 15/18] #36 Extract duplicated code to create rest template Signed-off-by: Sven Strittmatter --- .../persistence/defectdojo/http/Foo.java | 39 ++++++++++++++++++ .../service/GenericDefectDojoService.java | 40 ++----------------- .../service/ImportScanService2.java | 36 +---------------- 3 files changed, 43 insertions(+), 72 deletions(-) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java index 090194c2..93e93410 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java @@ -2,7 +2,17 @@ import io.securecodebox.persistence.defectdojo.config.Config; import lombok.NonNull; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.ProxyAuthenticationStrategy; import org.springframework.http.HttpHeaders; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; import java.nio.charset.StandardCharsets; import java.util.Base64; @@ -32,4 +42,33 @@ public HttpHeaders getDefectDojoAuthorizationHeaders() { return headers; } + + public RestTemplate setupRestTemplate() { + RestTemplate restTemplate; + + if (System.getProperty("http.proxyUser") != null && System.getProperty("http.proxyPassword") != null) { + // Configuring Proxy Authentication explicitly as it isn't done by default for spring rest templates :( + CredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials( + new AuthScope(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))), + new UsernamePasswordCredentials(System.getProperty("http.proxyUser"), System.getProperty("http.proxyPassword")) + ); + HttpClientBuilder clientBuilder = HttpClientBuilder.create(); + + clientBuilder.useSystemProperties(); + clientBuilder.setProxy(new HttpHost(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort")))); + clientBuilder.setDefaultCredentialsProvider(credsProvider); + clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()); + + CloseableHttpClient client = clientBuilder.build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setHttpClient(client); + restTemplate = new RestTemplate(factory); + } else { + restTemplate = new RestTemplate(); + } + + return restTemplate; + } } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java index 40b6f3e4..084c0b64 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java @@ -14,21 +14,13 @@ import io.securecodebox.persistence.defectdojo.exception.LoopException; import io.securecodebox.persistence.defectdojo.http.Foo; import io.securecodebox.persistence.defectdojo.model.BaseModel; -import io.securecodebox.persistence.defectdojo.model.Response; import io.securecodebox.persistence.defectdojo.model.Engagement; -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.ProxyAuthenticationStrategy; +import io.securecodebox.persistence.defectdojo.model.Response; +import lombok.Getter; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.ResourceHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; @@ -39,9 +31,7 @@ import java.net.URI; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.util.*; -import lombok.Getter; // FIXME: Should be package private bc implementation detail. abstract public class GenericDefectDojoService { @@ -80,31 +70,7 @@ private HttpHeaders getDefectDojoAuthorizationHeaders() { } private RestTemplate setupRestTemplate() { - RestTemplate restTemplate; - - if (System.getProperty("http.proxyUser") != null && System.getProperty("http.proxyPassword") != null) { - // Configuring Proxy Authentication explicitly as it isn't done by default for spring rest templates :( - CredentialsProvider credsProvider = new BasicCredentialsProvider(); - credsProvider.setCredentials( - new AuthScope(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))), - new UsernamePasswordCredentials(System.getProperty("http.proxyUser"), System.getProperty("http.proxyPassword")) - ); - HttpClientBuilder clientBuilder = HttpClientBuilder.create(); - - clientBuilder.useSystemProperties(); - clientBuilder.setProxy(new HttpHost(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort")))); - clientBuilder.setDefaultCredentialsProvider(credsProvider); - clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()); - - CloseableHttpClient client = clientBuilder.build(); - - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); - factory.setHttpClient(client); - restTemplate = new RestTemplate(factory); - } else { - restTemplate = new RestTemplate(); - } - + RestTemplate restTemplate = new Foo(config).setupRestTemplate(); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setObjectMapper(this.objectMapper); restTemplate.setMessageConverters(List.of( diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java index ba6ff5b9..e18ebfcb 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java @@ -24,20 +24,11 @@ import io.securecodebox.persistence.defectdojo.http.Foo; import io.securecodebox.persistence.defectdojo.model.ScanFile; import lombok.Data; -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.ProxyAuthenticationStrategy; import org.springframework.core.io.ByteArrayResource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.ResourceHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; @@ -75,32 +66,7 @@ private HttpHeaders getDefectDojoAuthorizationHeaders() { } protected RestTemplate setupRestTemplate() { - RestTemplate restTemplate; - - if (System.getProperty("http.proxyUser") != null && System.getProperty("http.proxyPassword") != null) { - // Configuring Proxy Authentication explicitly as it isn't done by default for spring rest templates :( - CredentialsProvider credsProvider = new BasicCredentialsProvider(); - credsProvider.setCredentials( - new AuthScope(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))), - new UsernamePasswordCredentials(System.getProperty("http.proxyUser"), System.getProperty("http.proxyPassword")) - ); - HttpClientBuilder clientBuilder = HttpClientBuilder.create(); - - clientBuilder.useSystemProperties(); - clientBuilder.setProxy(new HttpHost(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort")))); - clientBuilder.setDefaultCredentialsProvider(credsProvider); - clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()); - - CloseableHttpClient client = clientBuilder.build(); - - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); - factory.setHttpClient(client); - restTemplate = new RestTemplate(factory); - } else { - restTemplate = new RestTemplate(); - } - - return restTemplate; + return new Foo(config).setupRestTemplate(); } /** From 8d4cd069bd639ca25786762667e987117b543df6 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Mon, 4 Sep 2023 14:54:43 +0200 Subject: [PATCH 16/18] #36 Add missing SPDX headers Signed-off-by: Sven Strittmatter --- .../io/securecodebox/persistence/defectdojo/http/Foo.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java index 93e93410..f185ee99 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.http; import io.securecodebox.persistence.defectdojo.config.Config; From 40c0ba365d39c58ada47d14a3b8097e0f5782a81 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Mon, 4 Sep 2023 14:55:20 +0200 Subject: [PATCH 17/18] #36 Fix license header to meet SPDX spec Signed-off-by: Sven Strittmatter --- .../service/ImportScanService2.java | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java index e18ebfcb..36c660be 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java @@ -1,20 +1,7 @@ -/* - * secureCodeBox (SCB) - * Copyright 2021 iteratec GmbH - * https://www.iteratec.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.service; import com.fasterxml.jackson.annotation.JsonProperty; From a87c80ed7762ea90a35ee8135f76fdc5387c9872 Mon Sep 17 00:00:00 2001 From: Sven Strittmatter Date: Mon, 4 Sep 2023 14:56:40 +0200 Subject: [PATCH 18/18] #36 Add missing SPDX headers Signed-off-by: Sven Strittmatter --- .../persistence/defectdojo/http/MissingProxyConfigValue.java | 4 ++++ .../persistence/defectdojo/http/ProxyConfig.java | 4 ++++ .../persistence/defectdojo/http/ProxyConfigFactory.java | 4 ++++ .../persistence/defectdojo/http/ProxyConfigNames.java | 4 ++++ .../defectdojo/http/MissingProxyConfigValueTest.java | 4 ++++ .../persistence/defectdojo/http/ProxyConfigFactoryTest.java | 4 ++++ .../persistence/defectdojo/http/ProxyConfigTest.java | 4 ++++ 7 files changed, 28 insertions(+) diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java index dfbbe424..2324bc69 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.http; import lombok.NonNull; diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java index 9c8e09da..9729f675 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.http; import lombok.Builder; diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java index 2de68fff..0358726e 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.http; import lombok.NonNull; diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java index 04a0db04..85dd2f35 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.http; import lombok.Getter; diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java index 50493b7f..75613bc5 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.http; import org.junit.jupiter.api.Test; diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java index f02d3741..59d6e228 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.http; import org.junit.jupiter.api.Test; diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java index 4663561e..bb93248f 100644 --- a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java +++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + package io.securecodebox.persistence.defectdojo.http; import nl.jqno.equalsverifier.EqualsVerifier;