Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ public final class Config {
*/
private final int maxPageCountForGets;

/**
* Convenience constructor which sets {@link #DEFAULT_MAX_PAGE_COUNT_FOR_GETS}
*
* @param url not {@code null}
* @param apiKey not {@code null}
*/
public Config(final @NonNull String url, final @NonNull String apiKey) {
this(url, apiKey, DEFAULT_MAX_PAGE_COUNT_FOR_GETS);
}

/**
* Dedicated constructor
*
Expand Down Expand Up @@ -89,7 +99,7 @@ public static Config fromEnv() {
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)),
e);
e);
}
} else {
maxPageCountForGets = DEFAULT_MAX_PAGE_COUNT_FOR_GETS;
Expand Down
80 changes: 49 additions & 31 deletions src/main/java/io/securecodebox/persistence/defectdojo/http/Foo.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import lombok.NonNull;
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;
Expand All @@ -26,53 +27,70 @@
*/
public final class Foo {
private final Config config;
private final ProxyConfig proxyConfig;

public Foo(@NonNull final Config config) {
public Foo(@NonNull final Config config, @NonNull final ProxyConfig proxyConfig) {
super();
this.config = config;
this.proxyConfig = proxyConfig;
}

public HttpHeaders getDefectDojoAuthorizationHeaders() {
/**
* This method generates appropriate authorization headers
*
* @return never {@code null}
*/
public HttpHeaders generateAuthorizationHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Token " + this.config.getApiKey());
headers.set(HttpHeaders.AUTHORIZATION, "Token " + this.config.getApiKey());

String username = System.getProperty("http.proxyUser", "");
String password = System.getProperty("http.proxyPassword", "");

if (!username.isEmpty() || !password.isEmpty()) {
if (proxyConfig.isComplete()) {
// FIXME: System.out logging is a real bad code smell. Standard loging should be used.
System.out.println("Setting Proxy Auth Header...");
headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((username + ':' + password).getBytes(StandardCharsets.UTF_8)));
headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic " + encodeProxyCredentials(proxyConfig));
}

return headers;
}

public RestTemplate setupRestTemplate() {
RestTemplate restTemplate;
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));
}

if (System.getProperty("http.proxyUser") != null && System.getProperty("http.proxyPassword") != null) {
public RestTemplate createRestTemplate() {
if (proxyConfig.isComplete()) {
// Configuring Proxy Authentication explicitly as it isn't done by default for spring rest templates :(
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))),
new UsernamePasswordCredentials(System.getProperty("http.proxyUser"), System.getProperty("http.proxyPassword"))
);
HttpClientBuilder clientBuilder = HttpClientBuilder.create();

clientBuilder.useSystemProperties();
clientBuilder.setProxy(new HttpHost(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))));
clientBuilder.setDefaultCredentialsProvider(credsProvider);
clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());

CloseableHttpClient client = clientBuilder.build();

HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(client);
restTemplate = new RestTemplate(factory);
} else {
restTemplate = new RestTemplate();
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 restTemplate;
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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,39 @@
* </p>
*/
public final class ProxyConfigFactory {
static final ProxyConfig DEFAULT_CONFIG = ProxyConfig.NULL;
private final SystemPropertyFinder properties = new SystemPropertyFinder();

/**
* Creates a configuration based on {@link ProxyConfigNames environment variables}
* <p>
* We assume a complete proxy configuration only if {@link ProxyConfigNames#HTTP_PROXY_USER user} and
* {@link ProxyConfigNames#HTTP_PROXY_PASSWORD password} is configured. Unless an
* {@link #DEFAULT_CONFIG} configuration will be returned.
* </p>
* <p>
* Throws {@link MissingProxyConfigValue}, if not all configuration values are present.
* </p>
*
* @return never {@code null}
*/
public ProxyConfig create() {
final var builder = ProxyConfig.builder();

if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_USER)) {
throw new MissingProxyConfigValue(ProxyConfigNames.HTTP_PROXY_USER);
if (shouldCreateFromProperties()) {
return createFromProperties();
}

builder.user(properties.getProperty(ProxyConfigNames.HTTP_PROXY_USER));
return DEFAULT_CONFIG;
}

if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) {
throw new MissingProxyConfigValue(ProxyConfigNames.HTTP_PROXY_PASSWORD);
}
private boolean shouldCreateFromProperties() {
return properties.hasProperty(ProxyConfigNames.HTTP_PROXY_USER) &&
properties.hasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD);
}

builder.password(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD));
private ProxyConfig createFromProperties() {
final var builder = ProxyConfig.builder()
.user(properties.getProperty(ProxyConfigNames.HTTP_PROXY_USER))
.password(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD));

if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_HOST)) {
throw new MissingProxyConfigValue(ProxyConfigNames.HTTP_PROXY_HOST);
Expand All @@ -49,10 +66,10 @@ public ProxyConfig create() {
builder.port(Integer.parseInt(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PORT)));
} catch (final NumberFormatException e) {
throw new IllegalArgumentException(
String.format("Given port for proxy authentication configuration (property '%s') is not a valid number! Given value wa '%s'.",
ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(),
System.getProperty("http.proxyPort")),
e);
String.format("Given port for proxy authentication configuration (property '%s') is not a valid number! Given value wa '%s'.",
ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(),
System.getProperty("http.proxyPort")),
e);
}

return builder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
*/
class DefaultImportScanService implements ImportScanService {
private static final List<HttpMessageConverter<?>> HTTP_MESSAGE_CONVERTERS = List.of(
new FormHttpMessageConverter(),
new ResourceHttpMessageConverter(),
new MappingJackson2HttpMessageConverter());
new FormHttpMessageConverter(),
new ResourceHttpMessageConverter(),
new MappingJackson2HttpMessageConverter());
@Getter
private final String defectDojoUrl;
@Getter
Expand Down Expand Up @@ -130,11 +130,11 @@ public String getFilename() {
ImportScanResponse exchangeRequest(String endpoint, HttpEntity<?> payload) {
final var restTemplate = this.createRestTemplate();
return restTemplate.exchange(
generateApiUrl(endpoint),
HttpMethod.POST,
payload,
ImportScanResponse.class)
.getBody();
generateApiUrl(endpoint),
HttpMethod.POST,
payload,
ImportScanResponse.class)
.getBody();
}

String generateApiUrl(final String endpoint) {
Expand Down Expand Up @@ -187,10 +187,10 @@ boolean shouldConfigureProxySettings() {
ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() {
final var credentials = new BasicCredentialsProvider();
credentials.setCredentials(
new AuthScope(proxyConfig.getHost(), proxyConfig.getPort()),
new UsernamePasswordCredentials(
proxyConfig.getUser(),
proxyConfig.getPassword())
new AuthScope(proxyConfig.getHost(), proxyConfig.getPort()),
new UsernamePasswordCredentials(
proxyConfig.getUser(),
proxyConfig.getPassword())
);

final var clientBuilder = HttpClientBuilder.create();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
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.http.ProxyConfigFactory;
import io.securecodebox.persistence.defectdojo.model.BaseModel;
import io.securecodebox.persistence.defectdojo.model.Engagement;
import io.securecodebox.persistence.defectdojo.model.Response;
Expand All @@ -39,7 +40,7 @@ abstract public class GenericDefectDojoService<T extends BaseModel> {

protected ObjectMapper objectMapper;
protected ObjectMapper searchStringMapper;

@Getter
protected RestTemplate restTemplate;

Expand All @@ -55,7 +56,7 @@ public GenericDefectDojoService(Config config) {
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();
}

Expand All @@ -66,11 +67,11 @@ public GenericDefectDojoService(Config config) {
* @return The DefectDojo Authentication Header
*/
private HttpHeaders getDefectDojoAuthorizationHeaders() {
return new Foo(config).getDefectDojoAuthorizationHeaders();
return new Foo(config, new ProxyConfigFactory().create()).generateAuthorizationHeaders();
}

private RestTemplate setupRestTemplate() {
RestTemplate restTemplate = new Foo(config).setupRestTemplate();
RestTemplate restTemplate = new Foo(config, new ProxyConfigFactory().create()).createRestTemplate();
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(this.objectMapper);
restTemplate.setMessageConverters(List.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.securecodebox.persistence.defectdojo.config.Config;
import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.http.Foo;
import io.securecodebox.persistence.defectdojo.http.ProxyConfigFactory;
import io.securecodebox.persistence.defectdojo.model.ScanFile;
import lombok.Data;
import org.springframework.core.io.ByteArrayResource;
Expand Down Expand Up @@ -49,11 +50,11 @@ public ImportScanService2(Config config) {
* @return The DefectDojo Authentication Header
*/
private HttpHeaders getDefectDojoAuthorizationHeaders() {
return new Foo(config).getDefectDojoAuthorizationHeaders();
return new Foo(config, new ProxyConfigFactory().create()).generateAuthorizationHeaders();
}

protected RestTemplate setupRestTemplate() {
return new Foo(config).setupRestTemplate();
return new Foo(config, new ProxyConfigFactory().create()).createRestTemplate();
}

/**
Expand Down Expand Up @@ -117,7 +118,7 @@ public ImportScanResponse reimportScan(ScanFile scanFile, long testId, long lead
}

//overloading with optional parameter
public ImportScanResponse importScan(ScanFile scanFile, long engagementId, long lead, String currentDate, ScanType scanType, long testType, LinkedMultiValueMap<String, Object> additionalValues) {
public ImportScanResponse importScan(ScanFile scanFile, long engagementId, long lead, String currentDate, ScanType scanType, long testType, LinkedMultiValueMap<String, Object> additionalValues) {
additionalValues.add("engagement", Long.toString(engagementId));

return this.createFindings(scanFile, "import-scan", lead, currentDate, scanType, testType, additionalValues);
Expand Down
Loading