diff --git a/.sdkmanrc b/.sdkmanrc
index b0539704..318d1af5 100644
--- a/.sdkmanrc
+++ b/.sdkmanrc
@@ -4,4 +4,4 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
-java=17.0.7-tem
+java=17.0.10-tem
diff --git a/README.md b/README.md
index 9b59f365..cafab4d9 100644
--- a/README.md
+++ b/README.md
@@ -32,6 +32,7 @@ The client is supposed to be compatible with DefectDojo 1.10 and later, older ve
```java
import com.fasterxml.jackson.core.JsonProcessingException;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import io.securecodebox.persistence.defectdojo.config.Config;
import io.securecodebox.persistence.defectdojo.service.ProductTypeService;
@@ -41,7 +42,7 @@ public class DefectDojoClientTest {
public static void main(String[] args) throws URISyntaxException, JsonProcessingException {
// Configure DefectDojo URl and APIv2 Key
- var conf = new Config("https://defectdojo.example.com", "f8....");
+ var conf = new ClientConfig("https://defectdojo.example.com", "f8....");
var productTypeService = new ProductTypeService(conf);
var productTypes = productTypeService.search();
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/config/Config.java b/src/main/java/io/securecodebox/persistence/defectdojo/config/ClientConfig.java
similarity index 78%
rename from src/main/java/io/securecodebox/persistence/defectdojo/config/Config.java
rename to src/main/java/io/securecodebox/persistence/defectdojo/config/ClientConfig.java
index 8f1b20dc..defed2a0 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/config/Config.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/config/ClientConfig.java
@@ -4,7 +4,7 @@
package io.securecodebox.persistence.defectdojo.config;
-import io.securecodebox.persistence.defectdojo.exception.ConfigException;
+import io.securecodebox.persistence.defectdojo.exception.ClientConfigException;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
@@ -16,7 +16,11 @@
@Getter
@ToString
@EqualsAndHashCode
-public final class Config {
+public final class ClientConfig {
+ /**
+ * Path prefix for the Defectdojo REST API
+ */
+ public static final String API_PREFIX = "/api/v2/";
/**
* Default for {@link #maxPageCountForGets}
*/
@@ -24,7 +28,7 @@ public final class Config {
/**
* Null pattern object.
*/
- public static final Config NULL = new Config("", "", DEFAULT_MAX_PAGE_COUNT_FOR_GETS);
+ public static final ClientConfig NULL = new ClientConfig("", "", DEFAULT_MAX_PAGE_COUNT_FOR_GETS);
/**
* URL of the host which serves the DefectDojo API.
@@ -59,7 +63,7 @@ public final class Config {
* @param url not {@code null}
* @param apiKey not {@code null}
*/
- public Config(final @NonNull String url, final @NonNull String apiKey) {
+ public ClientConfig(final @NonNull String url, final @NonNull String apiKey) {
this(url, apiKey, DEFAULT_MAX_PAGE_COUNT_FOR_GETS);
}
@@ -70,7 +74,7 @@ public Config(final @NonNull String url, final @NonNull String apiKey) {
* @param apiKey not {@code null}
* @param maxPageCountForGets not less than 1
*/
- public Config(final @NonNull String url, final @NonNull String apiKey, final int maxPageCountForGets) {
+ public ClientConfig(final @NonNull String url, final @NonNull String apiKey, final int maxPageCountForGets) {
super();
this.url = url;
this.apiKey = apiKey;
@@ -90,7 +94,7 @@ private static int validateIsGreaterZero(final int number, final String name) {
*
* @return never {@code null}
*/
- public static Config fromEnv() {
+ public static ClientConfig fromEnv() {
final var url = findRequiredEnvVar(EnvVars.DEFECTDOJO_URL);
final var apiKey = findRequiredEnvVar(EnvVars.DEFECTDOJO_APIKEY);
final int maxPageCountForGets;
@@ -99,14 +103,14 @@ public static Config fromEnv() {
try {
maxPageCountForGets = Integer.parseInt(findEnvVar(EnvVars.DEFECTDOJO_MAX_PAGE_COUNT_FOR_GETS));
} catch (final NumberFormatException e) {
- throw new ConfigException(String.format("Given value for environment variable '%s' is not a valid number! Given was '%s'.", EnvVars.DEFECTDOJO_MAX_PAGE_COUNT_FOR_GETS.literal, findEnvVar(EnvVars.DEFECTDOJO_MAX_PAGE_COUNT_FOR_GETS)),
+ throw new ClientConfigException(String.format("Given value for environment variable '%s' is not a valid number! Given was '%s'.", EnvVars.DEFECTDOJO_MAX_PAGE_COUNT_FOR_GETS.literal, findEnvVar(EnvVars.DEFECTDOJO_MAX_PAGE_COUNT_FOR_GETS)),
e);
}
} else {
maxPageCountForGets = DEFAULT_MAX_PAGE_COUNT_FOR_GETS;
}
- return new Config(url, apiKey, maxPageCountForGets);
+ return new ClientConfig(url, apiKey, maxPageCountForGets);
}
private static boolean hasEnvVar(final @NonNull EnvVars name) {
@@ -121,7 +125,7 @@ private static String findRequiredEnvVar(final @NonNull EnvVars name) {
final var envVar = System.getenv(name.literal);
if (envVar == null) {
- throw new ConfigException(String.format("Missing environment variable '%s'!", name.literal));
+ throw new ClientConfigException(String.format("Missing environment variable '%s'!", name.literal));
}
return envVar;
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/exception/ClientConfigException.java b/src/main/java/io/securecodebox/persistence/defectdojo/exception/ClientConfigException.java
new file mode 100644
index 00000000..cb055211
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/exception/ClientConfigException.java
@@ -0,0 +1,21 @@
+// Copyright 2021 iteratec GmbH
+// SPDX-FileCopyrightText: 2023 iteratec GmbH
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package io.securecodebox.persistence.defectdojo.exception;
+
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+
+/**
+ * Indicates a missing/bad {@link ClientConfig config property}
+ */
+public final class ClientConfigException extends PersistenceException {
+ public ClientConfigException(final String message) {
+ super(message);
+ }
+
+ public ClientConfigException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/exception/ConfigException.java b/src/main/java/io/securecodebox/persistence/defectdojo/exception/ConfigException.java
deleted file mode 100644
index 38b159ba..00000000
--- a/src/main/java/io/securecodebox/persistence/defectdojo/exception/ConfigException.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2021 iteratec GmbH
-// SPDX-FileCopyrightText: 2023 iteratec GmbH
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package io.securecodebox.persistence.defectdojo.exception;
-
-/**
- * Indicates a missing {@link io.securecodebox.persistence.defectdojo.config.Config config property}
- */
-public final class ConfigException extends RuntimeException {
- public ConfigException(final String message) {
- super(message);
- }
-
- public ConfigException(final String message, final Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/exception/LoopException.java b/src/main/java/io/securecodebox/persistence/defectdojo/exception/LoopException.java
deleted file mode 100644
index 5bebd374..00000000
--- a/src/main/java/io/securecodebox/persistence/defectdojo/exception/LoopException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-// SPDX-FileCopyrightText: the secureCodeBox authors
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package io.securecodebox.persistence.defectdojo.exception;
-
-public final class LoopException extends RuntimeException {
- public LoopException(String message) {
- super(message);
- }
-
- public LoopException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/exception/PersistenceException.java b/src/main/java/io/securecodebox/persistence/defectdojo/exception/PersistenceException.java
index b480c094..e890c4c0 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/exception/PersistenceException.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/exception/PersistenceException.java
@@ -4,7 +4,10 @@
package io.securecodebox.persistence.defectdojo.exception;
-public final class PersistenceException extends RuntimeException {
+/**
+ * Generic exception which is thrown for any unforeseen error at runtime
+ */
+public class PersistenceException extends RuntimeException {
public PersistenceException(String message) {
super(message);
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/exception/TooManyResponsesException.java b/src/main/java/io/securecodebox/persistence/defectdojo/exception/TooManyResponsesException.java
new file mode 100644
index 00000000..6af9e238
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/exception/TooManyResponsesException.java
@@ -0,0 +1,16 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package io.securecodebox.persistence.defectdojo.exception;
+
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+
+/**
+ * Thrown if we receive more objects than {@link ClientConfig configured}
+ */
+public final class TooManyResponsesException extends PersistenceException {
+ public TooManyResponsesException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/AuthHeaderFactory.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/AuthHeaderFactory.java
new file mode 100644
index 00000000..90c5a323
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/AuthHeaderFactory.java
@@ -0,0 +1,50 @@
+package io.securecodebox.persistence.defectdojo.http;
+
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import lombok.NonNull;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+/**
+ * Utility class to create HTTP authorization headers
+ */
+@Slf4j
+public final class AuthHeaderFactory {
+ private final ClientConfig clientConfig;
+ @Setter
+ @NonNull
+ private ProxyConfig proxyConfig = ProxyConfig.NULL;
+
+ public AuthHeaderFactory(@NonNull ClientConfig clientConfig) {
+ super();
+ this.clientConfig = clientConfig;
+ }
+
+ /**
+ * This method generates appropriate authorization headers
+ *
+ * @return never {@code null}
+ */
+ public HttpHeaders generateAuthorizationHeaders() {
+ final var headers = new HttpHeaders();
+ log.debug("Add Authorization header.");
+ headers.set(HttpHeaders.AUTHORIZATION, "Token " + this.clientConfig.getApiKey());
+
+ if (proxyConfig.isComplete()) {
+ log.debug("Add Proxy-Authorization header.");
+ headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic " + encodeProxyCredentials(proxyConfig));
+ }
+
+ return headers;
+ }
+
+ String encodeProxyCredentials(@NonNull final ProxyConfig cfg) {
+ final var credential = String.format("%s:%s", cfg.getUser(), cfg.getPassword());
+ return Base64.getEncoder().encodeToString(credential.getBytes(StandardCharsets.UTF_8));
+ }
+
+}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java
deleted file mode 100644
index a44b06c9..00000000
--- a/src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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 lombok.extern.slf4j.Slf4j;
-import org.apache.http.HttpHost;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.Credentials;
-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.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
- */
-@Slf4j
-public final class Foo {
- private final Config config;
- private final ProxyConfig proxyConfig;
-
- public Foo(@NonNull final Config config, @NonNull final ProxyConfig proxyConfig) {
- super();
- this.config = config;
- this.proxyConfig = proxyConfig;
- }
-
- /**
- * This method generates appropriate authorization headers
- *
- * @return never {@code null}
- */
- public HttpHeaders generateAuthorizationHeaders() {
- HttpHeaders headers = new HttpHeaders();
- headers.set(HttpHeaders.AUTHORIZATION, "Token " + this.config.getApiKey());
-
- if (proxyConfig.isComplete()) {
- log.info("Setting Proxy Auth Header...");
- headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic " + encodeProxyCredentials(proxyConfig));
- }
-
- return headers;
- }
-
- static String encodeProxyCredentials(@NonNull final ProxyConfig cfg) {
- final var credential = String.format("%s:%s", cfg.getUser(), cfg.getPassword());
- return Base64.getEncoder().encodeToString(credential.getBytes(StandardCharsets.UTF_8));
- }
-
- public RestTemplate createRestTemplate() {
- if (proxyConfig.isComplete()) {
- // Configuring Proxy Authentication explicitly as it isn't done by default for spring rest templates :(
- final var builder = HttpClientBuilder.create()
- .useSystemProperties()
- .setProxy(createHttpHost())
- .setDefaultCredentialsProvider(createCredentialsProvider())
- .setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
-
- final var factory = new HttpComponentsClientHttpRequestFactory();
- factory.setHttpClient(builder.build());
-
- return new RestTemplate(factory);
- }
-
- return new RestTemplate();
- }
-
- CredentialsProvider createCredentialsProvider() {
- final var provider = new BasicCredentialsProvider();
- provider.setCredentials(createAuthScope(), createCredentials());
- return provider;
- }
-
- AuthScope createAuthScope() {
- return new AuthScope(proxyConfig.getHost(), proxyConfig.getPort());
- }
-
- Credentials createCredentials() {
- return new UsernamePasswordCredentials(proxyConfig.getUser(), proxyConfig.getPassword());
- }
-
- HttpHost createHttpHost() {
- return new HttpHost(proxyConfig.getHost(), proxyConfig.getPort());
- }
-}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyCredentialFactory.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyCredentialFactory.java
new file mode 100644
index 00000000..b927dedb
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/ProxyCredentialFactory.java
@@ -0,0 +1,34 @@
+package io.securecodebox.persistence.defectdojo.http;
+
+import lombok.NonNull;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+
+/**
+ * Utility class to create credentials to authenticate against a HTTP proxy
+ */
+final class ProxyCredentialFactory {
+ private final ProxyConfig proxyConfig;
+
+ ProxyCredentialFactory(@NonNull ProxyConfig proxyConfig) {
+ super();
+ this.proxyConfig = proxyConfig;
+ }
+
+ CredentialsProvider createCredentialsProvider() {
+ final var provider = new BasicCredentialsProvider();
+ provider.setCredentials(createAuthScope(), createCredentials());
+ return provider;
+ }
+
+ AuthScope createAuthScope() {
+ return new AuthScope(proxyConfig.getHost(), proxyConfig.getPort());
+ }
+
+ Credentials createCredentials() {
+ return new UsernamePasswordCredentials(proxyConfig.getUser(), proxyConfig.getPassword());
+ }
+}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/http/RestTemplateFactory.java b/src/main/java/io/securecodebox/persistence/defectdojo/http/RestTemplateFactory.java
new file mode 100644
index 00000000..1b0f7f71
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/http/RestTemplateFactory.java
@@ -0,0 +1,49 @@
+// SPDX-FileCopyrightText: the secureCodeBox authors
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package io.securecodebox.persistence.defectdojo.http;
+
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpHost;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.ProxyAuthenticationStrategy;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Factory to create preconfigured {@link RestTemplate}
+ */
+@Slf4j
+public final class RestTemplateFactory {
+ private final ProxyConfig proxyConfig;
+
+ public RestTemplateFactory(@NonNull ProxyConfig proxyConfig) {
+ super();
+ this.proxyConfig = proxyConfig;
+ }
+
+ public RestTemplate createRestTemplate() {
+ if (proxyConfig.isComplete()) {
+ log.debug("Configure proxy authentication for REST template.");
+ // Configuring Proxy Authentication explicitly as it isn't done by default for spring rest templates :(
+ final var builder = HttpClientBuilder.create()
+ .useSystemProperties()
+ .setProxy(createHttpHost())
+ .setDefaultCredentialsProvider(new ProxyCredentialFactory(proxyConfig).createCredentialsProvider())
+ .setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
+
+ final var factory = new HttpComponentsClientHttpRequestFactory();
+ factory.setHttpClient(builder.build());
+
+ return new RestTemplate(factory);
+ }
+
+ return new RestTemplate();
+ }
+
+ HttpHost createHttpHost() {
+ return new HttpHost(proxyConfig.getHost(), proxyConfig.getPort());
+ }
+}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/Endpoint.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/Endpoint.java
index d1b31085..556cc649 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/model/Endpoint.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/Endpoint.java
@@ -26,7 +26,7 @@ public final class Endpoint implements Model, HasId {
@JsonProperty
private String host;
- @JsonProperty("fqdm")
+ @JsonProperty("fqdm") // FIXME: This seems to be a type, should be fqdn.
private String fullyQualifiedDomainName;
@JsonProperty
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/Model.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/Model.java
index 1b5af800..d41427c8 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/model/Model.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/Model.java
@@ -6,5 +6,15 @@
* Interface for all models
*/
public interface Model {
+ /**
+ * Compares this model with the given query parameters
+ *
queryParams);
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparator.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparator.java
index 9715aae5..bf99bb94 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparator.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparator.java
@@ -14,18 +14,55 @@
*
*/
final class QueryParamsComparator {
-
+ /**
+ * Query parameter name for id
+ */
static final String QUERY_PARAM_KEY_FOR_ID = "id";
+ /**
+ * Query parameter name for name
+ */
static final String QUERY_PARAM_KEY_FOR_NAME = "name";
+ /**
+ * Hidden for pure static helper class
+ */
private QueryParamsComparator() {
super();
}
+ /**
+ * Determines whether the given object is {@code null} or not
+ *
+ * @param o maybe {@code null}
+ * @return {@code true} if {@code o} is {@code null}, else {@code false}
+ */
static boolean isNull(Object o) {
return o == null;
}
+ /**
+ * Determines whether the {@link HasId id} of the given model object is equal the given {@link #QUERY_PARAM_KEY_FOR_ID id}
+ *
+ * Example:
+ *
+ *
+ * {@code
+ * final var model = ...
+ * final var queryParams = new HashMap();
+ * queryParams.put(QueryParamsComparator.QUERY_PARAM_KEY_FOR_ID, 42);
+ *
+ * if (QueryParamsComparator.isIdEqual(model, queryParams)) {
+ * ...
+ * }
+ * }
+ *
+ *
+ * TODO: What about type conversions? The id is a long in the models, but it may be a string in the map. Should it be treated as equal (42 == "42")?
+ *
+ * @param model may be {@code null}
+ * @param queryParams may be {@code null}
+ * @return {@code true} id id is equal, else {@code false}
+ */
static boolean isIdEqual(HasId model, Map queryParams) {
if (isNull(model)) {
return false;
@@ -46,6 +83,28 @@ static boolean isIdEqual(HasId model, Map queryParams) {
return queryParams.get(QUERY_PARAM_KEY_FOR_ID).equals(model.getId());
}
+ /**
+ * Determines whether the {@link HasName name} of the given model object is equal the given {@link #QUERY_PARAM_KEY_FOR_NAME name}
+ *
+ * Example:
+ *
+ *
+ * {@code
+ * final var model = ...
+ * final var queryParams = new HashMap();
+ * queryParams.put(QueryParamsComparator.QUERY_PARAM_KEY_FOR_NAME, "foo");
+ *
+ * if (QueryParamsComparator.isNameEqual(model, queryParams)) {
+ * ...
+ * }
+ * }
+ *
+ *
+ *
+ * @param model may be {@code null}
+ * @param queryParams may be {@code null}
+ * @return {@code true} if name is equal, else {@code false}
+ */
static boolean isNameEqual(HasName model, Map queryParams) {
if (isNull(model)) {
return false;
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 00bb63bd..8d8b2d8e 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java
@@ -5,7 +5,7 @@
package io.securecodebox.persistence.defectdojo.service;
import io.securecodebox.persistence.defectdojo.ScanType;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.http.ProxyConfig;
import io.securecodebox.persistence.defectdojo.model.ScanFile;
@@ -56,13 +56,13 @@ class DefaultImportScanService implements ImportScanService {
/**
* Dedicated constructor.
*
- * @param config not {@code null}
+ * @param clientConfig not {@code null}
* @param proxyConfig not {@code null}
*/
- DefaultImportScanService(final @NonNull Config config, @NonNull ProxyConfig proxyConfig) {
+ DefaultImportScanService(final @NonNull ClientConfig clientConfig, @NonNull ProxyConfig proxyConfig) {
super();
- this.defectDojoUrl = config.getUrl();
- this.defectDojoApiKey = config.getApiKey();
+ this.defectDojoUrl = clientConfig.getUrl();
+ this.defectDojoApiKey = clientConfig.getApiKey();
this.proxyConfig = proxyConfig;
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefectDojoService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefectDojoService.java
index ed28a8e1..b5524a4a 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/DefectDojoService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/DefectDojoService.java
@@ -3,11 +3,9 @@
// SPDX-License-Identifier: Apache-2.0
package io.securecodebox.persistence.defectdojo.service;
-import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.Model;
import lombok.NonNull;
-import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -33,19 +31,15 @@ public interface DefectDojoService {
*
* @param queryParams not {@code null}
* @return not {@code null}, maybe empty
- * @throws URISyntaxException
- * @throws JsonProcessingException
*/
- List search(@NonNull Map queryParams) throws URISyntaxException, JsonProcessingException;
+ List search(@NonNull Map queryParams);
/**
* Get list of all model objects in DefectDojo
*
* @return never {@code null}, maybe empty
- * @throws URISyntaxException
- * @throws JsonProcessingException
*/
- List search() throws URISyntaxException, JsonProcessingException;
+ List search();
/**
* Search for a single model object in DefectDojo
@@ -55,10 +49,8 @@ public interface DefectDojoService {
*
* @param searchObject not {@code null}
* @return never {@code null}
- * @throws URISyntaxException
- * @throws JsonProcessingException
*/
- Optional searchUnique(@NonNull T searchObject) throws URISyntaxException, JsonProcessingException;
+ Optional searchUnique(@NonNull T searchObject);
/**
* Search for a single model object in DefectDojo
@@ -68,10 +60,8 @@ public interface DefectDojoService {
*
* @param queryParams not {@code null}
* @return never {@code null}
- * @throws URISyntaxException
- * @throws JsonProcessingException
*/
- Optional searchUnique(@NonNull Map queryParams) throws URISyntaxException, JsonProcessingException;
+ Optional searchUnique(@NonNull Map queryParams);
/**
* Create the given model object in DefectDojo
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/EndpointService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/EndpointService.java
index 97fc20c3..ed29d5a7 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/EndpointService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/EndpointService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.Endpoint;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import lombok.NonNull;
public class EndpointService extends GenericDefectDojoService {
- public EndpointService(Config config) {
- super(config);
+ public EndpointService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/EngagementService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/EngagementService.java
index 57877106..1f8521a7 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/EngagementService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/EngagementService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.Engagement;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import lombok.NonNull;
public class EngagementService extends GenericDefectDojoService {
- public EngagementService(Config config) {
- super(config);
+ public EngagementService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/FindingService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/FindingService.java
index 032a09f6..8d9950ee 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/FindingService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/FindingService.java
@@ -6,18 +6,18 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.Finding;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import lombok.NonNull;
-import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
public class FindingService extends GenericDefectDojoService {
- public FindingService(Config config) {
- super(config);
+ public FindingService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -31,12 +31,16 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
- public List getUnhandledFindingsForProduct(long productId, Finding.Severity minimumSeverity) throws URISyntaxException, JsonProcessingException {
+ public List getUnhandledFindingsForProduct(long productId, Finding.Severity minimumSeverity) {
final Map queryParams = Map.of(
"test__engagement__product", Long.toString(productId),
"active", Boolean.toString(true));
@@ -47,7 +51,7 @@ public List getUnhandledFindingsForProduct(long productId, Finding.Seve
.toList();
}
- public List getUnhandledFindingsForEngagement(long engagementId, Finding.Severity minimumSeverity) throws URISyntaxException, JsonProcessingException {
+ public List getUnhandledFindingsForEngagement(long engagementId, Finding.Severity minimumSeverity) {
final Map queryParams = Map.of(
"test__engagement", Long.toString(engagementId),
"active", Boolean.toString(true));
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 2119c618..00d3902c 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoService.java
@@ -4,20 +4,15 @@
package io.securecodebox.persistence.defectdojo.service;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.cfg.CoercionAction;
-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.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.TooManyResponsesException;
+import io.securecodebox.persistence.defectdojo.http.AuthHeaderFactory;
+import io.securecodebox.persistence.defectdojo.http.ProxyConfig;
import io.securecodebox.persistence.defectdojo.http.ProxyConfigFactory;
-import io.securecodebox.persistence.defectdojo.model.Engagement;
+import io.securecodebox.persistence.defectdojo.http.RestTemplateFactory;
import io.securecodebox.persistence.defectdojo.model.Model;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
-import lombok.Getter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
@@ -33,47 +28,50 @@
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
-import java.net.URISyntaxException;
import java.util.*;
-// TODO: Remove JsonProcessingException, URISyntaxException from public API and use a own runtime exception type bc these checked exceptions clutter the client coe.
+/**
+ * Generic base implementation with common functionality shared by services
+ *
+ * @param type of model the service handles
+ */
@Slf4j
abstract class GenericDefectDojoService implements DefectDojoService {
- private static final String API_PREFIX = "/api/v2/";
private static final long DEFECT_DOJO_OBJET_LIMIT = 100L;
- protected Config config;
+ private final ClientConfig clientConfig;
+ private final ProxyConfig proxyConfig;
+ private final RestTemplate restTemplate;
+ private final Mappers mapper = new Mappers();
- protected ObjectMapper objectMapper;
- protected ObjectMapper searchStringMapper;
-
- @Getter
- protected RestTemplate restTemplate;
+ /**
+ * Convenience constructor which initializes {@link #proxyConfig}
+ *
+ * @param clientConfig not {@code null}
+ */
+ public GenericDefectDojoService(ClientConfig clientConfig) {
+ this(clientConfig, new ProxyConfigFactory().create());
+ }
- public GenericDefectDojoService(@NonNull Config config) {
+ /**
+ * Dedicated constructor
+ *
+ * @param clientConfig not {@code null}
+ * @param proxyConfig not {@code null}
+ */
+ public GenericDefectDojoService(@NonNull ClientConfig clientConfig, @NonNull ProxyConfig proxyConfig) {
super();
- this.config = config;
-
- this.objectMapper = new ObjectMapper();
- this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- this.objectMapper.coercionConfigFor(Engagement.Status.class).setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
- this.objectMapper.findAndRegisterModules();
-
- this.searchStringMapper = new ObjectMapper();
- this.searchStringMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- this.searchStringMapper.coercionConfigFor(Engagement.Status.class).setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
- this.searchStringMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
-
- this.restTemplate = this.setupRestTemplate();
+ this.clientConfig = clientConfig;
+ this.proxyConfig = proxyConfig;
+ this.restTemplate = setupRestTemplate();
}
@Override
public final T get(long id) {
- var restTemplate = this.getRestTemplate();
- HttpEntity payload = new HttpEntity<>(getDefectDojoAuthorizationHeaders());
+ final HttpEntity payload = createRequestEntity(createAuthorizationHeaders());
- final var url = this.config.getUrl() + API_PREFIX + this.getUrlPath() + "/" + id;
+ final var url = createBaseUrl().resolve(String.valueOf(id));
log.debug("Requesting URL: {}", url);
- ResponseEntity response = restTemplate.exchange(
+ final ResponseEntity response = restTemplate.exchange(
url,
HttpMethod.GET,
payload,
@@ -84,35 +82,40 @@ public final T get(long id) {
}
@Override
- public final List search(@NonNull Map queryParams) throws URISyntaxException, JsonProcessingException {
- List objects = new LinkedList<>();
+ public final List search() {
+ return search(Collections.emptyMap());
+ }
+
+ @Override
+ public final List search(@NonNull Map queryParams) {
+ final List objects = new LinkedList<>();
boolean hasNext;
long page = 0;
do {
- var response = internalSearch(queryParams, DEFECT_DOJO_OBJET_LIMIT, DEFECT_DOJO_OBJET_LIMIT * page++);
+ final var response = internalSearch(queryParams, DEFECT_DOJO_OBJET_LIMIT, DEFECT_DOJO_OBJET_LIMIT * page++);
objects.addAll(response.getResults());
-
hasNext = response.getNext() != null;
- if (page > this.config.getMaxPageCountForGets()) {
- throw new LoopException("Found too many response object. Quitting after " + (page - 1) + " paginated API pages of " + DEFECT_DOJO_OBJET_LIMIT + " each.");
+
+ if (page > this.clientConfig.getMaxPageCountForGets()) {
+ final var msg = String.format(
+ "Found too many response object. Quitting after %d paginated API pages of %d each.",
+ page - 1,
+ DEFECT_DOJO_OBJET_LIMIT
+ );
+ throw new TooManyResponsesException(msg);
}
} while (hasNext);
return objects;
}
- @Override
- public final List search() throws URISyntaxException, JsonProcessingException {
- return search(new LinkedHashMap<>());
- }
-
@Override
@SuppressWarnings("unchecked")
- public final Optional searchUnique(T searchObject) throws URISyntaxException, JsonProcessingException {
- Map queryParams = searchStringMapper.convertValue(searchObject, Map.class);
-
- var objects = search(queryParams);
+ public final Optional searchUnique(@NonNull T searchObject) {
+ final Map queryParams = mapper.searchStringMapper()
+ .convertValue(searchObject, Map.class);
+ final var objects = search(queryParams);
return objects.stream()
.filter(object -> object != null && object.equalsQueryString(queryParams))
@@ -120,42 +123,48 @@ public final Optional searchUnique(T searchObject) throws URISyntaxException,
}
@Override
- public final Optional searchUnique(@NonNull Map queryParams) throws URISyntaxException, JsonProcessingException {
- var objects = search(queryParams);
+ public final Optional searchUnique(@NonNull Map queryParams) {
+ final var found = search(queryParams);
- return objects.stream()
+ return found.stream()
.filter(object -> object.equalsQueryString(queryParams))
.findFirst();
}
@Override
public final T create(@NonNull T object) {
- var restTemplate = this.getRestTemplate();
- HttpEntity payload = new HttpEntity<>(object, getDefectDojoAuthorizationHeaders());
+ final HttpEntity payload = createRequestEntity(object, createAuthorizationHeaders());
+ final ResponseEntity response = restTemplate.exchange(createBaseUrl(), HttpMethod.POST, payload, getModelClass());
- ResponseEntity response = restTemplate.exchange(this.config.getUrl() + API_PREFIX + getUrlPath() + "/", HttpMethod.POST, payload, getModelClass());
return response.getBody();
}
@Override
public final void delete(long id) {
- var restTemplate = this.getRestTemplate();
- HttpEntity payload = new HttpEntity<>(getDefectDojoAuthorizationHeaders());
-
- restTemplate.exchange(this.config.getUrl() + API_PREFIX + getUrlPath() + "/" + id + "/", HttpMethod.DELETE, payload, String.class);
+ final HttpEntity payload = createRequestEntity(createAuthorizationHeaders());
+ final var url = createBaseUrl().resolve(id + "/");
+ restTemplate.exchange(url, HttpMethod.DELETE, payload, String.class);
}
@Override
public final T update(@NonNull T object, long id) {
- var restTemplate = this.getRestTemplate();
- HttpEntity payload = new HttpEntity<>(object, getDefectDojoAuthorizationHeaders());
+ final HttpEntity payload = createRequestEntity(object, createAuthorizationHeaders());
+ final var url = createBaseUrl().resolve(id + "/");
+ final ResponseEntity response = restTemplate.exchange(url, HttpMethod.PUT, payload, getModelClass());
- ResponseEntity response = restTemplate.exchange(this.config.getUrl() + API_PREFIX + getUrlPath() + "/" + id + "/", HttpMethod.PUT, payload, getModelClass());
return response.getBody();
}
-
+
+ private HttpEntity createRequestEntity(HttpHeaders headers) {
+ return createRequestEntity("", headers);
+ }
+
+ private HttpEntity createRequestEntity(M body, HttpHeaders headers) {
+ return new HttpEntity<>(body, headers);
+ }
+
/**
- * Get the URL path for the REST endpoint relative to {@link #API_PREFIX}
+ * Get the URL path for the REST endpoint relative to {@link ClientConfig#API_PREFIX}
*
* @return not {@code null}, not empty
*/
@@ -173,50 +182,63 @@ public final T update(@NonNull T object, long id) {
*
* @param response not {@code null}, maybe empty
* @return not {@code null}
- * @throws JsonProcessingException if string is not parsable as JSON
*/
- protected abstract PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException;
+ protected abstract PaginatedResult deserializeList(@NonNull String response);
- /**
- * @return The DefectDojo Authentication Header
- */
- private HttpHeaders getDefectDojoAuthorizationHeaders() {
- return new Foo(config, new ProxyConfigFactory().create()).generateAuthorizationHeaders();
+ final URI createBaseUrl() {
+ final var buffer = clientConfig.getUrl() +
+ ClientConfig.API_PREFIX +
+ getUrlPath() +
+ '/';
+
+ return URI.create(buffer).normalize();
+ }
+
+ final ObjectMapper modelObjectMapper() {
+ // We only expose this mapper to subclasses.
+ return mapper.modelObjectMapper();
+ }
+
+ private HttpHeaders createAuthorizationHeaders() {
+ final var factory = new AuthHeaderFactory(clientConfig);
+ factory.setProxyConfig(proxyConfig);
+ return factory.generateAuthorizationHeaders();
}
private RestTemplate setupRestTemplate() {
- RestTemplate restTemplate = new Foo(config, new ProxyConfigFactory().create()).createRestTemplate();
- MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
- converter.setObjectMapper(this.objectMapper);
- restTemplate.setMessageConverters(List.of(
+ final RestTemplate template = new RestTemplateFactory(proxyConfig).createRestTemplate();
+ // TODO: Maybe all of this could be moved into the factory.
+ final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
+ converter.setObjectMapper(mapper.modelObjectMapper());
+ template.setMessageConverters(List.of(
new FormHttpMessageConverter(),
new ResourceHttpMessageConverter(),
new StringHttpMessageConverter(),
converter
));
- return restTemplate;
+ return template;
}
- protected PaginatedResult internalSearch(Map queryParams, long limit, long offset) throws JsonProcessingException, URISyntaxException {
- var restTemplate = this.getRestTemplate();
- HttpEntity payload = new HttpEntity<>(getDefectDojoAuthorizationHeaders());
-
- var mutableQueryParams = new HashMap<>(queryParams);
+ protected PaginatedResult internalSearch(Map queryParams, long limit, long offset) {
+ final HttpEntity payload = createRequestEntity(createAuthorizationHeaders());
+ final var mutableQueryParams = new HashMap<>(queryParams);
mutableQueryParams.put("limit", String.valueOf(limit));
mutableQueryParams.put("offset", String.valueOf(offset));
- var multiValueMap = new LinkedMultiValueMap();
+ final var multiValueMap = new LinkedMultiValueMap();
for (var entry : mutableQueryParams.entrySet()) {
multiValueMap.set(entry.getKey(), String.valueOf(entry.getValue()));
}
- var url = new URI(this.config.getUrl() + API_PREFIX + this.getUrlPath() + "/");
- log.debug("Requesting URL: " + url);
- var uriBuilder = UriComponentsBuilder.fromUri(url).queryParams(multiValueMap);
+ final var url = createBaseUrl();
+ final UriComponentsBuilder builder;
+ builder = UriComponentsBuilder
+ .fromUri(url)
+ .queryParams(multiValueMap);
- ResponseEntity responseString = restTemplate.exchange(
- uriBuilder.build(mutableQueryParams),
+ final ResponseEntity responseString = restTemplate.exchange(
+ builder.build(mutableQueryParams),
HttpMethod.GET,
payload,
String.class
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/GroupMemberService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/GroupMemberService.java
index ecd2176b..2c1dfdf1 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/GroupMemberService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/GroupMemberService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.GroupMember;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import lombok.NonNull;
public class GroupMemberService extends GenericDefectDojoService {
- public GroupMemberService(Config config) {
- super(config);
+ public GroupMemberService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/GroupService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/GroupService.java
index 0d5155b7..b2cdd0fd 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/GroupService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/GroupService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.Group;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import lombok.NonNull;
public class GroupService extends GenericDefectDojoService {
- public GroupService(Config config) {
- super(config);
+ public GroupService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
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 32ca3e5c..20150d93 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService.java
@@ -6,7 +6,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import io.securecodebox.persistence.defectdojo.ScanType;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import io.securecodebox.persistence.defectdojo.http.ProxyConfig;
import io.securecodebox.persistence.defectdojo.http.ProxyConfigFactory;
import io.securecodebox.persistence.defectdojo.model.ScanFile;
@@ -23,22 +23,22 @@ public interface ImportScanService {
/**
* Factory method to create new instance of service default implementation
*
- * @param config must not be {@code null}
+ * @param clientConfig must not be {@code null}
* @return never {@code null}
*/
- static ImportScanService createDefault(final Config config) {
- return createDefault(config, new ProxyConfigFactory().create());
+ static ImportScanService createDefault(final ClientConfig clientConfig) {
+ return createDefault(clientConfig, new ProxyConfigFactory().create());
}
/**
* Factory method to create new instance of service default implementation
*
- * @param config must not be {@code null}
+ * @param clientConfig 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);
+ static ImportScanService createDefault(@NonNull final ClientConfig clientConfig, @NonNull final ProxyConfig proxyConfig) {
+ return new DefaultImportScanService(clientConfig, proxyConfig);
}
default ImportScanResponse importScan(ScanFile scanFile, long engagementId, long lead, String currentDate, ScanType scanType, long testType) {
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 28d809b3..b3081885 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ImportScanService2.java
@@ -6,9 +6,10 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import io.securecodebox.persistence.defectdojo.ScanType;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
-import io.securecodebox.persistence.defectdojo.http.Foo;
+import io.securecodebox.persistence.defectdojo.http.AuthHeaderFactory;
+import io.securecodebox.persistence.defectdojo.http.RestTemplateFactory;
import io.securecodebox.persistence.defectdojo.http.ProxyConfigFactory;
import io.securecodebox.persistence.defectdojo.model.ScanFile;
import lombok.Data;
@@ -36,22 +37,24 @@
@Deprecated(forRemoval = true)
public class ImportScanService2 {
- private final Config config;
+ private final ClientConfig clientConfig;
- public ImportScanService2(Config config) {
+ public ImportScanService2(ClientConfig clientConfig) {
super();
- this.config = config;
+ this.clientConfig = clientConfig;
}
/**
* @return The DefectDojo Authentication Header
*/
private HttpHeaders getDefectDojoAuthorizationHeaders() {
- return new Foo(config, new ProxyConfigFactory().create()).generateAuthorizationHeaders();
+ final var factory = new AuthHeaderFactory(clientConfig);
+ factory.setProxyConfig(new ProxyConfigFactory().create());
+ return factory.generateAuthorizationHeaders();
}
protected RestTemplate setupRestTemplate() {
- return new Foo(config, new ProxyConfigFactory().create()).createRestTemplate();
+ return new RestTemplateFactory(new ProxyConfigFactory().create()).createRestTemplate();
}
/**
@@ -93,7 +96,7 @@ public String getFilename() {
var payload = new HttpEntity<>(mvn, headers);
- return restTemplate.exchange(config.getUrl() + "/api/v2/" + endpoint + "/", HttpMethod.POST, payload, ImportScanResponse.class).getBody();
+ return restTemplate.exchange(clientConfig.getUrl() + "/api/v2/" + endpoint + "/", HttpMethod.POST, payload, ImportScanResponse.class).getBody();
} catch (HttpClientErrorException e) {
throw new PersistenceException("Failed to attach findings to engagement.");
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/Mappers.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/Mappers.java
new file mode 100644
index 00000000..f5facea9
--- /dev/null
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/Mappers.java
@@ -0,0 +1,40 @@
+package io.securecodebox.persistence.defectdojo.service;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.cfg.CoercionAction;
+import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
+import io.securecodebox.persistence.defectdojo.model.Engagement;
+import lombok.Getter;
+import lombok.experimental.Accessors;
+
+/**
+ * Provides pre configured Jackson mappers
+ */
+@Getter
+@Accessors(fluent = true)
+final class Mappers {
+ private final ObjectMapper modelObjectMapper = new ObjectMapper();
+ private final ObjectMapper searchStringMapper = new ObjectMapper();
+
+ Mappers() {
+ super();
+ configureModelObjectMapper();
+ configureSearchStringMapper();
+ }
+
+ private void configureModelObjectMapper() {
+ modelObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ modelObjectMapper.coercionConfigFor(Engagement.Status.class)
+ .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
+ modelObjectMapper.findAndRegisterModules();
+ }
+
+ private void configureSearchStringMapper() {
+ searchStringMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ searchStringMapper.coercionConfigFor(Engagement.Status.class)
+ .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
+ searchStringMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
+ }
+}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductGroupService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductGroupService.java
index 40c8faee..5bfe4898 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductGroupService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductGroupService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.ProductGroup;
import lombok.NonNull;
public class ProductGroupService extends GenericDefectDojoService {
- public ProductGroupService(Config config) {
- super(config);
+ public ProductGroupService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductService.java
index 77429c02..08c47ec1 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductService.java
@@ -6,15 +6,16 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.Product;
import lombok.NonNull;
public class ProductService extends GenericDefectDojoService {
- public ProductService(Config config) {
- super(config);
+ public ProductService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -28,8 +29,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductTypeService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductTypeService.java
index fc8b5b0f..ae54229d 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductTypeService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ProductTypeService.java
@@ -6,15 +6,16 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.ProductType;
import lombok.NonNull;
public final class ProductTypeService extends GenericDefectDojoService {
- public ProductTypeService(Config config) {
- super(config);
+ public ProductTypeService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -28,8 +29,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/TestService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/TestService.java
index c715075c..34644d34 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/TestService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/TestService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.Test;
import lombok.NonNull;
public class TestService extends GenericDefectDojoService {
- public TestService(Config config) {
- super(config);
+ public TestService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/TestTypeService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/TestTypeService.java
index fc463a7b..bd46becd 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/TestTypeService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/TestTypeService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.TestType;
import lombok.NonNull;
public class TestTypeService extends GenericDefectDojoService {
- public TestTypeService(Config config) {
- super(config);
+ public TestTypeService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ToolConfigService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ToolConfigService.java
index 0212c45d..a016593f 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ToolConfigService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ToolConfigService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.ToolConfig;
import lombok.NonNull;
public class ToolConfigService extends GenericDefectDojoService {
- public ToolConfigService(Config config) {
- super(config);
+ public ToolConfigService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/ToolTypeService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/ToolTypeService.java
index 1941fb4f..3c8d96d6 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/ToolTypeService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/ToolTypeService.java
@@ -6,7 +6,8 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.ToolType;
import lombok.NonNull;
@@ -20,8 +21,8 @@ public class ToolTypeService extends GenericDefectDojoService {
@Deprecated(forRemoval = true) // Unused
public static final String SECURITY_TEST_SERVER_NAME = "Security Test Orchestration Engine";
- public ToolTypeService(Config config) {
- super(config);
+ public ToolTypeService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -35,8 +36,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/UserProfileService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/UserProfileService.java
index 2df7d424..20244bd1 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/UserProfileService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/UserProfileService.java
@@ -6,7 +6,8 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.UserProfile;
import lombok.NonNull;
@@ -15,8 +16,8 @@
public final class UserProfileService extends GenericDefectDojoService {
- public UserProfileService(Config config) {
- super(config);
+ public UserProfileService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -30,13 +31,18 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
+ protected PaginatedResult deserializeList(@NonNull String response) {
/* GenericDefectDojoService expects that the response from the defectdojo api is a list.
* This endpoint returns a single object though, to not break the code this response
* gets converted to a defectdojo response.
*/
- final var userProfile = this.objectMapper.readValue(response, new TypeReference() {
- });
+ final UserProfile userProfile;
+ try {
+ userProfile = modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
final var result = new PaginatedResult();
result.setResults(List.of(userProfile));
result.setCount(1);
diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/service/UserService.java b/src/main/java/io/securecodebox/persistence/defectdojo/service/UserService.java
index 5e666f3d..83375e12 100644
--- a/src/main/java/io/securecodebox/persistence/defectdojo/service/UserService.java
+++ b/src/main/java/io/securecodebox/persistence/defectdojo/service/UserService.java
@@ -6,14 +6,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import io.securecodebox.persistence.defectdojo.model.User;
import lombok.NonNull;
public class UserService extends GenericDefectDojoService {
- public UserService(Config config) {
- super(config);
+ public UserService(ClientConfig clientConfig) {
+ super(clientConfig);
}
@Override
@@ -27,8 +28,12 @@ protected Class getModelClass() {
}
@Override
- protected PaginatedResult deserializeList(@NonNull String response) throws JsonProcessingException {
- return this.objectMapper.readValue(response, new TypeReference<>() {
- });
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ try {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ } catch (JsonProcessingException e) {
+ throw new PersistenceException("Can't process JSON response!", e);
+ }
}
}
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/config/ConfigTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/config/ClientConfigTest.java
similarity index 80%
rename from src/test/java/io/securecodebox/persistence/defectdojo/config/ConfigTest.java
rename to src/test/java/io/securecodebox/persistence/defectdojo/config/ClientConfigTest.java
index 8ffa3de0..4052c871 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/config/ConfigTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/config/ClientConfigTest.java
@@ -4,7 +4,7 @@
package io.securecodebox.persistence.defectdojo.config;
-import io.securecodebox.persistence.defectdojo.exception.ConfigException;
+import io.securecodebox.persistence.defectdojo.exception.ClientConfigException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
@@ -20,10 +20,10 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
- * Tests for {@link Config}
+ * Tests for {@link ClientConfig}
*/
@ExtendWith(SystemStubsExtension.class)
-class ConfigTest {
+class ClientConfigTest {
@SystemStub
private EnvironmentVariables environmentVariables;
@@ -31,7 +31,7 @@ class ConfigTest {
@Test
void constructor_urlMustNotBeNull() {
final var thrown = assertThrows(NullPointerException.class, () -> {
- new Config(null, "apiKey", 1);
+ new ClientConfig(null, "apiKey", 1);
});
assertThat(thrown.getMessage(), startsWith("url "));
@@ -40,7 +40,7 @@ void constructor_urlMustNotBeNull() {
@Test
void constructor_apiKeyMustNotBeNull() {
final var thrown = assertThrows(NullPointerException.class, () -> {
- new Config("url", null, 1);
+ new ClientConfig("url", null, 1);
});
assertThat(thrown.getMessage(), startsWith("apiKey "));
@@ -50,7 +50,7 @@ void constructor_apiKeyMustNotBeNull() {
@ValueSource(ints = {0, -1, -2, -23, -42, Integer.MIN_VALUE})
void constructor_maxPageCountForGetsMustNotBeLessThanOne(final int number) {
final var thrown = assertThrows(IllegalArgumentException.class, () -> {
- new Config("url", "apiKey", number);
+ new ClientConfig("url", "apiKey", number);
});
assertThat(thrown.getMessage(), startsWith("maxPageCountForGets "));
@@ -63,7 +63,7 @@ void fromEnv() {
.set("DEFECTDOJO_APIKEY", "apikey")
.set("DEFECTDOJO_MAX_PAGE_COUNT_FOR_GETS", "23");
- final var sut = Config.fromEnv();
+ final var sut = ClientConfig.fromEnv();
assertAll(
() -> assertThat(sut.getUrl(), is("url")),
@@ -77,7 +77,7 @@ void fromEnv_throwsExceptionIfNoUrlSet() {
environmentVariables
.set("DEFECTDOJO_APIKEY", "apikey");
- final var thrown = assertThrows(ConfigException.class, Config::fromEnv);
+ final var thrown = assertThrows(ClientConfigException.class, ClientConfig::fromEnv);
assertThat(thrown.getMessage(), is("Missing environment variable 'DEFECTDOJO_URL'!"));
}
@@ -87,7 +87,7 @@ void fromEnv_throwsExceptionIfNoApiKeySet() {
environmentVariables
.set("DEFECTDOJO_URL", "url");
- final var thrown = assertThrows(ConfigException.class, Config::fromEnv);
+ final var thrown = assertThrows(ClientConfigException.class, ClientConfig::fromEnv);
assertThat(thrown.getMessage(), is("Missing environment variable 'DEFECTDOJO_APIKEY'!"));
}
@@ -98,8 +98,8 @@ void fromEnv_usesDefaultIfNoMaxPageCountForGetSet() {
.set("DEFECTDOJO_URL", "url")
.set("DEFECTDOJO_APIKEY", "apikey");
- final var sut = Config.fromEnv();
- assertThat(sut.getMaxPageCountForGets(), is(Config.DEFAULT_MAX_PAGE_COUNT_FOR_GETS));
+ final var sut = ClientConfig.fromEnv();
+ assertThat(sut.getMaxPageCountForGets(), is(ClientConfig.DEFAULT_MAX_PAGE_COUNT_FOR_GETS));
}
@Test
@@ -109,7 +109,7 @@ void fromEnv_throwsExceptionIfMaxPageCountForGetIsNotParseableToInteger() {
.set("DEFECTDOJO_APIKEY", "apikey")
.set("DEFECTDOJO_MAX_PAGE_COUNT_FOR_GETS", "foo");
- final var thrown = assertThrows(ConfigException.class, Config::fromEnv);
+ final var thrown = assertThrows(ClientConfigException.class, ClientConfig::fromEnv);
assertThat(thrown.getMessage(), is("Given value for environment variable 'DEFECTDOJO_MAX_PAGE_COUNT_FOR_GETS' is not a valid number! Given was 'foo'."));
}
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/AuthHeaderFactoryTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/AuthHeaderFactoryTest.java
new file mode 100644
index 00000000..41cd7637
--- /dev/null
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/AuthHeaderFactoryTest.java
@@ -0,0 +1,65 @@
+package io.securecodebox.persistence.defectdojo.http;
+
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpHeaders;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Tests for {@link AuthHeaderFactory}
+ */
+class AuthHeaderFactoryTest {
+ private final ClientConfig clientConfig = new ClientConfig("url", "apikey");
+ private final AuthHeaderFactory sut = new AuthHeaderFactory(clientConfig);
+
+ @Test
+ void setProxyConfig_doesNotAllowNull() {
+ assertThrows(NullPointerException.class, () -> sut.setProxyConfig(null));
+ }
+
+ @Test
+ void generateAuthorizationHeaders_withoutProxyAuth() {
+ assertAll(
+ () -> assertThat(
+ sut.generateAuthorizationHeaders().get(HttpHeaders.AUTHORIZATION),
+ contains("Token apikey")),
+ () -> assertThat(
+ sut.generateAuthorizationHeaders().get(HttpHeaders.PROXY_AUTHORIZATION),
+ not(contains("Basic dXNlcjpwdw==")))
+ );
+ }
+
+ @Test
+ void generateAuthorizationHeaders_withProxyAuth() {
+ final ProxyConfig proxyConfig = ProxyConfig.builder()
+ .user("user")
+ .password("pw")
+ .host("host")
+ .port(42)
+ .build();
+ sut.setProxyConfig(proxyConfig);
+
+ assertAll(
+ () -> assertThat(
+ sut.generateAuthorizationHeaders().get(HttpHeaders.AUTHORIZATION),
+ contains("Token apikey")),
+ () -> assertThat(
+ sut.generateAuthorizationHeaders().get(HttpHeaders.PROXY_AUTHORIZATION),
+ contains("Basic dXNlcjpwdw=="))
+ );
+ }
+
+ @Test
+ void encodeProxyCredentials() {
+ final var proxyConfig = ProxyConfig.builder()
+ .user("bärtram")
+ .password("gohze8Ae")
+ .build();
+
+ assertThat(sut.encodeProxyCredentials(proxyConfig), is("YsOkcnRyYW06Z29oemU4QWU="));
+ }
+}
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/FooTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/FooTest.java
deleted file mode 100644
index 58f6e287..00000000
--- a/src/test/java/io/securecodebox/persistence/defectdojo/http/FooTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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 org.junit.jupiter.api.Test;
-import org.springframework.http.HttpHeaders;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.*;
-import static org.junit.jupiter.api.Assertions.assertAll;
-
-/**
- * Tests for {@link Foo}
- */
-class FooTest {
- private final Config config = new Config("url", "apikey");
- private final ProxyConfig proxyConfig = ProxyConfig.builder()
- .user("user")
- .password("pw")
- .host("host")
- .port(42)
- .build();
- private final Foo sut = new Foo(config, proxyConfig);
-
- @Test
- void generateAuthorizationHeaders_withoutProxyAuth() {
- final var innerSut = new Foo(config, ProxyConfig.NULL);
-
- assertAll(
- () -> assertThat(
- innerSut.generateAuthorizationHeaders().get(HttpHeaders.AUTHORIZATION),
- contains("Token apikey")),
- () -> assertThat(
- innerSut.generateAuthorizationHeaders().get(HttpHeaders.PROXY_AUTHORIZATION),
- not(contains("Basic dXNlcjpwdw==")))
- );
- }
-
- @Test
- void generateAuthorizationHeaders_withProxyAuth() {
- final var innerSut = new Foo(config, proxyConfig);
-
- assertAll(
- () -> assertThat(
- innerSut.generateAuthorizationHeaders().get(HttpHeaders.AUTHORIZATION),
- contains("Token apikey")),
- () -> assertThat(
- innerSut.generateAuthorizationHeaders().get(HttpHeaders.PROXY_AUTHORIZATION),
- contains("Basic dXNlcjpwdw=="))
- );
- }
-
- @Test
- void encodeProxyCredentials() {
- final var proxyConfig = ProxyConfig.builder()
- .user("bärtram")
- .password("gohze8Ae")
- .build();
-
- assertThat(Foo.encodeProxyCredentials(proxyConfig), is("YsOkcnRyYW06Z29oemU4QWU="));
- }
-
- @Test
- void createCredentialsProvider() {
- final var result = sut.createCredentialsProvider();
- final var credentials = result.getCredentials(sut.createAuthScope());
-
- assertAll(
- () -> assertThat(credentials.getUserPrincipal().getName(), is(proxyConfig.getUser())),
- () -> assertThat(credentials.getPassword(), is(proxyConfig.getPassword()))
- );
- }
-
- @Test
- void createAuthScope() {
- final var result = sut.createAuthScope();
-
- assertAll(
- () -> assertThat(result.getHost(), is(proxyConfig.getHost())),
- () -> assertThat(result.getPort(), is(proxyConfig.getPort()))
- );
- }
-
- @Test
- void createCredentials() {
- final var result = sut.createCredentials();
-
- assertAll(
- () -> assertThat(result.getUserPrincipal().getName(), is(proxyConfig.getUser())),
- () -> assertThat(result.getPassword(), is(proxyConfig.getPassword()))
- );
- }
-
- @Test
- void createHttpHost() {
- final var result = sut.createHttpHost();
-
- assertAll(
- () -> assertThat(result.getHostName(), is(proxyConfig.getHost())),
- () -> assertThat(result.getPort(), is(proxyConfig.getPort()))
- );
- }
-}
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyCredentialFactoryTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyCredentialFactoryTest.java
new file mode 100644
index 00000000..72ac3849
--- /dev/null
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/ProxyCredentialFactoryTest.java
@@ -0,0 +1,51 @@
+package io.securecodebox.persistence.defectdojo.http;
+
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+/**
+ * Tests for {@link ProxyCredentialFactory}
+ */
+class ProxyCredentialFactoryTest {
+ private final ProxyConfig config = ProxyConfig.builder()
+ .user("user")
+ .password("pw")
+ .host("host")
+ .port(42)
+ .build();
+ private final ProxyCredentialFactory sut = new ProxyCredentialFactory(config);
+
+ @Test
+ void createCredentialsProvider() {
+ final var result = sut.createCredentialsProvider();
+ final var credentials = result.getCredentials(sut.createAuthScope());
+
+ assertAll(
+ () -> assertThat(credentials.getUserPrincipal().getName(), is(config.getUser())),
+ () -> assertThat(credentials.getPassword(), is(config.getPassword()))
+ );
+ }
+
+ @Test
+ void createAuthScope() {
+ final var result = sut.createAuthScope();
+
+ assertAll(
+ () -> assertThat(result.getHost(), is(config.getHost())),
+ () -> assertThat(result.getPort(), is(config.getPort()))
+ );
+ }
+
+ @Test
+ void createCredentials() {
+ final var result = sut.createCredentials();
+
+ assertAll(
+ () -> assertThat(result.getUserPrincipal().getName(), is(config.getUser())),
+ () -> assertThat(result.getPassword(), is(config.getPassword()))
+ );
+ }
+}
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/http/RestTemplateFactoryTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/http/RestTemplateFactoryTest.java
new file mode 100644
index 00000000..2cdb4d0a
--- /dev/null
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/http/RestTemplateFactoryTest.java
@@ -0,0 +1,36 @@
+// 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.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+/**
+ * Tests for {@link RestTemplateFactory}
+ */
+class RestTemplateFactoryTest {
+ private final ProxyConfig proxyConfig = ProxyConfig.builder()
+ .user("user")
+ .password("pw")
+ .host("host")
+ .port(42)
+ .build();
+ private final RestTemplateFactory sut = new RestTemplateFactory(proxyConfig);
+
+
+
+ @Test
+ void createHttpHost() {
+ final var result = sut.createHttpHost();
+
+ assertAll(
+ () -> assertThat(result.getHostName(), is(proxyConfig.getHost())),
+ () -> assertThat(result.getPort(), is(proxyConfig.getPort()))
+ );
+ }
+}
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 3f78888a..40d7a37b 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanServiceTest.java
@@ -4,7 +4,7 @@
package io.securecodebox.persistence.defectdojo.service;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import io.securecodebox.persistence.defectdojo.http.ProxyConfig;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -18,13 +18,13 @@
/**
* Tests for {@link DefaultImportScanService}
*/
-final class DefaultImportScanServiceTest {
- private final Config config = new Config(
+class DefaultImportScanServiceTest {
+ private final ClientConfig clientConfig = new ClientConfig(
"http://localhost",
"apiKey",
23
);
- private final DefaultImportScanService sut = new DefaultImportScanService(config, ProxyConfig.NULL);
+ private final DefaultImportScanService sut = new DefaultImportScanService(clientConfig, ProxyConfig.NULL);
@Test
void constructorShouldThrowExceptionOnNullConfig() {
@@ -36,7 +36,7 @@ void constructorShouldThrowExceptionOnNullConfig() {
@Test
void constructorShouldThrowExceptionOnNullProxyConfig() {
assertThrows(NullPointerException.class, () -> {
- new DefaultImportScanService(Config.NULL, null);
+ new DefaultImportScanService(ClientConfig.NULL, null);
});
}
@@ -57,7 +57,7 @@ void shouldConfigureProxySettings_trueIfProxyConfigIsComplete() {
.host("host")
.port(42)
.build();
- final var innerSut = new DefaultImportScanService(config, proxyConfig);
+ final var innerSut = new DefaultImportScanService(clientConfig, proxyConfig);
assertThat(innerSut.shouldConfigureProxySettings(), is(true));
}
@@ -66,7 +66,7 @@ void shouldConfigureProxySettings_trueIfProxyConfigIsComplete() {
void shouldConfigureProxySettings_falseIfProxyConfigIsIncomplete() {
final var proxyConfig = ProxyConfig.builder()
.build();
- final var innerSut = new DefaultImportScanService(config, proxyConfig);
+ final var innerSut = new DefaultImportScanService(clientConfig, proxyConfig);
assertThat(innerSut.shouldConfigureProxySettings(), is(false));
}
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/EndpointServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/EndpointServiceTest.java
index 42f29516..28f97535 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/EndpointServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/EndpointServiceTest.java
@@ -3,7 +3,6 @@
// SPDX-License-Identifier: Apache-2.0
package io.securecodebox.persistence.defectdojo.service;
-import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.Endpoint;
import org.junit.jupiter.api.Test;
@@ -147,7 +146,7 @@ void get_byId() {
@Test
- void searchUnique_withSearchObjectWhichReturnsEmptyResult() throws URISyntaxException, JsonProcessingException {
+ void searchUnique_withSearchObjectWhichReturnsEmptyResult() {
// Here we only test that the object properties are correctly mapped to get params,
// since the response parsing and binding is covered by the other tests.
stubFor(get(urlPathEqualTo("/api/v2/endpoints/"))
@@ -173,7 +172,7 @@ void searchUnique_withSearchObjectWhichReturnsEmptyResult() throws URISyntaxExce
}
@Test
- void searchUnique_withQueryParamsWhichReturnsEmptyResult() throws URISyntaxException, JsonProcessingException {
+ void searchUnique_withQueryParamsWhichReturnsEmptyResult() {
// Here we only test that the object properties are correctly mapped to get params,
// since the response parsing and binding is covered by the other tests.
stubFor(get(urlPathEqualTo("/api/v2/endpoints/"))
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/EngagementServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/EngagementServiceTest.java
index 45f60c39..44904b11 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/EngagementServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/EngagementServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.Engagement;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/FindingServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/FindingServiceTest.java
index c323d07a..5db8aa7b 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/FindingServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/FindingServiceTest.java
@@ -4,13 +4,8 @@
package io.securecodebox.persistence.defectdojo.service;
-import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.Finding;
-import io.securecodebox.persistence.defectdojo.model.RiskAcceptance;
-import lombok.Builder;
-import lombok.NonNull;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@@ -18,7 +13,6 @@
import java.time.OffsetDateTime;
import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoServiceTest.java
new file mode 100644
index 00000000..4ea76646
--- /dev/null
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/GenericDefectDojoServiceTest.java
@@ -0,0 +1,349 @@
+package io.securecodebox.persistence.defectdojo.service;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
+import io.securecodebox.persistence.defectdojo.http.ProxyConfig;
+import io.securecodebox.persistence.defectdojo.model.Model;
+import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
+import lombok.NonNull;
+import lombok.SneakyThrows;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpHeaders;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.Map;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Tests for {@link GenericDefectDojoService}
+ */
+final class GenericDefectDojoServiceTest {
+
+ private static final class TestModel implements Model {
+ @JsonProperty
+ private long id;
+
+ @JsonProperty
+ private String name = "";
+
+ @Override
+ public boolean equalsQueryString(@NonNull Map queryParams) {
+ // Stub this to false because we do not test this method here.
+ return false;
+ }
+ }
+
+ private static final class TestableGenericDefectDojoService extends GenericDefectDojoService {
+ private TestableGenericDefectDojoService(ClientConfig clientConfig) {
+ super(clientConfig);
+ }
+
+ private TestableGenericDefectDojoService(@NonNull ClientConfig clientConfig, @NonNull ProxyConfig proxyConfig) {
+ super(clientConfig, proxyConfig);
+ }
+
+ @Override
+ protected String getUrlPath() {
+ return "snafu";
+ }
+
+ @Override
+ protected Class getModelClass() {
+ return TestModel.class;
+ }
+
+ @Override
+ @SneakyThrows
+ protected PaginatedResult deserializeList(@NonNull String response) {
+ return modelObjectMapper().readValue(response, new TypeReference<>() {
+ });
+ }
+ }
+
+ private static final String JSON_SINGLE_OBJECT = """
+ {"id": 42, "name": "foo"}
+ """;
+ private static final String JSON_MULTIPLE_OBJECT = """
+ {
+ "count": 1,
+ "next": null,
+ "previous": null,
+ "results": [
+ {"id": 42, "name": "foo"}
+ ],
+ "prefetch": {}
+ }
+ """;
+
+ private final ClientConfig clientConfig = new ClientConfig("https://defectdojo.example.com:8080","api-key");
+ private final TestableGenericDefectDojoService sut = new TestableGenericDefectDojoService(clientConfig);
+
+ @Test
+ void createBaseUrl() {
+ assertThat(sut.createBaseUrl(), is(URI.create("https://defectdojo.example.com:8080/api/v2/snafu/")));
+ }
+
+ @Nested
+ class AuthenticationHeaderWithoutProxyConfig extends WireMockBaseTestCase {
+ private final TestableGenericDefectDojoService sut = new TestableGenericDefectDojoService(
+ conf(), ProxyConfig.NULL
+ );
+
+ @Test
+ void get_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/42"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_SINGLE_OBJECT.length()))
+ .withBody(JSON_SINGLE_OBJECT)));
+
+ sut.get(42L);
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/42"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withoutHeader(HttpHeaders.PROXY_AUTHORIZATION)
+ );
+ }
+
+ @Test
+ void search_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_MULTIPLE_OBJECT.length()))
+ .withBody(JSON_MULTIPLE_OBJECT)));
+
+ sut.search();
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withoutHeader(HttpHeaders.PROXY_AUTHORIZATION)
+ );
+ }
+
+ @Test
+ void searchWithQueryParams_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_MULTIPLE_OBJECT.length()))
+ .withBody(JSON_MULTIPLE_OBJECT)));
+
+ sut.search(Collections.emptyMap());
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withoutHeader(HttpHeaders.PROXY_AUTHORIZATION)
+ );
+ }
+
+ @Test
+ void searchUniqueWithObject_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_MULTIPLE_OBJECT.length()))
+ .withBody(JSON_MULTIPLE_OBJECT)));
+
+ sut.searchUnique(new TestModel());
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withoutHeader(HttpHeaders.PROXY_AUTHORIZATION)
+ );
+ }
+
+ @Test
+ void searchUniqueWithQueryParams_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_MULTIPLE_OBJECT.length()))
+ .withBody(JSON_MULTIPLE_OBJECT)));
+
+ sut.searchUnique(Collections.emptyMap());
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withoutHeader(HttpHeaders.PROXY_AUTHORIZATION)
+ );
+ }
+
+ @Test
+ void create_containsAuthHeaderInRequest() {
+ stubFor(post(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(created()
+ .withHeaders(responseHeaders(JSON_SINGLE_OBJECT.length()))
+ .withBody(JSON_SINGLE_OBJECT)));
+
+ sut.create(new TestModel());
+
+ verify(postRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withoutHeader(HttpHeaders.PROXY_AUTHORIZATION)
+ );
+ }
+
+ @Test
+ void delete_containsAuthHeaderInRequest() {
+ stubFor(delete(urlPathEqualTo("/api/v2/snafu/42/"))
+ .willReturn(ok()));
+
+ sut.delete(42);
+
+ verify(deleteRequestedFor(urlPathEqualTo("/api/v2/snafu/42/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withoutHeader(HttpHeaders.PROXY_AUTHORIZATION)
+ );
+ }
+
+ @Test
+ void update_containsAuthHeaderInRequest() {
+ stubFor(put(urlPathEqualTo("/api/v2/snafu/42/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_SINGLE_OBJECT.length()))
+ .withBody(JSON_SINGLE_OBJECT)));
+
+ sut.update(new TestModel(), 42);
+
+ verify(putRequestedFor(urlPathEqualTo("/api/v2/snafu/42/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withoutHeader(HttpHeaders.PROXY_AUTHORIZATION)
+ );
+ }
+ }
+
+ @Nested
+ @Disabled("FIXME: All tests fail with this commit because Spring tries to connect via the proxy now 😬")
+ class AuthenticationHeaderWithProxyConfig extends WireMockBaseTestCase {
+ private final ProxyConfig proxyConfig = ProxyConfig.builder()
+ .user("alf")
+ .password("test1234")
+ .host("localhost")
+ .port(4444)
+ .build();
+ private final TestableGenericDefectDojoService sut = new TestableGenericDefectDojoService(
+ conf(), proxyConfig
+ );
+
+ @Test
+ void get_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/42"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_SINGLE_OBJECT.length()))
+ .withBody(JSON_SINGLE_OBJECT)));
+
+ sut.get(42L);
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/42"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withHeader(HttpHeaders.PROXY_AUTHORIZATION, equalTo("Basic YWxmOnRlc3QxMjM0"))
+ );
+ }
+
+ @Test
+ void search_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_MULTIPLE_OBJECT.length()))
+ .withBody(JSON_MULTIPLE_OBJECT)));
+
+ sut.search();
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withHeader(HttpHeaders.PROXY_AUTHORIZATION, equalTo("Basic YWxmOnRlc3QxMjM0"))
+ );
+ }
+
+ @Test
+ void searchWithQueryParams_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_MULTIPLE_OBJECT.length()))
+ .withBody(JSON_MULTIPLE_OBJECT)));
+
+ sut.search(Collections.emptyMap());
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withHeader(HttpHeaders.PROXY_AUTHORIZATION, equalTo("Basic YWxmOnRlc3QxMjM0"))
+ );
+ }
+
+ @Test
+ void searchUniqueWithObject_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_MULTIPLE_OBJECT.length()))
+ .withBody(JSON_MULTIPLE_OBJECT)));
+
+ sut.searchUnique(new TestModel());
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withHeader(HttpHeaders.PROXY_AUTHORIZATION, equalTo("Basic YWxmOnRlc3QxMjM0"))
+ );
+ }
+
+ @Test
+ void searchUniqueWithQueryParams_containsAuthHeaderInRequest() {
+ stubFor(get(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_MULTIPLE_OBJECT.length()))
+ .withBody(JSON_MULTIPLE_OBJECT)));
+
+ sut.searchUnique(Collections.emptyMap());
+
+ verify(getRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withHeader(HttpHeaders.PROXY_AUTHORIZATION, equalTo("Basic YWxmOnRlc3QxMjM0"))
+ );
+ }
+
+ @Test
+ void create_containsAuthHeaderInRequest() {
+ stubFor(post(urlPathEqualTo("/api/v2/snafu/"))
+ .willReturn(created()
+ .withHeaders(responseHeaders(JSON_SINGLE_OBJECT.length()))
+ .withBody(JSON_SINGLE_OBJECT)));
+
+ sut.create(new TestModel());
+
+ verify(postRequestedFor(urlPathEqualTo("/api/v2/snafu/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withHeader(HttpHeaders.PROXY_AUTHORIZATION, equalTo("Basic YWxmOnRlc3QxMjM0"))
+ );
+ }
+
+ @Test
+ void delete_containsAuthHeaderInRequest() {
+ stubFor(delete(urlPathEqualTo("/api/v2/snafu/42/"))
+ .willReturn(ok()));
+
+ sut.delete(42);
+
+ verify(deleteRequestedFor(urlPathEqualTo("/api/v2/snafu/42/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withHeader(HttpHeaders.PROXY_AUTHORIZATION, equalTo("Basic YWxmOnRlc3QxMjM0"))
+ );
+ }
+
+ @Test
+ void update_containsAuthHeaderInRequest() {
+ stubFor(put(urlPathEqualTo("/api/v2/snafu/42/"))
+ .willReturn(ok()
+ .withHeaders(responseHeaders(JSON_SINGLE_OBJECT.length()))
+ .withBody(JSON_SINGLE_OBJECT)));
+
+ sut.update(new TestModel(), 42);
+
+ verify(putRequestedFor(urlPathEqualTo("/api/v2/snafu/42/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Token " + API_KEY))
+ .withHeader(HttpHeaders.PROXY_AUTHORIZATION, equalTo("Basic YWxmOnRlc3QxMjM0"))
+ );
+ }
+ }
+}
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/GroupMemberServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/GroupMemberServiceTest.java
index 293fbc47..ae9d39c4 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/GroupMemberServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/GroupMemberServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.GroupMember;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/GroupServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/GroupServiceTest.java
index d65c5e72..0a417d84 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/GroupServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/GroupServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.Group;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
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 9a5a8aae..1e2d6f23 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/ImportScanServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/ImportScanServiceTest.java
@@ -5,7 +5,7 @@
package io.securecodebox.persistence.defectdojo.service;
import io.securecodebox.persistence.defectdojo.ScanType;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import io.securecodebox.persistence.defectdojo.http.ProxyConfig;
import io.securecodebox.persistence.defectdojo.model.ScanFile;
import lombok.Getter;
@@ -28,21 +28,21 @@ class ImportScanServiceTest {
@Test
void createDefault_throwsExceptionIfNullPassedInAsConfig() {
- assertThrows(NullPointerException.class, () -> {
- ImportScanService.createDefault(null, ProxyConfig.NULL);
- });
+ assertThrows(
+ NullPointerException.class,
+ () -> ImportScanService.createDefault(null, ProxyConfig.NULL));
}
@Test
void createDefault_throwsExceptionIfNullPassedInAsProxyConfig() {
- assertThrows(NullPointerException.class, () -> {
- ImportScanService.createDefault(Config.NULL, null);
- });
+ assertThrows(
+ NullPointerException.class,
+ () -> ImportScanService.createDefault(ClientConfig.NULL, null));
}
@Test
void createDefault_passesConfig() {
- final var config = new Config(
+ final var config = new ClientConfig(
"url",
"apiKey",
23
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/ProductServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/ProductServiceTest.java
index 625072ed..747d9b2c 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/ProductServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/ProductServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.Product;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/ProductTypeServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/ProductTypeServiceTest.java
index 297c7bc4..8698b1c8 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/ProductTypeServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/ProductTypeServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.ProductType;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/TestServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/TestServiceTest.java
index 3976ede5..0fd27937 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/TestServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/TestServiceTest.java
@@ -7,7 +7,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.Test;
-import org.junit.jupiter.api.Disabled;
import java.io.IOException;
import java.net.URISyntaxException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/TestTypeServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/TestTypeServiceTest.java
index ebbe4ada..47a3e299 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/TestTypeServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/TestTypeServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.TestType;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/ToolConfigServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/ToolConfigServiceTest.java
index fd7dce2f..ff14a5f4 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/ToolConfigServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/ToolConfigServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.ToolConfig;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/ToolTypeServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/ToolTypeServiceTest.java
index 9ba5cdcb..bd526e66 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/ToolTypeServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/ToolTypeServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.ToolType;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/UserServiceTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/UserServiceTest.java
index 9a894779..a73992c5 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/UserServiceTest.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/UserServiceTest.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import io.securecodebox.persistence.defectdojo.model.User;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/service/WireMockBaseTestCase.java b/src/test/java/io/securecodebox/persistence/defectdojo/service/WireMockBaseTestCase.java
index 7c397426..af999e04 100644
--- a/src/test/java/io/securecodebox/persistence/defectdojo/service/WireMockBaseTestCase.java
+++ b/src/test/java/io/securecodebox/persistence/defectdojo/service/WireMockBaseTestCase.java
@@ -6,7 +6,7 @@
import com.github.tomakehurst.wiremock.http.HttpHeader;
import com.github.tomakehurst.wiremock.http.HttpHeaders;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
-import io.securecodebox.persistence.defectdojo.config.Config;
+import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import lombok.Getter;
import lombok.experimental.Accessors;
@@ -25,6 +25,7 @@
@WireMockTest(httpPort = WireMockBaseTestCase.PORT)
abstract class WireMockBaseTestCase {
static final int PORT = 8888;
+ static final String API_KEY = "not-required-for-tests";
static final String EMPTY_SEARCH_RESULT_RESPONSE_FIXTURE = """
{
"count": 0,
@@ -36,9 +37,7 @@ abstract class WireMockBaseTestCase {
""";
private static final String FIXTURE_BASE_PACKAGE = "io/securecodebox/persistence/defectdojo/service";
- private final Config conf = new Config(
- String.format("http://localhost:%d/", PORT),
- "not-required-for-tests");
+ private final ClientConfig conf = new ClientConfig(String.format("http://localhost:%d/", PORT), API_KEY);
String readFixtureFile(String fixtureFile) throws IOException {
final var fixtureFilePath = FIXTURE_BASE_PACKAGE + "/" + fixtureFile;