updated code to better handle TLS errors

This commit is contained in:
Jeremy Long
2017-05-21 18:04:26 -04:00
parent d457fd1452
commit 122c78648a
4 changed files with 108 additions and 76 deletions

View File

@@ -50,10 +50,11 @@ import javax.json.JsonReader;
import javax.json.JsonString; import javax.json.JsonString;
import javax.json.JsonValue; import javax.json.JsonValue;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.URLConnectionFailureException;
/** /**
* Used to analyze Node Package Manager (npm) package.json files via * Used to analyze Node Package Manager (npm) package.json files via Node
* Node Security Platform (nsp). * Security Platform (nsp).
* *
* @author Steve Springett * @author Steve Springett
*/ */
@@ -161,7 +162,7 @@ public class NspAnalyzer extends AbstractFileTypeAnalyzer {
// Submits the package payload to the nsp check service // Submits the package payload to the nsp check service
final List<Advisory> advisories = searcher.submitPackage(nspPayload); final List<Advisory> advisories = searcher.submitPackage(nspPayload);
for (Advisory advisory: advisories) { for (Advisory advisory : advisories) {
/* /*
* Create a new vulnerability out of the advisory returned by nsp. * Create a new vulnerability out of the advisory returned by nsp.
*/ */
@@ -247,23 +248,27 @@ public class NspAnalyzer extends AbstractFileTypeAnalyzer {
addToEvidence(packageJson, vendorEvidence, "author"); addToEvidence(packageJson, vendorEvidence, "author");
addToEvidence(packageJson, dependency.getVersionEvidence(), "version"); addToEvidence(packageJson, dependency.getVersionEvidence(), "version");
dependency.setDisplayFileName(String.format("%s/%s", file.getParentFile().getName(), file.getName())); dependency.setDisplayFileName(String.format("%s/%s", file.getParentFile().getName(), file.getName()));
} catch (URLConnectionFailureException e) {
this.setEnabled(false);
throw new AnalysisException(e.getMessage(), e);
} catch (IOException e) { } catch (IOException e) {
LOGGER.debug("Error reading dependency or connecting to Node Security Platform /check API", e); LOGGER.debug("Error reading dependency or connecting to Node Security Platform - check API", e);
this.setEnabled(false);
throw new AnalysisException(e.getMessage(), e);
} catch (JsonException e) { } catch (JsonException e) {
LOGGER.warn("Failed to parse package.json file.", e); throw new AnalysisException(String.format("Failed to parse %s file.", file.getPath()), e);
} }
} }
/** /**
* Processes a part of package.json (as defined by JsobObject) and * Processes a part of package.json (as defined by JsobObject) and update
* update the specified dependency with relevant info. * the specified dependency with relevant info.
* *
* @param dependency the Dependency to update * @param dependency the Dependency to update
* @param jsonObject the jsonObject to parse * @param jsonObject the jsonObject to parse
*/ */
private void processPackage(Dependency dependency, JsonObject jsonObject, String depType) { private void processPackage(Dependency dependency, JsonObject jsonObject, String depType) {
for (int i=0; i<jsonObject.size(); i++) { for (int i = 0; i < jsonObject.size(); i++) {
for (Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) { for (Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
/* /*
* Create identifies that include the npm module and version. Since these are defined, * Create identifies that include the npm module and version. Since these are defined,
@@ -273,7 +278,7 @@ public class NspAnalyzer extends AbstractFileTypeAnalyzer {
moduleName.setConfidence(Confidence.HIGHEST); moduleName.setConfidence(Confidence.HIGHEST);
String version = ""; String version = "";
if (entry.getValue() != null && entry.getValue().getValueType() == JsonValue.ValueType.STRING) { if (entry.getValue() != null && entry.getValue().getValueType() == JsonValue.ValueType.STRING) {
version = ((JsonString)entry.getValue()).getString(); version = ((JsonString) entry.getValue()).getString();
} }
final Identifier moduleVersion = new Identifier("npm", "Version", null, version); final Identifier moduleVersion = new Identifier("npm", "Version", null, version);
moduleVersion.setConfidence(Confidence.HIGHEST); moduleVersion.setConfidence(Confidence.HIGHEST);

View File

@@ -35,6 +35,7 @@ import javax.json.Json;
import javax.json.JsonArray; import javax.json.JsonArray;
import javax.json.JsonObject; import javax.json.JsonObject;
import javax.json.JsonReader; import javax.json.JsonReader;
import org.owasp.dependencycheck.utils.URLConnectionFailureException;
/** /**
* Class of methods to search via Node Security Platform. * Class of methods to search via Node Security Platform.
@@ -75,70 +76,80 @@ public class NspSearch {
} }
/** /**
* Submits the package.json file to the NSP public /check API and returns * Submits the package.json file to the NSP public /check API and returns a
* a list of zero or more Advisories. * list of zero or more Advisories.
* *
* @param packageJson the package.json file retrieved from the Dependency * @param packageJson the package.json file retrieved from the Dependency
* @return a List of zero or more Advisory object * @return a List of zero or more Advisory object
* @throws IOException if it's unable to connect to Node Security Platform * @throws IOException if it's unable to connect to Node Security Platform
*/ */
public List<Advisory> submitPackage(JsonObject packageJson) throws IOException { public List<Advisory> submitPackage(JsonObject packageJson) throws IOException {
List<Advisory> result = new ArrayList<>(); try {
byte[] packageDatabytes = packageJson.toString().getBytes(StandardCharsets.UTF_8); List<Advisory> result = new ArrayList<>();
byte[] packageDatabytes = packageJson.toString().getBytes(StandardCharsets.UTF_8);
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(nspCheckUrl, useProxy); final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(nspCheckUrl, useProxy);
conn.setDoOutput(true); conn.setDoOutput(true);
conn.setDoInput(true); conn.setDoInput(true);
conn.setRequestMethod("POST"); conn.setRequestMethod("POST");
conn.setRequestProperty("X-NSP-VERSION", "2.6.2"); conn.setRequestProperty("X-NSP-VERSION", "2.6.2");
conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Content-Length", Integer.toString(packageDatabytes.length)); conn.setRequestProperty("Content-Length", Integer.toString(packageDatabytes.length));
conn.connect(); conn.connect();
try (OutputStream os = new BufferedOutputStream(conn.getOutputStream())) { try (OutputStream os = new BufferedOutputStream(conn.getOutputStream())) {
os.write(packageDatabytes); os.write(packageDatabytes);
os.flush(); os.flush();
} }
if (conn.getResponseCode() == 200) { if (conn.getResponseCode() == 200) {
try (InputStream in = new BufferedInputStream(conn.getInputStream())) { try (InputStream in = new BufferedInputStream(conn.getInputStream())) {
JsonReader jsonReader = Json.createReader(in); JsonReader jsonReader = Json.createReader(in);
JsonArray array = jsonReader.readArray(); JsonArray array = jsonReader.readArray();
if (array != null) { if (array != null) {
for (int i=0; i<array.size(); i++) { for (int i = 0; i < array.size(); i++) {
JsonObject object = array.getJsonObject(i); JsonObject object = array.getJsonObject(i);
Advisory advisory = new Advisory(); Advisory advisory = new Advisory();
advisory.setId(object.getInt("id")); advisory.setId(object.getInt("id"));
advisory.setUpdatedAt(object.getString("updated_at", null)); advisory.setUpdatedAt(object.getString("updated_at", null));
advisory.setCreatedAt(object.getString("created_at", null)); advisory.setCreatedAt(object.getString("created_at", null));
advisory.setPublishDate(object.getString("publish_date", null)); advisory.setPublishDate(object.getString("publish_date", null));
advisory.setOverview(object.getString("overview")); advisory.setOverview(object.getString("overview"));
advisory.setRecommendation(object.getString("recommendation", null)); advisory.setRecommendation(object.getString("recommendation", null));
advisory.setCvssVector(object.getString("cvss_vector", null)); advisory.setCvssVector(object.getString("cvss_vector", null));
advisory.setCvssScore(Float.parseFloat(object.getJsonNumber("cvss_score").toString())); advisory.setCvssScore(Float.parseFloat(object.getJsonNumber("cvss_score").toString()));
advisory.setModule(object.getString("module", null)); advisory.setModule(object.getString("module", null));
advisory.setVersion(object.getString("version", null)); advisory.setVersion(object.getString("version", null));
advisory.setVulnerableVersions(object.getString("vulnerable_versions", null)); advisory.setVulnerableVersions(object.getString("vulnerable_versions", null));
advisory.setPatchedVersions(object.getString("patched_versions", null)); advisory.setPatchedVersions(object.getString("patched_versions", null));
advisory.setTitle(object.getString("title", null)); advisory.setTitle(object.getString("title", null));
advisory.setAdvisory(object.getString("advisory", null)); advisory.setAdvisory(object.getString("advisory", null));
JsonArray jsonPath = object.getJsonArray("path"); JsonArray jsonPath = object.getJsonArray("path");
List<String> stringPath = new ArrayList<>(); List<String> stringPath = new ArrayList<>();
for (int j=0; j<jsonPath.size(); j++) { for (int j = 0; j < jsonPath.size(); j++) {
stringPath.add(jsonPath.getString(j)); stringPath.add(jsonPath.getString(j));
}
advisory.setPath(stringPath.toArray(new String[stringPath.size()]));
result.add(advisory);
} }
advisory.setPath(stringPath.toArray(new String[stringPath.size()]));
result.add(advisory);
} }
} }
} else {
LOGGER.debug("Could not connect to Node Security Platform. Received response code: {} {}",
conn.getResponseCode(), conn.getResponseMessage());
throw new IOException("Could not connect to Node Security Platform");
} }
} else { return result;
LOGGER.debug("Could not connect to Node Security Platform. Received response code: {} {}", } catch (IOException ex) {
conn.getResponseCode(), conn.getResponseMessage()); if (ex instanceof javax.net.ssl.SSLHandshakeException
throw new IOException("Could not connect to Node Security Platform"); && ex.getMessage().contains("unable to find valid certification path to requested target")) {
final String msg = String.format("Unable to connect to '%s' - the Java trust store does not contain a trusted root for the cert. "
+ " Please see https://github.com/jeremylong/InstallCert for one method of updating the trusted certificates.", nspCheckUrl);
throw new URLConnectionFailureException(msg, ex);
}
throw ex;
} }
return result;
} }
} }

View File

@@ -18,6 +18,8 @@
package org.owasp.dependencycheck; package org.owasp.dependencycheck;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.junit.Test; import org.junit.Test;
@@ -58,18 +60,23 @@ public class EngineIT extends BaseDBTestCase {
try { try {
instance.analyzeDependencies(); instance.analyzeDependencies();
} catch (ExceptionCollection ex) { } catch (ExceptionCollection ex) {
if (ex.getExceptions().size() == 1 Set<String> allowedMessages = new HashSet<>();
&& (ex.getExceptions().get(0).getMessage().contains("bundle-audit") allowedMessages.add("bundle-audit");
|| ex.getExceptions().get(0).getMessage().contains("AssemblyAnalyzer"))) { allowedMessages.add("AssemblyAnalyzer");
//this is fine to ignore //allowedMessages.add("Unable to connect to");
} else if (ex.getExceptions().size() == 2 for (Throwable t : ex.getExceptions()) {
&& ((ex.getExceptions().get(0).getMessage().contains("bundle-audit") boolean isOk = false;
&& ex.getExceptions().get(1).getMessage().contains("AssemblyAnalyzer")) if (t.getMessage()!=null) {
|| (ex.getExceptions().get(1).getMessage().contains("bundle-audit") for (String msg : allowedMessages) {
&& ex.getExceptions().get(0).getMessage().contains("AssemblyAnalyzer")))) { if (t.getMessage().contains(msg)) {
//this is fine to ignore isOk=true;
} else { break;
throw ex; }
}
}
if (!isOk) {
throw ex;
}
} }
} }
DatabaseProperties prop = null; DatabaseProperties prop = null;

View File

@@ -32,6 +32,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import org.owasp.dependencycheck.utils.URLConnectionFailureException;
public class NspSearchTest extends BaseTest { public class NspSearchTest extends BaseTest {
@@ -45,8 +48,7 @@ public class NspSearchTest extends BaseTest {
searcher = new NspSearch(new URL(url)); searcher = new NspSearch(new URL(url));
} }
//@Test @Test
//todo: this test does not work in Java 7 - UNABLE TO FIND VALID CERTIFICATION PATH TO REQUESTED TARGET
public void testNspSearchPositive() throws Exception { public void testNspSearchPositive() throws Exception {
InputStream in = BaseTest.getResourceAsStream(this, "nsp/package.json"); InputStream in = BaseTest.getResourceAsStream(this, "nsp/package.json");
try (JsonReader jsonReader = Json.createReader(in)) { try (JsonReader jsonReader = Json.createReader(in)) {
@@ -56,17 +58,24 @@ public class NspSearchTest extends BaseTest {
final JsonObject nspPayload = builder.add("package", sanitizedJson).build(); final JsonObject nspPayload = builder.add("package", sanitizedJson).build();
final List<Advisory> advisories = searcher.submitPackage(nspPayload); final List<Advisory> advisories = searcher.submitPackage(nspPayload);
Assert.assertTrue(advisories.size() > 0); Assert.assertTrue(advisories.size() > 0);
} catch (Exception ex) {
assumeFalse(ex instanceof URLConnectionFailureException
&& ex.getMessage().contains("Unable to connect to "));
throw ex;
} }
} }
//@Test(expected = IOException.class) @Test
//todo: this test does not work in Java 7 - UNABLE TO FIND VALID CERTIFICATION PATH TO REQUESTED TARGET
public void testNspSearchNegative() throws Exception { public void testNspSearchNegative() throws Exception {
InputStream in = BaseTest.getResourceAsStream(this, "nsp/package.json"); InputStream in = BaseTest.getResourceAsStream(this, "nsp/package.json");
try (JsonReader jsonReader = Json.createReader(in)) { try (JsonReader jsonReader = Json.createReader(in)) {
final JsonObject packageJson = jsonReader.readObject(); final JsonObject packageJson = jsonReader.readObject();
final JsonObject sanitizedJson = SanitizePackage.sanitize(packageJson); final JsonObject sanitizedJson = SanitizePackage.sanitize(packageJson);
searcher.submitPackage(sanitizedJson); searcher.submitPackage(sanitizedJson);
} catch (Exception ex) {
assumeFalse(ex instanceof URLConnectionFailureException
&& ex.getMessage().contains("Unable to connect to "));
throw ex;
} }
} }