johannes.zahn
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/Foo.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java
new file mode 100644
index 00000000..f185ee99
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java
@@ -0,0 +1,78 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package io.securecodebox.persistence.defectdojo.http;
+
+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;
+
+/**
+ * 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;
+ }
+
+ 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/http/MissingProxyConfigValue.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java
new file mode 100644
index 00000000..2324bc69
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValue.java
@@ -0,0 +1,16 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+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/ProxyConfig.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java
new file mode 100644
index 00000000..9729f675
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfig.java
@@ -0,0 +1,88 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+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
+public class ProxyConfig {
+ /**
+ * Null pattern object.
+ */
+ public 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}
+ */
+ public 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/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..0358726e
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactory.java
@@ -0,0 +1,75 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package io.securecodebox.persistence.defectdojo.http;
+
+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.
+ *
+ */
+public final class ProxyConfigFactory {
+ private final SystemPropertyFinder properties = new SystemPropertyFinder();
+
+ public 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();
+ }
+
+ 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());
+ }
+ }
+
+}
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..85dd2f35
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigNames.java
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+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/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;
}
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..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,21 +45,23 @@ class DefaultImportScanService implements ImportScanService {
new FormHttpMessageConverter(),
new ResourceHttpMessageConverter(),
new MappingJackson2HttpMessageConverter());
- private final HttpRequester requester = new DefaultHttpRequester();
@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
@@ -85,7 +88,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 +103,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,17 +117,30 @@ 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
// We send the whole file content, so DefectDojo can parse the finding by itself.
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
*
@@ -136,133 +152,55 @@ 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 proxyConfig.isComplete();
}
/**
- * This interface abstracts the network side effect done by the underlying HTTP
- */
- interface HttpRequester {
- ImportScanResponse exchange(String endpoint, HttpEntity> payload);
- }
-
- /**
- * Default implementation which utilizes {@link RestTemplate}
+ * 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}
*/
- 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();
- }
-
- private RestTemplate createRestTemplate() {
- final var template = new RestTemplate();
-
- if (shouldConfigureProxySettings()) {
- template.setRequestFactory(createRequestFactoryWithProxyAuthConfig());
- }
-
- template.setMessageConverters(HTTP_MESSAGE_CONVERTERS);
-
- return template;
- }
-
- boolean shouldConfigureProxySettings() {
- return properties.hasProperty(ProxyConfigNames.HTTP_PROXY_USER)
- && properties.hasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD);
- }
-
- /**
- * 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;
- }
+ ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() {
+ final var credentials = new BasicCredentialsProvider();
+ credentials.setCredentials(
+ new AuthScope(proxyConfig.getHost(), proxyConfig.getPort()),
+ new UsernamePasswordCredentials(
+ proxyConfig.getUser(),
+ proxyConfig.getPassword())
+ );
+
+ final var clientBuilder = HttpClientBuilder.create();
+ clientBuilder.useSystemProperties();
+ clientBuilder.setProxy(new HttpHost(proxyConfig.getHost(), proxyConfig.getPort()));
+ clientBuilder.setDefaultCredentialsProvider(credentials);
+ clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
+
+ final var factory = new HttpComponentsClientHttpRequestFactory();
+ factory.setHttpClient(clientBuilder.build());
+ return factory;
}
}
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..084c0b64 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java
@@ -12,22 +12,15 @@
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;
-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;
@@ -38,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 {
@@ -75,46 +66,11 @@ 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() {
- 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/ImportScanService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java
index 437c32fc..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,28 +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!
- *
- */
- 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/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..36c660be
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java
@@ -0,0 +1,143 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+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.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.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 setupRestTemplate() {
+ return new Foo(config).setupRestTemplate();
+ }
+
+ /**
+ * 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.setupRestTemplate();
+ 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;
+ }
+}
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..75613bc5
--- /dev/null
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/MissingProxyConfigValueTest.java
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+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
new file mode 100644
index 00000000..59d6e228
--- /dev/null
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigFactoryTest.java
@@ -0,0 +1,97 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+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.*;
+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(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(
+ MissingProxyConfigValue.class,
+ sut::create);
+
+ assertThat(thrown.getMessage(), containsString("'http.proxyUser'"));
+ }
+
+ @Test
+ void create_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(
+ MissingProxyConfigValue.class,
+ sut::create);
+
+ assertThat(thrown.getMessage(), containsString("'http.proxyPassword'"));
+ }
+
+ @Test
+ void create_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(
+ MissingProxyConfigValue.class,
+ sut::create);
+
+ assertThat(thrown.getMessage(), containsString("'http.proxyHost'"));
+ }
+
+ @Test
+ void create_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(
+ MissingProxyConfigValue.class,
+ sut::create);
+
+ assertThat(thrown.getMessage(), containsString("'http.proxyPort'"));
+ }
+
+ @Test
+ void create_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::create);
+
+ 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/http/ProxyConfigTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java
new file mode 100644
index 00000000..bb93248f
--- /dev/null
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyConfigTest.java
@@ -0,0 +1,87 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+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));
+ }
+}
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..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,13 +5,15 @@
package io.securecodebox.persistence.defectdojo.service;
import io.securecodebox.persistence.defectdojo.config.Config;
+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 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}
@@ -22,25 +24,53 @@ class DefaultImportScanServiceTest {
"apiKey",
23
);
- private final DefaultImportScanService sut = new DefaultImportScanService(config);
+ private final DefaultImportScanService sut = new DefaultImportScanService(config, ProxyConfig.NULL);
@Test
void constructorShouldThrowExceptionOnNullConfig() {
assertThrows(NullPointerException.class, () -> {
- new DefaultImportScanService(null);
+ new DefaultImportScanService(null, ProxyConfig.NULL);
});
}
@Test
- void createDefectDojoAuthorizationHeaders_apiKeyFromConfigShouldBePresentAsAuthHeader() {
- final var authorizationHeaders = sut.createDefectDojoAuthorizationHeaders();
+ void constructorShouldThrowExceptionOnNullProxyConfig() {
+ assertThrows(NullPointerException.class, () -> {
+ new DefaultImportScanService(Config.NULL, null);
+ });
+ }
+ @Test
+ 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_trueIfProxyConfigIsComplete() {
+ final var proxyConfig = ProxyConfig.builder()
+ .user("user")
+ .password("pw")
+ .host("host")
+ .port(42)
+ .build();
+ final var innerSut = new DefaultImportScanService(config, proxyConfig);
+
+ assertThat(innerSut.shouldConfigureProxySettings(), is(true));
+ }
+
+ @Test
+ void shouldConfigureProxySettings_falseIfProxyConfigIsIncomplete() {
+ final var proxyConfig = ProxyConfig.builder()
+ .build();
+ final var innerSut = new DefaultImportScanService(config, proxyConfig);
+
+ assertThat(innerSut.shouldConfigureProxySettings(), is(false));
+ }
+
@Test
void generateApiUrl() {
assertThat(sut.generateApiUrl("foo"), is("http://localhost/api/v2/foo/"));
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())),