getEcosystems() {
HttpUriRequest request = new HttpGet(url);
try (final CloseableHttpResponse response = HttpClientPool.getClient().execute(request)) {
final StatusLine status = response.getStatusLine();
- if (status.getStatusCode() == 200) {
+ if (status.getStatusCode() == HttpStatus.SC_OK) {
try (InputStream in = response.getEntity().getContent();
Scanner scanner = new Scanner(in, StandardCharsets.UTF_8)) {
while (scanner.hasNextLine()) {
diff --git a/src/main/java/org/dependencytrack/tasks/VulnDbSyncTask.java b/src/main/java/org/dependencytrack/tasks/VulnDbSyncTask.java
index 86c6c217f7..0e0486eef3 100644
--- a/src/main/java/org/dependencytrack/tasks/VulnDbSyncTask.java
+++ b/src/main/java/org/dependencytrack/tasks/VulnDbSyncTask.java
@@ -32,17 +32,16 @@
import org.dependencytrack.notification.NotificationGroup;
import org.dependencytrack.notification.NotificationScope;
import org.dependencytrack.parser.vulndb.ModelConverter;
+import org.dependencytrack.parser.vulndb.VulnDbParser;
+import org.dependencytrack.parser.vulndb.model.Product;
+import org.dependencytrack.parser.vulndb.model.Results;
+import org.dependencytrack.parser.vulndb.model.Vendor;
+import org.dependencytrack.parser.vulndb.model.Version;
import org.dependencytrack.persistence.QueryManager;
import us.springett.parsers.cpe.Cpe;
import us.springett.parsers.cpe.CpeParser;
import us.springett.parsers.cpe.exceptions.CpeEncodingException;
import us.springett.parsers.cpe.exceptions.CpeParsingException;
-import us.springett.vulndbdatamirror.parser.VulnDbParser;
-import us.springett.vulndbdatamirror.parser.model.CPE;
-import us.springett.vulndbdatamirror.parser.model.Product;
-import us.springett.vulndbdatamirror.parser.model.Results;
-import us.springett.vulndbdatamirror.parser.model.Vendor;
-import us.springett.vulndbdatamirror.parser.model.Version;
import java.io.File;
import java.io.IOException;
@@ -54,7 +53,7 @@
* Subscriber task that performs synchronization with VulnDB mirrored data.
* This task relies on an existing mirror generated from vulndb-data-mirror. The mirror must exist
* in a 'vulndb' subdirectory of the Dependency-Track data directory. i.e. ~/dependency-track/vulndb
- *
+ *
* https://github.com/stevespringett/vulndb-data-mirror
*
* @author Steve Springett
@@ -85,7 +84,7 @@ public void inform(final Event e) {
LOGGER.info("Parsing: " + file.getName());
final VulnDbParser parser = new VulnDbParser();
try {
- final Results results = parser.parse(file, us.springett.vulndbdatamirror.parser.model.Vulnerability.class);
+ final Results results = parser.parse(file, org.dependencytrack.parser.vulndb.model.Vulnerability.class);
updateDatasource(results);
} catch (IOException ex) {
LOGGER.error("An error occurred while parsing VulnDB payload: " + file.getName(), ex);
@@ -116,14 +115,15 @@ public void inform(final Event e) {
/**
* Synchronizes the VulnDB vulnerabilities with the internal Dependency-Track database.
+ *
* @param results the results to synchronize
*/
private void updateDatasource(final Results results) {
LOGGER.info("Updating datasource with VulnDB vulnerabilities");
try (QueryManager qm = new QueryManager()) {
- for (final Object o: results.getResults()) {
- if (o instanceof us.springett.vulndbdatamirror.parser.model.Vulnerability) {
- final us.springett.vulndbdatamirror.parser.model.Vulnerability vulnDbVuln = (us.springett.vulndbdatamirror.parser.model.Vulnerability)o;
+ for (final Object o : results.getResults()) {
+ if (o instanceof org.dependencytrack.parser.vulndb.model.Vulnerability) {
+ final org.dependencytrack.parser.vulndb.model.Vulnerability vulnDbVuln = (org.dependencytrack.parser.vulndb.model.Vulnerability) o;
final org.dependencytrack.model.Vulnerability vulnerability = ModelConverter.convert(qm, vulnDbVuln);
final Vulnerability synchronizeVulnerability = qm.synchronizeVulnerability(vulnerability, false);
final List vsListOld = qm.detach(qm.getVulnerableSoftwareByVulnId(synchronizeVulnerability.getSource(), synchronizeVulnerability.getVulnId()));
@@ -138,28 +138,28 @@ private void updateDatasource(final Results results) {
}
public static List parseCpes(final QueryManager qm, final Vulnerability vulnerability,
- final us.springett.vulndbdatamirror.parser.model.Vulnerability vulnDbVuln) {
+ final org.dependencytrack.parser.vulndb.model.Vulnerability vulnDbVuln) {
// cpe:2.3:a:belavier_commerce:abantecart:1.2.8:*:*:*:*:*:*:*
final List vsList = new ArrayList<>();
- if (vulnDbVuln.getVendors() != null) {
- for (Vendor vendor: vulnDbVuln.getVendors()) {
- if (vendor.getProducts() != null) {
- for (Product product: vendor.getProducts()) {
- if (product.getVersions() != null) {
- for (Version version: product.getVersions()) {
+ if (vulnDbVuln.vendors() != null) {
+ for (Vendor vendor : vulnDbVuln.vendors()) {
+ if (vendor.products() != null) {
+ for (Product product : vendor.products()) {
+ if (product.versions() != null) {
+ for (Version version : product.versions()) {
if (version != null) {
- if (version.isAffected()) {
- if (version.getCpes() != null) {
- for (CPE cpeObject : version.getCpes()) {
+ if (version.affected()) {
+ if (version.cpes() != null) {
+ for (org.dependencytrack.parser.vulndb.model.Cpe cpeObject : version.cpes()) {
try {
- final Cpe cpe = CpeParser.parse(cpeObject.getCpe(), true);
+ final Cpe cpe = CpeParser.parse(cpeObject.cpe(), true);
final VulnerableSoftware vs = generateVulnerableSoftware(qm, cpe, vulnerability);
if (vs != null) {
vsList.add(vs);
}
} catch (CpeParsingException e) {
// Normally, this would be logged to error, however, VulnDB contains a lot of invalid CPEs
- LOGGER.debug("An error occurred parsing " + cpeObject.getCpe(), e);
+ LOGGER.debug("An error occurred parsing " + cpeObject.cpe(), e);
}
}
}
@@ -190,7 +190,6 @@ private static VulnerableSoftware generateVulnerableSoftware(final QueryManager
vs.setVersionStartExcluding(null);
vs.setVersionStartIncluding(null);
vs = qm.persist(vs);
- //Event.dispatch(new IndexEvent(IndexEvent.Action.CREATE, qm.detach(VulnerableSoftware.class, vs.getId())));
return vs;
} catch (CpeParsingException | CpeEncodingException e) {
LOGGER.warn("An error occurred while parsing: " + cpe.toCpe23FS() + " - The CPE is invalid and will be discarded.");
diff --git a/src/main/java/org/dependencytrack/tasks/VulnerabilityAnalysisTask.java b/src/main/java/org/dependencytrack/tasks/VulnerabilityAnalysisTask.java
index c601a8fe22..9afadbe8c6 100644
--- a/src/main/java/org/dependencytrack/tasks/VulnerabilityAnalysisTask.java
+++ b/src/main/java/org/dependencytrack/tasks/VulnerabilityAnalysisTask.java
@@ -26,21 +26,21 @@
import org.dependencytrack.event.OssIndexAnalysisEvent;
import org.dependencytrack.event.PortfolioVulnerabilityAnalysisEvent;
import org.dependencytrack.event.ProjectMetricsUpdateEvent;
+import org.dependencytrack.event.SnykAnalysisEvent;
import org.dependencytrack.event.VulnDbAnalysisEvent;
import org.dependencytrack.event.VulnerabilityAnalysisEvent;
-import org.dependencytrack.event.SnykAnalysisEvent;
-import org.dependencytrack.model.VulnerabilityAnalysisLevel;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.Project;
+import org.dependencytrack.model.VulnerabilityAnalysisLevel;
import org.dependencytrack.persistence.QueryManager;
import org.dependencytrack.policy.PolicyEngine;
+import org.dependencytrack.tasks.scanners.AnalyzerIdentity;
import org.dependencytrack.tasks.scanners.CacheableScanTask;
import org.dependencytrack.tasks.scanners.InternalAnalysisTask;
import org.dependencytrack.tasks.scanners.OssIndexAnalysisTask;
import org.dependencytrack.tasks.scanners.ScanTask;
-import org.dependencytrack.tasks.scanners.VulnDbAnalysisTask;
-import org.dependencytrack.tasks.scanners.AnalyzerIdentity;
import org.dependencytrack.tasks.scanners.SnykAnalysisTask;
+import org.dependencytrack.tasks.scanners.VulnDbAnalysisTask;
import java.time.Duration;
import java.time.Instant;
@@ -88,7 +88,7 @@ public void inform(final Event e) {
.stream()
.map(Project::getUuid)
.collect(Collectors.toList());
- for (final UUID projectUuid: projectUuids) {
+ for (final UUID projectUuid : projectUuids) {
final Project project = qm.getObjectByUuid(Project.class, projectUuid);
if (project == null) continue;
final List components = qm.getAllComponents(project);
@@ -142,7 +142,7 @@ private void performPolicyEvaluation(Project project, List components
private void inspectComponentReadiness(final Component component, final ScanTask scanTask, final List candidates) {
if (scanTask.isCapable(component)) {
if (scanTask.getClass().isAssignableFrom(CacheableScanTask.class)) {
- final CacheableScanTask cacheableScanTask = (CacheableScanTask)scanTask;
+ final CacheableScanTask cacheableScanTask = (CacheableScanTask) scanTask;
if (cacheableScanTask.shouldAnalyze(component.getPurl())) {
candidates.add(component);
} else {
@@ -158,7 +158,7 @@ private void performAnalysis(final Subscriber scanTask, final VulnerabilityAnaly
final AnalyzerIdentity analyzerIdentity, final Event eventType) {
Instant start = Instant.now();
event.setVulnerabilityAnalysisLevel(VulnerabilityAnalysisLevel.PERIODIC_ANALYSIS);
- if(eventType instanceof VulnerabilityAnalysisEvent) {
+ if (eventType instanceof VulnerabilityAnalysisEvent) {
event.setVulnerabilityAnalysisLevel(VulnerabilityAnalysisLevel.BOM_UPLOAD_ANALYSIS);
}
if (CollectionUtils.isNotEmpty(event.getComponents())) {
@@ -175,7 +175,7 @@ private void performAnalysis(final Subscriber scanTask, final VulnerabilityAnaly
event.getComponents().forEach(c -> c.setCacheResult(null));
Instant end = Instant.now();
Duration timeElapsed = Duration.between(start, end);
- LOGGER.debug("Time taken by perform analysis task by "+analyzerIdentity.name()+" : "+ timeElapsed.toMillis() +" milliseconds");
+ LOGGER.debug("Time taken by perform analysis task by " + analyzerIdentity.name() + " : " + timeElapsed.toMillis() + " milliseconds");
}
}
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/AbstractMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/AbstractMetaAnalyzer.java
index bca39977dd..5e0cee6ec2 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/AbstractMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/AbstractMetaAnalyzer.java
@@ -22,10 +22,19 @@
import alpine.notification.Notification;
import alpine.notification.NotificationLevel;
import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.utils.URIBuilder;
+import org.dependencytrack.common.HttpClientPool;
import org.dependencytrack.model.Component;
import org.dependencytrack.notification.NotificationConstants;
import org.dependencytrack.notification.NotificationGroup;
import org.dependencytrack.notification.NotificationScope;
+import org.dependencytrack.util.HttpUtil;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
/**
* Base abstract class that all IMetaAnalyzer implementations should likely extend.
@@ -40,7 +49,6 @@ public abstract class AbstractMetaAnalyzer implements IMetaAnalyzer {
protected String username;
protected String password;
-
/**
* {@inheritDoc}
*/
@@ -84,4 +92,20 @@ protected void handleRequestException(final Logger logger, final Exception e) {
);
}
+ protected CloseableHttpResponse processHttpRequest(String url) throws IOException {
+ final Logger logger = Logger.getLogger(getClass());
+ try {
+ URIBuilder uriBuilder = new URIBuilder(url);
+ final HttpUriRequest request = new HttpGet(uriBuilder.build().toString());
+ request.addHeader("accept", "application/json");
+ if (username != null || password != null) {
+ request.addHeader("Authorization", HttpUtil.basicAuthHeaderValue(username, password));
+ }
+ return HttpClientPool.getClient().execute(request);
+ }catch (URISyntaxException ex){
+ handleRequestException(logger, ex);
+ return null;
+ }
+ }
+
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/CargoMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/CargoMetaAnalyzer.java
index 43381f6c48..d1a9f80a79 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/CargoMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/CargoMetaAnalyzer.java
@@ -20,19 +20,18 @@
import alpine.common.logging.Logger;
import com.github.packageurl.PackageURL;
-import kong.unirest.GetRequest;
-import kong.unirest.HttpRequest;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import kong.unirest.json.JSONArray;
-import kong.unirest.json.JSONObject;
-import org.dependencytrack.common.UnirestFactory;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.util.EntityUtils;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.RepositoryType;
import org.dependencytrack.util.DateUtil;
+import java.io.IOException;
+
/**
* An IMetaAnalyzer implementation that supports Cargo via crates.io compatible repos
*
@@ -67,35 +66,30 @@ public RepositoryType supportedRepositoryType() {
* {@inheritDoc}
*/
public MetaModel analyze(final Component component) {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
final MetaModel meta = new MetaModel(component);
if (component.getPurl() != null) {
final String url = String.format(baseUrl + API_URL, component.getPurl().getName());
- try {
- final HttpRequest request = ui.get(url)
- .header("accept", "application/json");
- if (username != null || password != null) {
- request.basicAuth(username, password);
- }
- final HttpResponse response = request.asJson();
-
- if (response.getStatus() == 200) {
- if (response.getBody() != null && response.getBody().getObject() != null) {
- final JSONObject crate = response.getBody().getObject().optJSONObject("crate");
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ final HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ String responseString = EntityUtils.toString(entity);
+ var jsonObject = new JSONObject(responseString);
+ final JSONObject crate = jsonObject.optJSONObject("crate");
if (crate != null) {
final String latest = crate.getString("newest_version");
meta.setLatestVersion(latest);
}
- final JSONArray versions = response.getBody().getObject().optJSONArray("versions");
+ final JSONArray versions = jsonObject.optJSONArray("versions");
if (versions != null) {
- for (int i=0; i request = ui.get(url)
- .header("accept", "application/json");
- if (username != null || password != null) {
- request.basicAuth(username, password);
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
+ return meta;
}
- final HttpResponse response = request.asJson();
-
- if (response.getStatus() != 200) {
- handleUnexpectedHttpResponse(LOGGER, url, response.getStatus(), response.getStatusText(), component);
+ if (response.getEntity().getContent() == null) {
return meta;
}
-
- if (response.getBody() == null || response.getBody().getObject() == null) {
+ String jsonString = EntityUtils.toString(response.getEntity());
+ if (jsonString.equalsIgnoreCase("")) {
return meta;
}
-
+ if (jsonString.equalsIgnoreCase("{}")) {
+ return meta;
+ }
+ JSONObject jsonObject = new JSONObject(jsonString);
final String expectedResponsePackage = component.getPurl().getNamespace() + "/" + component.getPurl().getName();
- final JSONObject responsePackages = response
- .getBody()
- .getObject()
+ final JSONObject responsePackages = jsonObject
.getJSONObject("packages");
if (!responsePackages.has(expectedResponsePackage)) {
// the package no longer exists - like this one: https://repo.packagist.org/p/magento/adobe-ims.json
@@ -121,8 +114,7 @@ public MetaModel analyze(final Component component) {
final String version_normalized = composerPackage.getJSONObject(key).getString("version_normalized");
ComparableVersion currentComparableVersion = new ComparableVersion(version_normalized);
- if ( currentComparableVersion.compareTo(latestVersion) < 0)
- {
+ if (currentComparableVersion.compareTo(latestVersion) < 0) {
// smaller version can be skipped
return;
}
@@ -138,10 +130,11 @@ public MetaModel analyze(final Component component) {
LOGGER.warn("An error occurred while parsing upload time", e);
}
});
- } catch (UnirestException e) {
- handleRequestException(LOGGER, e);
+ } catch (IOException ex) {
+ handleRequestException(LOGGER, ex);
}
+
return meta;
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/GemMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/GemMetaAnalyzer.java
index 3747e29ebd..eeb9cdf59d 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/GemMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/GemMetaAnalyzer.java
@@ -20,15 +20,14 @@
import alpine.common.logging.Logger;
import com.github.packageurl.PackageURL;
-import kong.unirest.GetRequest;
-import kong.unirest.HttpRequest;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import org.dependencytrack.common.UnirestFactory;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.util.EntityUtils;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.RepositoryType;
+import org.json.JSONObject;
+
+import java.io.IOException;
/**
* An IMetaAnalyzer implementation that supports Ruby Gems.
@@ -64,29 +63,24 @@ public RepositoryType supportedRepositoryType() {
* {@inheritDoc}
*/
public MetaModel analyze(final Component component) {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
final MetaModel meta = new MetaModel(component);
if (component.getPurl() != null) {
final String url = String.format(baseUrl + API_URL, component.getPurl().getName());
- try {
- final HttpRequest request = ui.get(url)
- .header("accept", "application/json");
- if (username != null || password != null) {
- request.basicAuth(username, password);
- }
- final HttpResponse response = request.asJson();
-
- if (response.getStatus() == 200) {
- if (response.getBody() != null && response.getBody().getObject() != null) {
- final String latest = response.getBody().getObject().getString("version");
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
+ if(response.getEntity()!=null){
+ String responseString = EntityUtils.toString(response.getEntity());
+ var jsonObject = new JSONObject(responseString);
+ final String latest = jsonObject.getString("version");
meta.setLatestVersion(latest);
}
} else {
- handleUnexpectedHttpResponse(LOGGER, url, response.getStatus(), response.getStatusText(), component);
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
}
- } catch (UnirestException e) {
- handleRequestException(LOGGER, e);
+ }catch (IOException ex){
+ handleRequestException(LOGGER, ex);
}
+
}
return meta;
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/GoModulesMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/GoModulesMetaAnalyzer.java
index 7bbdf55ca9..d6f8eaaa8d 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/GoModulesMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/GoModulesMetaAnalyzer.java
@@ -20,18 +20,15 @@
import alpine.common.logging.Logger;
import com.github.packageurl.PackageURL;
-import kong.unirest.GetRequest;
-import kong.unirest.HttpRequest;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import kong.unirest.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
-import org.dependencytrack.common.UnirestFactory;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.util.EntityUtils;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.RepositoryType;
+import org.json.JSONObject;
+import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -66,21 +63,13 @@ public MetaModel analyze(final Component component) {
if (component.getPurl() == null || component.getPurl().getNamespace() == null) {
return meta;
}
-
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
final String url = String.format(baseUrl + API_URL, caseEncode(component.getPurl().getNamespace()), caseEncode(component.getPurl().getName()));
- try {
- final HttpRequest request = ui.get(url)
- .header("accept", "application/json");
- if (username != null || password != null) {
- request.basicAuth(username, password);
- }
- final HttpResponse response = request.asJson();
-
- if (response.getStatus() == 200) {
- if (response.getBody() != null && response.getBody().getObject() != null) {
- final JSONObject responseJson = response.getBody().getObject();
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ if (response.getEntity()!=null) {
+ String responseString = EntityUtils.toString(response.getEntity());
+ final var responseJson = new JSONObject(responseString);
meta.setLatestVersion(responseJson.getString("Version"));
// Module versions are prefixed with "v" in the Go ecosystem.
@@ -99,9 +88,9 @@ public MetaModel analyze(final Component component) {
}
}
} else {
- handleUnexpectedHttpResponse(LOGGER, url, response.getStatus(), response.getStatusText(), component);
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
}
- } catch (UnirestException | ParseException e) {
+ } catch (IOException | ParseException e) {
handleRequestException(LOGGER, e);
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/HexMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/HexMetaAnalyzer.java
index 0d5b23dd6b..a3a0f747ed 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/HexMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/HexMetaAnalyzer.java
@@ -20,18 +20,15 @@
import alpine.common.logging.Logger;
import com.github.packageurl.PackageURL;
-import kong.unirest.GetRequest;
-import kong.unirest.HttpRequest;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import kong.unirest.json.JSONArray;
-import kong.unirest.json.JSONObject;
-import org.dependencytrack.common.UnirestFactory;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.util.EntityUtils;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.RepositoryType;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -71,7 +68,6 @@ public RepositoryType supportedRepositoryType() {
* {@inheritDoc}
*/
public MetaModel analyze(final Component component) {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
final MetaModel meta = new MetaModel(component);
if (component.getPurl() != null) {
@@ -83,17 +79,12 @@ public MetaModel analyze(final Component component) {
}
final String url = String.format(baseUrl + API_URL, packageName);
- try {
- final HttpRequest request = ui.get(url)
- .header("accept", "application/json");
- if (username != null || password != null) {
- request.basicAuth(username, password);
- }
- final HttpResponse response = request.asJson();
-
- if (response.getStatus() == 200) {
- if (response.getBody() != null && response.getBody().getObject() != null) {
- final JSONArray releasesArray = response.getBody().getObject().getJSONArray("releases");
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ if (response.getEntity()!=null) {
+ String responseString = EntityUtils.toString(response.getEntity());
+ var jsonObject = new JSONObject(responseString);
+ final JSONArray releasesArray = jsonObject.getJSONArray("releases");
if (releasesArray.length() > 0) {
// The first one in the array is always the latest version
final JSONObject release = releasesArray.getJSONObject(0);
@@ -112,9 +103,9 @@ public MetaModel analyze(final Component component) {
}
}
} else {
- handleUnexpectedHttpResponse(LOGGER, url, response.getStatus(), response.getStatusText(), component);
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
}
- } catch (UnirestException e) {
+ } catch (IOException e) {
handleRequestException(LOGGER, e);
}
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/MavenMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/MavenMetaAnalyzer.java
index f3629c618e..dd2c2193e1 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/MavenMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/MavenMetaAnalyzer.java
@@ -21,15 +21,11 @@
import alpine.common.logging.Logger;
import com.github.packageurl.PackageURL;
import org.apache.http.HttpEntity;
-import org.apache.http.StatusLine;
+import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.dependencytrack.common.HttpClientPool;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.RepositoryType;
import org.dependencytrack.util.DateUtil;
-import org.dependencytrack.util.HttpUtil;
import org.dependencytrack.util.XmlUtil;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
@@ -81,44 +77,36 @@ public MetaModel analyze(final Component component) {
if (component.getPurl() != null) {
final String mavenGavUrl = component.getPurl().getNamespace().replaceAll("\\.", "/") + "/" + component.getPurl().getName();
final String url = String.format(baseUrl + REPO_METADATA_URL, mavenGavUrl);
- try {
- final HttpUriRequest request = new HttpGet(url);
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ final HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ try (InputStream in = entity.getContent()) {
+ final Document document = XmlUtil.buildSecureDocumentBuilder().parse(in);
+ final var xpathFactory = XPathFactory.newInstance();
+ final XPath xpath = xpathFactory.newXPath();
- if (username != null || password != null) {
- request.setHeader("Authorization", HttpUtil.basicAuthHeaderValue(username, password));
- }
-
- try (final CloseableHttpResponse response = HttpClientPool.getClient().execute(request)) {
- final StatusLine status = response.getStatusLine();
- if (status.getStatusCode() == 200) {
- final HttpEntity entity = response.getEntity();
- if (entity != null) {
- try (InputStream in = entity.getContent()) {
- final Document document = XmlUtil.buildSecureDocumentBuilder().parse(in);
- final XPathFactory xpathFactory = XPathFactory.newInstance();
- final XPath xpath = xpathFactory.newXPath();
+ final XPathExpression releaseExpression = xpath.compile("/metadata/versioning/release");
+ final XPathExpression latestExpression = xpath.compile("/metadata/versioning/latest");
+ final var release = (String) releaseExpression.evaluate(document, XPathConstants.STRING);
+ final String latest = (String) latestExpression.evaluate(document, XPathConstants.STRING);
- final XPathExpression releaseExpression = xpath.compile("/metadata/versioning/release");
- final XPathExpression latestExpression = xpath.compile("/metadata/versioning/latest");
- final String release = (String) releaseExpression.evaluate(document, XPathConstants.STRING);
- final String latest = (String) latestExpression.evaluate(document, XPathConstants.STRING);
+ final XPathExpression lastUpdatedExpression = xpath.compile("/metadata/versioning/lastUpdated");
+ final var lastUpdated = (String) lastUpdatedExpression.evaluate(document, XPathConstants.STRING);
- final XPathExpression lastUpdatedExpression = xpath.compile("/metadata/versioning/lastUpdated");
- final String lastUpdated = (String) lastUpdatedExpression.evaluate(document, XPathConstants.STRING);
-
- meta.setLatestVersion(release != null ? release: latest);
- if (lastUpdated != null) {
- meta.setPublishedTimestamp(DateUtil.parseDate(lastUpdated));
- }
+ meta.setLatestVersion(release != null ? release : latest);
+ if (lastUpdated != null) {
+ meta.setPublishedTimestamp(DateUtil.parseDate(lastUpdated));
}
}
- } else {
- handleUnexpectedHttpResponse(LOGGER, url, status.getStatusCode(), status.getReasonPhrase(), component);
}
+ } else {
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
}
} catch (IOException | ParserConfigurationException | SAXException | XPathExpressionException e) {
handleRequestException(LOGGER, e);
}
+
}
return meta;
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/NpmMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/NpmMetaAnalyzer.java
index 03ccf30bfc..0186f8af68 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/NpmMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/NpmMetaAnalyzer.java
@@ -20,15 +20,14 @@
import alpine.common.logging.Logger;
import com.github.packageurl.PackageURL;
-import kong.unirest.GetRequest;
-import kong.unirest.HttpRequest;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import org.dependencytrack.common.UnirestFactory;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.util.EntityUtils;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.RepositoryType;
+import org.json.JSONObject;
+
+import java.io.IOException;
/**
* An IMetaAnalyzer implementation that supports NPM.
@@ -64,7 +63,6 @@ public RepositoryType supportedRepositoryType() {
* {@inheritDoc}
*/
public MetaModel analyze(final Component component) {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
final MetaModel meta = new MetaModel(component);
if (component.getPurl() != null) {
@@ -76,25 +74,20 @@ public MetaModel analyze(final Component component) {
}
final String url = String.format(baseUrl + API_URL, packageName);
- try {
- final HttpRequest request = ui.get(url)
- .header("accept", "application/json");
- if (username != null || password != null) {
- request.basicAuth(username, password);
- }
- final HttpResponse response = request.asJson();
-
- if (response.getStatus() == 200) {
- if (response.getBody() != null && response.getBody().getObject() != null) {
- final String latest = response.getBody().getObject().optString("latest");
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ if (response.getEntity()!=null) {
+ String responseString = EntityUtils.toString(response.getEntity());
+ var jsonObject = new JSONObject(responseString);
+ final String latest = jsonObject.optString("latest");
if (latest != null) {
meta.setLatestVersion(latest);
}
}
} else {
- handleUnexpectedHttpResponse(LOGGER, url, response.getStatus(), response.getStatusText(), component);
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
}
- } catch (UnirestException e) {
+ } catch (IOException e) {
handleRequestException(LOGGER, e);
}
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/NugetMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/NugetMetaAnalyzer.java
index bd0333dc59..dba7b99ddd 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/NugetMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/NugetMetaAnalyzer.java
@@ -20,19 +20,16 @@
import alpine.common.logging.Logger;
import com.github.packageurl.PackageURL;
-import kong.unirest.GetRequest;
-import kong.unirest.HttpRequest;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import kong.unirest.json.JSONArray;
-import kong.unirest.json.JSONObject;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.util.EntityUtils;
import org.apache.maven.artifact.versioning.ComparableVersion;
-import org.dependencytrack.common.UnirestFactory;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.RepositoryType;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -107,19 +104,20 @@ public MetaModel analyze(final Component component) {
private boolean performVersionCheck(final MetaModel meta, final Component component) {
final String url = String.format(versionQueryUrl, component.getPurl().getName().toLowerCase());
- try {
- final HttpResponse response = httpGet(url);
- if (response.getStatus() == 200) {
- if (response.getBody() != null && response.getBody().getObject() != null) {
- final JSONArray versions = response.getBody().getObject().getJSONArray("versions");
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ if (response.getEntity() != null) {
+ String responseString = EntityUtils.toString(response.getEntity());
+ var jsonObject = new JSONObject(responseString);
+ final JSONArray versions = jsonObject.getJSONArray("versions");
final String latest = findLatestVersion(versions); // get the last version in the array
meta.setLatestVersion(latest);
}
return true;
} else {
- handleUnexpectedHttpResponse(LOGGER, url, response.getStatus(), response.getStatusText(), component);
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
}
- } catch (UnirestException e) {
+ } catch (IOException e) {
handleRequestException(LOGGER, e);
}
return false;
@@ -142,33 +140,25 @@ private String findLatestVersion(JSONArray versions) {
return latestVersion.toString();
}
- private HttpResponse httpGet(String url) {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
- final HttpRequest request = ui.get(url).header("accept", "application/json");
-
- if (username != null || password != null) {
- request.basicAuth(username, password);
- }
-
- return request.asJson();
- }
-
private boolean performLastPublishedCheck(final MetaModel meta, final Component component) {
final String url = String.format(registrationUrl, component.getPurl().getName().toLowerCase(), meta.getLatestVersion());
- try {
- final HttpResponse response = httpGet(url);
- if (response.getStatus() == 200) {
- if (response.getBody() != null && response.getBody().getObject() != null) {
- final String updateTime = response.getBody().getObject().optString("published", null);
- if (updateTime != null) {
- meta.setPublishedTimestamp(parseUpdateTime(updateTime));
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ if (response.getEntity() != null) {
+ String stringResponse = EntityUtils.toString(response.getEntity());
+ if (!stringResponse.equalsIgnoreCase("") && !stringResponse.equalsIgnoreCase("{}")) {
+ JSONObject jsonResponse = new JSONObject(stringResponse);
+ final String updateTime = jsonResponse.optString("published", null);
+ if (updateTime != null) {
+ meta.setPublishedTimestamp(parseUpdateTime(updateTime));
+ }
+ return true;
}
}
- return true;
} else {
- handleUnexpectedHttpResponse(LOGGER, url, response.getStatus(), response.getStatusText(), component);
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
}
- } catch (UnirestException e) {
+ } catch (IOException e) {
handleRequestException(LOGGER, e);
}
return false;
@@ -177,17 +167,22 @@ private boolean performLastPublishedCheck(final MetaModel meta, final Component
private void initializeEndpoints() {
final String url = baseUrl + INDEX_URL;
try {
- final HttpResponse response = httpGet(url);
- if (response.getStatus() == 200 && response.getBody() != null && response.getBody().getObject() != null) {
- final JSONArray resources = response.getBody().getObject().getJSONArray("resources");
- final JSONObject packageBaseResource = findResourceByType(resources, "PackageBaseAddress");
- final JSONObject registrationsBaseResource = findResourceByType(resources, "RegistrationsBaseUrl");
- if (packageBaseResource != null && registrationsBaseResource != null) {
- versionQueryUrl = packageBaseResource.getString("@id") + "%s/index.json";
- registrationUrl = registrationsBaseResource.getString("@id") + "%s/%s.json";
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ if(response.getEntity()!=null){
+ String responseString = EntityUtils.toString(response.getEntity());
+ JSONObject responseJson = new JSONObject(responseString);
+ final JSONArray resources = responseJson.getJSONArray("resources");
+ final JSONObject packageBaseResource = findResourceByType(resources, "PackageBaseAddress");
+ final JSONObject registrationsBaseResource = findResourceByType(resources, "RegistrationsBaseUrl");
+ if (packageBaseResource != null && registrationsBaseResource != null) {
+ versionQueryUrl = packageBaseResource.getString("@id") + "%s/index.json";
+ registrationUrl = registrationsBaseResource.getString("@id") + "%s/%s.json";
+ }
+ }
}
}
- } catch (UnirestException e) {
+ } catch (IOException e) {
handleRequestException(LOGGER, e);
}
}
diff --git a/src/main/java/org/dependencytrack/tasks/repositories/PypiMetaAnalyzer.java b/src/main/java/org/dependencytrack/tasks/repositories/PypiMetaAnalyzer.java
index bddda44aad..484571bd52 100644
--- a/src/main/java/org/dependencytrack/tasks/repositories/PypiMetaAnalyzer.java
+++ b/src/main/java/org/dependencytrack/tasks/repositories/PypiMetaAnalyzer.java
@@ -20,18 +20,15 @@
import alpine.common.logging.Logger;
import com.github.packageurl.PackageURL;
-import kong.unirest.GetRequest;
-import kong.unirest.HttpRequest;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import kong.unirest.json.JSONArray;
-import kong.unirest.json.JSONObject;
-import org.dependencytrack.common.UnirestFactory;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.util.EntityUtils;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.RepositoryType;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -71,25 +68,19 @@ public RepositoryType supportedRepositoryType() {
* {@inheritDoc}
*/
public MetaModel analyze(final Component component) {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
final MetaModel meta = new MetaModel(component);
if (component.getPurl() != null) {
final String url = String.format(baseUrl + API_URL, component.getPurl().getName());
- try {
- final HttpRequest request = ui.get(url)
- .header("accept", "application/json");
- if (username != null || password != null) {
- request.basicAuth(username, password);
- }
- final HttpResponse response = request.asJson();
-
- if (response.getStatus() == 200) {
- if (response.getBody() != null && response.getBody().getObject() != null) {
- final JSONObject info = response.getBody().getObject().getJSONObject("info");
+ try (final CloseableHttpResponse response = processHttpRequest(url)) {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ if (response.getEntity() != null) {
+ String stringResponse = EntityUtils.toString(response.getEntity());
+ JSONObject jsonObject = new JSONObject(stringResponse);
+ final JSONObject info = jsonObject.getJSONObject("info");
final String latest = info.optString("version", null);
if (latest != null) {
meta.setLatestVersion(latest);
- final JSONObject releases = response.getBody().getObject().getJSONObject("releases");
+ final JSONObject releases = jsonObject.getJSONObject("releases");
final JSONArray latestArray = releases.getJSONArray(latest);
if (latestArray.length() > 0) {
final JSONObject release = latestArray.getJSONObject(0);
@@ -107,12 +98,12 @@ public MetaModel analyze(final Component component) {
}
}
} else {
- handleUnexpectedHttpResponse(LOGGER, url, response.getStatus(), response.getStatusText(), component);
+ handleUnexpectedHttpResponse(LOGGER, url, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), component);
}
- } catch (UnirestException e) {
+ } catch (IOException e) {
handleRequestException(LOGGER, e);
}
}
return meta;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/dependencytrack/tasks/scanners/BaseComponentAnalyzerTask.java b/src/main/java/org/dependencytrack/tasks/scanners/BaseComponentAnalyzerTask.java
index 65c9156025..bf8ca516a2 100644
--- a/src/main/java/org/dependencytrack/tasks/scanners/BaseComponentAnalyzerTask.java
+++ b/src/main/java/org/dependencytrack/tasks/scanners/BaseComponentAnalyzerTask.java
@@ -147,7 +147,7 @@ protected void handleUnexpectedHttpResponse(final Logger logger, String url, fin
);
}
- protected void handleRequestException(final Logger logger, final Exception e) {
+ protected void handleRequestException(final Logger logger, final Throwable e) {
logger.error("Request failure", e);
Notification.dispatch(new Notification()
.scope(NotificationScope.SYSTEM)
diff --git a/src/main/java/org/dependencytrack/tasks/scanners/OssIndexAnalysisTask.java b/src/main/java/org/dependencytrack/tasks/scanners/OssIndexAnalysisTask.java
index c21709670d..2f10f1dd3e 100644
--- a/src/main/java/org/dependencytrack/tasks/scanners/OssIndexAnalysisTask.java
+++ b/src/main/java/org/dependencytrack/tasks/scanners/OssIndexAnalysisTask.java
@@ -33,17 +33,17 @@
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;
-import kong.unirest.HttpRequestWithBody;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import kong.unirest.json.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
+import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.util.EntityUtils;
import org.dependencytrack.common.ConfigKey;
+import org.dependencytrack.common.HttpClientPool;
import org.dependencytrack.common.ManagedHttpClientFactory;
-import org.dependencytrack.common.UnirestFactory;
import org.dependencytrack.event.OssIndexAnalysisEvent;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.ConfigPropertyConstants;
@@ -56,12 +56,15 @@
import org.dependencytrack.parser.ossindex.model.ComponentReport;
import org.dependencytrack.parser.ossindex.model.ComponentReportVulnerability;
import org.dependencytrack.persistence.QueryManager;
+import org.dependencytrack.util.HttpUtil;
import org.dependencytrack.util.NotificationUtil;
+import org.json.JSONObject;
import us.springett.cvss.Cvss;
import us.springett.cvss.CvssV2;
import us.springett.cvss.CvssV3;
import us.springett.cvss.Score;
+import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@@ -110,7 +113,7 @@ public class OssIndexAnalysisTask extends BaseComponentAnalyzerTask implements C
public AnalyzerIdentity getAnalyzerIdentity() {
return AnalyzerIdentity.OSSINDEX_ANALYZER;
}
-
+
/**
* {@inheritDoc}
*/
@@ -141,7 +144,7 @@ public void inform(final Event e) {
}
}
}
- final OssIndexAnalysisEvent event = (OssIndexAnalysisEvent)e;
+ final var event = (OssIndexAnalysisEvent) e;
LOGGER.info("Starting Sonatype OSS Index analysis task");
vulnerabilityAnalysisLevel = event.getVulnerabilityAnalysisLevel();
if (event.getComponents().size() > 0) {
@@ -184,6 +187,7 @@ public void applyAnalysisFromCache(final Component component) {
/**
* Analyzes a list of Components.
+ *
* @param components a list of Components
*/
public void analyze(final List components) {
@@ -202,11 +206,13 @@ public void analyze(final List components) {
final JSONObject json = new JSONObject();
json.put("coordinates", coordinates);
try {
- final List report = ossIndexRetryer.executeSupplier(() -> submit(json));
+ final List report = ossIndexRetryer.executeCheckedSupplier(() -> submit(json));
processResults(report, paginatedList);
- } catch (UnirestException e) {
- handleRequestException(LOGGER, e);
+ } catch (Throwable ex) {
+ handleRequestException(LOGGER, ex);
+ return;
}
+
LOGGER.info("Analyzing " + coordinates.size() + " component(s)");
}
paginatedComponents.nextPage();
@@ -218,15 +224,16 @@ public void analyze(final List components) {
* HTTP POST is used and PackageURL is specified that contains qualifiers (and possibly a subpath).
* Therefore, this method will return a String representation of a PackageURL without qualifier
* or subpath.
- *
+ *
* Additionally, as of October 2021, versions prefixed with "v" (as commonly done in the Go and PHP ecosystems)
* are triggering a bug in OSS Index that causes all vulnerabilities for the given component to be returned,
* not just the ones for the requested version: https://github.com/OSSIndex/vulns/issues/129#issuecomment-740666614
* As a result, this method will remove "v" prefixes from versions.
- *
+ *
* This method should be removed at a future date when OSSIndex resolves the issues.
- *
+ *
* TODO: Delete this method and workaround for OSSIndex bugs once Sonatype resolves them.
+ *
* @since 3.4.0
*/
@Deprecated
@@ -248,29 +255,33 @@ private static String minimizePurl(final PackageURL purl) {
/**
* Submits the payload to the Sonatype OSS Index service
*/
- private List submit(final JSONObject payload) throws UnirestException {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
- final HttpRequestWithBody request = ui.post(API_BASE_URL)
- .header(HttpHeaders.ACCEPT, "application/json")
- .header(HttpHeaders.CONTENT_TYPE, "application/json")
- .header(HttpHeaders.USER_AGENT, ManagedHttpClientFactory.getUserAgent());
+ private List submit(final JSONObject payload) throws IOException {
+ HttpPost request = new HttpPost(API_BASE_URL);
+ request.addHeader(HttpHeaders.ACCEPT, "application/json");
+ request.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
+ request.addHeader(HttpHeaders.USER_AGENT, ManagedHttpClientFactory.getUserAgent());
+ request.setEntity(new StringEntity(payload.toString()));
if (apiUsername != null && apiToken != null) {
- request.basicAuth(apiUsername, apiToken);
+ request.addHeader("Authorization", HttpUtil.basicAuthHeaderValue(apiUsername, apiToken));
}
- final HttpResponse jsonResponse = request.body(payload).asJson();
- if (jsonResponse.getStatus() == 200) {
- final OssIndexParser parser = new OssIndexParser();
- return parser.parse(jsonResponse.getBody());
- } else {
- handleUnexpectedHttpResponse(LOGGER, API_BASE_URL, jsonResponse.getStatus(), jsonResponse.getStatusText());
+ try (final CloseableHttpResponse response = HttpClientPool.getClient().execute(request)) {
+ HttpEntity responseEntity = response.getEntity();
+ String responseString = EntityUtils.toString(responseEntity);
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ final OssIndexParser parser = new OssIndexParser();
+ return parser.parse(responseString);
+ } else {
+ handleUnexpectedHttpResponse(LOGGER, API_BASE_URL, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
+ }
}
return new ArrayList<>();
+
}
private void processResults(final List report, final List componentsScanned) {
try (QueryManager qm = new QueryManager()) {
- for (final ComponentReport componentReport: report) {
- for (final Component c: componentsScanned) {
+ for (final ComponentReport componentReport : report) {
+ for (final Component c : componentsScanned) {
//final String componentPurl = component.getPurl().canonicalize(); // todo: put this back when minimizePurl() is removed
final String componentPurl = minimizePurl(c.getPurl());
final PackageURL sonatypePurl = oldPurlResolver(componentReport.getCoordinates());
@@ -282,7 +293,7 @@ private void processResults(final List report, final List>custom()
+ final RetryRegistry retryRegistry = RetryRegistry.of(RetryConfig.custom()
.intervalFunction(ofExponentialBackoff(
Duration.ofSeconds(Config.getInstance().getPropertyAsInt(ConfigKey.SNYK_RETRY_EXPONENTIAL_BACKOFF_INITIAL_DURATION_SECONDS)),
Config.getInstance().getPropertyAsInt(ConfigKey.SNYK_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER),
@@ -108,12 +111,12 @@ public class SnykAnalysisTask extends BaseComponentAnalyzerTask implements Cache
))
.maxAttempts(Config.getInstance().getPropertyAsInt(ConfigKey.SNYK_RETRY_MAX_ATTEMPTS))
.retryOnException(exception -> false)
- .retryOnResult(response -> HttpStatus.TOO_MANY_REQUESTS == response.getStatus())
+ .retryOnResult(response -> 429 == response.getStatusLine().getStatusCode())
.build());
RETRY = retryRegistry.retry("snyk-api");
RETRY.getEventPublisher()
- .onRetry(event -> LOGGER.debug("Will execute retry #%d in %s".formatted(event.getNumberOfRetryAttempts(), event.getWaitInterval())))
- .onError(event -> LOGGER.error("Retry failed after %d attempts: %s".formatted(event.getNumberOfRetryAttempts(), event.getLastThrowable())));
+ .onRetry(event -> LOGGER.debug("Will execute retry #%d in %s" .formatted(event.getNumberOfRetryAttempts(), event.getWaitInterval())))
+ .onError(event -> LOGGER.error("Retry failed after %d attempts: %s" .formatted(event.getNumberOfRetryAttempts(), event.getLastThrowable())));
TaggedRetryMetrics.ofRetryRegistry(retryRegistry)
.bindTo(Metrics.getRegistry());
@@ -238,7 +241,7 @@ public void analyze(final List components) {
countDownLatch.countDown();
if (exception != null) {
- LOGGER.error("An unexpected error occurred while analyzing %s".formatted(component), exception);
+ LOGGER.error("An unexpected error occurred while analyzing %s" .formatted(component), exception);
}
});
}
@@ -267,7 +270,7 @@ public void analyze(final List components) {
.scope(NotificationScope.SYSTEM)
.level(NotificationLevel.WARNING)
.group(NotificationGroup.ANALYZER)
- .title("Snyk API version %s is deprecated".formatted(apiVersion))
+ .title("Snyk API version %s is deprecated" .formatted(apiVersion))
.content(message));
}
}
@@ -294,28 +297,42 @@ public void applyAnalysisFromCache(final Component component) {
private void analyzeComponent(final Component component) {
final String encodedPurl = URLEncoder.encode(component.getPurl().getCoordinates(), StandardCharsets.UTF_8);
- final String requestUrl = "%s/rest/orgs/%s/packages/%s/issues?version=%s".formatted(apiBaseUrl, apiOrgId, encodedPurl, apiVersion);
- final GetRequest request = UnirestFactory.getUnirestInstance().get(requestUrl)
- .header(HttpHeaders.USER_AGENT, ManagedHttpClientFactory.getUserAgent())
- .header(HttpHeaders.AUTHORIZATION, "token " + apiTokenSupplier.get())
- .header(HttpHeaders.ACCEPT, "application/vnd.api+json");
-
- final HttpResponse response = RETRY.executeSupplier(request::asJson);
- apiVersionSunset = StringUtils.trimToNull(response.getHeaders().getFirst("Sunset"));
- if (response.isSuccess()) {
- handle(component, response.getBody().getObject());
- } else if (response.getBody() != null) {
- final List errors = new SnykParser().parseErrors(response.getBody().getObject());
- if (!errors.isEmpty()) {
- LOGGER.error("Analysis of component %s failed with HTTP status %d: \n%s"
- .formatted(component.getPurl(), response.getStatus(), errors.stream()
- .map(error -> " - %s: %s (%s)".formatted(error.title(), error.detail(), error.code()))
- .collect(Collectors.joining("\n"))));
- } else {
- handleUnexpectedHttpResponse(LOGGER, request.getUrl(), response.getStatus(), response.getStatusText());
+ final String requestUrl = "%s/rest/orgs/%s/packages/%s/issues?version=%s" .formatted(apiBaseUrl, apiOrgId, encodedPurl, apiVersion);
+ try {
+ URIBuilder uriBuilder = new URIBuilder(requestUrl);
+ final HttpUriRequest request = new HttpGet(uriBuilder.build().toString());
+ request.setHeader(HttpHeaders.USER_AGENT, ManagedHttpClientFactory.getUserAgent());
+ request.setHeader(HttpHeaders.AUTHORIZATION, "token " + apiTokenSupplier.get());
+ request.setHeader(HttpHeaders.ACCEPT, "application/vnd.api+json");
+ try (final CloseableHttpResponse response = RETRY.executeCheckedSupplier(() -> HttpClientPool.getClient().execute(request))) {
+ Header header = response.getFirstHeader("Sunset");
+ if (header != null) {
+ apiVersionSunset = StringUtils.trimToNull(header.getValue());
+ } else {
+ apiVersionSunset = null;
+ }
+ if (response.getStatusLine().getStatusCode() >= HttpStatus.SC_OK && response.getStatusLine().getStatusCode() < HttpStatus.SC_MULTIPLE_CHOICES) {
+ String responseString = EntityUtils.toString(response.getEntity());
+ JSONObject responseJson = new JSONObject(responseString);
+ handle(component, responseJson);
+ } else if (response.getEntity() != null) {
+ String responseString = EntityUtils.toString(response.getEntity());
+ JSONObject responseJson = new JSONObject(responseString);
+ final List errors = new SnykParser().parseErrors(responseJson);
+ if (!errors.isEmpty()) {
+ LOGGER.error("Analysis of component %s failed with HTTP status %d: \n%s"
+ .formatted(component.getPurl(), response.getStatusLine().getStatusCode(), errors.stream()
+ .map(error -> " - %s: %s (%s)" .formatted(error.title(), error.detail(), error.code()))
+ .collect(Collectors.joining("\n"))));
+ } else {
+ handleUnexpectedHttpResponse(LOGGER, request.getURI().toString(), response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
+ }
+ } else {
+ handleUnexpectedHttpResponse(LOGGER, request.getURI().toString(), response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
+ }
}
- } else {
- handleUnexpectedHttpResponse(LOGGER, request.getUrl(), response.getStatus(), response.getStatusText());
+ } catch (Throwable ex) {
+ handleRequestException(LOGGER, ex);
}
}
@@ -372,7 +389,7 @@ private Optional getApiBaseUrl() {
private Supplier createTokenSupplier(final String tokenValue) {
final String[] tokens = tokenValue.split(";");
if (tokens.length > 1) {
- LOGGER.debug("Will use %d tokens in round robin".formatted(tokens.length));
+ LOGGER.debug("Will use %d tokens in round robin" .formatted(tokens.length));
final var roundRobinAccessor = new RoundRobinAccessor<>(List.of(tokens));
return roundRobinAccessor::get;
}
diff --git a/src/main/java/org/dependencytrack/tasks/scanners/VulnDbAnalysisTask.java b/src/main/java/org/dependencytrack/tasks/scanners/VulnDbAnalysisTask.java
index 130a1fc2f0..9294eff845 100644
--- a/src/main/java/org/dependencytrack/tasks/scanners/VulnDbAnalysisTask.java
+++ b/src/main/java/org/dependencytrack/tasks/scanners/VulnDbAnalysisTask.java
@@ -23,18 +23,22 @@
import alpine.event.framework.Subscriber;
import alpine.model.ConfigProperty;
import alpine.security.crypto.DataEncryption;
-import org.dependencytrack.common.UnirestFactory;
+import oauth.signpost.exception.OAuthCommunicationException;
+import oauth.signpost.exception.OAuthExpectationFailedException;
+import oauth.signpost.exception.OAuthMessageSignerException;
import org.dependencytrack.event.VulnDbAnalysisEvent;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.ConfigPropertyConstants;
import org.dependencytrack.model.Vulnerability;
import org.dependencytrack.model.VulnerabilityAnalysisLevel;
import org.dependencytrack.parser.vulndb.ModelConverter;
+import org.dependencytrack.parser.vulndb.VulnDbClient;
+import org.dependencytrack.parser.vulndb.model.Results;
import org.dependencytrack.persistence.QueryManager;
import org.dependencytrack.util.NotificationUtil;
-import us.springett.vulndbdatamirror.client.VulnDbApi;
-import us.springett.vulndbdatamirror.parser.model.Results;
+import java.io.IOException;
+import java.net.URISyntaxException;
import java.util.List;
/**
@@ -45,17 +49,27 @@
*/
public class VulnDbAnalysisTask extends BaseComponentAnalyzerTask implements Subscriber {
+
private static final Logger LOGGER = Logger.getLogger(VulnDbAnalysisTask.class);
- private static final String TARGET_HOST = "https://vulndb.cyberriskanalytics.com/";
private static final int PAGE_SIZE = 100;
private VulnerabilityAnalysisLevel vulnerabilityAnalysisLevel;
private String apiConsumerKey;
private String apiConsumerSecret;
+ private String apiBaseUrl;
+
public AnalyzerIdentity getAnalyzerIdentity() {
return AnalyzerIdentity.VULNDB_ANALYZER;
}
+ public VulnDbAnalysisTask(String apiBaseUrl) {
+ this.apiBaseUrl = apiBaseUrl;
+ }
+
+ public VulnDbAnalysisTask() {
+ this("https://vulndb.cyberriskanalytics.com");
+ }
+
/**
* {@inheritDoc}
*/
@@ -73,6 +87,11 @@ public void inform(final Event e) {
ConfigPropertyConstants.SCANNER_VULNDB_OAUTH1_CONSUMER_SECRET.getGroupName(),
ConfigPropertyConstants.SCANNER_VULNDB_OAUTH1_CONSUMER_SECRET.getPropertyName()
);
+ if (this.apiBaseUrl == null) {
+ LOGGER.warn("No API base URL provided; Skipping");
+ return;
+ }
+
if (apiConsumerKey == null || apiConsumerKey.getPropertyValue() == null) {
LOGGER.warn("An OAuth 1.0a consumer key has not been specified for use with VulnDB. Skipping");
return;
@@ -89,10 +108,10 @@ public void inform(final Event e) {
return;
}
}
- final VulnDbAnalysisEvent event = (VulnDbAnalysisEvent)e;
+ final var event = (VulnDbAnalysisEvent) e;
vulnerabilityAnalysisLevel = event.getVulnerabilityAnalysisLevel();
LOGGER.info("Starting VulnDB analysis task");
- if (event.getComponents().size() > 0) {
+ if (!event.getComponents().isEmpty()) {
analyze(event.getComponents());
}
LOGGER.info("VulnDB analysis complete");
@@ -111,26 +130,35 @@ public boolean isCapable(final Component component) {
/**
* Analyzes a list of Components.
+ *
* @param components a list of Components
*/
public void analyze(final List components) {
- final VulnDbApi api = new VulnDbApi(this.apiConsumerKey, this.apiConsumerSecret, UnirestFactory.getUnirestInstance());
- for (final Component component: components) {
- if(isCacheCurrent(Vulnerability.Source.VULNDB, TARGET_HOST, component.getCpe())){
- applyAnalysisFromCache(Vulnerability.Source.VULNDB, TARGET_HOST, component.getCpe(),component, AnalyzerIdentity.VULNDB_ANALYZER, vulnerabilityAnalysisLevel);
- }
- else if (!component.isInternal() && isCapable(component)
- && !isCacheCurrent(Vulnerability.Source.VULNDB, TARGET_HOST, component.getCpe())) {
- int page = 1;
- boolean more = true;
- while (more) {
- final Results results = api.getVulnerabilitiesByCpe(component.getCpe(), PAGE_SIZE, page);
- if (results.isSuccessful()) {
- more = processResults(results, component);
- page++;
- } else {
- LOGGER.error(results.getErrorCondition());
- return;
+ final var api = new VulnDbClient(this.apiConsumerKey, this.apiConsumerSecret, this.apiBaseUrl);
+ for (final Component component : components) {
+ if (isCacheCurrent(Vulnerability.Source.VULNDB, apiBaseUrl, component.getCpe())) {
+ applyAnalysisFromCache(Vulnerability.Source.VULNDB, apiBaseUrl, component.getCpe(), component, AnalyzerIdentity.VULNDB_ANALYZER, vulnerabilityAnalysisLevel);
+ } else if (!component.isInternal() && isCapable(component)
+ && !isCacheCurrent(Vulnerability.Source.VULNDB, apiBaseUrl, component.getCpe())) {
+ if (!component.isInternal() && isCapable(component)
+ && !isCacheCurrent(Vulnerability.Source.VULNDB, apiBaseUrl, component.getCpe())) {
+ int page = 1;
+ boolean more = true;
+ while (more) {
+ try {
+ final Results results = api.getVulnerabilitiesByCpe(component.getCpe(), PAGE_SIZE, page);
+ if (results.isSuccessful()) {
+ more = processResults(results, component);
+ page++;
+ } else {
+ LOGGER.warn(results.getErrorCondition());
+ handleRequestException(LOGGER, new Exception(results.getErrorCondition()));
+ return;
+ }
+ } catch (IOException | OAuthMessageSignerException | OAuthExpectationFailedException |
+ URISyntaxException | OAuthCommunicationException ex) {
+ handleRequestException(LOGGER, ex);
+ }
}
}
}
@@ -141,8 +169,8 @@ else if (!component.isInternal() && isCapable(component)
private boolean processResults(final Results results, final Component component) {
try (final QueryManager qm = new QueryManager()) {
final Component vulnerableComponent = qm.getObjectByUuid(Component.class, component.getUuid()); // Refresh component and attach to current pm.
- for (us.springett.vulndbdatamirror.parser.model.Vulnerability vulnDbVuln : (List) results.getResults()) {
- Vulnerability vulnerability = qm.getVulnerabilityByVulnId(Vulnerability.Source.VULNDB, String.valueOf(vulnDbVuln.getId()));
+ for (org.dependencytrack.parser.vulndb.model.Vulnerability vulnDbVuln : (List) results.getResults()) {
+ Vulnerability vulnerability = qm.getVulnerabilityByVulnId(Vulnerability.Source.VULNDB, String.valueOf(vulnDbVuln.id()));
if (vulnerability == null) {
vulnerability = qm.createVulnerability(ModelConverter.convert(qm, vulnDbVuln), false);
} else {
@@ -152,8 +180,9 @@ private boolean processResults(final Results results, final Component component)
qm.addVulnerability(vulnerability, vulnerableComponent, this.getAnalyzerIdentity());
addVulnerabilityToCache(vulnerableComponent, vulnerability);
}
- updateAnalysisCacheStats(qm, Vulnerability.Source.VULNDB, TARGET_HOST, vulnerableComponent.getCpe(), vulnerableComponent.getCacheResult());
+ updateAnalysisCacheStats(qm, Vulnerability.Source.VULNDB, apiBaseUrl, vulnerableComponent.getCpe(), vulnerableComponent.getCacheResult());
return results.getPage() * PAGE_SIZE < results.getTotal();
}
}
+
}
diff --git a/src/main/java/org/dependencytrack/util/XmlUtil.java b/src/main/java/org/dependencytrack/util/XmlUtil.java
index df10739290..f7aff024f8 100644
--- a/src/main/java/org/dependencytrack/util/XmlUtil.java
+++ b/src/main/java/org/dependencytrack/util/XmlUtil.java
@@ -31,9 +31,11 @@
import java.io.InputStream;
import static org.apache.xerces.jaxp.JAXPConstants.JAXP_SCHEMA_LANGUAGE;
+
import static org.apache.xerces.jaxp.JAXPConstants.JAXP_SCHEMA_SOURCE;
import static org.apache.xerces.jaxp.JAXPConstants.W3C_XML_SCHEMA;
+
public final class XmlUtil {
private XmlUtil() { }
diff --git a/src/test/java/org/dependencytrack/ResourceTest.java b/src/test/java/org/dependencytrack/ResourceTest.java
index f9761c4d54..9d7ce0d1d1 100644
--- a/src/test/java/org/dependencytrack/ResourceTest.java
+++ b/src/test/java/org/dependencytrack/ResourceTest.java
@@ -29,10 +29,7 @@
import org.dependencytrack.persistence.QueryManager;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider;
-import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.JerseyTest;
-import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
-import org.glassfish.jersey.test.spi.TestContainer;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.After;
import org.junit.Before;
diff --git a/src/test/java/org/dependencytrack/auth/PermissionsTest.java b/src/test/java/org/dependencytrack/auth/PermissionsTest.java
index 997174970b..5d7408b6e1 100644
--- a/src/test/java/org/dependencytrack/auth/PermissionsTest.java
+++ b/src/test/java/org/dependencytrack/auth/PermissionsTest.java
@@ -21,8 +21,18 @@
import org.junit.Assert;
import org.junit.Test;
-import static org.dependencytrack.auth.Permissions.Constants.*;
-
+import static org.dependencytrack.auth.Permissions.Constants.PORTFOLIO_MANAGEMENT;
+import static org.dependencytrack.auth.Permissions.Constants.BOM_UPLOAD;
+import static org.dependencytrack.auth.Permissions.Constants.VIEW_PORTFOLIO;
+import static org.dependencytrack.auth.Permissions.Constants.VIEW_VULNERABILITY;
+import static org.dependencytrack.auth.Permissions.Constants.VULNERABILITY_ANALYSIS;
+import static org.dependencytrack.auth.Permissions.Constants.VIEW_POLICY_VIOLATION;
+import static org.dependencytrack.auth.Permissions.Constants.VULNERABILITY_MANAGEMENT;
+import static org.dependencytrack.auth.Permissions.Constants.POLICY_VIOLATION_ANALYSIS;
+import static org.dependencytrack.auth.Permissions.Constants.ACCESS_MANAGEMENT;
+import static org.dependencytrack.auth.Permissions.Constants.SYSTEM_CONFIGURATION;
+import static org.dependencytrack.auth.Permissions.Constants.PROJECT_CREATION_UPLOAD;
+import static org.dependencytrack.auth.Permissions.Constants.POLICY_MANAGEMENT;
public class PermissionsTest {
@Test
diff --git a/src/test/java/org/dependencytrack/integration/ApiClient.java b/src/test/java/org/dependencytrack/integration/ApiClient.java
deleted file mode 100644
index d0d7d35a97..0000000000
--- a/src/test/java/org/dependencytrack/integration/ApiClient.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file is part of Dependency-Track.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright (c) Steve Springett. All Rights Reserved.
- */
-package org.dependencytrack.integration;
-
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.UnirestException;
-import kong.unirest.UnirestInstance;
-import kong.unirest.json.JSONObject;
-import org.apache.commons.io.FileUtils;
-import org.dependencytrack.common.UnirestFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Base64;
-import java.util.UUID;
-
-public class ApiClient {
-
- private String baseUrl;
- private String apiKey;
-
- public ApiClient(String baseUrl, String apiKey) {
- this.baseUrl = baseUrl;
- this.apiKey = apiKey;
- }
-
- public UUID createProject(String name, String version) throws UnirestException {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
- final HttpResponse response = ui.put(baseUrl + "/api/v1/project")
- .header("Content-Type", "application/json")
- .header("X-API-Key", apiKey)
- .body(new JSONObject()
- .put("name", name)
- .put("version", version)
- )
- .asJson();
- if (response.getStatus() == 201) {
- return UUID.fromString(response.getBody().getObject().getString("uuid"));
- }
- System.out.println("Error creating project " + name + " status: " + response.getStatus());
- return null;
- }
-
- public boolean uploadBom(UUID uuid, File bom) throws IOException, UnirestException {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
- final HttpResponse response = ui.put(baseUrl + "/api/v1/bom")
- .header("Content-Type", "application/json")
- .header("X-API-Key", apiKey)
- .body(new JSONObject()
- .put("project", uuid.toString())
- .put("bom", Base64.getEncoder().encodeToString(FileUtils.readFileToByteArray(bom)))
- )
- .asJson();
- return (response.getStatus() == 200);
- }
-
- public boolean uploadScan(UUID uuid, File scan) throws IOException, UnirestException {
- final UnirestInstance ui = UnirestFactory.getUnirestInstance();
- final HttpResponse response = ui.put(baseUrl + "/api/v1/scan")
- .header("Content-Type", "application/json")
- .header("X-API-Key", apiKey)
- .body(new JSONObject()
- .put("project", uuid.toString())
- .put("scan", Base64.getEncoder().encodeToString(FileUtils.readFileToByteArray(scan)))
- )
- .asJson();
- return (response.getStatus() == 200);
- }
-}
diff --git a/src/test/java/org/dependencytrack/integration/PopulateData.java b/src/test/java/org/dependencytrack/integration/PopulateData.java
deleted file mode 100644
index d27b06e418..0000000000
--- a/src/test/java/org/dependencytrack/integration/PopulateData.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * This file is part of Dependency-Track.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright (c) Steve Springett. All Rights Reserved.
- */
-package org.dependencytrack.integration;
-
-import org.junit.Test;
-
-import java.io.File;
-import java.util.UUID;
-
-public class PopulateData {
-
- private static final String BASE_URL = "http://localhost:8080";
- private static final String API_KEY = "hETzpWanQkXV6KsJsfPuFoNBRZdiiDyY";
-
- @Test
- public void doit() throws Exception {
- ApiClient api = new ApiClient(BASE_URL, API_KEY);
- UUID uuid = api.createProject("SonarQube", "5.6");
-
- File file = new File(this.getClass().getResource("/integration/sonarqube-6.5.spdx").getFile());
-
- if (file.exists()) {
- System.out.println("Found It");
- api.uploadBom(uuid, file);
- }
-
- }
-
-
- public static void main(String[] args) throws Exception {
- final PopulateData populateData = new PopulateData();
- populateData.doit();
- }
-}
diff --git a/src/test/java/org/dependencytrack/integrations/defectdojo/DefectDojoClientTest.java b/src/test/java/org/dependencytrack/integrations/defectdojo/DefectDojoClientTest.java
index de604eb990..590854e299 100644
--- a/src/test/java/org/dependencytrack/integrations/defectdojo/DefectDojoClientTest.java
+++ b/src/test/java/org/dependencytrack/integrations/defectdojo/DefectDojoClientTest.java
@@ -18,116 +18,60 @@
*/
package org.dependencytrack.integrations.defectdojo;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import com.github.tomakehurst.wiremock.matching.EqualToPattern;
import org.apache.commons.io.input.NullInputStream;
import org.apache.http.HttpHeaders;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
+import org.apache.http.entity.ContentType;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.contrib.java.lang.system.EnvironmentVariables;
-import org.junit.rules.ExpectedException;
-import org.mockserver.client.MockServerClient;
-import org.mockserver.integration.ClientAndServer;
-import org.mockserver.verify.VerificationTimes;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.net.URL;
-import static org.mockserver.integration.ClientAndServer.startClientAndServer;
-import static org.mockserver.model.HttpRequest.request;
-import static org.mockserver.model.HttpResponse.response;
-
public class DefectDojoClientTest {
- private static ClientAndServer mockServer;
- private static MockServerClient testClient;
-
- @Rule
- public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
-
@Rule
- public ExpectedException thrown = ExpectedException.none();
+ public WireMockRule wireMockRule = new WireMockRule();
- @Before
- public void before() {
- environmentVariables.set("http_proxy", "http://127.0.0.1:1080");
- testClient = new MockServerClient("localhost", 1080);
- }
-
- @After
- public void after() {
- testClient.clear(
- request()
- .withPath("/defectdojo/api/v2/import-scan/")
- );
- testClient.clear(
- request()
- .withPath("/defectdojo/api/v2/reimport-scan/")
- );
- }
-
- @BeforeClass
- public static void beforeClass() {
- mockServer = startClientAndServer(1080);
- }
-
- @AfterClass
- public static void afterClass() {
- mockServer.stop();
- }
@Test
public void testUploadFindingsPositiveCase() throws Exception {
+ WireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/defectdojo/api/v2/import-scan/"))
+ .withMultipartRequestBody(WireMock.aMultipart().withName("engagement").
+ withBody(WireMock.equalTo("12345"))));
+ InputStream stream = new ByteArrayInputStream("test input" .getBytes());
String token = "db975c97-98b1-4988-8d6a-9c3e044dfff3";
String engagementId = "12345";
- testClient.when(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.AUTHORIZATION, "Token " + token)
- .withPath("/defectdojo/api/v2/import-scan/")
- )
- .respond(
- response()
- .withStatusCode(201)
- .withHeader(HttpHeaders.CONTENT_TYPE, "application/json")
- );
DefectDojoUploader uploader = new DefectDojoUploader();
- DefectDojoClient client = new DefectDojoClient(uploader, new URL("https://localhost/defectdojo"));
- client.uploadDependencyTrackFindings(token, engagementId, new NullInputStream(0));
- testClient.verify(
- request()
- .withMethod("POST")
- .withPath("/defectdojo/api/v2/import-scan/"),
- VerificationTimes.exactly(1)
- );
+ DefectDojoClient client = new DefectDojoClient(uploader, new URL(wireMockRule.baseUrl() + "/defectdojo"));
+ client.uploadDependencyTrackFindings(token, engagementId, stream);
+
+ WireMock.verify(WireMock.postRequestedFor(WireMock.urlPathEqualTo("/defectdojo/api/v2/import-scan/"))
+ .withAnyRequestBodyPart(WireMock.aMultipart().withName("engagement").
+ withBody(WireMock.equalTo("12345")
+ )).withAnyRequestBodyPart(WireMock.aMultipart().withName("file")
+ .withBody(WireMock.equalTo("test input")).withHeader("Content-Type", WireMock.equalTo(ContentType.APPLICATION_OCTET_STREAM.getMimeType()))));
}
+
@Test
public void testUploadFindingsNegativeCase() throws Exception {
String token = "db975c97-98b1-4988-8d6a-9c3e044dfff2";
String engagementId = "";
- testClient.when(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.AUTHORIZATION, "Token " + token)
- .withPath("/defectdojo/api/v2/import-scan/")
- )
- .respond(
- response()
- .withStatusCode(400)
- .withHeader(HttpHeaders.CONTENT_TYPE, "application/json")
- );
+ WireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/defectdojo/api/v2/import-scan/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, new EqualToPattern("Token " + token))
+ .withMultipartRequestBody(WireMock.aMultipart().withName("engagement").
+ withBody(WireMock.equalTo(""))).willReturn(WireMock.aResponse().withStatus(400).withHeader(HttpHeaders.CONTENT_TYPE, "application/json")));
DefectDojoUploader uploader = new DefectDojoUploader();
- DefectDojoClient client = new DefectDojoClient(uploader, new URL("https://localhost/defectdojo"));
+ DefectDojoClient client = new DefectDojoClient(uploader, new URL(wireMockRule.baseUrl() + "/defectdojo"));
client.uploadDependencyTrackFindings(token, engagementId, new NullInputStream(16));
- testClient.verify(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.AUTHORIZATION, "Token " + token)
- .withPath("/defectdojo/api/v2/import-scan/"),
- VerificationTimes.exactly(1)
- );
+ WireMock.verify(WireMock.postRequestedFor(WireMock.urlPathEqualTo("/defectdojo/api/v2/import-scan/"))
+ .withAnyRequestBodyPart(WireMock.aMultipart().withName("engagement").
+ withBody(WireMock.equalTo("")
+ )));
}
@Test
@@ -135,26 +79,17 @@ public void testReimportFindingsPositiveCase() throws Exception {
String token = "db975c97-98b1-4988-8d6a-9c3e044dfff3";
String testId = "15";
String engagementId = "67890";
- testClient.when(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.AUTHORIZATION, "Token " + token)
- .withPath("/defectdojo/api/v2/reimport-scan/")
- )
- .respond(
- response()
- .withStatusCode(201)
- .withHeader(HttpHeaders.CONTENT_TYPE, "application/json")
- );
+ WireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/defectdojo/api/v2/reimport-scan/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, new EqualToPattern("Token " + token))
+ .withMultipartRequestBody(WireMock.aMultipart().withName("engagement").
+ withBody(WireMock.equalTo(engagementId))).willReturn(WireMock.aResponse().withStatus(201).withHeader(HttpHeaders.CONTENT_TYPE, "application/json")));
DefectDojoUploader uploader = new DefectDojoUploader();
- DefectDojoClient client = new DefectDojoClient(uploader, new URL("https://localhost/defectdojo"));
+ DefectDojoClient client = new DefectDojoClient(uploader, new URL(wireMockRule.baseUrl() + "/defectdojo"));
client.reimportDependencyTrackFindings(token, engagementId, new NullInputStream(0), testId);
- testClient.verify(
- request()
- .withMethod("POST")
- .withPath("/defectdojo/api/v2/reimport-scan/"),
- VerificationTimes.exactly(1)
- );
+ WireMock.verify(WireMock.postRequestedFor(WireMock.urlPathEqualTo("/defectdojo/api/v2/reimport-scan/"))
+ .withAnyRequestBodyPart(WireMock.aMultipart().withName("engagement").
+ withBody(WireMock.equalTo(engagementId)
+ )));
}
@Test
@@ -162,26 +97,16 @@ public void testReimportFindingsNegativeCase() throws Exception {
String token = "db975c97-98b1-4988-8d6a-9c3e044dfff2";
String testId = "14";
String engagementId = "";
- testClient.when(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.AUTHORIZATION, "Token " + token)
- .withPath("/defectdojo/api/v2/reimport-scan/")
- )
- .respond(
- response()
- .withStatusCode(400)
- .withHeader(HttpHeaders.CONTENT_TYPE, "application/json")
- );
+ WireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/defectdojo/api/v2/reimport-scan/"))
+ .withHeader(HttpHeaders.AUTHORIZATION, new EqualToPattern("Token " + token))
+ .withMultipartRequestBody(WireMock.aMultipart().withName("engagement").
+ withBody(WireMock.equalTo(""))).willReturn(WireMock.aResponse().withStatus(400).withHeader(HttpHeaders.CONTENT_TYPE, "application/json")));
DefectDojoUploader uploader = new DefectDojoUploader();
- DefectDojoClient client = new DefectDojoClient(uploader, new URL("https://localhost/defectdojo"));
+ DefectDojoClient client = new DefectDojoClient(uploader, new URL(wireMockRule.baseUrl() + "/defectdojo"));
client.reimportDependencyTrackFindings(token, engagementId, new NullInputStream(16), testId);
- testClient.verify(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.AUTHORIZATION, "Token " + token)
- .withPath("/defectdojo/api/v2/reimport-scan/"),
- VerificationTimes.exactly(1)
- );
+ WireMock.verify(WireMock.postRequestedFor(WireMock.urlPathEqualTo("/defectdojo/api/v2/reimport-scan/"))
+ .withAnyRequestBodyPart(WireMock.aMultipart().withName("engagement").
+ withBody(WireMock.equalTo(engagementId)
+ )));
}
}
diff --git a/src/test/java/org/dependencytrack/integrations/fortifyssc/FortifySscClientTest.java b/src/test/java/org/dependencytrack/integrations/fortifyssc/FortifySscClientTest.java
index 0e1db80ee2..b67f2d71b9 100644
--- a/src/test/java/org/dependencytrack/integrations/fortifyssc/FortifySscClientTest.java
+++ b/src/test/java/org/dependencytrack/integrations/fortifyssc/FortifySscClientTest.java
@@ -18,90 +18,48 @@
*/
package org.dependencytrack.integrations.fortifyssc;
-import org.apache.commons.io.input.NullInputStream;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import com.github.tomakehurst.wiremock.matching.EqualToPattern;
import org.apache.http.HttpHeaders;
-import org.junit.AfterClass;
+import org.apache.http.entity.ContentType;
import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.contrib.java.lang.system.EnvironmentVariables;
-import org.junit.rules.ExpectedException;
-import org.mockserver.client.MockServerClient;
-import org.mockserver.integration.ClientAndServer;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
-import static org.mockserver.integration.ClientAndServer.startClientAndServer;
-import static org.mockserver.model.HttpRequest.request;
-import static org.mockserver.model.HttpResponse.response;
-
public class FortifySscClientTest {
- private static ClientAndServer mockServer;
-
- @Rule
- public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
-
@Rule
- public ExpectedException thrown = ExpectedException.none();
+ public WireMockRule wireMockRule = new WireMockRule();
- @Before
- public void before() {
- environmentVariables.set("http_proxy", "http://127.0.0.1:1080");
- }
-
- @BeforeClass
- public static void beforeClass() {
- mockServer = startClientAndServer(1080);
- }
-
- @AfterClass
- public static void after() {
- mockServer.stop();
- }
@Test
public void testOneTimeTokenPositiveCase() throws Exception {
- new MockServerClient("localhost", 1080)
- .when(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.AUTHORIZATION, "FortifyToken " + Base64.getEncoder().encodeToString("2d5e4a06-945e-405f-a3c2-112bb3053453".getBytes(StandardCharsets.UTF_8)))
- .withPath("/ssc/api/v1/fileTokens")
- .withBody("{\"fileTokenType\":\"UPLOAD\"}")
- )
- .respond(
- response()
- .withStatusCode(201)
- .withHeader(HttpHeaders.CONTENT_TYPE, "application/json")
- .withBody("{ \"data\": { \"token\": \"db975c97-98b1-4988-8d6a-9c3e044dfff3\" }}")
- );
+ WireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/ssc/api/v1/fileTokens"))
+ .withHeader(HttpHeaders.AUTHORIZATION, new EqualToPattern("FortifyToken " + Base64.getEncoder().encodeToString("2d5e4a06-945e-405f-a3c2-112bb3053453" .getBytes(StandardCharsets.UTF_8))))
+ .withRequestBody(WireMock.equalToJson("{\"fileTokenType\":\"UPLOAD\"}"))
+ .willReturn(WireMock.aResponse().withHeader(HttpHeaders.CONTENT_TYPE, "application/json")
+ .withBody("{ \"data\": { \"token\": \"db975c97-98b1-4988-8d6a-9c3e044dfff3\" }}").withStatus(201)));
FortifySscUploader uploader = new FortifySscUploader();
- FortifySscClient client = new FortifySscClient(uploader, new URL("https://localhost/ssc"));
+ FortifySscClient client = new FortifySscClient(uploader, new URL(wireMockRule.baseUrl() + "/ssc"));
String token = client.generateOneTimeUploadToken("2d5e4a06-945e-405f-a3c2-112bb3053453");
Assert.assertEquals("db975c97-98b1-4988-8d6a-9c3e044dfff3", token);
}
@Test
public void testOneTimeTokenInvalidCredentials() throws Exception {
- new MockServerClient("localhost", 1080)
- .when(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.AUTHORIZATION, "FortifyToken " + Base64.getEncoder().encodeToString("wrong".getBytes(StandardCharsets.UTF_8)))
- .withPath("/ssc/api/v1/fileTokens")
- .withBody("{\"fileTokenType\":\"UPLOAD\"}")
- )
- .respond(
- response()
- .withStatusCode(401)
- );
+ WireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/ssc/api/v1/fileTokens"))
+ .withHeader(HttpHeaders.AUTHORIZATION, new EqualToPattern("FortifyToken " + Base64.getEncoder().encodeToString("wrong" .getBytes(StandardCharsets.UTF_8))))
+ .withRequestBody(WireMock.equalToJson("{\"fileTokenType\":\"UPLOAD\"}"))
+ .willReturn(WireMock.aResponse().withHeader(HttpHeaders.CONTENT_TYPE, "application/json").withStatus(401)));
FortifySscUploader uploader = new FortifySscUploader();
- FortifySscClient client = new FortifySscClient(uploader, new URL("https://localhost/ssc"));
+ FortifySscClient client = new FortifySscClient(uploader, new URL(wireMockRule.baseUrl() + "/ssc"));
String token = client.generateOneTimeUploadToken("wrong");
Assert.assertNull(token);
}
@@ -110,47 +68,47 @@ public void testOneTimeTokenInvalidCredentials() throws Exception {
public void testUploadFindingsPositiveCase() throws Exception {
String token = "db975c97-98b1-4988-8d6a-9c3e044dfff3";
String applicationVersion = "12345";
- new MockServerClient("localhost", 1080)
- .when(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.ACCEPT, "application/xml")
- .withPath("/ssc/upload/resultFileUpload.html?mat=" + token + "&engineType=DEPENDENCY_TRACK&entityId=" + applicationVersion)
- .withQueryStringParameter("engineType", "DEPENDENCY_TRACK")
- .withQueryStringParameter("mat", token)
- .withQueryStringParameter("entityId", applicationVersion)
- )
- .respond(
- response()
- .withStatusCode(200)
- .withHeader(HttpHeaders.CONTENT_TYPE, "application/xml")
- );
+ WireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/ssc/upload/resultFileUpload.html"))
+ .withHeader(HttpHeaders.ACCEPT, new EqualToPattern("application/xml"))
+ .withQueryParam("engineType", new EqualToPattern("DEPENDENCY_TRACK"))
+ .withQueryParam("mat", new EqualToPattern(token))
+ .withQueryParam("entityId", new EqualToPattern(applicationVersion))
+ .willReturn(WireMock.aResponse().withHeader(HttpHeaders.CONTENT_TYPE, "application/xml").withStatus(200)));
FortifySscUploader uploader = new FortifySscUploader();
- FortifySscClient client = new FortifySscClient(uploader, new URL("https://localhost/ssc"));
- client.uploadDependencyTrackFindings(token, applicationVersion, new NullInputStream(0));
+ FortifySscClient client = new FortifySscClient(uploader, new URL(wireMockRule.baseUrl() + "/ssc"));
+ InputStream stream = new ByteArrayInputStream("test input" .getBytes());
+ client.uploadDependencyTrackFindings(token, applicationVersion, stream);
+
+ WireMock.verify(WireMock.postRequestedFor(WireMock.urlPathEqualTo("/ssc/upload/resultFileUpload.html"))
+ .withQueryParam("engineType", new EqualToPattern("DEPENDENCY_TRACK"))
+ .withQueryParam("mat", new EqualToPattern(token))
+ .withQueryParam("entityId", new EqualToPattern(applicationVersion))
+ .withAnyRequestBodyPart(WireMock.aMultipart().withName("files[]")
+ .withBody(WireMock.equalTo("test input")).withHeader("Content-Type", WireMock.equalTo(ContentType.APPLICATION_OCTET_STREAM.getMimeType()))));
}
@Test
public void testUploadFindingsNegativeCase() throws Exception {
String token = "db975c97-98b1-4988-8d6a-9c3e044dfff3";
String applicationVersion = "";
- new MockServerClient("localhost", 1080)
- .when(
- request()
- .withMethod("POST")
- .withHeader(HttpHeaders.ACCEPT, "application/xml")
- .withPath("/ssc/upload/resultFileUpload.html?mat=" + token + "&engineType=DEPENDENCY_TRACK&entityId=" + applicationVersion)
- .withQueryStringParameter("engineType", "DEPENDENCY_TRACK")
- .withQueryStringParameter("mat", token)
- .withQueryStringParameter("entityId", applicationVersion)
- )
- .respond(
- response()
- .withStatusCode(400)
- .withHeader(HttpHeaders.CONTENT_TYPE, "application/xml")
- );
+
+ WireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/ssc/upload/resultFileUpload.html"))
+ .withHeader(HttpHeaders.ACCEPT, new EqualToPattern("application/xml"))
+ .withQueryParam("engineType", new EqualToPattern("DEPENDENCY_TRACK"))
+ .withQueryParam("mat", new EqualToPattern(token))
+ .withQueryParam("entityId", new EqualToPattern(applicationVersion))
+ .willReturn(WireMock.aResponse().withHeader(HttpHeaders.CONTENT_TYPE, "application/xml").withStatus(400)));
FortifySscUploader uploader = new FortifySscUploader();
- FortifySscClient client = new FortifySscClient(uploader, new URL("https://localhost/ssc"));
- client.uploadDependencyTrackFindings(token, applicationVersion, new NullInputStream(16));
+ FortifySscClient client = new FortifySscClient(uploader, new URL(wireMockRule.baseUrl() + "/ssc"));
+ InputStream stream = new ByteArrayInputStream("test input" .getBytes());
+ client.uploadDependencyTrackFindings(token, applicationVersion, stream);
+
+ WireMock.verify(WireMock.postRequestedFor(WireMock.urlPathEqualTo("/ssc/upload/resultFileUpload.html"))
+ .withQueryParam("engineType", new EqualToPattern("DEPENDENCY_TRACK"))
+ .withQueryParam("mat", new EqualToPattern(token))
+ .withQueryParam("entityId", new EqualToPattern(applicationVersion))
+ .withAnyRequestBodyPart(WireMock.aMultipart().withName("files[]")
+ .withBody(WireMock.equalTo("test input")).withHeader("Content-Type", WireMock.equalTo(ContentType.APPLICATION_OCTET_STREAM.getMimeType()))));
+
}
}
diff --git a/src/test/java/org/dependencytrack/parser/osv/OsvAdvisoryParserTest.java b/src/test/java/org/dependencytrack/parser/osv/OsvAdvisoryParserTest.java
index d33dc3fe66..4ba6b8ba4f 100644
--- a/src/test/java/org/dependencytrack/parser/osv/OsvAdvisoryParserTest.java
+++ b/src/test/java/org/dependencytrack/parser/osv/OsvAdvisoryParserTest.java
@@ -1,7 +1,7 @@
package org.dependencytrack.parser.osv;
-import kong.unirest.json.JSONArray;
-import kong.unirest.json.JSONObject;
+import org.json.JSONArray;
+import org.json.JSONObject;
import org.dependencytrack.parser.osv.model.OsvAdvisory;
import org.dependencytrack.parser.osv.model.OsvAffectedPackage;
import org.junit.Assert;
diff --git a/src/test/java/org/dependencytrack/parser/snyk/SnykParserTest.java b/src/test/java/org/dependencytrack/parser/snyk/SnykParserTest.java
index 5d855dc4e9..104dccbcec 100644
--- a/src/test/java/org/dependencytrack/parser/snyk/SnykParserTest.java
+++ b/src/test/java/org/dependencytrack/parser/snyk/SnykParserTest.java
@@ -19,8 +19,8 @@
package org.dependencytrack.parser.snyk;
import alpine.model.IConfigProperty;
-import kong.unirest.json.JSONArray;
-import kong.unirest.json.JSONObject;
+import org.json.JSONArray;
+import org.json.JSONObject;
import org.dependencytrack.PersistenceCapableTest;
import org.dependencytrack.model.VulnerableSoftware;
import org.dependencytrack.parser.snyk.model.SnykError;
diff --git a/src/test/java/org/dependencytrack/persistence/ProjectQueryFilterBuilderTest.java b/src/test/java/org/dependencytrack/persistence/ProjectQueryFilterBuilderTest.java
index b21a161229..0a8180b382 100644
--- a/src/test/java/org/dependencytrack/persistence/ProjectQueryFilterBuilderTest.java
+++ b/src/test/java/org/dependencytrack/persistence/ProjectQueryFilterBuilderTest.java
@@ -4,7 +4,9 @@
import java.util.Map;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
public class ProjectQueryFilterBuilderTest {
diff --git a/src/test/java/org/dependencytrack/policy/CwePolicyEvaluatorTest.java b/src/test/java/org/dependencytrack/policy/CwePolicyEvaluatorTest.java
index 1754bb4670..7c2db0c5f1 100644
--- a/src/test/java/org/dependencytrack/policy/CwePolicyEvaluatorTest.java
+++ b/src/test/java/org/dependencytrack/policy/CwePolicyEvaluatorTest.java
@@ -19,7 +19,11 @@
package org.dependencytrack.policy;
import org.dependencytrack.PersistenceCapableTest;
-import org.dependencytrack.model.*;
+import org.dependencytrack.model.Project;
+import org.dependencytrack.model.Policy;
+import org.dependencytrack.model.Component;
+import org.dependencytrack.model.PolicyCondition;
+import org.dependencytrack.model.Vulnerability;
import org.dependencytrack.tasks.scanners.AnalyzerIdentity;
import org.junit.Assert;
import org.junit.Test;
diff --git a/src/test/java/org/dependencytrack/policy/PolicyEngineTest.java b/src/test/java/org/dependencytrack/policy/PolicyEngineTest.java
index 69935b26b9..d4f4850121 100644
--- a/src/test/java/org/dependencytrack/policy/PolicyEngineTest.java
+++ b/src/test/java/org/dependencytrack/policy/PolicyEngineTest.java
@@ -19,7 +19,16 @@
package org.dependencytrack.policy;
import org.dependencytrack.PersistenceCapableTest;
-import org.dependencytrack.model.*;
+import org.dependencytrack.model.Component;
+import org.dependencytrack.model.License;
+import org.dependencytrack.model.LicenseGroup;
+import org.dependencytrack.model.Policy;
+import org.dependencytrack.model.PolicyCondition;
+import org.dependencytrack.model.PolicyViolation;
+import org.dependencytrack.model.Project;
+import org.dependencytrack.model.Severity;
+import org.dependencytrack.model.Tag;
+import org.dependencytrack.model.Vulnerability;
import org.dependencytrack.tasks.scanners.AnalyzerIdentity;
import org.junit.Assert;
import org.junit.Test;
@@ -28,6 +37,7 @@
import java.util.Collections;
import java.util.List;
import java.util.UUID;
+
public class PolicyEngineTest extends PersistenceCapableTest {
@Test
diff --git a/src/test/java/org/dependencytrack/search/FuzzyVulnerableSoftwareSearchManagerTest.java b/src/test/java/org/dependencytrack/search/FuzzyVulnerableSoftwareSearchManagerTest.java
index ffba4925d2..8c38d900a3 100644
--- a/src/test/java/org/dependencytrack/search/FuzzyVulnerableSoftwareSearchManagerTest.java
+++ b/src/test/java/org/dependencytrack/search/FuzzyVulnerableSoftwareSearchManagerTest.java
@@ -3,10 +3,13 @@
import alpine.Config;
import org.apache.commons.io.FileUtils;
import org.dependencytrack.model.Component;
-import org.dependencytrack.model.Vulnerability;
import org.dependencytrack.model.VulnerableSoftware;
import org.dependencytrack.persistence.QueryManager;
-import org.junit.*;
+import org.junit.Before;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
import us.springett.parsers.cpe.Cpe;
import us.springett.parsers.cpe.CpeParser;
import us.springett.parsers.cpe.exceptions.CpeEncodingException;
@@ -20,9 +23,14 @@
import java.util.UUID;
import java.util.regex.Pattern;
-import static org.mockito.Mockito.*;
-
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class FuzzyVulnerableSoftwareSearchManagerTest {
private static final File INDEX_DIRECTORY;
diff --git a/src/test/java/org/dependencytrack/tasks/OsvDownloadTaskTest.java b/src/test/java/org/dependencytrack/tasks/OsvDownloadTaskTest.java
index a3fcbc8630..e54a4f6269 100644
--- a/src/test/java/org/dependencytrack/tasks/OsvDownloadTaskTest.java
+++ b/src/test/java/org/dependencytrack/tasks/OsvDownloadTaskTest.java
@@ -18,7 +18,7 @@
import alpine.model.ConfigProperty;
import alpine.model.IConfigProperty;
import com.github.packageurl.PackageURL;
-import kong.unirest.json.JSONObject;
+import org.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.dependencytrack.PersistenceCapableTest;
import org.dependencytrack.model.AffectedVersionAttribution;
diff --git a/src/test/java/org/dependencytrack/tasks/repositories/NugetMetaAnalyzerTest.java b/src/test/java/org/dependencytrack/tasks/repositories/NugetMetaAnalyzerTest.java
index 4082d52dbc..df1870781b 100644
--- a/src/test/java/org/dependencytrack/tasks/repositories/NugetMetaAnalyzerTest.java
+++ b/src/test/java/org/dependencytrack/tasks/repositories/NugetMetaAnalyzerTest.java
@@ -79,10 +79,10 @@ public void testAnalyzerWithPrivatePackageRepository() throws Exception {
.withHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.withBody(mockIndexResponse)
);
+ String encodedBasicHeader = "Basic OnBhc3N3b3Jk";
- String encodedBasicHeader = "Basic bnVsbDpwYXNzd29yZA==";
String mockVersionResponse = readResourceFileToString("/unit/tasks/repositories/https---localhost-1080-v3-flat2" +
- "-nunitprivate-index.json");
+ "-nunitprivate-index.json");
new MockServerClient("localhost", mockServer.getPort())
.when(
request()
@@ -112,18 +112,15 @@ public void testAnalyzerWithPrivatePackageRepository() throws Exception {
.withHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.withBody(mockRegistrationResponse)
);
-
Component component = new Component();
component.setPurl(new PackageURL("pkg:nuget/NUnitPrivate@5.0.1"));
NugetMetaAnalyzer analyzer = new NugetMetaAnalyzer();
analyzer.setRepositoryUsernameAndPassword(null, "password");
analyzer.setRepositoryBaseUrl("http://localhost:1080");
MetaModel metaModel = analyzer.analyze(component);
-
Assert.assertEquals("5.0.2", metaModel.getLatestVersion());
Assert.assertNotNull(metaModel.getPublishedTimestamp());
}
-
private String readResourceFileToString(String fileName) throws Exception {
return Files.readString(Paths.get(getClass().getResource(fileName).toURI()));
}
diff --git a/src/test/java/org/dependencytrack/tasks/scanners/SnykAnalysisTaskTest.java b/src/test/java/org/dependencytrack/tasks/scanners/SnykAnalysisTaskTest.java
index ab03102770..781cc53f6e 100644
--- a/src/test/java/org/dependencytrack/tasks/scanners/SnykAnalysisTaskTest.java
+++ b/src/test/java/org/dependencytrack/tasks/scanners/SnykAnalysisTaskTest.java
@@ -262,7 +262,7 @@ public void testAnalyzeWithRateLimiting() {
}
],
"links": {
- "self": "/orgs/fd53e445-dc38-4b25-9c8a-5f68ed79f537/packages/pkg%3Amaven%2Fcom.fasterxml.woodstox%2Fwoodstox-core%405.0.0/issues?version=2022-11-14&limit=1000&offset=0"
+ "self": "/orgs/fd53e445-dc38-4b25-9c8a-5f68ed79f537/packages/pkg%3Amaven%2Fcom.fasterxml.woodstox%2Fwoodstox-core%405.0.0/issues?version=2023-01-04&limit=1000&offset=0"
},
"meta": {
"package": {
@@ -354,7 +354,7 @@ public void testAnalyzeWithNoIssues() {
},
"data": [],
"links": {
- "self": "/orgs/da563045-a462-421a-ae47-53239fe46612/packages/pkg%3Amaven%2Fcom.fasterxml.woodstox%2Fwoodstox-core%406.4.0/issues?version=2022-11-14&limit=1000&offset=0"
+ "self": "/orgs/da563045-a462-421a-ae47-53239fe46612/packages/pkg%3Amaven%2Fcom.fasterxml.woodstox%2Fwoodstox-core%406.4.0/issues?version=2023-01-04&limit=1000&offset=0"
},
"meta": {
"package": {
@@ -563,7 +563,7 @@ public void testAnalyzeWithDeprecatedApiVersion() throws Exception {
},
"data": [],
"links": {
- "self": "/orgs/da563045-a462-421a-ae47-53239fe46612/packages/pkg%3Amaven%2Fcom.fasterxml.woodstox%2Fwoodstox-core%406.4.0/issues?version=2022-11-14&limit=1000&offset=0"
+ "self": "/orgs/da563045-a462-421a-ae47-53239fe46612/packages/pkg%3Amaven%2Fcom.fasterxml.woodstox%2Fwoodstox-core%406.4.0/issues?version=2023-01-04&limit=1000&offset=0"
},
"meta": {
"package": {
diff --git a/src/test/java/org/dependencytrack/tasks/scanners/VulnDBAnalysisTaskTest.java b/src/test/java/org/dependencytrack/tasks/scanners/VulnDBAnalysisTaskTest.java
new file mode 100644
index 0000000000..6ba0985abb
--- /dev/null
+++ b/src/test/java/org/dependencytrack/tasks/scanners/VulnDBAnalysisTaskTest.java
@@ -0,0 +1,338 @@
+/*
+ * This file is part of Dependency-Track.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) Steve Springett. All Rights Reserved.
+ */
+package org.dependencytrack.tasks.scanners;
+
+import alpine.model.IConfigProperty;
+import alpine.notification.Notification;
+import alpine.notification.NotificationService;
+import alpine.notification.Subscriber;
+import alpine.notification.Subscription;
+import alpine.security.crypto.DataEncryption;
+import org.apache.http.HttpHeaders;
+import org.assertj.core.api.SoftAssertions;
+import org.dependencytrack.PersistenceCapableTest;
+import org.dependencytrack.event.VulnDbAnalysisEvent;
+import org.dependencytrack.model.Component;
+import org.dependencytrack.model.ComponentAnalysisCache;
+import org.dependencytrack.model.Project;
+import org.dependencytrack.model.Severity;
+import org.dependencytrack.model.Vulnerability;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockserver.integration.ClientAndServer;
+import org.mockserver.model.Header;
+
+import javax.jdo.Query;
+import javax.json.Json;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.dependencytrack.model.ConfigPropertyConstants.SCANNER_ANALYSIS_CACHE_VALIDITY_PERIOD;
+import static org.dependencytrack.model.ConfigPropertyConstants.SCANNER_VULNDB_ENABLED;
+import static org.dependencytrack.model.ConfigPropertyConstants.SCANNER_VULNDB_OAUTH1_CONSUMER_KEY;
+import static org.dependencytrack.model.ConfigPropertyConstants.SCANNER_VULNDB_OAUTH1_CONSUMER_SECRET;
+import static org.mockserver.model.HttpRequest.request;
+import static org.mockserver.model.HttpResponse.response;
+
+public class VulnDBAnalysisTaskTest extends PersistenceCapableTest {
+
+ private static ClientAndServer mockServer;
+
+ @BeforeClass
+ public static void beforeClass() {
+ NotificationService.getInstance().subscribe(new Subscription(NotificationSubscriber.class));
+ mockServer = ClientAndServer.startClientAndServer(1080);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ qm.createConfigProperty(SCANNER_VULNDB_ENABLED.getGroupName(),
+ SCANNER_VULNDB_ENABLED.getPropertyName(),
+ "true",
+ IConfigProperty.PropertyType.BOOLEAN,
+ "vulndb");
+ qm.createConfigProperty(SCANNER_ANALYSIS_CACHE_VALIDITY_PERIOD.getGroupName(),
+ SCANNER_ANALYSIS_CACHE_VALIDITY_PERIOD.getPropertyName(),
+ "86400",
+ IConfigProperty.PropertyType.STRING,
+ "cache");
+ qm.createConfigProperty(SCANNER_VULNDB_OAUTH1_CONSUMER_KEY.getGroupName(),
+ SCANNER_VULNDB_OAUTH1_CONSUMER_KEY.getPropertyName(),
+ DataEncryption.encryptAsString("secret"),
+ IConfigProperty.PropertyType.STRING,
+ "secret");
+ qm.createConfigProperty(SCANNER_VULNDB_OAUTH1_CONSUMER_SECRET.getGroupName(),
+ SCANNER_VULNDB_OAUTH1_CONSUMER_SECRET.getPropertyName(),
+ DataEncryption.encryptAsString("secret"),
+ IConfigProperty.PropertyType.STRING,
+ "secret");
+ }
+
+ @After
+ public void tearDown() {
+ mockServer.reset();
+ NOTIFICATIONS.clear();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ mockServer.stop();
+ NotificationService.getInstance().unsubscribe(new Subscription(NotificationSubscriber.class));
+ }
+
+ @Test
+ public void testIsCapable() {
+ final var asserts = new SoftAssertions();
+
+ for (final Map.Entry test : Map.of(
+ "cpe:2.3:a:apache:log4j:2.0:-:*:*:*:*:*:*", true,
+ "cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*", true
+ ).entrySet()) {
+ final var component = new Component();
+ component.setCpe(test.getKey());
+ asserts.assertThat(new VulnDbAnalysisTask("http://localhost:1080").isCapable(component)).isEqualTo(test.getValue());
+ }
+
+ asserts.assertAll();
+ }
+
+ @Test
+ public void testAnalyzeWithOneIssue() {
+ mockServer
+ .when(request()
+ .withMethod("GET")
+ .withPath("/api/v1/vulnerabilities/find_by_cpe")
+ .withHeader(new Header("X-User-Agent", "Dependency Track (https://github.com/DependencyTrack/dependency-track)"))
+ .withQueryStringParameter("cpe", "cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*"))
+ .respond(response()
+ .withStatusCode(200)
+ .withHeader(HttpHeaders.CONTENT_TYPE, "application/vnd.api+json")
+ .withBody("""
+ {
+ "current_page": 1,
+ "total_entries": 1,
+ "results": [
+ {
+ "vulndb_id": 1,
+ "title": "test title",
+ "classifications": [
+ {
+ "id": 1,
+ "name": "test vulnerability",
+ "longname": "test vulnerability 1 1",
+ "description": "test test",
+ "mediumtext": "some text"
+ }
+ ],
+ "authors": [
+ {
+ "id": 23,
+ "name": "test author",
+ "company": "test company"
+ }
+ ],
+ "ext_references": [
+ {
+ "type": "external test reference",
+ "value": "external test reference value"
+ }
+ ],
+ "ext_texts": [
+ {
+ "type": "external test texts",
+ "value": "external test texts value"
+ }
+ ],
+ "cvss_metrics": [
+
+ ],
+ "cvss_version_three_metrics": [
+
+ ],
+ "nvd_additional_information": [
+ {
+ "summary": "test summary",
+ "cwe_id": "test1",
+ "cve_id": "test4"
+ }
+ ],
+ "vendors": [
+ {
+ "vendor": {
+ "id": 1,
+ "name": "vendor one test",
+ "short_name": "test",
+ "vendor_url": "http://test.com",
+ "products": [
+ {
+ "id": 45,
+ "name": "test product name",
+ "versions": [
+ {
+ "id": 2,
+ "name": "version 2",
+ "affected": false,
+ "cpe": [
+ {
+ "cpe": "test cpe",
+ "type": "test type"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ """));
+
+ var project = new Project();
+ project.setName("acme-app");
+ project = qm.createProject(project, null, false);
+
+ var component = new Component();
+ component.setProject(project);
+ component.setGroup("com.fasterxml.woodstox");
+ component.setName("woodstox-core");
+ component.setVersion("6.4.0");
+ component.setCpe("cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*");
+ component = qm.createComponent(component, false);
+
+ new VulnDbAnalysisTask("http://localhost:1080").inform(new VulnDbAnalysisEvent(component));
+
+ final List vulnerabilities = qm.getAllVulnerabilities(component);
+
+ assertThat(vulnerabilities).hasSize(1);
+
+ final Query cacheQuery = qm.getPersistenceManager().newQuery(ComponentAnalysisCache.class);
+ final List cacheEntries = cacheQuery.executeList();
+ assertThat(cacheEntries).hasSize(1);
+
+ final ComponentAnalysisCache cacheEntry = cacheEntries.get(0);
+ assertThat(cacheEntry.getTarget()).isEqualTo("cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*");
+ List result = new ArrayList();
+ result.add(1);
+ assertThat(cacheEntry.getResult())
+ .containsEntry("vulnIds", Json.createArrayBuilder(result).build());
+ }
+
+ @Test
+ public void testAnalyzeWithNoIssue() {
+ mockServer
+ .when(request()
+ .withMethod("GET")
+ .withPath("/api/v1/vulnerabilities/find_by_cpe")
+ .withHeader(new Header("X-User-Agent", "Dependency Track (https://github.com/DependencyTrack/dependency-track)"))
+ .withQueryStringParameter("cpe", "cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*"))
+ .respond(response()
+ .withStatusCode(200)
+ .withHeader(HttpHeaders.CONTENT_TYPE, "application/vnd.api+json")
+ .withBody("""
+ {
+ "current_page": 1,
+ "total_entries": 1,
+ "results": []
+ }
+ """));
+
+ var project = new Project();
+ project.setName("acme-app");
+ project = qm.createProject(project, null, false);
+
+ var component = new Component();
+ component.setProject(project);
+ component.setGroup("com.fasterxml.woodstox");
+ component.setName("woodstox-core");
+ component.setVersion("6.4.0");
+ component.setCpe("cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*");
+ component = qm.createComponent(component, false);
+
+ new VulnDbAnalysisTask("http://localhost:1080").inform(new VulnDbAnalysisEvent(component));
+
+ final List vulnerabilities = qm.getAllVulnerabilities(component);
+
+ assertThat(vulnerabilities).hasSize(0);
+
+ final Query cacheQuery = qm.getPersistenceManager().newQuery(ComponentAnalysisCache.class);
+ final List cacheEntries = cacheQuery.executeList();
+ assertThat(cacheEntries).hasSize(1);
+
+ final ComponentAnalysisCache cacheEntry = cacheEntries.get(0);
+ assertThat(cacheEntry.getTarget()).isEqualTo("cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*");
+ assertThat(cacheEntry.getResult())
+ .isNull();
+ }
+
+ @Test
+ public void testAnalyzeWithCurrentCache() {
+ var vuln = new Vulnerability();
+ vuln.setVulnId("VULNDB-001");
+ vuln.setSource(Vulnerability.Source.VULNDB);
+ vuln.setSeverity(Severity.HIGH);
+ vuln = qm.createVulnerability(vuln, false);
+
+ qm.updateComponentAnalysisCache(ComponentAnalysisCache.CacheType.VULNERABILITY, "http://localhost:1080",
+ Vulnerability.Source.VULNDB.name(), "cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*", new Date(),
+ Json.createObjectBuilder()
+ .add("vulnIds", Json.createArrayBuilder().add(vuln.getId()))
+ .build());
+
+ var project = new Project();
+ project.setName("acme-app");
+ project = qm.createProject(project, null, false);
+
+ var component = new Component();
+ component.setProject(project);
+ component.setGroup("com.fasterxml.woodstox");
+ component.setName("woodstox-core");
+ component.setVersion("5.0.0");
+ component.setCpe("cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*");
+ component = qm.createComponent(component, false);
+
+ new VulnDbAnalysisTask("http://localhost:1080").inform(new VulnDbAnalysisEvent(component));
+
+ final List vulnerabilities = qm.getAllVulnerabilities(component);
+ assertThat(vulnerabilities).hasSize(1);
+
+ mockServer.verifyZeroInteractions();
+ }
+
+ private static final ConcurrentLinkedQueue NOTIFICATIONS = new ConcurrentLinkedQueue<>();
+
+ public static class NotificationSubscriber implements Subscriber {
+
+ @Override
+ public void inform(final Notification notification) {
+ NOTIFICATIONS.add(notification);
+ }
+
+ }
+
+}
\ No newline at end of file