mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-17 23:04:07 +01:00
Fixes issue 75
Changed getConnection to public and made one which makes using the proxy optional, even if configured Added a preflight request and proxy logic Former-commit-id: 19fdfcf4edacacfa3724c8969c7da74a593f9a7c
This commit is contained in:
@@ -93,6 +93,10 @@ public class NexusAnalyzer extends AbstractAnalyzer {
|
|||||||
LOGGER.fine(String.format("Nexus Analyzer URL: %s", searchUrl));
|
LOGGER.fine(String.format("Nexus Analyzer URL: %s", searchUrl));
|
||||||
try {
|
try {
|
||||||
searcher = new NexusSearch(new URL(searchUrl));
|
searcher = new NexusSearch(new URL(searchUrl));
|
||||||
|
if (! searcher.preflightRequest()) {
|
||||||
|
LOGGER.warning("There was an issue getting Nexus status. Disabling analyzer.");
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
} catch (MalformedURLException mue) {
|
} catch (MalformedURLException mue) {
|
||||||
// I know that initialize can throw an exception, but we'll
|
// I know that initialize can throw an exception, but we'll
|
||||||
// just disable the analyzer if the URL isn't valid
|
// just disable the analyzer if the URL isn't valid
|
||||||
|
|||||||
@@ -19,13 +19,19 @@ package org.owasp.dependencycheck.data.nexus;
|
|||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,40 +46,71 @@ public class NexusSearch {
|
|||||||
*/
|
*/
|
||||||
private final URL rootURL;
|
private final URL rootURL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to use the Proxy when making requests
|
||||||
|
*/
|
||||||
|
private boolean useProxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for logging.
|
* Used for logging.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(NexusSearch.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(NexusSearch.class
|
||||||
|
.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a NexusSearch for the given repository URL.
|
* Creates a NexusSearch for the given repository URL.
|
||||||
*
|
*
|
||||||
* @param rootURL the root URL of the repository on which searches should execute. full URL's are calculated
|
* @param rootURL
|
||||||
* relative to this URL, so it should end with a /
|
* the root URL of the repository on which searches should
|
||||||
|
* execute. full URL's are calculated relative to this URL, so it
|
||||||
|
* should end with a /
|
||||||
*/
|
*/
|
||||||
public NexusSearch(URL rootURL) {
|
public NexusSearch(URL rootURL) {
|
||||||
this.rootURL = rootURL;
|
this.rootURL = rootURL;
|
||||||
|
try {
|
||||||
|
if (null != Settings.getString(Settings.KEYS.PROXY_URL)
|
||||||
|
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
||||||
|
useProxy = true;
|
||||||
|
LOGGER.fine("Using proxy");
|
||||||
|
} else {
|
||||||
|
useProxy = false;
|
||||||
|
LOGGER.fine("Not using proxy");
|
||||||
|
}
|
||||||
|
} catch (InvalidSettingException ise) {
|
||||||
|
useProxy = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches the configured Nexus repository for the given sha1 hash. If the artifact is found, a
|
* Searches the configured Nexus repository for the given sha1 hash. If the
|
||||||
* <code>MavenArtifact</code> is populated with the coordinate information.
|
* artifact is found, a <code>MavenArtifact</code> is populated with the
|
||||||
|
* coordinate information.
|
||||||
*
|
*
|
||||||
* @param sha1 The SHA-1 hash string for which to search
|
* @param sha1
|
||||||
|
* The SHA-1 hash string for which to search
|
||||||
* @return the populated Maven coordinates
|
* @return the populated Maven coordinates
|
||||||
* @throws IOException if it's unable to connect to the specified repositor or if the specified artifact is not
|
* @throws IOException
|
||||||
* found.
|
* if it's unable to connect to the specified repositor or if
|
||||||
|
* the specified artifact is not found.
|
||||||
*/
|
*/
|
||||||
public MavenArtifact searchSha1(String sha1) throws IOException {
|
public MavenArtifact searchSha1(String sha1) throws IOException {
|
||||||
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
||||||
throw new IllegalArgumentException("Invalid SHA1 format");
|
throw new IllegalArgumentException("Invalid SHA1 format");
|
||||||
}
|
}
|
||||||
|
|
||||||
final URL url = new URL(rootURL, String.format("identify/sha1/%s", sha1.toLowerCase()));
|
final URL url = new URL(rootURL, String.format("identify/sha1/%s",
|
||||||
|
sha1.toLowerCase()));
|
||||||
|
|
||||||
LOGGER.fine(String.format("Searching Nexus url %s", url.toString()));
|
LOGGER.fine(String.format("Searching Nexus url %s", url.toString()));
|
||||||
|
|
||||||
final URLConnection conn = url.openConnection();
|
// Determine if we need to use a proxy. The rules:
|
||||||
|
// 1) If the proxy is set, AND the setting is set to true, use the proxy
|
||||||
|
// 2) Otherwise, don't use the proxy (either the proxy isn't configured,
|
||||||
|
// or proxy is specifically
|
||||||
|
// set to false
|
||||||
|
URLConnection conn = null;
|
||||||
|
conn = Downloader.getConnection(url, useProxy);
|
||||||
|
|
||||||
conn.setDoOutput(true);
|
conn.setDoOutput(true);
|
||||||
|
|
||||||
// JSON would be more elegant, but there's not currently a dependency
|
// JSON would be more elegant, but there's not currently a dependency
|
||||||
@@ -82,23 +119,65 @@ public class NexusSearch {
|
|||||||
conn.connect();
|
conn.connect();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
final DocumentBuilder builder = DocumentBuilderFactory
|
||||||
|
.newInstance().newDocumentBuilder();
|
||||||
final Document doc = builder.parse(conn.getInputStream());
|
final Document doc = builder.parse(conn.getInputStream());
|
||||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
final String groupId = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/groupId", doc);
|
final String groupId = xpath
|
||||||
final String artifactId = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/artifactId", doc);
|
.evaluate(
|
||||||
final String version = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/version", doc);
|
"/org.sonatype.nexus.rest.model.NexusArtifact/groupId",
|
||||||
final String link = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink", doc);
|
doc);
|
||||||
|
final String artifactId = xpath.evaluate(
|
||||||
|
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactId",
|
||||||
|
doc);
|
||||||
|
final String version = xpath
|
||||||
|
.evaluate(
|
||||||
|
"/org.sonatype.nexus.rest.model.NexusArtifact/version",
|
||||||
|
doc);
|
||||||
|
final String link = xpath
|
||||||
|
.evaluate(
|
||||||
|
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink",
|
||||||
|
doc);
|
||||||
return new MavenArtifact(groupId, artifactId, version, link);
|
return new MavenArtifact(groupId, artifactId, version, link);
|
||||||
} catch (FileNotFoundException fnfe) {
|
} catch (FileNotFoundException fnfe) {
|
||||||
// This is what we get when the SHA1 they sent doesn't exist in Nexus. This
|
// This is what we get when the SHA1 they sent doesn't exist in
|
||||||
|
// Nexus. This
|
||||||
// is useful upstream for recovery, so we just re-throw it
|
// is useful upstream for recovery, so we just re-throw it
|
||||||
throw fnfe;
|
throw fnfe;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Anything else is jacked-up XML stuff that we really can't recover from well
|
// Anything else is jacked-up XML stuff that we really can't recover
|
||||||
|
// from well
|
||||||
throw new IOException(e.getMessage(), e);
|
throw new IOException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do a preflight request to see if the repository is actually working.
|
||||||
|
*
|
||||||
|
* @return whether the repository is listening and returns the /status URL
|
||||||
|
* correctly
|
||||||
|
*/
|
||||||
|
public boolean preflightRequest() {
|
||||||
|
try {
|
||||||
|
HttpURLConnection conn = Downloader.getConnection(new URL(rootURL, "status"));
|
||||||
|
conn.addRequestProperty("Accept", "application/xml");
|
||||||
|
conn.connect();
|
||||||
|
if (conn.getResponseCode() != 200) {
|
||||||
|
LOGGER.warning("Expected 200 result from Nexus, got " + conn.getResponseCode());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
|
final Document doc = builder.parse(conn.getInputStream());
|
||||||
|
if (doc.getDocumentElement().getNodeName() != "status") {
|
||||||
|
LOGGER.warning("Expected root node name of status, got " + doc.getDocumentElement().getNodeName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: cc=120:sw=4:ts=4:sts=4
|
// vim: cc=120:sw=4:ts=4:sts=4
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ public final class Downloader {
|
|||||||
* @return an HttpURLConnection
|
* @return an HttpURLConnection
|
||||||
* @throws DownloadFailedException thrown if there is an exception
|
* @throws DownloadFailedException thrown if there is an exception
|
||||||
*/
|
*/
|
||||||
private static HttpURLConnection getConnection(URL url) throws DownloadFailedException {
|
public static HttpURLConnection getConnection(URL url) throws DownloadFailedException {
|
||||||
HttpURLConnection conn = null;
|
HttpURLConnection conn = null;
|
||||||
Proxy proxy = null;
|
Proxy proxy = null;
|
||||||
final String proxyUrl = Settings.getString(Settings.KEYS.PROXY_URL);
|
final String proxyUrl = Settings.getString(Settings.KEYS.PROXY_URL);
|
||||||
@@ -219,4 +219,28 @@ public final class Downloader {
|
|||||||
}
|
}
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to get an HttpURLConnection. The use of a proxy here is optional as there
|
||||||
|
* may be cases where a proxy is configured but we don't want to use it (for example, if there's
|
||||||
|
* an internal repository configured)
|
||||||
|
*
|
||||||
|
* @param url the url to connect to
|
||||||
|
* @parem proxy whether to use the proxy (if configured)
|
||||||
|
* @throws DownloadFailedException thrown if there is an exception
|
||||||
|
*/
|
||||||
|
public static HttpURLConnection getConnection(URL url, boolean proxy) throws DownloadFailedException {
|
||||||
|
if (proxy) {
|
||||||
|
return getConnection(url);
|
||||||
|
}
|
||||||
|
HttpURLConnection conn = null;
|
||||||
|
try {
|
||||||
|
conn = (HttpURLConnection)url.openConnection();
|
||||||
|
final int timeout = Settings.getInt(Settings.KEYS.CONNECTION_TIMEOUT, 60000);
|
||||||
|
conn.setConnectTimeout(timeout);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new DownloadFailedException("Error getting connection.", ioe);
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,10 @@ public final class Settings {
|
|||||||
* The properties key for the Nexus search URL.
|
* The properties key for the Nexus search URL.
|
||||||
*/
|
*/
|
||||||
public static final String ANALYZER_NEXUS_URL = "analyzer.nexus.url";
|
public static final String ANALYZER_NEXUS_URL = "analyzer.nexus.url";
|
||||||
|
/**
|
||||||
|
* The properties key for using the proxy to reach Nexus
|
||||||
|
*/
|
||||||
|
public static final String ANALYZER_NEXUS_PROXY = "analyzer.nexus.proxy";
|
||||||
/**
|
/**
|
||||||
* The path to mono, if available.
|
* The path to mono, if available.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -45,4 +45,6 @@ cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
|||||||
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
||||||
analyzer.nexus.enabled=true
|
analyzer.nexus.enabled=true
|
||||||
analyzer.nexus.url=http://repository.sonatype.org/service/local/
|
analyzer.nexus.url=http://repository.sonatype.org/service/local/
|
||||||
|
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||||
|
# are configured
|
||||||
|
analyzer.nexus.proxy=true
|
||||||
|
|||||||
@@ -17,13 +17,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.nexus;
|
package org.owasp.dependencycheck.data.nexus;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import org.junit.Assume;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
@@ -37,6 +39,7 @@ public class NexusSearchTest {
|
|||||||
String nexusUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
String nexusUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
||||||
LOGGER.fine(nexusUrl);
|
LOGGER.fine(nexusUrl);
|
||||||
searcher = new NexusSearch(new URL(nexusUrl));
|
searcher = new NexusSearch(new URL(nexusUrl));
|
||||||
|
Assume.assumeTrue(searcher.preflightRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
@@ -52,7 +55,6 @@ public class NexusSearchTest {
|
|||||||
// This test does generate network traffic and communicates with a host
|
// This test does generate network traffic and communicates with a host
|
||||||
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
||||||
// test it anyway
|
// test it anyway
|
||||||
@Ignore
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidSha1() throws Exception {
|
public void testValidSha1() throws Exception {
|
||||||
MavenArtifact ma = searcher.searchSha1("9977a8d04e75609cf01badc4eb6a9c7198c4c5ea");
|
MavenArtifact ma = searcher.searchSha1("9977a8d04e75609cf01badc4eb6a9c7198c4c5ea");
|
||||||
@@ -65,7 +67,6 @@ public class NexusSearchTest {
|
|||||||
// This test does generate network traffic and communicates with a host
|
// This test does generate network traffic and communicates with a host
|
||||||
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
||||||
// test it anyway
|
// test it anyway
|
||||||
@Ignore
|
|
||||||
@Test(expected = FileNotFoundException.class)
|
@Test(expected = FileNotFoundException.class)
|
||||||
public void testMissingSha1() throws Exception {
|
public void testMissingSha1() throws Exception {
|
||||||
searcher.searchSha1("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
|
searcher.searchSha1("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
|
||||||
|
|||||||
@@ -50,3 +50,6 @@ cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
|||||||
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
||||||
analyzer.nexus.enabled=true
|
analyzer.nexus.enabled=true
|
||||||
analyzer.nexus.url=http://repository.sonatype.org/service/local/
|
analyzer.nexus.url=http://repository.sonatype.org/service/local/
|
||||||
|
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||||
|
# are configured
|
||||||
|
analyzer.nexus.proxy=true
|
||||||
|
|||||||
Reference in New Issue
Block a user