Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

36 refactoring #93

Merged
merged 10 commits into from
Sep 5, 2023
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