Skip to content
This repository was archived by the owner on Feb 26, 2021. It is now read-only.

Commit 989bf4b

Browse files
authored
Enable use without scb (#98)
Enable use without scb
2 parents e811d9c + 537d669 commit 989bf4b

File tree

9 files changed

+394
-7
lines changed

9 files changed

+394
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
*
3+
* SecureCodeBox (SCB)
4+
* Copyright 2015-2018 iteratec GmbH
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
* /
18+
*/
19+
package io.securecodebox.persistence;
20+
21+
public class DefectDojoLoopException extends RuntimeException{
22+
public DefectDojoLoopException(String message) {
23+
super(message);
24+
}
25+
26+
public DefectDojoLoopException(String message, Throwable cause) {
27+
super(message, cause);
28+
}
29+
}

scb-persistenceproviders/defectdojo-persistenceprovider/src/main/java/io/securecodebox/persistence/DefectDojoService.java

Lines changed: 170 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
*/
1919
package io.securecodebox.persistence;
2020

21-
2221
import io.securecodebox.persistence.models.*;
22+
2323
import org.slf4j.Logger;
2424
import org.slf4j.LoggerFactory;
2525
import org.springframework.beans.factory.annotation.Value;
@@ -43,7 +43,10 @@
4343
import java.time.LocalDate;
4444
import java.time.format.DateTimeFormatter;
4545
import java.util.Arrays;
46+
import java.util.LinkedList;
47+
import java.util.List;
4648
import java.util.Optional;
49+
import java.util.Iterator;
4750

4851
@Component
4952
@ConditionalOnProperty(name = "securecodebox.persistence.defectdojo.enabled", havingValue = "true")
@@ -181,8 +184,13 @@ public EngagementResponse createEngagement(EngagementPayload engagementPayload)
181184
throw new DefectDojoPersistenceException("Failed to create Engagement for SecurityTest", e);
182185
}
183186
}
184-
185187
public ImportScanResponse createFindings(String rawResult, long engagementId, long lead, String currentDate,String defectDojoScanName) {
188+
return createFindings(rawResult, engagementId, lead, currentDate,defectDojoScanName, "");
189+
}
190+
/**
191+
* Till version 1.5.4. testName (in defectdojo _test_type_) must be defectDojoScanName, afterwards, you can have somethings else
192+
*/
193+
public ImportScanResponse createFindings(String rawResult, long engagementId, long lead, String currentDate,String defectDojoScanName, String testName) {
186194
RestTemplate restTemplate = new RestTemplate();
187195
HttpHeaders headers = getHeaders();
188196
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
@@ -193,7 +201,12 @@ public ImportScanResponse createFindings(String rawResult, long engagementId, lo
193201
mvn.add("lead", Long.toString(lead));
194202
mvn.add("scan_date", currentDate);
195203
mvn.add("scan_type", defectDojoScanName);
196-
204+
mvn.add("close_old_findings", "true");
205+
mvn.add("skip_duplicates", "false");
206+
207+
if(!testName.isEmpty())
208+
mvn.add("test_type", testName);
209+
197210
try {
198211
ByteArrayResource contentsAsResource = new ByteArrayResource(rawResult.getBytes(StandardCharsets.UTF_8)) {
199212
@Override
@@ -214,10 +227,10 @@ public String getFilename() {
214227
}
215228
}
216229
public ImportScanResponse createFindingsForEngagementName(String engagementName, String rawResults, String defectDojoScanName, long productId, long lead){
217-
return createFindingsForEngagementName(engagementName, rawResults, defectDojoScanName, productId, lead, new EngagementPayload());
230+
return createFindingsForEngagementName(engagementName, rawResults, defectDojoScanName, productId, lead, new EngagementPayload(), "");
218231
}
219232

220-
public ImportScanResponse createFindingsForEngagementName(String engagementName, String rawResults, String defectDojoScanName, long productId, long lead, EngagementPayload engagementPayload){
233+
public ImportScanResponse createFindingsForEngagementName(String engagementName, String rawResults, String defectDojoScanName, long productId, long lead, EngagementPayload engagementPayload, String testName){
221234
Long engagementId = getEngagementIdByEngagementName(engagementName, productId).orElseGet(() -> {
222235
engagementPayload.setName(engagementName);
223236
engagementPayload.setProduct(productId);
@@ -227,9 +240,28 @@ public ImportScanResponse createFindingsForEngagementName(String engagementName,
227240
return createEngagement(engagementPayload).getId();
228241
});
229242

230-
return createFindings(rawResults, engagementId, lead, currentDate(), defectDojoScanName);
243+
return createFindings(rawResults, engagementId, lead, currentDate(), defectDojoScanName, testName);
231244
}
232245

246+
public ImportScanResponse createFindingsForEngagementName(String engagementName, String rawResults, String defectDojoScanName, String productName, long lead, EngagementPayload engagementPayload, String testName){
247+
long productId = 0;
248+
try {
249+
productId = retrieveProductId(productName);
250+
} catch(DefectDojoProductNotFound e) {
251+
LOG.debug("Given product does not exists");
252+
}
253+
if(productId == 0) {
254+
ProductResponse productResponse = createProduct(productName);
255+
productId = productResponse.getId();
256+
}
257+
258+
return createFindingsForEngagementName(engagementName, rawResults, defectDojoScanName, productId, lead, engagementPayload, testName);
259+
}
260+
261+
private Optional<Long> getEngagementIdByEngagementName(String engagementName, String productName){
262+
long productId = retrieveProductId(productName);
263+
return getEngagementIdByEngagementName(engagementName, productId, 0L);
264+
}
233265
private Optional<Long> getEngagementIdByEngagementName(String engagementName, long productId){
234266
return getEngagementIdByEngagementName(engagementName, productId, 0L);
235267
}
@@ -257,4 +289,136 @@ private Optional<Long> getEngagementIdByEngagementName(String engagementName, lo
257289
LOG.warn("Engagement with name '{}' not found.", engagementName);
258290
return Optional.empty();
259291
}
292+
public ProductResponse createProduct(String productName) {
293+
RestTemplate restTemplate = new RestTemplate();
294+
ProductPayload productPayload = new ProductPayload(productName, "Description missing");
295+
HttpEntity<ProductPayload> payload = new HttpEntity<>(productPayload, getHeaders());
296+
297+
try {
298+
ResponseEntity<ProductResponse> response = restTemplate.exchange(defectDojoUrl + "/api/v2/products/", HttpMethod.POST, payload, ProductResponse.class);
299+
return response.getBody();
300+
} catch (HttpClientErrorException e) {
301+
LOG.warn("Failed to create product {}", e);
302+
LOG.warn("Failure response body. {}", e.getResponseBodyAsString());
303+
throw new DefectDojoPersistenceException("Failed to create product", e);
304+
}
305+
}
306+
307+
public void deleteUnusedBranches(List<String> existingBranches, String producName) {
308+
long productId = retrieveProductId(producName);
309+
deleteUnusedBranches(existingBranches, productId);
310+
}
311+
312+
/**
313+
* Deletes engagements based on branch tag
314+
* Be aware that the branch tag MUST be set, otherwise all engagments will be deleted
315+
*/
316+
public void deleteUnusedBranches(List<String> existingBranches, long productId) {
317+
RestTemplate restTemplate = new RestTemplate();
318+
319+
//get existing branches
320+
List<EngagementResponse> engagementPayloads = getEngagementsForProduct(productId, 0);
321+
for(EngagementResponse engagementPayload : engagementPayloads) {
322+
boolean branchExists = false;
323+
for(String existingBranchName : existingBranches) {
324+
if(existingBranchName.equals(engagementPayload.getBanch())) {
325+
branchExists = true;
326+
break;
327+
}
328+
}
329+
if(!branchExists) {
330+
deleteEnageament(engagementPayload.getId());
331+
LOG.info("Deleted engagement with id " + engagementPayload.getId() + ", branch " + engagementPayload.getBanch());
332+
}
333+
}
334+
}
335+
336+
private List<EngagementResponse> getEngagementsForProduct(long productId, long offset) throws DefectDojoLoopException{
337+
if(offset > 9999) {
338+
throw new DefectDojoLoopException("offset engagement products too much!");
339+
}
340+
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(defectDojoUrl + "/api/v2/engagements")
341+
.queryParam("product", Long.toString(productId))
342+
.queryParam("limit", Long.toString(50L))
343+
.queryParam("offset", Long.toString(offset));
344+
345+
RestTemplate restTemplate = new RestTemplate();
346+
HttpEntity engagementRequest = new HttpEntity(getHeaders());
347+
348+
ResponseEntity<DefectDojoResponse<EngagementResponse>> engagementResponse = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, engagementRequest, new ParameterizedTypeReference<DefectDojoResponse<EngagementResponse>>(){});
349+
List<EngagementResponse> engagementPayloads = new LinkedList<EngagementResponse>();
350+
for(EngagementResponse engagement : engagementResponse.getBody().getResults()){
351+
engagementPayloads.add(engagement);
352+
}
353+
if(engagementResponse.getBody().getNext() != null){
354+
engagementPayloads.addAll(getEngagementsForProduct(productId, offset + 1));;
355+
}
356+
return engagementPayloads;
357+
}
358+
public void deleteEnageament(long engagementId){
359+
RestTemplate restTemplate = new RestTemplate();
360+
361+
String uri = defectDojoUrl + "/api/v2/engagements/" + engagementId + "/?id=" + engagementId;
362+
HttpEntity request = new HttpEntity(getHeaders());
363+
try {
364+
ResponseEntity<DefectDojoResponse> response = restTemplate.exchange(uri, HttpMethod.GET, request, DefectDojoResponse.class);
365+
} catch (HttpClientErrorException e) {
366+
LOG.warn("Failed to delete engagment {}, engagementId: " + engagementId, e);
367+
LOG.warn("Failure response body. {}", e.getResponseBodyAsString());
368+
throw new DefectDojoPersistenceException("Failed to delete product", e);
369+
}
370+
}
371+
372+
/* options is created as follows:
373+
MultiValueMap<String, String> mvn = new LinkedMultiValueMap<>();
374+
mvn.add("engagement", Long.toString(engagementId));
375+
*/
376+
private List<Finding> getCurrentFindings(long engagementId, LinkedMultiValueMap<String, String> options){
377+
RestTemplate restTemplate = new RestTemplate();
378+
379+
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(defectDojoUrl + "/api/v2/findings/")
380+
.queryParam("active", "true")
381+
.queryParam("false_p", "false")
382+
.queryParam("duplicate", "false")
383+
.queryParam("test__engagement", Long.toString(engagementId));
384+
385+
if(options != null) {
386+
builder = prepareParameters(options, builder);
387+
}
388+
389+
HttpEntity request = new HttpEntity(getHeaders());
390+
try {
391+
ResponseEntity<DefectDojoResponse<Finding>> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, request, new ParameterizedTypeReference<DefectDojoResponse<Finding>>(){});
392+
List<Finding> findings = new LinkedList<Finding>();
393+
for(Finding finding : response.getBody().getResults()){
394+
findings.add(finding);
395+
}
396+
return findings;
397+
} catch (HttpClientErrorException e) {
398+
LOG.warn("Failed to get findings {}, engagementId: " + engagementId, e);
399+
LOG.warn("Failure response body. {}", e.getResponseBodyAsString());
400+
throw new DefectDojoPersistenceException("Failed to get findings", e);
401+
}
402+
}
403+
private UriComponentsBuilder prepareParameters(LinkedMultiValueMap<String, String> queryParameters, UriComponentsBuilder builder) {
404+
Iterator<String> it = queryParameters.keySet().iterator();
405+
406+
while(it.hasNext()){
407+
String theKey = (String)it.next();
408+
builder.replaceQueryParam(theKey, queryParameters.getFirst(theKey));
409+
}
410+
return builder;
411+
}
412+
413+
public List<Finding> receiveNonHandeldFindings(String productName, String engagementName, String minimumServerity, LinkedMultiValueMap<String, String> options){
414+
Long engagementId = getEngagementIdByEngagementName(engagementName, productName).orElse(0L);
415+
//getCurrentFindings
416+
List<Finding> findings = new LinkedList<Finding>();
417+
for (String serverity : Finding.getServeritiesAndHigherServerities(minimumServerity)) {
418+
LinkedMultiValueMap<String, String> optionTemp = options.clone();
419+
optionTemp.add("serverity", serverity);
420+
findings.addAll(getCurrentFindings(engagementId, optionTemp));
421+
}
422+
return findings;
423+
}
260424
}

scb-persistenceproviders/defectdojo-persistenceprovider/src/main/java/io/securecodebox/persistence/models/DefectDojoProduct.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,11 @@ public class DefectDojoProduct {
2121

2222
@JsonProperty("authorized_users")
2323
List<String> authorizedUsers;
24+
25+
public DefectDojoProduct() {}
26+
27+
public DefectDojoProduct(String productName, String productDescription) {
28+
name = productName;
29+
description = productDescription;
30+
}
2431
}

scb-persistenceproviders/defectdojo-persistenceprovider/src/main/java/io/securecodebox/persistence/models/EngagementPayload.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public class EngagementPayload {
6363
protected String commitHash;
6464

6565
@JsonProperty("branch_tag")
66-
protected String branch;
66+
public String branch;
6767

6868
@JsonProperty("source_code_management_uri")
6969
protected String repo;
@@ -80,6 +80,9 @@ public class EngagementPayload {
8080
@JsonProperty
8181
protected String description;
8282

83+
@JsonProperty("deduplication_on_engagement")
84+
protected boolean deduplicationOnEngagement;
85+
8386
/**
8487
* Currently only contains the statuses relevant to us.
8588
* If you need others, feel free to add them ;)

scb-persistenceproviders/defectdojo-persistenceprovider/src/main/java/io/securecodebox/persistence/models/EngagementResponse.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ public class EngagementResponse {
2727
@JsonProperty
2828
protected String name;
2929

30+
@JsonProperty("branch_tag")
31+
protected String branch;
32+
3033
public long getId() {
3134
return id;
3235
}
@@ -42,4 +45,12 @@ public String getName() {
4245
public void setName(String name) {
4346
this.name = name;
4447
}
48+
49+
public String getBanch() {
50+
return branch;
51+
}
52+
53+
public void setBranch(String branch) {
54+
this.branch = branch;
55+
}
4556
}

0 commit comments

Comments
 (0)