Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@

import java.io.IOException;
import java.net.URI;
import java.time.*;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SecureCodeBoxFindingsToDefectDojoMapper {
private static final Logger LOG = LoggerFactory.getLogger(SecureCodeBoxFindingsToDefectDojoMapper.class);
Expand All @@ -25,6 +29,7 @@ public class SecureCodeBoxFindingsToDefectDojoMapper {

/**
* Converts a SecureCodeBox Findings JSON String to a DefectDojo Findings JSON String.
*
* @param scbFindingsJson SecureCodeBox Findings JSON File as String
* @return DefectDojo Findings JSON File as String, compatible with the DefectDojo Generic JSON Parser
* @throws IOException
Expand All @@ -33,9 +38,10 @@ public static String fromSecureCodeboxFindingsJson(String scbFindingsJson) throw
LOG.debug("Converting SecureCodeBox Findings to DefectDojo Findings");
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<DefectDojoImportFinding> DefectDojoImportFindings = new ArrayList<>();
List<SecureCodeBoxFinding> secureCodeBoxFindings = mapper.readValue(scbFindingsJson, new TypeReference<>() {});
for (SecureCodeBoxFinding secureCodeBoxFinding : secureCodeBoxFindings){
DefectDojoImportFindings.add(fromSecureCodeBoxFinding(secureCodeBoxFinding));
List<SecureCodeBoxFinding> secureCodeBoxFindings = mapper.readValue(scbFindingsJson, new TypeReference<>() {
});
for (SecureCodeBoxFinding secureCodeBoxFinding : secureCodeBoxFindings) {
DefectDojoImportFindings.add(fromSecureCodeBoxFinding(secureCodeBoxFinding));
}
// create the result where the format has to be {"findings": [finding1, findings2, ...]}
ObjectNode ddFindingJson = mapper.createObjectNode();
Expand All @@ -47,48 +53,54 @@ public static String fromSecureCodeboxFindingsJson(String scbFindingsJson) throw
/**
* Converts a SecureCodeBox Finding to a DefectDojo Finding,
* that can be imported by the DefectDojo Generic JSON Parser.
*
* @param secureCodeBoxFinding Finding in SecureCodeBox format.
* @return Finding in DefectDojo Format, compatible with the DefectDojo Generic JSON Parser
* @throws JsonProcessingException
*/
protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxFinding secureCodeBoxFinding) throws JsonProcessingException {
//set basic info
//set basic Finding info
DefectDojoImportFinding result = new DefectDojoImportFinding();
result.setTitle(secureCodeBoxFinding.getName());
result.setSeverity(capitalize(secureCodeBoxFinding.getSeverity().toString()));
if (secureCodeBoxFinding.getSeverity() != null)
result.setSeverity(capitalize(secureCodeBoxFinding.getSeverity().toString()));
result.setUniqueIdFromTool(secureCodeBoxFinding.getId());

// set Description as combination of finding description and finding attributes
// set DefectDojo description as combination of SecureCodeBox Finding description and Finding attributes
String description = secureCodeBoxFinding.getDescription();
if (secureCodeBoxFinding.getAttributes()!=null) {
if (secureCodeBoxFinding.getAttributes() != null) {
String attributesJson = prettyJSONPrinter.writeValueAsString(secureCodeBoxFinding.getAttributes());
description = description + "\n " + attributesJson;
description = description + "\n " + attributesJson;
}
result.setDescription(description);
setFindingTimestamp(secureCodeBoxFinding, result);
setFindingLocation(secureCodeBoxFinding, result);
return result;
}

private static void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) {
if (secureCodeBoxFinding.getLocation() != null && !secureCodeBoxFinding.getLocation().isEmpty()) {
try {
URI.create(secureCodeBoxFinding.getLocation());
result.setEndpoints(Collections.singletonList(secureCodeBoxFinding.getLocation()));
} catch (IllegalArgumentException e) {
LOG.warn("Couldn't parse the secureCodeBox location, because it: {} is not a vailid uri: {}", e, secureCodeBoxFinding.getLocation());
}
}
}

//set finding date
private static void setFindingTimestamp(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) {
Instant instant;
if (secureCodeBoxFinding.getTimestamp() != null) {
instant = Instant.from(DateTimeFormatter.ISO_INSTANT.parse(secureCodeBoxFinding.getTimestamp()));
}
else {
} else {
instant = Instant.now();
}
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
result.setDate(dtf.format(localDateTime));

//set finding location
try {
URI.create(secureCodeBoxFinding.getLocation());
result.setEndpoints(Collections.singletonList(secureCodeBoxFinding.getLocation()));
} catch (IllegalArgumentException e) {
LOG.warn("Couldn't parse the secureCodeBox location, because it: {} s not a vailid uri: {}", e, secureCodeBoxFinding.getLocation());
}
return result;
}

private static String capitalize(String str) {
if(str == null || str.isEmpty()) {
if (str == null || str.isEmpty()) {
return str;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.securecodebox.persistence.mapping;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.securecodebox.persistence.models.SecureCodeBoxFinding;
Expand Down Expand Up @@ -36,7 +37,7 @@ public void yieldsCorrectResult() throws IOException {
// if whitespaces should be ignored in strings, a Custom Comperator could be used
// then the result and expected result would not have to match exactly.
// see https://www.baeldung.com/jackson-compare-two-json-objects
assertEquals(actualJSON,expectedJSON);
assertEquals(actualJSON, expectedJSON);
}

@Test
Expand All @@ -63,7 +64,7 @@ public void correctlyParsesFindings() throws IOException {
assertEquals(ddFinding.getEndpoints().get(0), location);
assertTrue(ddFinding.getDescription().startsWith(description));
//Description should consist of description and attributes as JSON
String attributesJson = ddFinding.getDescription().substring(description.length()+1);
String attributesJson = ddFinding.getDescription().substring(description.length() + 1);
String expectedAttributeJson = "{\n" +
" \"attribute_1\" : {\n" +
" \"sub_attribute\" : \"1\"\n" +
Expand All @@ -75,6 +76,14 @@ public void correctlyParsesFindings() throws IOException {
var expectedJson = mapper.readTree(attributesJson);
var actualJson = mapper.readTree(expectedAttributeJson);
assertNotNull(actualJson);
assertEquals(mapper.readTree(attributesJson),mapper.readTree(expectedAttributeJson));
assertEquals(mapper.readTree(attributesJson), mapper.readTree(expectedAttributeJson));
}

@Test
public void doesntThrowUnexpectedExceptionOnEmptyFinding() throws JsonProcessingException {
var emptyScbFinding = SecureCodeBoxFinding.builder().build();
var ddFinding = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeBoxFinding(emptyScbFinding);
assertNull(ddFinding.getTitle());
assertNull(ddFinding.getDescription());
}
}