Skip to content

Commit 99b039f

Browse files
WeltraumschafManuelNeuer
authored andcommitted
#36 Extract network side effect into interface so we can mock this out in the tests
Signed-off-by: Sven Strittmatter <sven.strittmatter@iteratec.com>
1 parent 763e9f4 commit 99b039f

File tree

3 files changed

+284
-208
lines changed

3 files changed

+284
-208
lines changed

src/main/java/io/securecodebox/persistence/defectdojo/service/DefaultImportScanService.java

Lines changed: 110 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class DefaultImportScanService implements ImportScanService {
4545
new FormHttpMessageConverter(),
4646
new ResourceHttpMessageConverter(),
4747
new MappingJackson2HttpMessageConverter());
48-
private final SystemPropertyFinder properties = new SystemPropertyFinder();
48+
private final HttpRequester requester = new DefaultHttpRequester();
4949
@Getter
5050
private final String defectDojoUrl;
5151
@Getter
@@ -115,31 +115,17 @@ public String getFilename() {
115115
}
116116
};
117117

118-
// FIXME: Why do we add the whole byte array resiurce here as object? Is not simply the file name sufficient here? Then we could use <String, String>
118+
// FIXME: Why do we add the whole byte array resource here as object? Is not simply the file name sufficient here? Then we could use <String, String>
119119
// We send the whole file content, so DefectDojo can parse the finding by itself.
120120
body.add("file", contentsAsResource);
121121

122122
final var payload = new HttpEntity<MultiValueMap<String, Object>>(body, headers);
123-
return exchangeRequest(endpoint, payload);
123+
return requester.exchange(generateApiUrl(endpoint), payload);
124124
} catch (HttpClientErrorException e) {
125125
throw new DefectDojoPersistenceException("Failed to attach findings to engagement.");
126126
}
127127
}
128128

129-
ImportScanResponse exchangeRequest(String endpoint, HttpEntity<?> payload) {
130-
final var restTemplate = this.createRestTemplate();
131-
return restTemplate.exchange(
132-
generateApiUrl(endpoint),
133-
HttpMethod.POST,
134-
payload,
135-
ImportScanResponse.class)
136-
.getBody();
137-
}
138-
139-
String generateApiUrl(final String endpoint) {
140-
return String.format("%s/api/v2/%s/", getDefectDojoUrl(), endpoint);
141-
}
142-
143129
/**
144130
* The DefectDojo Authentication Header
145131
*
@@ -151,104 +137,133 @@ HttpHeaders createDefectDojoAuthorizationHeaders() {
151137
return authorizationHeader;
152138
}
153139

154-
private RestTemplate createRestTemplate() {
155-
final var template = new RestTemplate();
140+
String generateApiUrl(final String endpoint) {
141+
return String.format("%s/api/v2/%s/", getDefectDojoUrl(), endpoint);
142+
}
156143

157-
if (shouldConfigureProxySettings()) {
158-
template.setRequestFactory(createRequestFactoryWithProxyAuthConfig());
144+
private static class SystemPropertyFinder {
145+
private boolean hasProperty(@NonNull final ProxyConfigNames name) {
146+
return System.getProperty(name.getLiterat()) != null;
159147
}
160148

161-
template.setMessageConverters(HTTP_MESSAGE_CONVERTERS);
149+
private boolean notHasProperty(@NonNull final ProxyConfigNames name) {
150+
return !hasProperty(name);
151+
}
162152

163-
return template;
153+
private String getProperty(@NonNull final ProxyConfigNames name) {
154+
return System.getProperty(name.getLiterat());
155+
}
164156
}
165157

166-
boolean shouldConfigureProxySettings() {
167-
return properties.hasProperty(ProxyConfigNames.HTTP_PROXY_USER)
168-
&& properties.hasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD);
158+
final static class MissingProxyAuthenticationConfig extends RuntimeException {
159+
MissingProxyAuthenticationConfig(ProxyConfigNames name) {
160+
super(String.format("Expected System property '%s' not set!", name.getLiterat()));
161+
}
169162
}
170163

171164
/**
172-
* Configuring proxy authentication explicitly
173-
*
174-
* <p>
175-
* This isn't done by default for spring rest templates.This method expects these four system properties (Java flag
176-
* {@literal -DpropertyName}) to be set:
177-
* </p>
178-
* <ul>
179-
* <li>http.proxyUser</li>
180-
* <li>http.proxyPassword</li>
181-
* <li>http.proxyHost</li>
182-
* <li>http.proxyPort</li>
183-
* </ul>
184-
*
185-
* @return never {@code null}
165+
* This interface abstracts the network side effect done by the underlying HTTP
186166
*/
187-
ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() {
188-
if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_USER)) {
189-
throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_USER);
190-
}
191-
192-
if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) {
193-
throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PASSWORD);
194-
}
195-
196-
if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_HOST)) {
197-
throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_HOST);
198-
}
167+
interface HttpRequester {
168+
ImportScanResponse exchange(String endpoint, HttpEntity<?> payload);
169+
}
199170

200-
if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PORT)) {
201-
throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PORT);
171+
/**
172+
* Default implementation which utilizes {@link RestTemplate}
173+
*/
174+
static final class DefaultHttpRequester implements HttpRequester {
175+
private final SystemPropertyFinder properties = new SystemPropertyFinder();
176+
177+
@Override
178+
public ImportScanResponse exchange(final String url, final HttpEntity<?> payload) {
179+
final var restTemplate = this.createRestTemplate();
180+
return restTemplate.exchange(
181+
url,
182+
HttpMethod.POST,
183+
payload,
184+
ImportScanResponse.class)
185+
.getBody();
202186
}
203187

204-
final var proxyHost = properties.getProperty(ProxyConfigNames.HTTP_PROXY_HOST);
205-
final int proxyPort;
206-
try {
207-
proxyPort = Integer.parseInt(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PORT));
208-
} catch (final NumberFormatException e) {
209-
throw new IllegalArgumentException(
210-
String.format("Given port for proxy authentication configuration (property '%s') is not a valid number! Given value wa '%s'.",
211-
ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(),
212-
System.getProperty("http.proxyPort")),
213-
e);
214-
}
188+
private RestTemplate createRestTemplate() {
189+
final var template = new RestTemplate();
215190

216-
final var credentials = new BasicCredentialsProvider();
217-
credentials.setCredentials(
218-
new AuthScope(proxyHost, proxyPort),
219-
new UsernamePasswordCredentials(
220-
properties.getProperty(ProxyConfigNames.HTTP_PROXY_USER),
221-
properties.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD))
222-
);
223-
224-
final var clientBuilder = HttpClientBuilder.create();
225-
clientBuilder.useSystemProperties();
226-
clientBuilder.setProxy(new HttpHost(proxyHost, proxyPort));
227-
clientBuilder.setDefaultCredentialsProvider(credentials);
228-
clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
229-
230-
final var factory = new HttpComponentsClientHttpRequestFactory();
231-
factory.setHttpClient(clientBuilder.build());
232-
return factory;
233-
}
191+
if (shouldConfigureProxySettings()) {
192+
template.setRequestFactory(createRequestFactoryWithProxyAuthConfig());
193+
}
234194

235-
private static class SystemPropertyFinder {
236-
private boolean hasProperty(@NonNull final ProxyConfigNames name) {
237-
return System.getProperty(name.getLiterat()) != null;
238-
}
195+
template.setMessageConverters(HTTP_MESSAGE_CONVERTERS);
239196

240-
private boolean notHasProperty(@NonNull final ProxyConfigNames name) {
241-
return !hasProperty(name);
197+
return template;
242198
}
243199

244-
private String getProperty(@NonNull final ProxyConfigNames name) {
245-
return System.getProperty(name.getLiterat());
200+
boolean shouldConfigureProxySettings() {
201+
return properties.hasProperty(ProxyConfigNames.HTTP_PROXY_USER)
202+
&& properties.hasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD);
246203
}
247-
}
248204

249-
final static class MissingProxyAuthenticationConfig extends RuntimeException {
250-
MissingProxyAuthenticationConfig(ProxyConfigNames name) {
251-
super(String.format("Expected System property '%s' not set!", name.getLiterat()));
205+
/**
206+
* Configuring proxy authentication explicitly
207+
*
208+
* <p>
209+
* This isn't done by default for spring rest templates.This method expects these four system properties (Java flag
210+
* {@literal -DpropertyName}) to be set:
211+
* </p>
212+
* <ul>
213+
* <li>http.proxyUser</li>
214+
* <li>http.proxyPassword</li>
215+
* <li>http.proxyHost</li>
216+
* <li>http.proxyPort</li>
217+
* </ul>
218+
*
219+
* @return never {@code null}
220+
*/
221+
ClientHttpRequestFactory createRequestFactoryWithProxyAuthConfig() {
222+
if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_USER)) {
223+
throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_USER);
224+
}
225+
226+
if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD)) {
227+
throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PASSWORD);
228+
}
229+
230+
if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_HOST)) {
231+
throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_HOST);
232+
}
233+
234+
if (properties.notHasProperty(ProxyConfigNames.HTTP_PROXY_PORT)) {
235+
throw new MissingProxyAuthenticationConfig(ProxyConfigNames.HTTP_PROXY_PORT);
236+
}
237+
238+
final var proxyHost = properties.getProperty(ProxyConfigNames.HTTP_PROXY_HOST);
239+
final int proxyPort;
240+
try {
241+
proxyPort = Integer.parseInt(properties.getProperty(ProxyConfigNames.HTTP_PROXY_PORT));
242+
} catch (final NumberFormatException e) {
243+
throw new IllegalArgumentException(
244+
String.format("Given port for proxy authentication configuration (property '%s') is not a valid number! Given value wa '%s'.",
245+
ProxyConfigNames.HTTP_PROXY_PORT.getLiterat(),
246+
System.getProperty("http.proxyPort")),
247+
e);
248+
}
249+
250+
final var credentials = new BasicCredentialsProvider();
251+
credentials.setCredentials(
252+
new AuthScope(proxyHost, proxyPort),
253+
new UsernamePasswordCredentials(
254+
properties.getProperty(ProxyConfigNames.HTTP_PROXY_USER),
255+
properties.getProperty(ProxyConfigNames.HTTP_PROXY_PASSWORD))
256+
);
257+
258+
final var clientBuilder = HttpClientBuilder.create();
259+
clientBuilder.useSystemProperties();
260+
clientBuilder.setProxy(new HttpHost(proxyHost, proxyPort));
261+
clientBuilder.setDefaultCredentialsProvider(credentials);
262+
clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
263+
264+
final var factory = new HttpComponentsClientHttpRequestFactory();
265+
factory.setHttpClient(clientBuilder.build());
266+
return factory;
252267
}
253268
}
254269
}

0 commit comments

Comments
 (0)