diff --git a/.github/issue_template.md b/.github/issue_template.md
new file mode 100644
index 000000000..f2a77a5bc
--- /dev/null
+++ b/.github/issue_template.md
@@ -0,0 +1,18 @@
+### Reporting Bugs/Errors
+When reporting errors, 99% of the time log file output is required. Please post the log file as a [gist](https://gist.github.com/) and provide a link in the new issue.
+
+### Reporting False Positives
+When reporting a false positive please include:
+- The location of the dependency (Maven GAV, URL to download the dependency, etc.)
+- The CPE that is believed to be false positive
+ - Please report the CPE not the CVE
+
+#### Example
+False positive on library foo.jar - reported as cpe:/a:apache:tomcat:7.0
+```xml
+
+ org.sample
+ foo
+ 1.0
+
+```
\ No newline at end of file
diff --git a/dependency-check-ant/pom.xml b/dependency-check-ant/pom.xml
index 99ec93329..9c6685dd1 100644
--- a/dependency-check-ant/pom.xml
+++ b/dependency-check-ant/pom.xml
@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
org.owasp
dependency-check-parent
- 1.4.1-SNAPSHOT
+ 1.4.3-SNAPSHOT
dependency-check-ant
diff --git a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java
index 78f6e823a..6c38786d4 100644
--- a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java
+++ b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java
@@ -18,7 +18,6 @@
package org.owasp.dependencycheck.taskdefs;
import java.io.File;
-import java.io.IOException;
import java.util.List;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
@@ -32,9 +31,12 @@ import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
+import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
import org.owasp.dependencycheck.utils.Settings;
@@ -806,52 +808,67 @@ public class Check extends Update {
engine = new Engine(Check.class.getClassLoader());
if (isUpdateOnly()) {
log("Deprecated 'UpdateOnly' property set; please use the UpdateTask instead", Project.MSG_WARN);
- engine.doUpdates();
- } else {
try {
- for (Resource resource : path) {
- final FileProvider provider = resource.as(FileProvider.class);
- if (provider != null) {
- final File file = provider.getFile();
- if (file != null && file.exists()) {
- engine.scan(file);
- }
+ engine.doUpdates();
+ } catch (UpdateException ex) {
+ if (this.isFailOnError()) {
+ throw new BuildException(ex);
+ }
+ log(ex.getMessage(), Project.MSG_ERR);
+ }
+ } else {
+ for (Resource resource : path) {
+ final FileProvider provider = resource.as(FileProvider.class);
+ if (provider != null) {
+ final File file = provider.getFile();
+ if (file != null && file.exists()) {
+ engine.scan(file);
}
}
+ }
+ try {
engine.analyzeDependencies();
- DatabaseProperties prop = null;
- CveDB cve = null;
- try {
- cve = new CveDB();
- cve.open();
- prop = cve.getDatabaseProperties();
- } catch (DatabaseException ex) {
- log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
- } finally {
- if (cve != null) {
- cve.close();
- }
+ } catch (ExceptionCollection ex) {
+ if (this.isFailOnError()) {
+ throw new BuildException(ex);
}
- final ReportGenerator reporter = new ReportGenerator(getProjectName(), engine.getDependencies(), engine.getAnalyzers(), prop);
- reporter.generateReports(reportOutputDirectory, reportFormat);
+ }
+ DatabaseProperties prop = null;
+ CveDB cve = null;
+ try {
+ cve = new CveDB();
+ cve.open();
+ prop = cve.getDatabaseProperties();
+ } catch (DatabaseException ex) {
+ log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
+ } finally {
+ if (cve != null) {
+ cve.close();
+ }
+ }
+ final ReportGenerator reporter = new ReportGenerator(getProjectName(), engine.getDependencies(), engine.getAnalyzers(), prop);
+ reporter.generateReports(reportOutputDirectory, reportFormat);
- if (this.failBuildOnCVSS <= 10) {
- checkForFailure(engine.getDependencies());
- }
- if (this.showSummary) {
- showSummary(engine.getDependencies());
- }
- } catch (IOException ex) {
- log("Unable to generate dependency-check report", ex, Project.MSG_DEBUG);
- throw new BuildException("Unable to generate dependency-check report", ex);
- } catch (Exception ex) {
- log("An exception occurred; unable to continue task", ex, Project.MSG_DEBUG);
- throw new BuildException("An exception occurred; unable to continue task", ex);
+ if (this.failBuildOnCVSS <= 10) {
+ checkForFailure(engine.getDependencies());
+ }
+ if (this.showSummary) {
+ showSummary(engine.getDependencies());
}
}
} catch (DatabaseException ex) {
- log("Unable to connect to the dependency-check database; analysis has stopped", ex, Project.MSG_ERR);
+ final String msg = "Unable to connect to the dependency-check database; analysis has stopped";
+ if (this.isFailOnError()) {
+ throw new BuildException(msg, ex);
+ }
+ log(msg, ex, Project.MSG_ERR);
+ } catch (ReportException ex) {
+ final String msg = "Unable to generate the dependency-check report";
+ if (this.isFailOnError()) {
+ throw new BuildException(msg, ex);
+ }
+ log(msg, ex, Project.MSG_ERR);
} finally {
Settings.cleanup(true);
if (engine != null) {
diff --git a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java
index ce28b0645..3bc335fb0 100644
--- a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java
+++ b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java
@@ -71,6 +71,30 @@ public class Purge extends Task {
this.dataDirectory = dataDirectory;
}
+ /**
+ * Indicates if dependency-check should fail the build if an exception
+ * occurs.
+ */
+ private boolean failOnError = true;
+
+ /**
+ * Get the value of failOnError.
+ *
+ * @return the value of failOnError
+ */
+ public boolean isFailOnError() {
+ return failOnError;
+ }
+
+ /**
+ * Set the value of failOnError.
+ *
+ * @param failOnError new value of failOnError
+ */
+ public void setFailOnError(boolean failOnError) {
+ this.failOnError = failOnError;
+ }
+
@Override
public void execute() throws BuildException {
populateSettings();
@@ -81,30 +105,49 @@ public class Purge extends Task {
if (db.delete()) {
log("Database file purged; local copy of the NVD has been removed", Project.MSG_INFO);
} else {
- log(String.format("Unable to delete '%s'; please delete the file manually", db.getAbsolutePath()), Project.MSG_ERR);
+ final String msg = String.format("Unable to delete '%s'; please delete the file manually", db.getAbsolutePath());
+ if (this.failOnError) {
+ throw new BuildException(msg);
+ }
+ log(msg, Project.MSG_ERR);
}
} else {
- log(String.format("Unable to purge database; the database file does not exists: %s", db.getAbsolutePath()), Project.MSG_ERR);
+ final String msg = String.format("Unable to purge database; the database file does not exists: %s", db.getAbsolutePath());
+ if (this.failOnError) {
+ throw new BuildException(msg);
+ }
+ log(msg, Project.MSG_ERR);
}
} catch (IOException ex) {
- log("Unable to delete the database", Project.MSG_ERR);
+ final String msg = "Unable to delete the database";
+ if (this.failOnError) {
+ throw new BuildException(msg);
+ }
+ log(msg, Project.MSG_ERR);
} finally {
Settings.cleanup(true);
}
}
/**
- * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
- * required to change the proxy server, port, and connection timeout.
+ * Takes the properties supplied and updates the dependency-check settings.
+ * Additionally, this sets the system properties required to change the
+ * proxy server, port, and connection timeout.
+ *
+ * @throws BuildException thrown if the properties file cannot be read.
*/
- protected void populateSettings() {
+ protected void populateSettings() throws BuildException {
Settings.initialize();
InputStream taskProperties = null;
try {
taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
Settings.mergeProperties(taskProperties);
} catch (IOException ex) {
- log("Unable to load the dependency-check ant task.properties file.", ex, Project.MSG_WARN);
+ final String msg = "Unable to load the dependency-check ant task.properties file.";
+ if (this.failOnError) {
+ throw new BuildException(msg, ex);
+ }
+ log(msg, ex, Project.MSG_WARN);
} finally {
if (taskProperties != null) {
try {
diff --git a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
index d121f21c1..5648c7c3e 100644
--- a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
+++ b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
@@ -18,14 +18,17 @@
package org.owasp.dependencycheck.taskdefs;
import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.impl.StaticLoggerBinder;
/**
- * An Ant task definition to execute dependency-check update. This will download the latest data from the National Vulnerability
- * Database (NVD) and store a copy in the local database.
+ * An Ant task definition to execute dependency-check update. This will download
+ * the latest data from the National Vulnerability Database (NVD) and store a
+ * copy in the local database.
*
* @author Jeremy Long
*/
@@ -381,10 +384,11 @@ public class Update extends Purge {
}
/**
- * Executes the update by initializing the settings, downloads the NVD XML data, and then processes the data storing it in the
- * local database.
+ * Executes the update by initializing the settings, downloads the NVD XML
+ * data, and then processes the data storing it in the local database.
*
- * @throws BuildException thrown if a connection to the local database cannot be made.
+ * @throws BuildException thrown if a connection to the local database
+ * cannot be made.
*/
@Override
public void execute() throws BuildException {
@@ -392,9 +396,20 @@ public class Update extends Purge {
Engine engine = null;
try {
engine = new Engine(Update.class.getClassLoader());
- engine.doUpdates();
+ try {
+ engine.doUpdates();
+ } catch (UpdateException ex) {
+ if (this.isFailOnError()) {
+ throw new BuildException(ex);
+ }
+ log(ex.getMessage(), Project.MSG_ERR);
+ }
} catch (DatabaseException ex) {
- throw new BuildException("Unable to connect to the dependency-check database; unable to update the NVD data", ex);
+ final String msg = "Unable to connect to the dependency-check database; unable to update the NVD data";
+ if (this.isFailOnError()) {
+ throw new BuildException(msg, ex);
+ }
+ log(msg, Project.MSG_ERR);
} finally {
Settings.cleanup(true);
if (engine != null) {
@@ -404,8 +419,9 @@ public class Update extends Purge {
}
/**
- * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
- * required to change the proxy server, port, and connection timeout.
+ * Takes the properties supplied and updates the dependency-check settings.
+ * Additionally, this sets the system properties required to change the
+ * proxy server, port, and connection timeout.
*
* @throws BuildException thrown when an invalid setting is configured.
*/
diff --git a/dependency-check-ant/src/site/markdown/config-purge.md b/dependency-check-ant/src/site/markdown/config-purge.md
index 80c9f5d91..e7026070a 100644
--- a/dependency-check-ant/src/site/markdown/config-purge.md
+++ b/dependency-check-ant/src/site/markdown/config-purge.md
@@ -14,6 +14,7 @@ Configuration: dependency-check-purge Task
--------------------
The following properties can be set on the dependency-check-purge task.
-Property | Description | Default Value
-----------------------|----------------------------------------------------------------|------------------
-dataDirectory | Data directory that is used to store the local copy of the NVD | data
+Property | Description | Default Value
+----------------------|------------------------------------------------------------------------|------------------
+dataDirectory | Data directory that is used to store the local copy of the NVD | data
+failOnError | Whether the build should fail if there is an error executing the purge | true
diff --git a/dependency-check-ant/src/site/markdown/config-update.md b/dependency-check-ant/src/site/markdown/config-update.md
index dd62e3dbe..87c772b80 100644
--- a/dependency-check-ant/src/site/markdown/config-update.md
+++ b/dependency-check-ant/src/site/markdown/config-update.md
@@ -24,6 +24,7 @@ proxyPort | The Proxy Port. |
proxyUsername | Defines the proxy user name. |
proxyPassword | Defines the proxy password. |
connectionTimeout | The URL Connection Timeout. |
+failOnError | Whether the build should fail if there is an error executing the update | true
Advanced Configuration
====================
diff --git a/dependency-check-ant/src/site/markdown/configuration.md b/dependency-check-ant/src/site/markdown/configuration.md
index e2bf57a24..a711cd013 100644
--- a/dependency-check-ant/src/site/markdown/configuration.md
+++ b/dependency-check-ant/src/site/markdown/configuration.md
@@ -34,6 +34,7 @@ Property | Description
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
cveValidForHours | Sets the number of hours to wait before checking for new updates from the NVD | 4
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
+failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true
projectName | The name of the project being scanned. | Dependency-Check
reportFormat | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
diff --git a/dependency-check-cli/pom.xml b/dependency-check-cli/pom.xml
index 29689775e..584a4a72b 100644
--- a/dependency-check-cli/pom.xml
+++ b/dependency-check-cli/pom.xml
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
org.owasp
dependency-check-parent
- 1.4.1-SNAPSHOT
+ 1.4.3-SNAPSHOT
dependency-check-cli
diff --git a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java
index c8bc71cd6..5d3a8fa18 100644
--- a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java
+++ b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java
@@ -37,6 +37,10 @@ import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.core.FileAppender;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
+import org.owasp.dependencycheck.exception.ReportException;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.slf4j.impl.StaticLoggerBinder;
/**
@@ -57,21 +61,26 @@ public class App {
* @param args the command line arguments
*/
public static void main(String[] args) {
+ int exitCode = 0;
try {
Settings.initialize();
final App app = new App();
- app.run(args);
+ exitCode = app.run(args);
+ LOGGER.debug("Exit code: " + exitCode);
} finally {
Settings.cleanup(true);
}
+ System.exit(exitCode);
}
/**
* Main CLI entry-point into the application.
*
* @param args the command line arguments
+ * @return the exit code to return
*/
- public void run(String[] args) {
+ public int run(String[] args) {
+ int exitCode = 0;
final CliParser cli = new CliParser();
try {
@@ -79,11 +88,11 @@ public class App {
} catch (FileNotFoundException ex) {
System.err.println(ex.getMessage());
cli.printHelp();
- return;
+ return -1;
} catch (ParseException ex) {
System.err.println(ex.getMessage());
cli.printHelp();
- return;
+ return -2;
}
if (cli.getVerboseLog() != null) {
@@ -93,8 +102,15 @@ public class App {
if (cli.isPurge()) {
if (cli.getConnectionString() != null) {
LOGGER.error("Unable to purge the database when using a non-default connection string");
+ exitCode = -3;
} else {
- populateSettings(cli);
+ try {
+ populateSettings(cli);
+ } catch (InvalidSettingException ex) {
+ LOGGER.error(ex.getMessage());
+ LOGGER.debug("Error loading properties file", ex);
+ exitCode = -4;
+ }
File db;
try {
db = new File(Settings.getDataDirectory(), "dc.h2.db");
@@ -103,46 +119,96 @@ public class App {
LOGGER.info("Database file purged; local copy of the NVD has been removed");
} else {
LOGGER.error("Unable to delete '{}'; please delete the file manually", db.getAbsolutePath());
+ exitCode = -5;
}
} else {
LOGGER.error("Unable to purge database; the database file does not exists: {}", db.getAbsolutePath());
+ exitCode = -6;
}
} catch (IOException ex) {
LOGGER.error("Unable to delete the database");
+ exitCode = -7;
}
}
} else if (cli.isGetVersion()) {
cli.printVersionInfo();
} else if (cli.isUpdateOnly()) {
- populateSettings(cli);
- runUpdateOnly();
+ try {
+ populateSettings(cli);
+ } catch (InvalidSettingException ex) {
+ LOGGER.error(ex.getMessage());
+ LOGGER.debug("Error loading properties file", ex);
+ exitCode = -4;
+ }
+ try {
+ runUpdateOnly();
+ } catch (UpdateException ex) {
+ LOGGER.error(ex.getMessage());
+ exitCode = -8;
+ } catch (DatabaseException ex) {
+ LOGGER.error(ex.getMessage());
+ exitCode = -9;
+ }
} else if (cli.isRunScan()) {
- populateSettings(cli);
+ try {
+ populateSettings(cli);
+ } catch (InvalidSettingException ex) {
+ LOGGER.error(ex.getMessage());
+ LOGGER.debug("Error loading properties file", ex);
+ exitCode = -4;
+ }
try {
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), cli.getScanFiles(),
cli.getExcludeList(), cli.getSymLinkDepth());
} catch (InvalidScanPathException ex) {
LOGGER.error("An invalid scan path was detected; unable to scan '//*' paths");
+ exitCode = -10;
+ } catch (DatabaseException ex) {
+ LOGGER.error(ex.getMessage());
+ exitCode = -11;
+ } catch (ReportException ex) {
+ LOGGER.error(ex.getMessage());
+ exitCode = -12;
+ } catch (ExceptionCollection ex) {
+ if (ex.isFatal()) {
+ exitCode = -13;
+ LOGGER.error("One or more fatal errors occured");
+ } else {
+ exitCode = -14;
+ }
+ for (Throwable e : ex.getExceptions()) {
+ LOGGER.error(e.getMessage());
+ }
}
} else {
cli.printHelp();
}
+ return exitCode;
}
/**
- * Scans the specified directories and writes the dependency reports to the reportDirectory.
+ * Scans the specified directories and writes the dependency reports to the
+ * reportDirectory.
*
- * @param reportDirectory the path to the directory where the reports will be written
+ * @param reportDirectory the path to the directory where the reports will
+ * be written
* @param outputFormat the output format of the report
* @param applicationName the application name for the report
* @param files the files/directories to scan
* @param excludes the patterns for files/directories to exclude
* @param symLinkDepth the depth that symbolic links will be followed
*
- * @throws InvalidScanPathException thrown if the path to scan starts with "//"
+ * @throws InvalidScanPathException thrown if the path to scan starts with
+ * "//"
+ * @throws ReportException thrown when the report cannot be generated
+ * @throws DatabaseException thrown when there is an error connecting to the
+ * database
+ * @throws ExceptionCollection thrown when an exception occurs during
+ * analysis; there may be multiple exceptions contained within the
+ * collection.
*/
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files,
- String[] excludes, int symLinkDepth) throws InvalidScanPathException {
+ String[] excludes, int symLinkDepth) throws InvalidScanPathException, DatabaseException, ExceptionCollection, ReportException {
Engine engine = null;
try {
engine = new Engine();
@@ -174,8 +240,6 @@ public class App {
include = "**/*";
}
}
- //LOGGER.debug("baseDir: {}", baseDir);
- //LOGGER.debug("include: {}", include);
scanner.setBasedir(baseDir);
final String[] includes = {include};
scanner.setIncludes(includes);
@@ -197,7 +261,15 @@ public class App {
}
engine.scan(paths);
- engine.analyzeDependencies();
+ ExceptionCollection exCol = null;
+ try {
+ engine.analyzeDependencies();
+ } catch (ExceptionCollection ex) {
+ if (ex.isFatal()) {
+ throw ex;
+ }
+ exCol = ex;
+ }
final List dependencies = engine.getDependencies();
DatabaseProperties prop = null;
CveDB cve = null;
@@ -205,8 +277,6 @@ public class App {
cve = new CveDB();
cve.open();
prop = cve.getDatabaseProperties();
- } catch (DatabaseException ex) {
- LOGGER.debug("Unable to retrieve DB Properties", ex);
} finally {
if (cve != null) {
cve.close();
@@ -215,34 +285,37 @@ public class App {
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
try {
report.generateReports(reportDirectory, outputFormat);
- } catch (IOException ex) {
- LOGGER.error("There was an IO error while attempting to generate the report.");
- LOGGER.debug("", ex);
- } catch (Throwable ex) {
- LOGGER.error("There was an error while attempting to generate the report.");
- LOGGER.debug("", ex);
+ } catch (ReportException ex) {
+ if (exCol != null) {
+ exCol.addException(ex);
+ throw exCol;
+ } else {
+ throw ex;
+ }
+ }
+ if (exCol != null && exCol.getExceptions().size()>0) {
+ throw exCol;
}
- } catch (DatabaseException ex) {
- LOGGER.error("Unable to connect to the dependency-check database; analysis has stopped");
- LOGGER.debug("", ex);
} finally {
if (engine != null) {
engine.cleanup();
}
}
+
}
/**
* Only executes the update phase of dependency-check.
+ *
+ * @throws UpdateException thrown if there is an error updating
+ * @throws DatabaseException thrown if a fatal error occurred and a
+ * connection to the database could not be established
*/
- private void runUpdateOnly() {
+ private void runUpdateOnly() throws UpdateException, DatabaseException {
Engine engine = null;
try {
engine = new Engine();
engine.doUpdates();
- } catch (DatabaseException ex) {
- LOGGER.error("Unable to connect to the dependency-check database; analysis has stopped");
- LOGGER.debug("", ex);
} finally {
if (engine != null) {
engine.cleanup();
@@ -253,11 +326,13 @@ public class App {
/**
* Updates the global Settings.
*
- * @param cli a reference to the CLI Parser that contains the command line arguments used to set the corresponding settings in
- * the core engine.
+ * @param cli a reference to the CLI Parser that contains the command line
+ * arguments used to set the corresponding settings in the core engine.
+ *
+ * @throws InvalidSettingException thrown when a user defined properties
+ * file is unable to be loaded.
*/
- private void populateSettings(CliParser cli) {
-
+ private void populateSettings(CliParser cli) throws InvalidSettingException {
final boolean autoUpdate = cli.isAutoUpdate();
final String connectionTimeout = cli.getConnectionTimeout();
final String proxyServer = cli.getProxyServer();
@@ -286,11 +361,9 @@ public class App {
try {
Settings.mergeProperties(propertiesFile);
} catch (FileNotFoundException ex) {
- LOGGER.error("Unable to load properties file '{}'", propertiesFile.getPath());
- LOGGER.debug("", ex);
+ throw new InvalidSettingException("Unable to find properties file '" + propertiesFile.getPath() + "'", ex);
} catch (IOException ex) {
- LOGGER.error("Unable to find properties file '{}'", propertiesFile.getPath());
- LOGGER.debug("", ex);
+ throw new InvalidSettingException("Error reading properties file '" + propertiesFile.getPath() + "'", ex);
}
}
// We have to wait until we've merged the properties before attempting to set whether we use
@@ -385,15 +458,16 @@ public class App {
}
/**
- * Takes a path and resolves it to be a canonical & absolute path. The caveats are that this method will take an Ant style
- * file selector path (../someDir/**\/*.jar) and convert it to an absolute/canonical path (at least to the left of the first *
- * or ?).
+ * Takes a path and resolves it to be a canonical & absolute path. The
+ * caveats are that this method will take an Ant style file selector path
+ * (../someDir/**\/*.jar) and convert it to an absolute/canonical path (at
+ * least to the left of the first * or ?).
*
* @param path the path to canonicalize
* @return the canonical path
*/
protected String ensureCanonicalPath(String path) {
- String basePath = null;
+ String basePath;
String wildCards = null;
final String file = path.replace('\\', '/');
if (file.contains("*") || file.contains("?")) {
diff --git a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java
index d2e522834..19d826bf3 100644
--- a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java
+++ b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java
@@ -966,7 +966,7 @@ public final class CliParser {
*/
public void printVersionInfo() {
final String version = String.format("%s version %s",
- Settings.getString(Settings.KEYS.APPLICATION_VAME, "dependency-check"),
+ Settings.getString(Settings.KEYS.APPLICATION_NAME, "dependency-check"),
Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
System.out.println(version);
}
diff --git a/dependency-check-core/pom.xml b/dependency-check-core/pom.xml
index 387601cdd..dd7419c56 100644
--- a/dependency-check-core/pom.xml
+++ b/dependency-check-core/pom.xml
@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
org.owasp
dependency-check-parent
- 1.4.1-SNAPSHOT
+ 1.4.3-SNAPSHOT
dependency-check-core
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java
index 675eee417..5560c4adc 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java
@@ -30,6 +30,8 @@ import org.owasp.dependencycheck.data.update.UpdateService;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.NoDataException;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
+import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
@@ -47,8 +49,10 @@ import java.util.Map;
import java.util.Set;
/**
- * Scans files, directories, etc. for Dependencies. Analyzers are loaded and used to process the files found by the scan, if a
- * file is encountered and an Analyzer is associated with the file type then the file is turned into a dependency.
+ * Scans files, directories, etc. for Dependencies. Analyzers are loaded and
+ * used to process the files found by the scan, if a file is encountered and an
+ * Analyzer is associated with the file type then the file is turned into a
+ * dependency.
*
* @author Jeremy Long
*/
@@ -69,7 +73,8 @@ public class Engine implements FileFilter {
private final Set fileTypeAnalyzers = new HashSet();
/**
- * The ClassLoader to use when dynamically loading Analyzer and Update services.
+ * The ClassLoader to use when dynamically loading Analyzer and Update
+ * services.
*/
private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
/**
@@ -80,7 +85,8 @@ public class Engine implements FileFilter {
/**
* Creates a new Engine.
*
- * @throws DatabaseException thrown if there is an error connecting to the database
+ * @throws DatabaseException thrown if there is an error connecting to the
+ * database
*/
public Engine() throws DatabaseException {
initializeEngine();
@@ -90,7 +96,8 @@ public class Engine implements FileFilter {
* Creates a new Engine.
*
* @param serviceClassLoader a reference the class loader being used
- * @throws DatabaseException thrown if there is an error connecting to the database
+ * @throws DatabaseException thrown if there is an error connecting to the
+ * database
*/
public Engine(ClassLoader serviceClassLoader) throws DatabaseException {
this.serviceClassLoader = serviceClassLoader;
@@ -98,9 +105,11 @@ public class Engine implements FileFilter {
}
/**
- * Creates a new Engine using the specified classloader to dynamically load Analyzer and Update services.
+ * Creates a new Engine using the specified classloader to dynamically load
+ * Analyzer and Update services.
*
- * @throws DatabaseException thrown if there is an error connecting to the database
+ * @throws DatabaseException thrown if there is an error connecting to the
+ * database
*/
protected final void initializeEngine() throws DatabaseException {
ConnectionFactory.initialize();
@@ -115,7 +124,8 @@ public class Engine implements FileFilter {
}
/**
- * Loads the analyzers specified in the configuration file (or system properties).
+ * Loads the analyzers specified in the configuration file (or system
+ * properties).
*/
private void loadAnalyzers() {
if (!analyzers.isEmpty()) {
@@ -164,8 +174,9 @@ public class Engine implements FileFilter {
}
/**
- * Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies
- * identified are added to the dependency collection.
+ * Scans an array of files or directories. If a directory is specified, it
+ * will be scanned recursively. Any dependencies identified are added to the
+ * dependency collection.
*
* @param paths an array of paths to files or directories to be analyzed
* @return the list of dependencies scanned
@@ -183,8 +194,9 @@ public class Engine implements FileFilter {
}
/**
- * Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies identified
- * are added to the dependency collection.
+ * Scans a given file or directory. If a directory is specified, it will be
+ * scanned recursively. Any dependencies identified are added to the
+ * dependency collection.
*
* @param path the path to a file or directory to be analyzed
* @return the list of dependencies scanned
@@ -195,8 +207,9 @@ public class Engine implements FileFilter {
}
/**
- * Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies
- * identified are added to the dependency collection.
+ * Scans an array of files or directories. If a directory is specified, it
+ * will be scanned recursively. Any dependencies identified are added to the
+ * dependency collection.
*
* @param files an array of paths to files or directories to be analyzed.
* @return the list of dependencies
@@ -214,8 +227,9 @@ public class Engine implements FileFilter {
}
/**
- * Scans a collection of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies
- * identified are added to the dependency collection.
+ * Scans a collection of files or directories. If a directory is specified,
+ * it will be scanned recursively. Any dependencies identified are added to
+ * the dependency collection.
*
* @param files a set of paths to files or directories to be analyzed
* @return the list of dependencies scanned
@@ -233,8 +247,9 @@ public class Engine implements FileFilter {
}
/**
- * Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies identified
- * are added to the dependency collection.
+ * Scans a given file or directory. If a directory is specified, it will be
+ * scanned recursively. Any dependencies identified are added to the
+ * dependency collection.
*
* @param file the path to a file or directory to be analyzed
* @return the list of dependencies scanned
@@ -257,7 +272,8 @@ public class Engine implements FileFilter {
}
/**
- * Recursively scans files and directories. Any dependencies identified are added to the dependency collection.
+ * Recursively scans files and directories. Any dependencies identified are
+ * added to the dependency collection.
*
* @param dir the directory to scan
* @return the list of Dependency objects scanned
@@ -282,7 +298,8 @@ public class Engine implements FileFilter {
}
/**
- * Scans a specified file. If a dependency is identified it is added to the dependency collection.
+ * Scans a specified file. If a dependency is identified it is added to the
+ * dependency collection.
*
* @param file The file to scan
* @return the scanned dependency
@@ -301,20 +318,38 @@ public class Engine implements FileFilter {
}
/**
- * Runs the analyzers against all of the dependencies. Since the mutable dependencies list is exposed via
- * {@link #getDependencies()}, this method iterates over a copy of the dependencies list. Thus, the potential for
- * {@link java.util.ConcurrentModificationException}s is avoided, and analyzers may safely add or remove entries from the
- * dependencies list.
+ * Runs the analyzers against all of the dependencies. Since the mutable
+ * dependencies list is exposed via {@link #getDependencies()}, this method
+ * iterates over a copy of the dependencies list. Thus, the potential for
+ * {@link java.util.ConcurrentModificationException}s is avoided, and
+ * analyzers may safely add or remove entries from the dependencies list.
+ *
+ * Every effort is made to complete analysis on the dependencies. In some
+ * cases an exception will occur with part of the analysis being performed
+ * which may not affect the entire analysis. If an exception occurs it will
+ * be included in the thrown exception collection.
+ *
+ * @throws ExceptionCollection a collections of any exceptions that occurred
+ * during analysis
*/
- public void analyzeDependencies() {
+ public void analyzeDependencies() throws ExceptionCollection {
+ final List exceptions = new ArrayList();
boolean autoUpdate = true;
try {
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
} catch (InvalidSettingException ex) {
LOGGER.debug("Invalid setting for auto-update; using true.");
+ exceptions.add(ex);
}
if (autoUpdate) {
- doUpdates();
+ try {
+ doUpdates();
+ } catch (UpdateException ex) {
+ exceptions.add(ex);
+ LOGGER.warn("Unable to update Cached Web DataSource, using local "
+ + "data instead. Results may not include recent vulnerabilities.");
+ LOGGER.debug("Update Error", ex);
+ }
}
//need to ensure that data exists
@@ -323,12 +358,13 @@ public class Engine implements FileFilter {
} catch (NoDataException ex) {
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
LOGGER.debug("", ex);
- return;
+ exceptions.add(ex);
+ throw new ExceptionCollection("Unable to continue dependency-check analysis.", exceptions, true);
} catch (DatabaseException ex) {
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
LOGGER.debug("", ex);
- return;
-
+ exceptions.add(ex);
+ throw new ExceptionCollection("Unable to connect to the dependency-check database", exceptions, true);
}
LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
@@ -340,7 +376,12 @@ public class Engine implements FileFilter {
final List analyzerList = analyzers.get(phase);
for (Analyzer a : analyzerList) {
- a = initializeAnalyzer(a);
+ try {
+ a = initializeAnalyzer(a);
+ } catch (InitializationException ex) {
+ exceptions.add(ex);
+ continue;
+ }
/* need to create a copy of the collection because some of the
* analyzers may modify it. This prevents ConcurrentModificationExceptions.
@@ -361,10 +402,12 @@ public class Engine implements FileFilter {
} catch (AnalysisException ex) {
LOGGER.warn("An error occurred while analyzing '{}'.", d.getActualFilePath());
LOGGER.debug("", ex);
+ exceptions.add(ex);
} catch (Throwable ex) {
//final AnalysisException ax = new AnalysisException(axMsg, ex);
LOGGER.warn("An unexpected error occurred during analysis of '{}'", d.getActualFilePath());
LOGGER.debug("", ex);
+ exceptions.add(ex);
}
}
}
@@ -380,6 +423,9 @@ public class Engine implements FileFilter {
LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
LOGGER.info("Analysis Complete ({} ms)", System.currentTimeMillis() - analysisStart);
+ if (exceptions.size() > 0) {
+ throw new ExceptionCollection("One or more exceptions occured during dependency-check analysis", exceptions);
+ }
}
/**
@@ -387,12 +433,14 @@ public class Engine implements FileFilter {
*
* @param analyzer the analyzer to initialize
* @return the initialized analyzer
+ * @throws InitializationException thrown when there is a problem
+ * initializing the analyzer
*/
- protected Analyzer initializeAnalyzer(Analyzer analyzer) {
+ protected Analyzer initializeAnalyzer(Analyzer analyzer) throws InitializationException {
try {
LOGGER.debug("Initializing {}", analyzer.getName());
analyzer.initialize();
- } catch (Throwable ex) {
+ } catch (InitializationException ex) {
LOGGER.error("Exception occurred initializing {}.", analyzer.getName());
LOGGER.debug("", ex);
try {
@@ -400,6 +448,16 @@ public class Engine implements FileFilter {
} catch (Throwable ex1) {
LOGGER.trace("", ex1);
}
+ throw ex;
+ } catch (Throwable ex) {
+ LOGGER.error("Unexpected exception occurred initializing {}.", analyzer.getName());
+ LOGGER.debug("", ex);
+ try {
+ analyzer.close();
+ } catch (Throwable ex1) {
+ LOGGER.trace("", ex1);
+ }
+ throw new InitializationException("Unexpected Exception", ex);
}
return analyzer;
}
@@ -419,28 +477,26 @@ public class Engine implements FileFilter {
}
/**
- * Cycles through the cached web data sources and calls update on all of them.
+ * Cycles through the cached web data sources and calls update on all of
+ * them.
+ *
+ * @throws UpdateException thrown if the operation fails
*/
- public void doUpdates() {
+ public void doUpdates() throws UpdateException {
LOGGER.info("Checking for updates");
final long updateStart = System.currentTimeMillis();
final UpdateService service = new UpdateService(serviceClassLoader);
final Iterator iterator = service.getDataSources();
while (iterator.hasNext()) {
final CachedWebDataSource source = iterator.next();
- try {
- source.update();
- } catch (UpdateException ex) {
- LOGGER.warn(
- "Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
- LOGGER.debug("Unable to update details for {}", source.getClass().getName(), ex);
- }
+ source.update();
}
LOGGER.info("Check for updates complete ({} ms)", System.currentTimeMillis() - updateStart);
}
/**
- * Returns a full list of all of the analyzers. This is useful for reporting which analyzers where used.
+ * Returns a full list of all of the analyzers. This is useful for reporting
+ * which analyzers where used.
*
* @return a list of Analyzers
*/
@@ -457,7 +513,8 @@ public class Engine implements FileFilter {
* Checks all analyzers to see if an extension is supported.
*
* @param file a file extension
- * @return true or false depending on whether or not the file extension is supported
+ * @return true or false depending on whether or not the file extension is
+ * supported
*/
@Override
public boolean accept(File file) {
@@ -483,10 +540,12 @@ public class Engine implements FileFilter {
}
/**
- * Checks the CPE Index to ensure documents exists. If none exist a NoDataException is thrown.
+ * Checks the CPE Index to ensure documents exists. If none exist a
+ * NoDataException is thrown.
*
* @throws NoDataException thrown if no data exists in the CPE Index
- * @throws DatabaseException thrown if there is an exception opening the database
+ * @throws DatabaseException thrown if there is an exception opening the
+ * database
*/
private void ensureDataExists() throws NoDataException, DatabaseException {
final CveDB cve = new CveDB();
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java
index b2b63955e..56ab93810 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java
@@ -27,6 +27,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.ScanAgentException;
import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.utils.Settings;
@@ -34,10 +35,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting evidence
- * from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it takes a list of
- * dependencies that can be programmatically added from data in a spreadsheet, database or some other datasource and conduct a
- * scan based on this pre-defined evidence.
+ * This class provides a way to easily conduct a scan solely based on existing
+ * evidence metadata rather than collecting evidence from the files themselves.
+ * This class is based on the Ant task and Maven plugin with the exception that
+ * it takes a list of dependencies that can be programmatically added from data
+ * in a spreadsheet, database or some other datasource and conduct a scan based
+ * on this pre-defined evidence.
*
* Example:
*
@@ -138,7 +141,8 @@ public class DependencyCheckScanAgent {
}
/**
- * Specifies the destination directory for the generated Dependency-Check report.
+ * Specifies the destination directory for the generated Dependency-Check
+ * report.
*/
private String reportOutputDirectory;
@@ -161,9 +165,11 @@ public class DependencyCheckScanAgent {
}
/**
- * Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which
- * means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11. The valid range
- * for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
+ * Specifies if the build should be failed if a CVSS score above a specified
+ * level is identified. The default is 11 which means since the CVSS scores
+ * are 0-10, by default the build will never fail and the CVSS score is set
+ * to 11. The valid range for the fail build on CVSS is 0 to 11, where
+ * anything above 10 will not cause the build to fail.
*/
private float failBuildOnCVSS = 11;
@@ -186,8 +192,8 @@ public class DependencyCheckScanAgent {
}
/**
- * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
- * is true.
+ * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
+ * recommended that this be turned to false. Default is true.
*/
private boolean autoUpdate = true;
@@ -233,8 +239,9 @@ public class DependencyCheckScanAgent {
}
/**
- * The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the
- * Site plugin unless the externalReport is set to true. Default is HTML.
+ * The report format to be generated (HTML, XML, VULN, ALL). This
+ * configuration option has no affect if using this within the Site plugin
+ * unless the externalReport is set to true. Default is HTML.
*/
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
@@ -283,7 +290,9 @@ public class DependencyCheckScanAgent {
* Get the value of proxyServer.
*
* @return the value of proxyServer
- * @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()} instead
+ * @deprecated use
+ * {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()}
+ * instead
*/
@Deprecated
public String getProxyUrl() {
@@ -694,8 +703,8 @@ public class DependencyCheckScanAgent {
}
/**
- * Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
- * files.
+ * Additional ZIP File extensions to add analyze. This should be a
+ * comma-separated list of file extensions to treat like ZIP files.
*/
private String zipExtensions;
@@ -836,11 +845,17 @@ public class DependencyCheckScanAgent {
* Executes the Dependency-Check on the dependent libraries.
*
* @return the Engine used to scan the dependencies.
- * @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the database
+ * @throws ExceptionCollection a collection of one or more exceptions that
+ * occurred during analysis.
*/
- private Engine executeDependencyCheck() throws DatabaseException {
+ private Engine executeDependencyCheck() throws ExceptionCollection {
populateSettings();
- final Engine engine = new Engine();
+ final Engine engine;
+ try {
+ engine = new Engine();
+ } catch (DatabaseException ex) {
+ throw new ExceptionCollection(ex, true);
+ }
engine.setDependencies(this.dependencies);
engine.analyzeDependencies();
return engine;
@@ -881,8 +896,9 @@ public class DependencyCheckScanAgent {
}
/**
- * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
- * required to change the proxy server, port, and connection timeout.
+ * Takes the properties supplied and updates the dependency-check settings.
+ * Additionally, this sets the system properties required to change the
+ * proxy server, port, and connection timeout.
*/
private void populateSettings() {
Settings.initialize();
@@ -925,7 +941,8 @@ public class DependencyCheckScanAgent {
* Executes the dependency-check and generates the report.
*
* @return a reference to the engine used to perform the scan.
- * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
+ * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
+ * there is an exception executing the scan.
*/
public Engine execute() throws ScanAgentException {
Engine engine = null;
@@ -940,10 +957,12 @@ public class DependencyCheckScanAgent {
if (this.failBuildOnCVSS <= 10) {
checkForFailure(engine.getDependencies());
}
- } catch (DatabaseException ex) {
- LOGGER.error(
- "Unable to connect to the dependency-check database; analysis has stopped");
- LOGGER.debug("", ex);
+ } catch (ExceptionCollection ex) {
+ if (ex.isFatal()) {
+ LOGGER.error("A fatal exception occurred during analysis; analysis has stopped. Please see the debug log for more details.");
+ LOGGER.debug("", ex);
+ }
+ throw new ScanAgentException("One or more exceptions occurred during analysis; please see the debug log for more details.", ex);
} finally {
Settings.cleanup(true);
if (engine != null) {
@@ -954,11 +973,12 @@ public class DependencyCheckScanAgent {
}
/**
- * Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
- * configuration.
+ * Checks to see if a vulnerability has been identified with a CVSS score
+ * that is above the threshold set in the configuration.
*
* @param dependencies the list of dependency objects
- * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
+ * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
+ * there is an exception executing the scan.
*/
private void checkForFailure(List dependencies) throws ScanAgentException {
final StringBuilder ids = new StringBuilder();
@@ -986,7 +1006,8 @@ public class DependencyCheckScanAgent {
}
/**
- * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
+ * Generates a warning message listing a summary of dependencies and their
+ * associated CPE and CVE entries.
*
* @param dependencies a list of dependency objects
*/
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java
index 5a14171c7..62e502254 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java
@@ -367,7 +367,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase();
try {
if (ZIPPABLES.contains(archiveExt)) {
- BufferedInputStream in = new BufferedInputStream(fis);
+ final BufferedInputStream in = new BufferedInputStream(fis);
ensureReadableJar(archiveExt, in);
extractArchive(new ZipArchiveInputStream(in), destination, engine);
} else if ("tar".equals(archiveExt)) {
@@ -413,7 +413,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
private void ensureReadableJar(final String archiveExt, BufferedInputStream in) throws IOException {
if ("jar".equals(archiveExt) && in.markSupported()) {
in.mark(7);
- byte[] b = new byte[7];
+ final byte[] b = new byte[7];
in.read(b);
if (b[0] == '#'
&& b[1] == '!'
@@ -441,6 +441,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
}
}
}
+ } else {
+ in.reset();
}
}
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java
index 815881155..3733809c9 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java
@@ -574,15 +574,14 @@ public class CPEAnalyzer implements Analyzer {
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
collected.add(match);
- } else //TODO the following isn't quite right is it? need to think about this guessing game a bit more.
- {
- if (evVer.getVersionParts().size() <= dbVer.getVersionParts().size()
- && evVer.matchesAtLeastThreeLevels(dbVer)) {
- if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
- if (bestGuess.getVersionParts().size() < dbVer.getVersionParts().size()) {
- bestGuess = dbVer;
- bestGuessConf = conf;
- }
+
+ //TODO the following isn't quite right is it? need to think about this guessing game a bit more.
+ } else if (evVer.getVersionParts().size() <= dbVer.getVersionParts().size()
+ && evVer.matchesAtLeastThreeLevels(dbVer)) {
+ if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
+ if (bestGuess.getVersionParts().size() < dbVer.getVersionParts().size()) {
+ bestGuess = dbVer;
+ bestGuessConf = conf;
}
}
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java
index fcaaeb102..5e6dee5b8 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java
@@ -93,26 +93,27 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
//add version evidence
final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName);
+ final String packageName = DependencyVersionUtil.parsePreVersion(fileName);
if (version != null) {
// If the version number is just a number like 2 or 23, reduce the confidence
// a shade. This should hopefully correct for cases like log4j.jar or
// struts2-core.jar
if (version.getVersionParts() == null || version.getVersionParts().size() < 2) {
- dependency.getVersionEvidence().addEvidence("file", "name",
+ dependency.getVersionEvidence().addEvidence("file", "version",
version.toString(), Confidence.MEDIUM);
} else {
dependency.getVersionEvidence().addEvidence("file", "version",
version.toString(), Confidence.HIGHEST);
}
dependency.getVersionEvidence().addEvidence("file", "name",
- fileName, Confidence.MEDIUM);
+ packageName, Confidence.MEDIUM);
}
if (!IGNORED_FILES.accept(f)) {
dependency.getProductEvidence().addEvidence("file", "name",
- fileName, Confidence.HIGH);
+ packageName, Confidence.HIGH);
dependency.getVendorEvidence().addEvidence("file", "name",
- fileName, Confidence.HIGH);
+ packageName, Confidence.HIGH);
}
}
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/HintAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/HintAnalyzer.java
index b4ebcbfe0..5c206037b 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/HintAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/HintAnalyzer.java
@@ -32,7 +32,6 @@ import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.xml.suppression.PropertyType;
-import org.owasp.dependencycheck.xml.suppression.SuppressionParseException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.FileUtils;
@@ -255,7 +254,7 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
if (product.contains(zendframeworkProduct)) {
dependency.getProductEvidence().addEvidence("hint analyzer", "vendor", "zend_framework", Confidence.HIGHEST);
}
-
+
//sun/oracle problem
final Iterator itr = dependency.getVendorEvidence().iterator();
final List newEntries = new ArrayList();
@@ -279,7 +278,7 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* Loads the hint rules file.
*
- * @throws SuppressionParseException thrown if the XML cannot be parsed.
+ * @throws HintParseException thrown if the XML cannot be parsed.
*/
private void loadHintRules() throws HintParseException {
final HintParser parser = new HintParser();
@@ -293,7 +292,7 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
LOGGER.error("Unable to parse the base hint data file");
LOGGER.debug("Unable to parse the base hint data file", ex);
}
- final String filePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
+ final String filePath = Settings.getString(Settings.KEYS.HINTS_FILE);
if (filePath == null) {
return;
}
@@ -327,7 +326,7 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
if (file != null) {
try {
- Hints newHints = parser.parseHints(file);
+ final Hints newHints = parser.parseHints(file);
hints.getHintRules().addAll(newHints.getHintRules());
hints.getVendorDuplicatingHintRules().addAll(newHints.getVendorDuplicatingHintRules());
LOGGER.debug("{} hint rules were loaded.", hints.getHintRules().size());
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java
index 9d952c14c..9edbcf6ab 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java
@@ -39,7 +39,6 @@ import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
-import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import org.apache.commons.compress.utils.IOUtils;
@@ -646,9 +645,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
* @return whether evidence was identified parsing the manifest
* @throws IOException if there is an issue reading the JAR file
*/
- protected boolean parseManifest(Dependency dependency,
- List classInformation)
- throws IOException {
+ protected boolean parseManifest(Dependency dependency, List classInformation) throws IOException {
boolean foundSomething = false;
JarFile jar = null;
try {
@@ -667,7 +664,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
final EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
final EvidenceCollection productEvidence = dependency.getProductEvidence();
final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
-
String source = "Manifest";
String specificationVersion = null;
boolean hasImplementationVersion = false;
@@ -689,7 +685,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
foundSomething = true;
versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
} else if ("specification-version".equalsIgnoreCase(key)) {
- specificationVersion = key;
+ specificationVersion = value;
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
foundSomething = true;
vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
@@ -784,7 +780,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
}
}
}
-
for (Map.Entry item : manifest.getEntries().entrySet()) {
final String name = item.getKey();
source = "manifest: " + name;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java
index 5bade7829..56001c9d7 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java
@@ -53,6 +53,9 @@ import org.slf4j.LoggerFactory;
@Experimental
public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
+ /**
+ * The logger.
+ */
private static final Logger LOGGER = LoggerFactory.getLogger(RubyBundleAuditAnalyzer.class);
/**
@@ -151,7 +154,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
setEnabled(false);
cvedb.close();
cvedb = null;
- String msg = String.format("Exception from bundle-audit process: %s. Disabling %s", ae.getCause(), ANALYZER_NAME);
+ final String msg = String.format("Exception from bundle-audit process: %s. Disabling %s", ae.getCause(), ANALYZER_NAME);
throw new InitializationException(msg, ae);
} catch (IOException ex) {
setEnabled(false);
@@ -163,12 +166,12 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
exitValue = process.waitFor();
} catch (InterruptedException ex) {
setEnabled(false);
- String msg = String.format("Bundle-audit process was interupted. Disabling %s", ANALYZER_NAME);
+ final String msg = String.format("Bundle-audit process was interupted. Disabling %s", ANALYZER_NAME);
throw new InitializationException(msg);
}
if (0 == exitValue) {
setEnabled(false);
- String msg = String.format("Unexpected exit code from bundle-audit process. Disabling %s: %s", ANALYZER_NAME, exitValue);
+ final String msg = String.format("Unexpected exit code from bundle-audit process. Disabling %s: %s", ANALYZER_NAME, exitValue);
throw new InitializationException(msg);
} else {
BufferedReader reader = null;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/cpe/CpeMemoryIndex.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/cpe/CpeMemoryIndex.java
index 666a2ffbe..5caed2e4f 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/cpe/CpeMemoryIndex.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/cpe/CpeMemoryIndex.java
@@ -38,7 +38,6 @@ import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.RAMDirectory;
-import org.owasp.dependencycheck.data.lucene.FieldAnalyzer;
import org.owasp.dependencycheck.data.lucene.LuceneUtils;
import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -48,8 +47,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * An in memory lucene index that contains the vendor/product combinations from the CPE (application) identifiers within the NVD
- * CVE data.
+ * An in memory lucene index that contains the vendor/product combinations from
+ * the CPE (application) identifiers within the NVD CVE data.
*
* @author Jeremy Long
*/
@@ -144,19 +143,6 @@ public final class CpeMemoryIndex {
return openState;
}
- /**
- * Creates the indexing analyzer for the CPE Index.
- *
- * @return the CPE Analyzer.
- * @deprecated the search field analyzer must be used to include the token concatenating filter.
- */
- @Deprecated
- private Analyzer createIndexingAnalyzer() {
- final Map fieldAnalyzers = new HashMap();
- fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
- return new PerFieldAnalyzerWrapper(new FieldAnalyzer(LuceneUtils.CURRENT_VERSION), fieldAnalyzers);
- }
-
/**
* Creates an Analyzer for searching the CPE Index.
*
@@ -275,7 +261,8 @@ public final class CpeMemoryIndex {
* @param maxQueryResults the maximum number of documents to return
* @return the TopDocs found by the search
* @throws ParseException thrown when the searchString is invalid
- * @throws IOException is thrown if there is an issue with the underlying Index
+ * @throws IOException is thrown if there is an issue with the underlying
+ * Index
*/
public TopDocs search(String searchString, int maxQueryResults) throws ParseException, IOException {
if (searchString == null || searchString.trim().isEmpty()) {
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/lucene/FieldAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/lucene/FieldAnalyzer.java
index 534259f07..0736c9fb0 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/lucene/FieldAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/lucene/FieldAnalyzer.java
@@ -34,7 +34,7 @@ import org.apache.lucene.util.Version;
* index the CPE fields vendor and product.
*
* @author Jeremy Long
- * @Deprecated the field analyzer should not be used, instead use the
+ * @deprecated the field analyzer should not be used, instead use the
* SearchFieldAnalyzer so that the token analyzing filter is used.
*/
@Deprecated
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java
index fc920956c..8b770ec66 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java
@@ -68,17 +68,16 @@ public class CveDB {
private ResourceBundle statementBundle = null;
/**
- * Creates a new CveDB object and opens the database
- * connection. Note, the connection must be closed by the caller by calling
- * the close method. ======= Does the underlying connection support batch
- * operations?
+ * Creates a new CveDB object and opens the database connection. Note, the
+ * connection must be closed by the caller by calling the close method.
+ * ======= Does the underlying connection support batch operations?
*/
private boolean batchSupported;
/**
* Creates a new CveDB object and opens the database connection. Note, the
* connection must be closed by the caller by calling the close method.
- *
+ *
* @throws DatabaseException thrown if there is an exception opening the
* database.
*/
@@ -659,7 +658,7 @@ public class CveDB {
+ "If the problem persist try deleting the files in '{}' and running {} again. If the problem continues, please "
+ "create a log file (see documentation at http://jeremylong.github.io/DependencyCheck/) and open a ticket at "
+ "https://github.com/jeremylong/DependencyCheck/issues and include the log file.\n\n",
- dd, dd, Settings.getString(Settings.KEYS.APPLICATION_VAME));
+ dd, dd, Settings.getString(Settings.KEYS.APPLICATION_NAME));
LOGGER.debug("", ex);
} finally {
DBUtils.closeResultSet(rs);
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java
index 24293b969..4c778e7b2 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java
@@ -43,9 +43,10 @@ public class CPEHandler extends DefaultHandler {
/**
* The Starts with expression to filter CVE entries by CPE.
*/
- private static final String CPE_STARTS_WITH = Settings.getString(Settings.KEYS.CVE_CPE_STARTS_WITH_FILTER,"cpe:/a:");
+ private static final String CPE_STARTS_WITH = Settings.getString(Settings.KEYS.CVE_CPE_STARTS_WITH_FILTER, "cpe:/a:");
/**
- * The text content of the node being processed. This can be used during the end element event.
+ * The text content of the node being processed. This can be used during the
+ * end element event.
*/
private StringBuilder nodeText = null;
/**
@@ -77,7 +78,8 @@ public class CPEHandler extends DefaultHandler {
* @param localName the local name
* @param qName the qualified name
* @param attributes the attributes
- * @throws SAXException thrown if there is an exception processing the element
+ * @throws SAXException thrown if there is an exception processing the
+ * element
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
@@ -128,7 +130,8 @@ public class CPEHandler extends DefaultHandler {
* @param ch the char array
* @param start the start position of the data read
* @param length the length of the data read
- * @throws SAXException thrown if there is an exception processing the characters
+ * @throws SAXException thrown if there is an exception processing the
+ * characters
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
@@ -138,12 +141,14 @@ public class CPEHandler extends DefaultHandler {
}
/**
- * Handles the end element event. Stores the CPE data in the Cve Database if the cpe item node is ending.
+ * Handles the end element event. Stores the CPE data in the Cve Database if
+ * the cpe item node is ending.
*
* @param uri the element's uri
* @param localName the local name
* @param qName the qualified name
- * @throws SAXException thrown if there is an exception processing the element
+ * @throws SAXException thrown if there is an exception processing the
+ * element
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
@@ -182,7 +187,8 @@ public class CPEHandler extends DefaultHandler {
//
/**
- * A simple class to maintain information about the current element while parsing the CPE XML.
+ * A simple class to maintain information about the current element while
+ * parsing the CPE XML.
*/
protected static final class Element {
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java
index 0d5762708..6df4e5fa6 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java
@@ -36,6 +36,9 @@ import org.slf4j.LoggerFactory;
*/
public class UpdateableNvdCve implements Iterable, Iterator {
+ /**
+ * A reference to the logger.
+ */
private static final Logger LOGGER = LoggerFactory.getLogger(UpdateableNvdCve.class);
/**
* A collection of sources of data.
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ExceptionCollection.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ExceptionCollection.java
new file mode 100644
index 000000000..cf0a1015f
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ExceptionCollection.java
@@ -0,0 +1,214 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2016 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.exception;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A collection of several exceptions.
+ *
+ * @author Jeremy Lomg
+ */
+public class ExceptionCollection extends Exception {
+
+ /**
+ * Instantiates a new exception collection.
+ *
+ * @param exceptions a list of exceptions
+ */
+ public ExceptionCollection(List exceptions) {
+ super();
+ this.exceptions = exceptions;
+ }
+
+ /**
+ * Instantiates a new exception collection.
+ *
+ * @param msg the exception message
+ * @param exceptions a list of exceptions
+ */
+ public ExceptionCollection(String msg, List exceptions) {
+ super(msg);
+ this.exceptions = exceptions;
+ }
+
+ /**
+ * Instantiates a new exception collection.
+ *
+ * @param exceptions a list of exceptions
+ * @param fatal indicates if the exception that occurred is fatal - meaning
+ * that no analysis was performed.
+ */
+ public ExceptionCollection(List exceptions, boolean fatal) {
+ super();
+ this.exceptions = exceptions;
+ this.fatal = fatal;
+ }
+
+ /**
+ * Instantiates a new exception collection.
+ *
+ * @param msg the exception message
+ * @param exceptions a list of exceptions
+ * @param fatal indicates if the exception that occurred is fatal - meaning
+ * that no analysis was performed.
+ */
+ public ExceptionCollection(String msg, List exceptions, boolean fatal) {
+ super(msg);
+ this.exceptions = exceptions;
+ this.fatal = fatal;
+ }
+
+ /**
+ * Instantiates a new exception collection.
+ *
+ * @param exceptions a list of exceptions
+ * @param fatal indicates if the exception that occurred is fatal - meaning
+ * that no analysis was performed.
+ */
+ public ExceptionCollection(Throwable exceptions, boolean fatal) {
+ super();
+ this.exceptions = new ArrayList();
+ this.exceptions.add(exceptions);
+ this.fatal = fatal;
+ }
+ /**
+ * Instantiates a new exception collection.
+ *
+ * @param msg the exception message
+ * @param exception a list of exceptions
+ */
+ public ExceptionCollection(String msg, Throwable exception) {
+ super(msg);
+ this.exceptions = new ArrayList();
+ this.exceptions.add(exception);
+ this.fatal = false;
+ }
+
+ /**
+ * Instantiates a new exception collection.
+ */
+ public ExceptionCollection() {
+ super();
+ this.exceptions = new ArrayList();
+ }
+ /**
+ * The serial version uid.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * A collection of exceptions.
+ */
+ private List exceptions;
+
+ /**
+ * Get the value of exceptions.
+ *
+ * @return the value of exceptions
+ */
+ public List getExceptions() {
+ return exceptions;
+ }
+
+ /**
+ * Adds an exception to the collection.
+ *
+ * @param ex the exception to add
+ */
+ public void addException(Throwable ex) {
+ this.exceptions.add(ex);
+ }
+
+ /**
+ * Adds an exception to the collection.
+ *
+ * @param ex the exception to add
+ * @param fatal flag indicating if this is a fatal error
+ */
+ public void addException(Throwable ex, boolean fatal) {
+ addException(ex);
+ this.fatal = fatal;
+ }
+
+ /**
+ * Flag indicating if a fatal exception occurred that would prevent the
+ * attempt at completing the analysis even if exceptions occurred.
+ */
+ private boolean fatal = false;
+
+ /**
+ * Get the value of fatal.
+ *
+ * @return the value of fatal
+ */
+ public boolean isFatal() {
+ return fatal;
+ }
+
+ /**
+ * Set the value of fatal.
+ *
+ * @param fatal new value of fatal
+ */
+ public void setFatal(boolean fatal) {
+ this.fatal = fatal;
+ }
+
+ /**
+ * Prints the stack trace.
+ *
+ * @param s the writer to print to
+ */
+ @Override
+ public void printStackTrace(PrintWriter s) {
+ s.println("Multiple Exceptions Occured");
+ super.printStackTrace(s);
+ for (Throwable t : this.exceptions) {
+ s.println("Next Exception:");
+ t.printStackTrace(s);
+ }
+ }
+
+ /**
+ * Prints the stack trace.
+ *
+ * @param s the stream to write the stack trace to
+ */
+ @Override
+ public void printStackTrace(PrintStream s) {
+ s.println("Multiple Exceptions Occured");
+ super.printStackTrace(s);
+ for (Throwable t : this.exceptions) {
+ s.println("Next Exception:");
+ t.printStackTrace(s);
+ }
+ }
+
+ /**
+ * Prints the stack trace to standard error.
+ */
+ @Override
+ public void printStackTrace() {
+ this.printStackTrace(System.err);
+ }
+
+}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ReportException.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ReportException.java
new file mode 100644
index 000000000..7199b3520
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ReportException.java
@@ -0,0 +1,66 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2016 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.exception;
+
+/**
+ * An exception used when generating reports.
+ *
+ * @author Jeremy Long
+ */
+public class ReportException extends Exception {
+
+ /**
+ * The serial version uid.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new ReportException.
+ */
+ public ReportException() {
+ super();
+ }
+
+ /**
+ * Creates a new ReportException.
+ *
+ * @param msg a message for the exception.
+ */
+ public ReportException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new ReportException.
+ *
+ * @param ex the cause of the exception.
+ */
+ public ReportException(Throwable ex) {
+ super(ex);
+ }
+
+ /**
+ * Creates a new ReportException.
+ *
+ * @param msg a message for the exception.
+ * @param ex the cause of the exception.
+ */
+ public ReportException(String msg, Throwable ex) {
+ super(msg, ex);
+ }
+}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java
index b47f9a8b9..99b7b387d 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java
@@ -26,6 +26,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -37,13 +38,16 @@ import org.apache.velocity.runtime.RuntimeConstants;
import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.dependency.Dependency;
+import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * The ReportGenerator is used to, as the name implies, generate reports. Internally the generator uses the Velocity
- * Templating Engine. The ReportGenerator exposes a list of Dependencies to the template when generating the report.
+ * The ReportGenerator is used to, as the name implies, generate reports.
+ * Internally the generator uses the Velocity Templating Engine. The
+ * ReportGenerator exposes a list of Dependencies to the template when
+ * generating the report.
*
* @author Jeremy Long
*/
@@ -79,7 +83,7 @@ public class ReportGenerator {
/**
* The Velocity Engine.
*/
- private final VelocityEngine engine;
+ private final VelocityEngine velocityEngine;
/**
* The Velocity Engine Context.
*/
@@ -91,13 +95,14 @@ public class ReportGenerator {
* @param applicationName the application name being analyzed
* @param dependencies the list of dependencies
* @param analyzers the list of analyzers used
- * @param properties the database properties (containing timestamps of the NVD CVE data)
+ * @param properties the database properties (containing timestamps of the
+ * NVD CVE data)
*/
public ReportGenerator(String applicationName, List dependencies, List analyzers, DatabaseProperties properties) {
- engine = createVelocityEngine();
+ velocityEngine = createVelocityEngine();
context = createContext();
- engine.init();
+ velocityEngine.init();
final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy 'at' HH:mm:ss z");
final DateFormat dateFormatXML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
@@ -119,19 +124,19 @@ public class ReportGenerator {
/**
* Creates a new Velocity Engine.
*
- * @return a velocity engine.
+ * @return a velocity engine
*/
private VelocityEngine createVelocityEngine() {
- final VelocityEngine engine = new VelocityEngine();
+ final VelocityEngine velocity = new VelocityEngine();
// Logging redirection for Velocity - Required by Jenkins and other server applications
- engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
- return engine;
+ velocity.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
+ return velocity;
}
/**
* Creates a new Velocity Context.
*
- * @return a Velocity Context.
+ * @return a Velocity Context
*/
private Context createContext() {
return new VelocityContext();
@@ -143,7 +148,7 @@ public class ReportGenerator {
* @param outputStream the OutputStream to send the generated report to
* @param format the format the report should be written in
* @throws IOException is thrown when the template file does not exist
- * @throws Exception is thrown if there is an error writing out the reports.
+ * @throws Exception is thrown if there is an error writing out the reports
*/
public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception {
if (format == Format.XML || format == Format.ALL) {
@@ -162,10 +167,9 @@ public class ReportGenerator {
*
* @param outputDir the path where the reports should be written
* @param format the format the report should be written in
- * @throws IOException is thrown when the template file does not exist
- * @throws Exception is thrown if there is an error writing out the reports.
+ * @throws ReportException is thrown if there is an error writing out the reports
*/
- public void generateReports(String outputDir, Format format) throws IOException, Exception {
+ public void generateReports(String outputDir, Format format) throws ReportException {
if (format == Format.XML || format == Format.ALL) {
generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
}
@@ -181,11 +185,12 @@ public class ReportGenerator {
* Generates the Dependency Reports for the identified dependencies.
*
* @param outputDir the path where the reports should be written
- * @param outputFormat the format the report should be written in (XML, HTML, ALL)
- * @throws IOException is thrown when the template file does not exist
- * @throws Exception is thrown if there is an error writing out the reports.
+ * @param outputFormat the format the report should be written in (XML,
+ * HTML, ALL)
+ * @throws ReportException is thrown if there is an error creating out the
+ * reports
*/
- public void generateReports(String outputDir, String outputFormat) throws IOException, Exception {
+ public void generateReports(String outputDir, String outputFormat) throws ReportException {
final String format = outputFormat.toUpperCase();
final String pathToCheck = outputDir.toLowerCase();
if (format.matches("^(XML|HTML|VULN|ALL)$")) {
@@ -217,16 +222,16 @@ public class ReportGenerator {
}
/**
- * Generates a report from a given Velocity Template. The template name provided can be the name of a template
- * contained in the jar file, such as 'XmlReport' or 'HtmlReport', or the template name can be the path to a
+ * Generates a report from a given Velocity Template. The template name
+ * provided can be the name of a template contained in the jar file, such as
+ * 'XmlReport' or 'HtmlReport', or the template name can be the path to a
* template file.
*
- * @param templateName the name of the template to load.
- * @param outputStream the OutputStream to write the report to.
- * @throws IOException is thrown when the template file does not exist.
- * @throws Exception is thrown when an exception occurs.
+ * @param templateName the name of the template to load
+ * @param outputStream the OutputStream to write the report to
+ * @throws ReportException is thrown when an exception occurs
*/
- protected void generateReport(String templateName, OutputStream outputStream) throws IOException, Exception {
+ protected void generateReport(String templateName, OutputStream outputStream) throws ReportException {
InputStream input = null;
String templatePath = null;
final File f = new File(templateName);
@@ -235,27 +240,30 @@ public class ReportGenerator {
templatePath = templateName;
input = new FileInputStream(f);
} catch (FileNotFoundException ex) {
- LOGGER.error("Unable to generate the report, the report template file could not be found.");
- LOGGER.debug("", ex);
+ throw new ReportException("Unable to locate template file: " + templateName, ex);
}
} else {
templatePath = "templates/" + templateName + ".vsl";
input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
}
if (input == null) {
- throw new IOException("Template file doesn't exist");
+ throw new ReportException("Template file doesn't exist: " + templatePath);
}
- final InputStreamReader reader = new InputStreamReader(input, "UTF-8");
+ InputStreamReader reader = null;
OutputStreamWriter writer = null;
try {
+ reader = new InputStreamReader(input, "UTF-8");
writer = new OutputStreamWriter(outputStream, "UTF-8");
-
- if (!engine.evaluate(context, writer, templatePath, reader)) {
- throw new Exception("Failed to convert the template into html.");
+ if (!velocityEngine.evaluate(context, writer, templatePath, reader)) {
+ throw new ReportException("Failed to convert the template into html.");
}
writer.flush();
+ } catch (UnsupportedEncodingException ex) {
+ throw new ReportException("Unable to generate the report using UTF-8", ex);
+ } catch (IOException ex) {
+ throw new ReportException("Unable to write the report", ex);
} finally {
if (writer != null) {
try {
@@ -271,25 +279,27 @@ public class ReportGenerator {
LOGGER.trace("", ex);
}
}
- try {
- reader.close();
- } catch (IOException ex) {
- LOGGER.trace("", ex);
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ex) {
+ LOGGER.trace("", ex);
+ }
}
}
}
/**
- * Generates a report from a given Velocity Template. The template name provided can be the name of a template
- * contained in the jar file, such as 'XmlReport' or 'HtmlReport', or the template name can be the path to a
+ * Generates a report from a given Velocity Template. The template name
+ * provided can be the name of a template contained in the jar file, such as
+ * 'XmlReport' or 'HtmlReport', or the template name can be the path to a
* template file.
*
- * @param templateName the name of the template to load.
- * @param outFileName the filename and path to write the report to.
- * @throws IOException is thrown when the template file does not exist.
- * @throws Exception is thrown when an exception occurs.
+ * @param templateName the name of the template to load
+ * @param outFileName the filename and path to write the report to
+ * @throws ReportException is thrown when the report cannot be generated
*/
- protected void generateReport(String templateName, String outFileName) throws Exception {
+ protected void generateReport(String templateName, String outFileName) throws ReportException {
File outFile = new File(outFileName);
if (outFile.getParentFile() == null) {
outFile = new File(".", outFileName);
@@ -297,7 +307,7 @@ public class ReportGenerator {
if (!outFile.getParentFile().exists()) {
final boolean created = outFile.getParentFile().mkdirs();
if (!created) {
- throw new Exception("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
+ throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
}
}
@@ -305,6 +315,8 @@ public class ReportGenerator {
try {
outputSteam = new FileOutputStream(outFile);
generateReport(templateName, outputSteam);
+ } catch (FileNotFoundException ex) {
+ throw new ReportException("Unable to write to file: " + outFile, ex);
} finally {
if (outputSteam != null) {
try {
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java
index 483413dcb..b91510b1e 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java
@@ -39,6 +39,11 @@ public final class DependencyVersionUtil {
* are missing a version number using the previous regex.
*/
private static final Pattern RX_SINGLE_VERSION = Pattern.compile("\\d+(\\.?([_-](release|beta|alpha)|[a-zA-Z_-]{1,3}\\d{1,8}))?");
+
+ /**
+ * Regular expression to extract the part before the version numbers if there are any based on RX_VERSION. In most cases, this part represents a more accurate name.
+ */
+ private static final Pattern RX_PRE_VERSION = Pattern.compile("^(.+)[_-](\\d+\\.\\d{1,6})+");
/**
* Private constructor for utility class.
@@ -95,4 +100,27 @@ public final class DependencyVersionUtil {
}
return new DependencyVersion(version);
}
+
+ /**
+ *
+ * A utility class to extract the part before version numbers from file names (or other strings containing version numbers.
+ * In most cases, this part represents a more accurate name than the full file name.
+ *
+ * Example:
+ * Give the file name: library-name-1.4.1r2-release.jar
+ * This function would return: library-name
+ *
+ * @param text the text being analyzed
+ * @return the part before the version numbers if any, otherwise return the text itself.
+ */
+ public static String parsePreVersion(String text) {
+ if(parseVersion(text) == null)
+ return text;
+
+ Matcher matcher = RX_PRE_VERSION.matcher(text);
+ if (matcher.find()) {
+ return matcher.group(1);
+ }
+ return text;
+ }
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/HintHandler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/HintHandler.java
index c5bd0f7b3..9634fb3d2 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/HintHandler.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/HintHandler.java
@@ -197,11 +197,11 @@ public class HintHandler extends DefaultHandler {
vendorDuplicatingHintRules.add(new VendorDuplicatingHintRule(attr.getValue(VALUE), attr.getValue(DUPLICATE)));
}
}
-
+
/**
* Handles the end element event.
*
- * @param uri the element's uri
+ * @param uri the element's URI
* @param localName the local name
* @param qName the qualified name
* @throws SAXException thrown if there is an exception processing the
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/HintRule.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/HintRule.java
index ec85d98f2..1d9df8d4d 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/HintRule.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/HintRule.java
@@ -72,9 +72,9 @@ public class HintRule {
}
/**
- * Get the value of givenProduct
+ * Get the value of givenProduct.
*
- * @return the value of givenProduct.
+ * @return the value of givenProduct
*/
public List getGivenProduct() {
return givenProduct;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/Hints.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/Hints.java
index 0240d2fc1..34e465004 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/Hints.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/hints/Hints.java
@@ -32,7 +32,7 @@ public class Hints {
private List hintRules;
/**
- * Get the value of hintRules
+ * Get the value of hintRules.
*
* @return the value of hintRules
*/
@@ -41,7 +41,7 @@ public class Hints {
}
/**
- * Set the value of hintRules
+ * Set the value of hintRules.
*
* @param hintRules new value of hintRules
*/
@@ -55,7 +55,7 @@ public class Hints {
private List vendorDuplicatingHintRules;
/**
- * Get the value of vendorDuplicatingHintRules
+ * Get the value of vendorDuplicatingHintRules.
*
* @return the value of vendorDuplicatingHintRules
*/
@@ -64,12 +64,11 @@ public class Hints {
}
/**
- * Set the value of vendorDuplicatingHintRules
+ * Set the value of vendorDuplicatingHintRules.
*
* @param vendorDuplicatingHintRules new value of vendorDuplicatingHintRules
*/
public void setVendorDuplicatingHintRules(List vendorDuplicatingHintRules) {
this.vendorDuplicatingHintRules = vendorDuplicatingHintRules;
}
-
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionErrorHandler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionErrorHandler.java
index bacbcb5a0..e36bc5365 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionErrorHandler.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionErrorHandler.java
@@ -70,7 +70,7 @@ public class SuppressionErrorHandler implements ErrorHandler {
*/
@Override
public void warning(SAXParseException ex) throws SAXException {
- LOGGER.debug("", ex);
+ //LOGGER.debug("", ex);
}
/**
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/EngineIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/EngineIntegrationTest.java
index 1e12e6a82..bceefc23b 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/EngineIntegrationTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/EngineIntegrationTest.java
@@ -17,12 +17,19 @@
*/
package org.owasp.dependencycheck;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
+import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
+import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.reporting.ReportGenerator;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
/**
@@ -34,10 +41,14 @@ public class EngineIntegrationTest extends BaseDBTestCase {
/**
* Test running the entire engine.
*
- * @throws Exception is thrown when an exception occurs.
+ * @throws java.io.IOException
+ * @throws org.owasp.dependencycheck.utils.InvalidSettingException
+ * @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException
+ * @throws org.owasp.dependencycheck.exception.ReportException
+ * @throws org.owasp.dependencycheck.exception.ExceptionCollection
*/
@Test
- public void testEngine() throws Exception {
+ public void testEngine() throws IOException, InvalidSettingException, DatabaseException, ReportException, ExceptionCollection {
String testClasses = "target/test-classes";
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
@@ -45,7 +56,23 @@ public class EngineIntegrationTest extends BaseDBTestCase {
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
instance.scan(testClasses);
assertTrue(instance.getDependencies().size() > 0);
- instance.analyzeDependencies();
+ try {
+ instance.analyzeDependencies();
+ } catch (ExceptionCollection ex) {
+ if (ex.getExceptions().size()==1 &&
+ (ex.getExceptions().get(0).getMessage().contains("bundle-audit") ||
+ ex.getExceptions().get(0).getMessage().contains("AssemblyAnalyzer"))) {
+ //this is fine to ignore
+ } else if (ex.getExceptions().size()==2 &&
+ ((ex.getExceptions().get(0).getMessage().contains("bundle-audit") &&
+ ex.getExceptions().get(1).getMessage().contains("AssemblyAnalyzer")) ||
+ (ex.getExceptions().get(1).getMessage().contains("bundle-audit") &&
+ ex.getExceptions().get(0).getMessage().contains("AssemblyAnalyzer")))) {
+ //this is fine to ignore
+ } else {
+ throw ex;
+ }
+ }
CveDB cveDB = new CveDB();
cveDB.open();
DatabaseProperties dbProp = cveDB.getDatabaseProperties();
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java
index 6299850ee..c1b57ab66 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java
@@ -26,6 +26,7 @@ import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.util.logging.Level;
import org.junit.After;
import org.junit.Assume;
@@ -40,6 +41,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -175,6 +177,7 @@ public class RubyBundleAuditAnalyzerTest extends BaseDBTestCase {
* Test Ruby dependencies and their paths.
*
* @throws AnalysisException is thrown when an exception occurs.
+ * @throws DatabaseException thrown when an exception occurs
*/
@Test
public void testDependenciesPath() throws AnalysisException, DatabaseException {
@@ -186,6 +189,8 @@ public class RubyBundleAuditAnalyzerTest extends BaseDBTestCase {
} catch (NullPointerException ex) {
LOGGER.error("NPE", ex);
throw ex;
+ } catch (ExceptionCollection ex) {
+ Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", ex);
}
List dependencies = engine.getDependencies();
LOGGER.info(dependencies.size() + " dependencies found.");
diff --git a/dependency-check-maven/pom.xml b/dependency-check-maven/pom.xml
index aa33ce2f8..d6f48ff87 100644
--- a/dependency-check-maven/pom.xml
+++ b/dependency-check-maven/pom.xml
@@ -20,7 +20,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
org.owasp
dependency-check-parent
- 1.4.1-SNAPSHOT
+ 1.4.3-SNAPSHOT
dependency-check-maven
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
index f801f000d..d17854dd0 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
@@ -36,11 +36,13 @@ import org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
+import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.utils.Settings;
/**
- * Maven Plugin that checks project dependencies and the dependencies of all child modules to see if they have any known published
- * vulnerabilities.
+ * Maven Plugin that checks project dependencies and the dependencies of all
+ * child modules to see if they have any known published vulnerabilities.
*
* @author Jeremy Long
*/
@@ -55,18 +57,27 @@ import org.owasp.dependencycheck.utils.Settings;
public class AggregateMojo extends BaseDependencyCheckMojo {
/**
- * Executes the aggregate dependency-check goal. This runs dependency-check and generates the subsequent reports.
+ * The key to store aggregate exception in the root Maven execution context.
+ */
+ private static final String AGGREGATE_EXCEPTIONS = "AggregateExceptions";
+
+ /**
+ * Executes the aggregate dependency-check goal. This runs dependency-check
+ * and generates the subsequent reports.
*
- * @throws MojoExecutionException thrown if there is ane exception running the mojo
- * @throws MojoFailureException thrown if dependency-check is configured to fail the build
+ * @throws MojoExecutionException thrown if there is ane exception running
+ * the mojo
+ * @throws MojoFailureException thrown if dependency-check is configured to
+ * fail the build
*/
@Override
public void runCheck() throws MojoExecutionException, MojoFailureException {
- final Engine engine = generateDataFile();
+ final MavenEngine engine = generateDataFile();
+ if (engine == null) {
+ return;
+ }
- //if (getProject() == getReactorProjects().get(getReactorProjects().size() - 1)) {
if (getProject() == getLastProject()) {
-
//ensure that the .ser file was created for each.
for (MavenProject current : getReactorProjects()) {
final File dataFile = getDataFile(current);
@@ -76,7 +87,6 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
generateDataFile(engine, current);
}
}
-
for (MavenProject current : getReactorProjects()) {
List dependencies = readDataFile(current);
if (dependencies == null) {
@@ -90,10 +100,8 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
getLog().debug(String.format("Adding %d dependencies from %s", childDeps.size(), reportOn.getName()));
}
dependencies.addAll(childDeps);
- } else {
- if (getLog().isDebugEnabled()) {
- getLog().debug(String.format("No dependencies read for %s", reportOn.getName()));
- }
+ } else if (getLog().isDebugEnabled()) {
+ getLog().debug(String.format("No dependencies read for %s", reportOn.getName()));
}
}
engine.getDependencies().clear();
@@ -118,7 +126,21 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
//we shouldn't write this because nothing is configured to generate this report.
outputDir = new File(current.getBuild().getDirectory());
}
- writeReports(engine, current, outputDir);
+ try {
+ writeReports(engine, current, outputDir);
+ } catch (ReportException ex) {
+ ExceptionCollection exCol = (ExceptionCollection) engine.getExecutionRoot().getContextValue(AGGREGATE_EXCEPTIONS);
+ if (exCol == null) {
+ exCol = new ExceptionCollection("Error writing aggregate report", ex);
+ } else {
+ exCol.addException(ex);
+ }
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException("One or more exceptions occured during dependency-check analysis", exCol);
+ } else {
+ getLog().debug("One or more exceptions occured during dependency-check analysis", exCol);
+ }
+ }
}
}
engine.cleanup();
@@ -126,7 +148,8 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
}
/**
- * Gets the last project in the reactor - taking into account skipped projects.
+ * Gets the last project in the reactor - taking into account skipped
+ * projects.
*
* @return the last project in the reactor
*/
@@ -152,7 +175,8 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
}
/**
- * Returns a set containing all the descendant projects of the given project.
+ * Returns a set containing all the descendant projects of the given
+ * project.
*
* @param project the project for which all descendants will be returned
* @return the set of descendant projects
@@ -232,49 +256,85 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
* Test if the project has pom packaging
*
* @param mavenProject Project to test
- * @return true if it has a pom packaging; otherwise false
+ * @return true if it has a pom packaging; otherwise
+ * false
*/
protected boolean isMultiModule(MavenProject mavenProject) {
return "pom".equals(mavenProject.getPackaging());
}
/**
- * Initializes the engine, runs a scan, and writes the serialized dependencies to disk.
+ * Initializes the engine, runs a scan, and writes the serialized
+ * dependencies to disk.
*
- * @return the Engine used to execute dependency-check
- * @throws MojoExecutionException thrown if there is an exception running the mojo
- * @throws MojoFailureException thrown if dependency-check is configured to fail the build if severe CVEs are identified.
+ * @return the MavenEngine used to execute dependency-check
+ * @throws MojoExecutionException thrown if there is an exception running
+ * the mojo
+ * @throws MojoFailureException thrown if dependency-check is configured to
+ * fail the build if severe CVEs are identified.
*/
- protected Engine generateDataFile() throws MojoExecutionException, MojoFailureException {
- final Engine engine;
+ protected MavenEngine generateDataFile() throws MojoExecutionException, MojoFailureException {
+ MavenEngine engine = null;
try {
engine = initializeEngine();
} catch (DatabaseException ex) {
if (getLog().isDebugEnabled()) {
getLog().debug("Database connection error", ex);
}
- throw new MojoExecutionException("An exception occured connecting to the local database. Please see the log file for more details.", ex);
+ final String msg = "An exception occured connecting to the local database. Please see the log file for more details.";
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException(msg, ex);
+ }
+ getLog().error(msg, ex);
+ return null;
}
return generateDataFile(engine, getProject());
}
/**
- * Runs dependency-check's Engine and writes the serialized dependencies to disk.
+ * Runs dependency-check's MavenEngine and writes the serialized
+ * dependencies to disk.
*
- * @param engine the Engine to use when scanning.
+ * @param engine the MavenEngine to use when scanning.
* @param project the project to scan and generate the data file for
- * @return the Engine used to execute dependency-check
- * @throws MojoExecutionException thrown if there is an exception running the mojo
- * @throws MojoFailureException thrown if dependency-check is configured to fail the build if severe CVEs are identified.
+ * @return the MavenEngine used to execute dependency-check
+ * @throws MojoExecutionException thrown if there is an exception running
+ * the mojo
+ * @throws MojoFailureException thrown if dependency-check is configured to
+ * fail the build if severe CVEs are identified.
*/
- protected Engine generateDataFile(Engine engine, MavenProject project) throws MojoExecutionException, MojoFailureException {
+ protected MavenEngine generateDataFile(MavenEngine engine, MavenProject project) throws MojoExecutionException, MojoFailureException {
if (getLog().isDebugEnabled()) {
getLog().debug(String.format("Begin Scanning: %s", project.getName()));
}
engine.getDependencies().clear();
engine.resetFileTypeAnalyzers();
scanArtifacts(project, engine);
- engine.analyzeDependencies();
+ try {
+ engine.analyzeDependencies();
+ } catch (ExceptionCollection ex) {
+ ExceptionCollection col = (ExceptionCollection) engine.getExecutionRoot().getContextValue(AGGREGATE_EXCEPTIONS);
+ if (col == null) {
+ col = ex;
+ } else if (ex.isFatal()) {
+ col.setFatal(true);
+ col.getExceptions().addAll(ex.getExceptions());
+ }
+ if (col.isFatal()) {
+ final String msg = String.format("Fatal exception(s) analyzing %s", project.getName());
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException(msg, ex);
+ }
+ getLog().error(msg, col);
+ return null;
+ } else {
+ final String msg = String.format("Exception(s) analyzing %s", project.getName());
+ if (getLog().isDebugEnabled()) {
+ getLog().debug(msg, ex);
+ }
+ engine.getExecutionRoot().setContextValue(AGGREGATE_EXCEPTIONS, col);
+ }
+ }
final File target = new File(project.getBuild().getDirectory());
writeDataFile(project, target, engine.getDependencies());
showSummary(project, engine.getDependencies());
@@ -306,7 +366,8 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
}
/**
- * Gets the description of the Dependency-Check report to be displayed in the Maven Generated Reports page.
+ * Gets the description of the Dependency-Check report to be displayed in
+ * the Maven Generated Reports page.
*
* @param locale The Locale to get the description for
* @return the description
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
index aff052420..3df3f6d75 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
@@ -47,6 +47,7 @@ import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
+import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.utils.ExpectedOjectInputStream;
import org.owasp.dependencycheck.utils.Settings;
@@ -69,14 +70,28 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
* System specific new line character.
*/
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
+ //
+ //
/**
* Sets whether or not the external report format should be used.
*/
@Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
private String dataFileName;
+ /**
+ * Sets whether or not the external report format should be used.
+ */
+ @Parameter(property = "failOnError", defaultValue = "true", required = true)
+ private boolean failOnError;
+
+ /**
+ * Returns if the mojo should fail the build if an exception occurs.
+ *
+ * @return whether or not the mojo should fail the build
+ */
+ protected boolean isFailOnError() {
+ return failOnError;
+ }
- //
- //
/**
* The Maven Project Object.
*/
@@ -111,13 +126,11 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
* recommended that this be turned to false. Default is true.
*/
- @SuppressWarnings("CanBeFinal")
@Parameter(property = "autoUpdate")
private Boolean autoUpdate;
/**
* Sets whether Experimental analyzers are enabled. Default is false.
*/
- @SuppressWarnings("CanBeFinal")
@Parameter(property = "enableExperimental")
private Boolean enableExperimental;
/**
@@ -145,7 +158,6 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
/**
* The maven settings proxy id.
*/
- @SuppressWarnings("CanBeFinal")
@Parameter(property = "mavenSettingsProxyId", required = false)
private String mavenSettingsProxyId;
@@ -162,6 +174,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
/**
* Flag indicating whether or not to show a summary in the output.
*/
+ @SuppressWarnings("CanBeFinal")
@Parameter(property = "showSummary", defaultValue = "true", required = false)
private boolean showSummary = true;
@@ -541,7 +554,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
* @param project the project to scan the dependencies of
* @param engine the engine to use to scan the dependencies
*/
- protected void scanArtifacts(MavenProject project, Engine engine) {
+ protected void scanArtifacts(MavenProject project, MavenEngine engine) {
for (Artifact a : project.getArtifacts()) {
if (excludeFromScan(a)) {
continue;
@@ -649,14 +662,14 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
//
/**
- * Initializes a new Engine that can be used for scanning.
+ * Initializes a new MavenEngine that can be used for scanning.
*
- * @return a newly instantiated Engine
+ * @return a newly instantiated MavenEngine
* @throws DatabaseException thrown if there is a database exception
*/
- protected Engine initializeEngine() throws DatabaseException {
+ protected MavenEngine initializeEngine() throws DatabaseException {
populateSettings();
- return new Engine(this.project,
+ return new MavenEngine(this.project,
this.reactorProjects);
}
@@ -875,10 +888,11 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
* Generates the reports for a given dependency-check engine.
*
* @param engine a dependency-check engine
- * @param p the maven project
- * @param outputDir the directory path to write the report(s).
+ * @param p the Maven project
+ * @param outputDir the directory path to write the report(s)
+ * @throws ReportException thrown if there is an error writing the report
*/
- protected void writeReports(Engine engine, MavenProject p, File outputDir) {
+ protected void writeReports(MavenEngine engine, MavenProject p, File outputDir) throws ReportException {
DatabaseProperties prop = null;
CveDB cve = null;
try {
@@ -897,19 +911,11 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
final ReportGenerator r = new ReportGenerator(p.getName(), engine.getDependencies(), engine.getAnalyzers(), prop);
try {
r.generateReports(outputDir.getAbsolutePath(), format);
- } catch (IOException ex) {
- getLog().error(
- "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
- if (getLog().isDebugEnabled()) {
- getLog().debug("", ex);
- }
- } catch (Throwable ex) {
- getLog().error(
- "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
- if (getLog().isDebugEnabled()) {
- getLog().debug("", ex);
- }
+ } catch (ReportException ex) {
+ final String msg = String.format("Error generating the report for %s", p.getName());
+ throw new ReportException(msg, ex);
}
+
}
//
@@ -1074,8 +1080,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
* scan data between the "check" and "aggregate" phase.
*
* @param project the Maven project to read the data file from
- * @return a Engine object populated with dependencies if the
- * serialized data file exists; otherwise null is returned
+ * @return a MavenEngine object populated with dependencies if
+ * the serialized data file exists; otherwise null is returned
*/
protected List readDataFile(MavenProject project) {
final Object oPath = project.getContextValue(this.getDataFileContextKey());
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java
index 17ba52bf1..ccada1b5c 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java
@@ -26,10 +26,13 @@ import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
+import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.utils.Settings;
/**
- * Maven Plugin that checks the project dependencies to see if they have any known published vulnerabilities.
+ * Maven Plugin that checks the project dependencies to see if they have any
+ * known published vulnerabilities.
*
* @author Jeremy Long
*/
@@ -45,7 +48,8 @@ public class CheckMojo extends BaseDependencyCheckMojo {
/**
* Returns whether or not a the report can be generated.
*
- * @return true if the report can be generated; otherwise false
+ * @return true if the report can be generated; otherwise
+ * false
*/
@Override
public boolean canGenerateReport() {
@@ -60,33 +64,65 @@ public class CheckMojo extends BaseDependencyCheckMojo {
}
/**
- * Executes the dependency-check engine on the project's dependencies and generates the report.
+ * Executes the dependency-check engine on the project's dependencies and
+ * generates the report.
*
- * @throws MojoExecutionException thrown if there is an exception executing the goal
- * @throws MojoFailureException thrown if dependency-check is configured to fail the build
+ * @throws MojoExecutionException thrown if there is an exception executing
+ * the goal
+ * @throws MojoFailureException thrown if dependency-check is configured to
+ * fail the build
*/
@Override
public void runCheck() throws MojoExecutionException, MojoFailureException {
- final Engine engine;
+ MavenEngine engine = null;
try {
engine = initializeEngine();
} catch (DatabaseException ex) {
if (getLog().isDebugEnabled()) {
getLog().debug("Database connection error", ex);
}
- throw new MojoExecutionException("An exception occured connecting to the local database. Please see the log file for more details.", ex);
+ final String msg = "An exception occured connecting to the local database. Please see the log file for more details.";
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException(msg, ex);
+ }
+ getLog().error(msg);
}
- scanArtifacts(getProject(), engine);
- if (engine.getDependencies().isEmpty()) {
- getLog().info("No dependencies were identified that could be analyzed by dependency-check");
- } else {
- engine.analyzeDependencies();
- writeReports(engine, getProject(), getCorrectOutputDirectory());
- writeDataFile(getProject(), null, engine.getDependencies());
- showSummary(getProject(), engine.getDependencies());
- checkForFailure(engine.getDependencies());
+ if (engine != null) {
+ scanArtifacts(getProject(), engine);
+ if (engine.getDependencies().isEmpty()) {
+ getLog().info("No dependencies were identified that could be analyzed by dependency-check");
+ } else {
+ ExceptionCollection exCol = null;
+ try {
+ engine.analyzeDependencies();
+ } catch (ExceptionCollection ex) {
+ if (this.isFailOnError() && ex.isFatal()) {
+ throw new MojoExecutionException("One or more exceptions occured during analysis", ex);
+ }
+ exCol = ex;
+ }
+ if (exCol == null || !exCol.isFatal()) {
+ try {
+ writeReports(engine, getProject(), getCorrectOutputDirectory());
+ } catch (ReportException ex) {
+ if (this.isFailOnError()) {
+ if (exCol != null) {
+ exCol.addException(ex);
+ } else {
+ exCol = new ExceptionCollection("Unable to write the dependency-check report", ex);
+ }
+ }
+ }
+ writeDataFile(getProject(), null, engine.getDependencies());
+ showSummary(getProject(), engine.getDependencies());
+ checkForFailure(engine.getDependencies());
+ if (exCol != null && this.isFailOnError()) {
+ throw new MojoExecutionException("One or more exceptions occured during dependency-check analysis", exCol);
+ }
+ }
+ }
+ engine.cleanup();
}
- engine.cleanup();
Settings.cleanup();
}
@@ -109,7 +145,8 @@ public class CheckMojo extends BaseDependencyCheckMojo {
}
/**
- * Gets the description of the Dependency-Check report to be displayed in the Maven Generated Reports page.
+ * Gets the description of the Dependency-Check report to be displayed in
+ * the Maven Generated Reports page.
*
* @param locale The Locale to get the description for
* @return the description
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/Engine.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/MavenEngine.java
similarity index 81%
rename from dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/Engine.java
rename to dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/MavenEngine.java
index f849c8a7e..9edf53ae4 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/Engine.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/MavenEngine.java
@@ -23,22 +23,25 @@ import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.analyzer.CPEAnalyzer;
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
+import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * A modified version of the core engine specifically designed to persist some data between multiple executions of a multi-module
- * Maven project.
+ * A modified version of the core engine specifically designed to persist some
+ * data between multiple executions of a multi-module Maven project.
*
* @author Jeremy Long
*/
-public class Engine extends org.owasp.dependencycheck.Engine {
+public class MavenEngine extends org.owasp.dependencycheck.Engine {
/**
* The logger.
*/
- private static final transient Logger LOGGER = LoggerFactory.getLogger(Engine.class);
+ private static final transient Logger LOGGER = LoggerFactory.getLogger(MavenEngine.class);
/**
* A key used to persist an object in the MavenProject.
*/
@@ -52,18 +55,21 @@ public class Engine extends org.owasp.dependencycheck.Engine {
*/
private List reactorProjects;
/**
- * Key used in the MavenProject context values to note whether or not an update has been executed.
+ * Key used in the MavenProject context values to note whether or not an
+ * update has been executed.
*/
public static final String UPDATE_EXECUTED_FLAG = "dependency-check-update-executed";
/**
- * Creates a new Engine to perform anyalsis on dependencies.
+ * Creates a new Engine to perform analysis on dependencies.
*
* @param project the current Maven project
- * @param reactorProjects the reactor projects for the current Maven execution
- * @throws DatabaseException thrown if there is an issue connecting to the database
+ * @param reactorProjects the reactor projects for the current Maven
+ * execution
+ * @throws DatabaseException thrown if there is an issue connecting to the
+ * database
*/
- public Engine(MavenProject project, List reactorProjects) throws DatabaseException {
+ public MavenEngine(MavenProject project, List reactorProjects) throws DatabaseException {
this.currentProject = project;
this.reactorProjects = reactorProjects;
initializeEngine();
@@ -71,9 +77,12 @@ public class Engine extends org.owasp.dependencycheck.Engine {
/**
* Runs the analyzers against all of the dependencies.
+ *
+ * @throws ExceptionCollection thrown if an exception occurred; contains a
+ * collection of exceptions that occurred during analysis.
*/
@Override
- public void analyzeDependencies() {
+ public void analyzeDependencies() throws ExceptionCollection {
final MavenProject root = getExecutionRoot();
if (root != null) {
LOGGER.debug("Checking root project, {}, if updates have already been completed", root.getArtifactId());
@@ -91,8 +100,10 @@ public class Engine extends org.owasp.dependencycheck.Engine {
/**
* Runs the update steps of dependency-check.
+ *
+ * @throws UpdateException thrown if there is an exception
*/
- public void update() {
+ public void update() throws UpdateException {
final MavenProject root = getExecutionRoot();
if (root != null && root.getContextValue(UPDATE_EXECUTED_FLAG) != null) {
System.setProperty(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE.toString());
@@ -103,20 +114,21 @@ public class Engine extends org.owasp.dependencycheck.Engine {
/**
* This constructor should not be called. Use Engine(MavenProject) instead.
*
- * @throws DatabaseException thrown if there is an issue connecting to the database
+ * @throws DatabaseException thrown if there is an issue connecting to the
+ * database
*/
- private Engine() throws DatabaseException {
+ private MavenEngine() throws DatabaseException {
}
/**
- * Initializes the given analyzer. This skips the initialization of the CPEAnalyzer if it has been initialized by a previous
- * execution.
+ * Initializes the given analyzer. This skips the initialization of the
+ * CPEAnalyzer if it has been initialized by a previous execution.
*
* @param analyzer the analyzer to initialize
* @return the initialized analyzer
*/
@Override
- protected Analyzer initializeAnalyzer(Analyzer analyzer) {
+ protected Analyzer initializeAnalyzer(Analyzer analyzer) throws InitializationException {
if (analyzer instanceof CPEAnalyzer) {
CPEAnalyzer cpe = getPreviouslyLoadedCPEAnalyzer();
if (cpe != null && cpe.isOpen()) {
@@ -129,7 +141,8 @@ public class Engine extends org.owasp.dependencycheck.Engine {
}
/**
- * Releases resources used by the analyzers by calling close() on each analyzer.
+ * Releases resources used by the analyzers by calling close() on each
+ * analyzer.
*/
@Override
public void cleanup() {
@@ -195,7 +208,7 @@ public class Engine extends org.owasp.dependencycheck.Engine {
*
* @return the root Maven Project
*/
- private MavenProject getExecutionRoot() {
+ MavenProject getExecutionRoot() {
if (reactorProjects == null) {
return null;
}
@@ -216,8 +229,10 @@ public class Engine extends org.owasp.dependencycheck.Engine {
}
/**
- * Resets the file type analyzers so that they can be re-used to scan additional directories. Without the reset the analyzer
- * might be disabled because the first scan/analyze did not identify any files that could be processed by the analyzer.
+ * Resets the file type analyzers so that they can be re-used to scan
+ * additional directories. Without the reset the analyzer might be disabled
+ * because the first scan/analyze did not identify any files that could be
+ * processed by the analyzer.
*/
public void resetFileTypeAnalyzers() {
for (FileTypeAnalyzer a : getFileTypeAnalyzers()) {
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/PurgeMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/PurgeMojo.java
index 2075a2c0c..62c14a0dd 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/PurgeMojo.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/PurgeMojo.java
@@ -54,14 +54,20 @@ public class PurgeMojo extends BaseDependencyCheckMojo {
/**
* Purges the local copy of the NVD.
*
- * @throws MojoExecutionException thrown if there is an exception executing the goal
- * @throws MojoFailureException thrown if dependency-check is configured to fail the build
+ * @throws MojoExecutionException thrown if there is an exception executing
+ * the goal
+ * @throws MojoFailureException thrown if dependency-check is configured to
+ * fail the build
*/
@Override
public void runCheck() throws MojoExecutionException, MojoFailureException {
if (getConnectionString() != null && !getConnectionString().isEmpty()) {
- getLog().error("Unable to purge the local NVD when using a non-default connection string");
+ final String msg = "Unable to purge the local NVD when using a non-default connection string";
+ if (this.isFailOnError()) {
+ throw new MojoFailureException(msg);
+ }
+ getLog().error(msg);
} else {
populateSettings();
File db;
@@ -71,13 +77,25 @@ public class PurgeMojo extends BaseDependencyCheckMojo {
if (db.delete()) {
getLog().info("Database file purged; local copy of the NVD has been removed");
} else {
- getLog().error(String.format("Unable to delete '%s'; please delete the file manually", db.getAbsolutePath()));
+ final String msg = String.format("Unable to delete '%s'; please delete the file manually", db.getAbsolutePath());
+ if (this.isFailOnError()) {
+ throw new MojoFailureException(msg);
+ }
+ getLog().error(msg);
}
} else {
- getLog().error(String.format("Unable to purge database; the database file does not exists: %s", db.getAbsolutePath()));
+ final String msg = String.format("Unable to purge database; the database file does not exists: %s", db.getAbsolutePath());
+ if (this.isFailOnError()) {
+ throw new MojoFailureException(msg);
+ }
+ getLog().error(msg);
}
} catch (IOException ex) {
- getLog().error("Unable to delete the database");
+ final String msg = "Unable to delete the database";
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException(msg, ex);
+ }
+ getLog().error(msg);
}
Settings.cleanup();
}
@@ -95,7 +113,8 @@ public class PurgeMojo extends BaseDependencyCheckMojo {
}
/**
- * Gets the description of the Dependency-Check report to be displayed in the Maven Generated Reports page.
+ * Gets the description of the Dependency-Check report to be displayed in
+ * the Maven Generated Reports page.
*
* @param locale The Locale to get the description for
* @return the description
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/UpdateMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/UpdateMojo.java
index 8bb457b9b..bedb80a7c 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/UpdateMojo.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/UpdateMojo.java
@@ -24,10 +24,12 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.utils.Settings;
/**
- * Maven Plugin that checks the project dependencies to see if they have any known published vulnerabilities.
+ * Maven Plugin that checks the project dependencies to see if they have any
+ * known published vulnerabilities.
*
* @author Jeremy Long
*/
@@ -51,14 +53,17 @@ public class UpdateMojo extends BaseDependencyCheckMojo {
}
/**
- * Executes the dependency-check engine on the project's dependencies and generates the report.
+ * Executes the dependency-check engine on the project's dependencies and
+ * generates the report.
*
- * @throws MojoExecutionException thrown if there is an exception executing the goal
- * @throws MojoFailureException thrown if dependency-check is configured to fail the build
+ * @throws MojoExecutionException thrown if there is an exception executing
+ * the goal
+ * @throws MojoFailureException thrown if dependency-check is configured to
+ * fail the build
*/
@Override
public void runCheck() throws MojoExecutionException, MojoFailureException {
- final Engine engine;
+ MavenEngine engine = null;
try {
engine = initializeEngine();
engine.update();
@@ -66,9 +71,21 @@ public class UpdateMojo extends BaseDependencyCheckMojo {
if (getLog().isDebugEnabled()) {
getLog().debug("Database connection error", ex);
}
- throw new MojoExecutionException("An exception occured connecting to the local database. Please see the log file for more details.", ex);
+ final String msg = "An exception occured connecting to the local database. Please see the log file for more details.";
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException(msg, ex);
+ }
+ getLog().error(msg);
+ } catch (UpdateException ex) {
+ final String msg = "An exception occured while downloading updates. Please see the log file for more details.";
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException(msg, ex);
+ }
+ getLog().error(msg);
+ }
+ if (engine != null) {
+ engine.cleanup();
}
- engine.cleanup();
Settings.cleanup();
}
@@ -84,7 +101,8 @@ public class UpdateMojo extends BaseDependencyCheckMojo {
}
/**
- * Gets the description of the Dependency-Check report to be displayed in the Maven Generated Reports page.
+ * Gets the description of the Dependency-Check report to be displayed in
+ * the Maven Generated Reports page.
*
* @param locale The Locale to get the description for
* @return the description
@@ -93,5 +111,4 @@ public class UpdateMojo extends BaseDependencyCheckMojo {
public String getDescription(Locale locale) {
return "Updates the local cache of the NVD data from NIST.";
}
-
}
diff --git a/dependency-check-maven/src/site/markdown/configuration.md b/dependency-check-maven/src/site/markdown/configuration.md
index 44b68a512..2707e091c 100644
--- a/dependency-check-maven/src/site/markdown/configuration.md
+++ b/dependency-check-maven/src/site/markdown/configuration.md
@@ -17,6 +17,7 @@ Property | Description | Default Value
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
cveValidForHours | Sets the number of hours to wait before checking for new updates from the NVD. | 4
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
+failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
name | The name of the report in the site | dependency-check or dependency-check:aggregate
outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
diff --git a/dependency-check-maven/src/site/markdown/index.md.vm b/dependency-check-maven/src/site/markdown/index.md.vm
index 49312f4ba..c4e5c1c2a 100644
--- a/dependency-check-maven/src/site/markdown/index.md.vm
+++ b/dependency-check-maven/src/site/markdown/index.md.vm
@@ -53,18 +53,16 @@ Create an aggregated dependency-check report within the site.
...
-
- org.owasp
- dependency-check-maven
- ${project.version}
-
-
-
- aggregate
-
-
-
-
+ org.owasp
+ dependency-check-maven
+ ${project.version}
+
+
+
+ aggregate
+
+
+
...
diff --git a/dependency-check-maven/src/test/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojoTest.java b/dependency-check-maven/src/test/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojoTest.java
index f66e34939..d103d0d9e 100644
--- a/dependency-check-maven/src/test/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojoTest.java
+++ b/dependency-check-maven/src/test/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojoTest.java
@@ -90,7 +90,7 @@ public class BaseDependencyCheckMojoTest extends BaseTest {
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
- Engine engine = new Engine(null, null);
+ MavenEngine engine = new MavenEngine(null, null);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
assertTrue(engine.getDependencies().isEmpty());
diff --git a/dependency-check-utils/pom.xml b/dependency-check-utils/pom.xml
index 709ab9f4c..c5c10da90 100644
--- a/dependency-check-utils/pom.xml
+++ b/dependency-check-utils/pom.xml
@@ -20,7 +20,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved.
org.owasp
dependency-check-parent
- 1.4.1-SNAPSHOT
+ 1.4.3-SNAPSHOT
dependency-check-utils
diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Downloader.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Downloader.java
index 850a302e7..894c2fab2 100644
--- a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Downloader.java
+++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Downloader.java
@@ -175,7 +175,7 @@ public final class Downloader {
}
LOGGER.debug("Download of {} complete", url.toString());
} catch (IOException ex) {
- checkForSslExceptionn(ex);
+ checkForCommonExceptionTypes(ex);
final String msg = format("Error saving '%s' to file '%s'%nConnection Timeout: %d%nEncoding: %s%n",
url.toString(), outputPath.getAbsolutePath(), conn.getConnectTimeout(), encoding);
throw new DownloadFailedException(msg, ex);
@@ -261,8 +261,9 @@ public final class Downloader {
} catch (URLConnectionFailureException ex) {
throw new DownloadFailedException(format("Error creating URL Connection for HTTP %s request.", httpMethod), ex);
} catch (IOException ex) {
- checkForSslExceptionn(ex);
- LOGGER.debug("IO Exception: " + ex.getMessage(), ex);
+ checkForCommonExceptionTypes(ex);
+ LOGGER.error("IO Exception: " + ex.getMessage());
+ LOGGER.debug("Exception details", ex);
if (ex.getCause() != null) {
LOGGER.debug("IO Exception cause: " + ex.getCause().getMessage(), ex.getCause());
}
@@ -292,15 +293,21 @@ public final class Downloader {
/**
* Analyzes the IOException, logs the appropriate information for debugging
* purposes, and then throws a DownloadFailedException that wraps the IO
- * Exception.
+ * Exception for common IO Exceptions. This is to provide additional details
+ * to assist in resolution of the exception.
*
* @param ex the original exception
* @throws DownloadFailedException a wrapper exception that contains the
* original exception as the cause
*/
- protected static void checkForSslExceptionn(IOException ex) throws DownloadFailedException {
+ protected static void checkForCommonExceptionTypes(IOException ex) throws DownloadFailedException {
Throwable cause = ex;
while (cause != null) {
+ if (cause instanceof java.net.UnknownHostException) {
+ final String msg = String.format("Unable to resolve domain '%s'", cause.getMessage());
+ LOGGER.error(msg);
+ throw new DownloadFailedException(msg);
+ }
if (cause instanceof InvalidAlgorithmParameterException) {
final String keystore = System.getProperty("javax.net.ssl.keyStore");
final String version = System.getProperty("java.version");
diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/SSLSocketFactoryEx.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/SSLSocketFactoryEx.java
new file mode 100644
index 000000000..727eb24f7
--- /dev/null
+++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/SSLSocketFactoryEx.java
@@ -0,0 +1,385 @@
+package org.owasp.dependencycheck.utils;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to enable additional ciphers used by the SSL Socket. This
+ * is specifically because the NVD stopped supporting TLS 1.0 and Java 6 and 7
+ * clients by default were unable to connect to download the NVD data feeds.
+ *
+ * The following code was copied from
+ * http://stackoverflow.com/questions/1037590/which-cipher-suites-to-enable-for-ssl-socket/23365536#23365536
+ *
+ * @author jww
+ */
+public class SSLSocketFactoryEx extends SSLSocketFactory {
+
+ /**
+ * The Logger for use throughout the class.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(SSLSocketFactoryEx.class);
+
+ /**
+ * Constructs a new SSLSocketFactory.
+ *
+ * @throws NoSuchAlgorithmException thrown when an algorithm is not
+ * supported
+ * @throws KeyManagementException thrown if initialization fails
+ */
+ public SSLSocketFactoryEx() throws NoSuchAlgorithmException, KeyManagementException {
+ initSSLSocketFactoryEx(null, null, null);
+ }
+
+ /**
+ * Constructs a new SSLSocketFactory.
+ *
+ * @param km the key manager
+ * @param tm the trust manager
+ * @param random secure random
+ * @throws NoSuchAlgorithmException thrown when an algorithm is not
+ * supported
+ * @throws KeyManagementException thrown if initialization fails
+ */
+ public SSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random) throws NoSuchAlgorithmException, KeyManagementException {
+ initSSLSocketFactoryEx(km, tm, random);
+ }
+
+ /**
+ * Constructs a new SSLSocketFactory.
+ *
+ * @param ctx the SSL context
+ * @throws NoSuchAlgorithmException thrown when an algorithm is not
+ * supported
+ * @throws KeyManagementException thrown if initialization fails
+ */
+ public SSLSocketFactoryEx(SSLContext ctx) throws NoSuchAlgorithmException, KeyManagementException {
+ initSSLSocketFactoryEx(ctx);
+ }
+
+ /**
+ * Returns the default cipher suites.
+ *
+ * @return the default cipher suites
+ */
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return Arrays.copyOf(ciphers, ciphers.length);
+ }
+
+ /**
+ * Returns the supported cipher suites.
+ *
+ * @return the supported cipher suites
+ */
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return Arrays.copyOf(ciphers, ciphers.length);
+ }
+
+ /**
+ * Returns the default protocols.
+ *
+ * @return the default protocols
+ */
+ public String[] getDefaultProtocols() {
+ return Arrays.copyOf(protocols, protocols.length);
+ }
+
+ /**
+ * Returns the supported protocols.
+ *
+ * @return the supported protocols
+ */
+ public String[] getSupportedProtocols() {
+ return Arrays.copyOf(protocols, protocols.length);
+ }
+
+ /**
+ * Creates an SSL Socket.
+ *
+ * @param s the base socket
+ * @param host the host
+ * @param port the port
+ * @param autoClose if the socket should auto-close
+ * @return the SSL Socket
+ * @throws IOException thrown if the creation fails
+ */
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
+ final SSLSocketFactory factory = sslCtxt.getSocketFactory();
+ final SSLSocket ss = (SSLSocket) factory.createSocket(s, host, port, autoClose);
+
+ ss.setEnabledProtocols(protocols);
+ ss.setEnabledCipherSuites(ciphers);
+
+ return ss;
+ }
+
+ /**
+ * Creates a new SSL Socket.
+ *
+ * @param address the address to connect to
+ * @param port the port number
+ * @param localAddress the local address
+ * @param localPort the local port
+ * @return the SSL Socket
+ * @throws IOException thrown if the creation fails
+ */
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
+ final SSLSocketFactory factory = sslCtxt.getSocketFactory();
+ final SSLSocket ss = (SSLSocket) factory.createSocket(address, port, localAddress, localPort);
+
+ ss.setEnabledProtocols(protocols);
+ ss.setEnabledCipherSuites(ciphers);
+
+ return ss;
+ }
+
+ /**
+ * Creates a new SSL Socket.
+ *
+ * @param host the host to connect to
+ * @param port the port to connect to
+ * @param localHost the local host
+ * @param localPort the local port
+ * @return the SSL Socket
+ * @throws IOException thrown if the creation fails
+ */
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
+ final SSLSocketFactory factory = sslCtxt.getSocketFactory();
+ final SSLSocket ss = (SSLSocket) factory.createSocket(host, port, localHost, localPort);
+
+ ss.setEnabledProtocols(protocols);
+ ss.setEnabledCipherSuites(ciphers);
+
+ return ss;
+ }
+
+ /**
+ * Creates a new SSL Socket.
+ *
+ * @param host the host to connect to
+ * @param port the port to connect to
+ * @return the SSL Socket
+ * @throws IOException thrown if the creation fails
+ */
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ final SSLSocketFactory factory = sslCtxt.getSocketFactory();
+ final SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
+
+ ss.setEnabledProtocols(protocols);
+ ss.setEnabledCipherSuites(ciphers);
+
+ return ss;
+ }
+
+ /**
+ * Creates a new SSL Socket.
+ *
+ * @param host the host to connect to
+ * @param port the port to connect to
+ * @return the SSL Socket
+ * @throws IOException thrown if the creation fails
+ */
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ final SSLSocketFactory factory = sslCtxt.getSocketFactory();
+ final SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
+
+ ss.setEnabledProtocols(protocols);
+ ss.setEnabledCipherSuites(ciphers);
+
+ return ss;
+ }
+
+ /**
+ * Initializes the SSL Socket Factory Extension.
+ *
+ * @param km the key managers
+ * @param tm the trust managers
+ * @param random the secure random number generator
+ * @throws NoSuchAlgorithmException thrown when an algorithm is not
+ * supported
+ * @throws KeyManagementException thrown if initialization fails
+ */
+ private void initSSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random)
+ throws NoSuchAlgorithmException, KeyManagementException {
+ sslCtxt = SSLContext.getInstance("TLS");
+ sslCtxt.init(km, tm, random);
+
+ protocols = getProtocolList();
+ ciphers = getCipherList();
+ }
+
+ /**
+ * Initializes the SSL Socket Factory Extension.
+ *
+ * @param ctx the SSL context
+ * @throws NoSuchAlgorithmException thrown when an algorithm is not
+ * supported
+ * @throws KeyManagementException thrown if initialization fails
+ */
+ private void initSSLSocketFactoryEx(SSLContext ctx)
+ throws NoSuchAlgorithmException, KeyManagementException {
+ sslCtxt = ctx;
+
+ protocols = getProtocolList();
+ ciphers = getCipherList();
+ }
+
+ /**
+ * Returns the protocol list.
+ *
+ * @return the protocol list
+ */
+ protected String[] getProtocolList() {
+ final String[] preferredProtocols = {"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
+ String[] availableProtocols = null;
+
+ SSLSocket socket = null;
+
+ try {
+ final SSLSocketFactory factory = sslCtxt.getSocketFactory();
+ socket = (SSLSocket) factory.createSocket();
+
+ availableProtocols = socket.getSupportedProtocols();
+ Arrays.sort(availableProtocols);
+ } catch (Exception ex) {
+ LOGGER.debug("Error getting protocol list, using TLSv1", ex);
+ return new String[]{"TLSv1"};
+ } finally {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException ex) {
+ LOGGER.trace("Error closing socket", ex);
+ }
+ }
+ }
+
+ final List aa = new ArrayList();
+ for (String preferredProtocol : preferredProtocols) {
+ final int idx = Arrays.binarySearch(availableProtocols, preferredProtocol);
+ if (idx >= 0) {
+ aa.add(preferredProtocol);
+ }
+ }
+
+ return aa.toArray(new String[0]);
+ }
+
+ /**
+ * Returns the cipher list.
+ *
+ * @return the cipher list
+ */
+ protected String[] getCipherList() {
+ final String[] preferredCiphers = {
+ // *_CHACHA20_POLY1305 are 3x to 4x faster than existing cipher suites.
+ // http://googleonlinesecurity.blogspot.com/2014/04/speeding-up-and-strengthening-https.html
+ // Use them if available. Normative names can be found at (TLS spec depends on IPSec spec):
+ // http://tools.ietf.org/html/draft-nir-ipsecme-chacha20-poly1305-01
+ // http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-02
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_SHA",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_SHA",
+ "TLS_DHE_RSA_WITH_CHACHA20_POLY1305",
+ "TLS_RSA_WITH_CHACHA20_POLY1305",
+ "TLS_DHE_RSA_WITH_CHACHA20_SHA",
+ "TLS_RSA_WITH_CHACHA20_SHA",
+ // Done with bleeding edge, back to TLS v1.2 and below
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+ // TLS v1.0 (with some SSLv3 interop)
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA384",
+ "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+ "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",
+ // RSA key transport sucks, but they are needed as a fallback.
+ // For example, microsoft.com fails under all versions of TLS
+ // if they are not included. If only TLS 1.0 is available at
+ // the client, then google.com will fail too. TLS v1.3 is
+ // trying to deprecate them, so it will be interesteng to see
+ // what happens.
+ "TLS_RSA_WITH_AES_256_CBC_SHA256",
+ "TLS_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_RSA_WITH_AES_128_CBC_SHA256",
+ "TLS_RSA_WITH_AES_128_CBC_SHA",
+ };
+
+ String[] availableCiphers;
+
+ try {
+ final SSLSocketFactory factory = sslCtxt.getSocketFactory();
+ availableCiphers = factory.getSupportedCipherSuites();
+ Arrays.sort(availableCiphers);
+ } catch (Exception e) {
+ LOGGER.debug("Error retrieving ciphers", e);
+ return new String[]{
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+ "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_RSA_WITH_AES_256_CBC_SHA256",
+ "TLS_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_RSA_WITH_AES_128_CBC_SHA256",
+ "TLS_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
+ };
+ }
+
+ final List aa = new ArrayList();
+ for (String preferredCipher : preferredCiphers) {
+ final int idx = Arrays.binarySearch(availableCiphers, preferredCipher);
+ if (idx >= 0) {
+ aa.add(preferredCipher);
+ }
+ }
+
+ aa.add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
+
+ return aa.toArray(new String[0]);
+ }
+
+ /**
+ * The SSL context.
+ */
+ private SSLContext sslCtxt;
+ /**
+ * The cipher suites.
+ */
+ private String[] ciphers;
+ /**
+ * The protocols.
+ */
+ private String[] protocols;
+}
diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java
index 5f42e6f7d..359d24171 100644
--- a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java
+++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java
@@ -46,7 +46,8 @@ public final class Settings {
public static final class KEYS {
/**
- * private constructor because this is a "utility" class containing constants
+ * private constructor because this is a "utility" class containing
+ * constants
*/
private KEYS() {
//do nothing
@@ -54,29 +55,34 @@ public final class Settings {
/**
* The key to obtain the application name.
*/
- public static final String APPLICATION_VAME = "application.name";
+ public static final String APPLICATION_NAME = "application.name";
/**
* The key to obtain the application version.
*/
public static final String APPLICATION_VERSION = "application.version";
/**
- * The key to obtain the URL to retrieve the current release version from.
+ * The key to obtain the URL to retrieve the current release version
+ * from.
*/
public static final String ENGINE_VERSION_CHECK_URL = "engine.version.url";
/**
- * The properties key indicating whether or not the cached data sources should be updated.
+ * The properties key indicating whether or not the cached data sources
+ * should be updated.
*/
public static final String AUTO_UPDATE = "autoupdate";
/**
- * The database driver class name. If this is not in the properties file the embedded database is used.
+ * The database driver class name. If this is not in the properties file
+ * the embedded database is used.
*/
public static final String DB_DRIVER_NAME = "data.driver_name";
/**
- * The database driver class name. If this is not in the properties file the embedded database is used.
+ * The database driver class name. If this is not in the properties file
+ * the embedded database is used.
*/
public static final String DB_DRIVER_PATH = "data.driver_path";
/**
- * The database connection string. If this is not in the properties file the embedded database is used.
+ * The database connection string. If this is not in the properties file
+ * the embedded database is used.
*/
public static final String DB_CONNECTION_STRING = "data.connection_string";
/**
@@ -101,36 +107,41 @@ public final class Settings {
public static final String DB_VERSION = "data.version";
/**
* The starts with filter used to exclude CVE entries from the database.
- * By default this is set to 'cpe:/a:' which limits the CVEs imported to
- * just those that are related to applications. If this were set to just
- * 'cpe:' the OS, hardware, and application related CVEs would be imported.
+ * By default this is set to 'cpe:/a:' which limits the CVEs imported to
+ * just those that are related to applications. If this were set to just
+ * 'cpe:' the OS, hardware, and application related CVEs would be
+ * imported.
*/
public static final String CVE_CPE_STARTS_WITH_FILTER = "cve.cpe.startswith.filter";
/**
- * The properties key for the URL to retrieve the "meta" data from about the CVE entries.
+ * The properties key for the URL to retrieve the "meta" data from about
+ * the CVE entries.
*/
public static final String CVE_META_URL = "cve.url.meta";
/**
- * The properties key for the URL to retrieve the recently modified and added CVE entries (last 8 days) using the 2.0
- * schema.
+ * The properties key for the URL to retrieve the recently modified and
+ * added CVE entries (last 8 days) using the 2.0 schema.
*/
public static final String CVE_MODIFIED_20_URL = "cve.url-2.0.modified";
/**
- * The properties key for the URL to retrieve the recently modified and added CVE entries (last 8 days) using the 1.2
- * schema.
+ * The properties key for the URL to retrieve the recently modified and
+ * added CVE entries (last 8 days) using the 1.2 schema.
*/
public static final String CVE_MODIFIED_12_URL = "cve.url-1.2.modified";
/**
- * The properties key for the URL to retrieve the recently modified and added CVE entries (last 8 days).
+ * The properties key for the URL to retrieve the recently modified and
+ * added CVE entries (last 8 days).
*/
public static final String CVE_MODIFIED_VALID_FOR_DAYS = "cve.url.modified.validfordays";
/**
- * The properties key to control the skipping of the check for CVE updates.
+ * The properties key to control the skipping of the check for CVE
+ * updates.
*/
public static final String CVE_CHECK_VALID_FOR_HOURS = "cve.check.validforhours";
/**
- * The properties key for the telling us how many cve.url.* URLs exists. This is used in combination with CVE_BASE_URL to
- * be able to retrieve the URLs for all of the files that make up the NVD CVE listing.
+ * The properties key for the telling us how many cve.url.* URLs exists.
+ * This is used in combination with CVE_BASE_URL to be able to retrieve
+ * the URLs for all of the files that make up the NVD CVE listing.
*/
public static final String CVE_START_YEAR = "cve.startyear";
/**
@@ -142,7 +153,8 @@ public final class Settings {
*/
public static final String CVE_SCHEMA_2_0 = "cve.url-2.0.base";
/**
- * The properties key that indicates how often the CPE data needs to be updated.
+ * The properties key that indicates how often the CPE data needs to be
+ * updated.
*/
public static final String CPE_MODIFIED_VALID_FOR_DAYS = "cpe.validfordays";
/**
@@ -152,7 +164,9 @@ public final class Settings {
/**
* The properties key for the proxy server.
*
- * @deprecated use {@link org.owasp.dependencycheck.utils.Settings.KEYS#PROXY_SERVER} instead.
+ * @deprecated use
+ * {@link org.owasp.dependencycheck.utils.Settings.KEYS#PROXY_SERVER}
+ * instead.
*/
@Deprecated
public static final String PROXY_URL = "proxy.server";
@@ -161,7 +175,8 @@ public final class Settings {
*/
public static final String PROXY_SERVER = "proxy.server";
/**
- * The properties key for the proxy port - this must be an integer value.
+ * The properties key for the proxy port - this must be an integer
+ * value.
*/
public static final String PROXY_PORT = "proxy.port";
/**
@@ -209,19 +224,23 @@ public final class Settings {
*/
public static final String ANALYZER_ARCHIVE_ENABLED = "analyzer.archive.enabled";
/**
- * The properties key for whether the node.js package analyzer is enabled.
+ * The properties key for whether the node.js package analyzer is
+ * enabled.
*/
public static final String ANALYZER_NODE_PACKAGE_ENABLED = "analyzer.node.package.enabled";
/**
- * The properties key for whether the composer lock file analyzer is enabled.
+ * The properties key for whether the composer lock file analyzer is
+ * enabled.
*/
public static final String ANALYZER_COMPOSER_LOCK_ENABLED = "analyzer.composer.lock.enabled";
/**
- * The properties key for whether the Python Distribution analyzer is enabled.
+ * The properties key for whether the Python Distribution analyzer is
+ * enabled.
*/
public static final String ANALYZER_PYTHON_DISTRIBUTION_ENABLED = "analyzer.python.distribution.enabled";
/**
- * The properties key for whether the Python Package analyzer is enabled.
+ * The properties key for whether the Python Package analyzer is
+ * enabled.
*/
public static final String ANALYZER_PYTHON_PACKAGE_ENABLED = "analyzer.python.package.enabled";
/**
@@ -237,7 +256,8 @@ public final class Settings {
*/
public static final String ANALYZER_CMAKE_ENABLED = "analyzer.cmake.enabled";
/**
- * The properties key for whether the Ruby Bundler Audit analyzer is enabled.
+ * The properties key for whether the Ruby Bundler Audit analyzer is
+ * enabled.
*/
public static final String ANALYZER_BUNDLE_AUDIT_ENABLED = "analyzer.bundle.audit.enabled";
/**
@@ -339,7 +359,8 @@ public final class Settings {
private Properties props = null;
/**
- * Private constructor for the Settings class. This class loads the properties files.
+ * Private constructor for the Settings class. This class loads the
+ * properties files.
*
* @param propertiesFilePath the path to the base properties file to load
*/
@@ -365,16 +386,18 @@ public final class Settings {
}
/**
- * Initializes the thread local settings object. Note, to use the settings object you must call this method. However, you must
- * also call Settings.cleanup() to properly release resources.
+ * Initializes the thread local settings object. Note, to use the settings
+ * object you must call this method. However, you must also call
+ * Settings.cleanup() to properly release resources.
*/
public static void initialize() {
LOCAL_SETTINGS.set(new Settings(PROPERTIES_FILE));
}
/**
- * Initializes the thread local settings object. Note, to use the settings object you must call this method. However, you must
- * also call Settings.cleanup() to properly release resources.
+ * Initializes the thread local settings object. Note, to use the settings
+ * object you must call this method. However, you must also call
+ * Settings.cleanup() to properly release resources.
*
* @param propertiesFilePath the path to the base properties file to load
*/
@@ -393,7 +416,8 @@ public final class Settings {
/**
* Cleans up resources to prevent memory leaks.
*
- * @param deleteTemporary flag indicating whether any temporary directories generated should be removed
+ * @param deleteTemporary flag indicating whether any temporary directories
+ * generated should be removed
*/
public static void cleanup(boolean deleteTemporary) {
if (deleteTemporary && tempDirectory != null && tempDirectory.exists()) {
@@ -433,7 +457,8 @@ public final class Settings {
}
/**
- * Logs the properties. This will not log any properties that contain 'password' in the key.
+ * Logs the properties. This will not log any properties that contain
+ * 'password' in the key.
*
* @param header the header to print with the log message
* @param properties the properties to log
@@ -549,13 +574,16 @@ public final class Settings {
}
/**
- * Merges a new properties file into the current properties. This method allows for the loading of a user provided properties
- * file.
- * Note: even if using this method - system properties will be loaded before properties loaded from files.
+ * Merges a new properties file into the current properties. This method
+ * allows for the loading of a user provided properties file.
+ * Note: even if using this method - system properties will be loaded
+ * before properties loaded from files.
*
* @param filePath the path to the properties file to merge.
- * @throws FileNotFoundException is thrown when the filePath points to a non-existent file
- * @throws IOException is thrown when there is an exception loading/merging the properties
+ * @throws FileNotFoundException is thrown when the filePath points to a
+ * non-existent file
+ * @throws IOException is thrown when there is an exception loading/merging
+ * the properties
*/
public static void mergeProperties(File filePath) throws FileNotFoundException, IOException {
FileInputStream fis = null;
@@ -574,13 +602,16 @@ public final class Settings {
}
/**
- * Merges a new properties file into the current properties. This method allows for the loading of a user provided properties
- * file.
- * Note: even if using this method - system properties will be loaded before properties loaded from files.
+ * Merges a new properties file into the current properties. This method
+ * allows for the loading of a user provided properties file.
+ * Note: even if using this method - system properties will be loaded before
+ * properties loaded from files.
*
* @param filePath the path to the properties file to merge.
- * @throws FileNotFoundException is thrown when the filePath points to a non-existent file
- * @throws IOException is thrown when there is an exception loading/merging the properties
+ * @throws FileNotFoundException is thrown when the filePath points to a
+ * non-existent file
+ * @throws IOException is thrown when there is an exception loading/merging
+ * the properties
*/
public static void mergeProperties(String filePath) throws FileNotFoundException, IOException {
FileInputStream fis = null;
@@ -599,12 +630,14 @@ public final class Settings {
}
/**
- * Merges a new properties file into the current properties. This method allows for the loading of a user provided properties
- * file.
- * Note: even if using this method - system properties will be loaded before properties loaded from files.
+ * Merges a new properties file into the current properties. This method
+ * allows for the loading of a user provided properties file.
+ * Note: even if using this method - system properties will be loaded
+ * before properties loaded from files.
*
* @param stream an Input Stream pointing at a properties file to merge
- * @throws IOException is thrown when there is an exception loading/merging the properties
+ * @throws IOException is thrown when there is an exception loading/merging
+ * the properties
*/
public static void mergeProperties(InputStream stream) throws IOException {
LOCAL_SETTINGS.get().props.load(stream);
@@ -612,9 +645,10 @@ public final class Settings {
}
/**
- * Returns a value from the properties file as a File object. If the value was specified as a system property or passed in via
- * the -Dprop=value argument - this method will return the value from the system properties before the values in the contained
- * configuration file.
+ * Returns a value from the properties file as a File object. If the value
+ * was specified as a system property or passed in via the -Dprop=value
+ * argument - this method will return the value from the system properties
+ * before the values in the contained configuration file.
*
* @param key the key to lookup within the properties file
* @return the property from the properties file converted to a File object
@@ -628,13 +662,15 @@ public final class Settings {
}
/**
- * Returns a value from the properties file as a File object. If the value was specified as a system property or passed in via
- * the -Dprop=value argument - this method will return the value from the system properties before the values in the contained
- * configuration file.
+ * Returns a value from the properties file as a File object. If the value
+ * was specified as a system property or passed in via the -Dprop=value
+ * argument - this method will return the value from the system properties
+ * before the values in the contained configuration file.
*
- * This method will check the configured base directory and will use this as the base of the file path. Additionally, if the
- * base directory begins with a leading "[JAR]\" sequence with the path to the folder containing the JAR file containing this
- * class.
+ * This method will check the configured base directory and will use this as
+ * the base of the file path. Additionally, if the base directory begins
+ * with a leading "[JAR]\" sequence with the path to the folder containing
+ * the JAR file containing this class.
*
* @param key the key to lookup within the properties file
* @return the property from the properties file converted to a File object
@@ -657,7 +693,8 @@ public final class Settings {
}
/**
- * Attempts to retrieve the folder containing the Jar file containing the Settings class.
+ * Attempts to retrieve the folder containing the Jar file containing the
+ * Settings class.
*
* @return a File object
*/
@@ -679,9 +716,10 @@ public final class Settings {
}
/**
- * Returns a value from the properties file. If the value was specified as a system property or passed in via the -Dprop=value
- * argument - this method will return the value from the system properties before the values in the contained configuration
- * file.
+ * Returns a value from the properties file. If the value was specified as a
+ * system property or passed in via the -Dprop=value argument - this method
+ * will return the value from the system properties before the values in the
+ * contained configuration file.
*
* @param key the key to lookup within the properties file
* @param defaultValue the default value for the requested property
@@ -693,7 +731,8 @@ public final class Settings {
}
/**
- * A reference to the temporary directory; used incase it needs to be deleted during cleanup.
+ * A reference to the temporary directory; used incase it needs to be
+ * deleted during cleanup.
*/
private static File tempDirectory = null;
@@ -701,7 +740,8 @@ public final class Settings {
* Returns the temporary directory.
*
* @return the temporary directory
- * @throws java.io.IOException thrown if the temporary directory does not exist and cannot be created
+ * @throws java.io.IOException thrown if the temporary directory does not
+ * exist and cannot be created
*/
public static File getTempDirectory() throws IOException {
final File tmpDir = new File(Settings.getString(Settings.KEYS.TEMP_DIRECTORY, System.getProperty("java.io.tmpdir")), "dctemp");
@@ -714,9 +754,10 @@ public final class Settings {
}
/**
- * Returns a value from the properties file. If the value was specified as a system property or passed in via the -Dprop=value
- * argument - this method will return the value from the system properties before the values in the contained configuration
- * file.
+ * Returns a value from the properties file. If the value was specified as a
+ * system property or passed in via the -Dprop=value argument - this method
+ * will return the value from the system properties before the values in the
+ * contained configuration file.
*
* @param key the key to lookup within the properties file
* @return the property from the properties file
@@ -726,7 +767,8 @@ public final class Settings {
}
/**
- * Removes a property from the local properties collection. This is mainly used in test cases.
+ * Removes a property from the local properties collection. This is mainly
+ * used in test cases.
*
* @param key the property key to remove
*/
@@ -735,13 +777,15 @@ public final class Settings {
}
/**
- * Returns an int value from the properties file. If the value was specified as a system property or passed in via the
- * -Dprop=value argument - this method will return the value from the system properties before the values in the contained
- * configuration file.
+ * Returns an int value from the properties file. If the value was specified
+ * as a system property or passed in via the -Dprop=value argument - this
+ * method will return the value from the system properties before the values
+ * in the contained configuration file.
*
* @param key the key to lookup within the properties file
* @return the property from the properties file
- * @throws InvalidSettingException is thrown if there is an error retrieving the setting
+ * @throws InvalidSettingException is thrown if there is an error retrieving
+ * the setting
*/
public static int getInt(String key) throws InvalidSettingException {
try {
@@ -752,14 +796,15 @@ public final class Settings {
}
/**
- * Returns an int value from the properties file. If the value was specified as a system property or passed in via the
- * -Dprop=value argument - this method will return the value from the system properties before the values in the contained
- * configuration file.
+ * Returns an int value from the properties file. If the value was specified
+ * as a system property or passed in via the -Dprop=value argument - this
+ * method will return the value from the system properties before the values
+ * in the contained configuration file.
*
* @param key the key to lookup within the properties file
* @param defaultValue the default value to return
- * @return the property from the properties file or the defaultValue if the property does not exist or cannot be converted to
- * an integer
+ * @return the property from the properties file or the defaultValue if the
+ * property does not exist or cannot be converted to an integer
*/
public static int getInt(String key, int defaultValue) {
int value;
@@ -775,13 +820,15 @@ public final class Settings {
}
/**
- * Returns a long value from the properties file. If the value was specified as a system property or passed in via the
- * -Dprop=value argument - this method will return the value from the system properties before the values in the contained
- * configuration file.
+ * Returns a long value from the properties file. If the value was specified
+ * as a system property or passed in via the -Dprop=value argument - this
+ * method will return the value from the system properties before the values
+ * in the contained configuration file.
*
* @param key the key to lookup within the properties file
* @return the property from the properties file
- * @throws InvalidSettingException is thrown if there is an error retrieving the setting
+ * @throws InvalidSettingException is thrown if there is an error retrieving
+ * the setting
*/
public static long getLong(String key) throws InvalidSettingException {
try {
@@ -792,38 +839,47 @@ public final class Settings {
}
/**
- * Returns a boolean value from the properties file. If the value was specified as a system property or passed in via the
- * -Dprop=value argument this method will return the value from the system properties before the values in the
- * contained configuration file.
+ * Returns a boolean value from the properties file. If the value was
+ * specified as a system property or passed in via the
+ * -Dprop=value argument this method will return the value from
+ * the system properties before the values in the contained configuration
+ * file.
*
* @param key the key to lookup within the properties file
* @return the property from the properties file
- * @throws InvalidSettingException is thrown if there is an error retrieving the setting
+ * @throws InvalidSettingException is thrown if there is an error retrieving
+ * the setting
*/
public static boolean getBoolean(String key) throws InvalidSettingException {
return Boolean.parseBoolean(Settings.getString(key));
}
/**
- * Returns a boolean value from the properties file. If the value was specified as a system property or passed in via the
- * -Dprop=value argument this method will return the value from the system properties before the values in the
- * contained configuration file.
+ * Returns a boolean value from the properties file. If the value was
+ * specified as a system property or passed in via the
+ * -Dprop=value argument this method will return the value from
+ * the system properties before the values in the contained configuration
+ * file.
*
* @param key the key to lookup within the properties file
- * @param defaultValue the default value to return if the setting does not exist
+ * @param defaultValue the default value to return if the setting does not
+ * exist
* @return the property from the properties file
- * @throws InvalidSettingException is thrown if there is an error retrieving the setting
+ * @throws InvalidSettingException is thrown if there is an error retrieving
+ * the setting
*/
public static boolean getBoolean(String key, boolean defaultValue) throws InvalidSettingException {
return Boolean.parseBoolean(Settings.getString(key, Boolean.toString(defaultValue)));
}
/**
- * Returns a connection string from the configured properties. If the connection string contains a %s, this method will
- * determine the 'data' directory and replace the %s with the path to the data directory. If the data directory does not
- * exists it will be created.
+ * Returns a connection string from the configured properties. If the
+ * connection string contains a %s, this method will determine the 'data'
+ * directory and replace the %s with the path to the data directory. If the
+ * data directory does not exists it will be created.
*
- * @param connectionStringKey the property file key for the connection string
+ * @param connectionStringKey the property file key for the connection
+ * string
* @param dbFileNameKey the settings key for the db filename
* @return the connection string
* @throws IOException thrown the data directory cannot be created
@@ -860,8 +916,9 @@ public final class Settings {
}
/**
- * Retrieves the directory that the JAR file exists in so that we can ensure we always use a common data directory for the
- * embedded H2 database. This is public solely for some unit tests; otherwise this should be private.
+ * Retrieves the directory that the JAR file exists in so that we can ensure
+ * we always use a common data directory for the embedded H2 database. This
+ * is public solely for some unit tests; otherwise this should be private.
*
* @return the data directory to store data files
* @throws IOException is thrown if an IOException occurs of course...
diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/URLConnectionFactory.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/URLConnectionFactory.java
index cbeb00a64..8a50a33cc 100644
--- a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/URLConnectionFactory.java
+++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/URLConnectionFactory.java
@@ -28,15 +28,28 @@ import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import javax.net.ssl.HttpsURLConnection;
+import org.apache.commons.lang3.JavaVersion;
+import org.apache.commons.lang3.SystemUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
- * A URLConnection Factory to create new connections. This encapsulates several configuration checks to ensure that the connection
- * uses the correct proxy settings.
+ * A URLConnection Factory to create new connections. This encapsulates several
+ * configuration checks to ensure that the connection uses the correct proxy
+ * settings.
*
* @author Jeremy Long
*/
public final class URLConnectionFactory {
+ /**
+ * The logger.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(URLConnectionFactory.class);
+
/**
* Private constructor for this factory.
*/
@@ -44,8 +57,9 @@ public final class URLConnectionFactory {
}
/**
- * Utility method to create an HttpURLConnection. If the application is configured to use a proxy this method will retrieve
- * the proxy settings and use them when setting up the connection.
+ * Utility method to create an HttpURLConnection. If the application is
+ * configured to use a proxy this method will retrieve the proxy settings
+ * and use them when setting up the connection.
*
* @param url the url to connect to
* @return an HttpURLConnection
@@ -95,6 +109,7 @@ public final class URLConnectionFactory {
}
throw new URLConnectionFailureException("Error getting connection.", ex);
}
+ configureTLS(url, conn);
return conn;
}
@@ -140,8 +155,10 @@ public final class URLConnectionFactory {
}
/**
- * Utility method to create 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)
+ * Utility method to create 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
* @param proxy whether to use the proxy (if configured)
@@ -161,6 +178,29 @@ public final class URLConnectionFactory {
} catch (IOException ioe) {
throw new URLConnectionFailureException("Error getting connection.", ioe);
}
+ configureTLS(url, conn);
return conn;
}
+
+ /**
+ * If the protocol is HTTPS, this will configure the cipher suites so that
+ * connections can be made to the NVD, and others, using older versions of
+ * Java.
+ *
+ * @param url the URL
+ * @param conn the connection
+ */
+ private static void configureTLS(URL url, HttpURLConnection conn) {
+ if ("https".equals(url.getProtocol()) && !SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_8)) {
+ try {
+ final HttpsURLConnection secCon = (HttpsURLConnection) conn;
+ final SSLSocketFactoryEx factory = new SSLSocketFactoryEx();
+ secCon.setSSLSocketFactory(factory);
+ } catch (NoSuchAlgorithmException ex) {
+ LOGGER.debug("Unsupported algorithm in SSLSocketFactoryEx", ex);
+ } catch (KeyManagementException ex) {
+ LOGGER.debug("Key mnagement eception in SSLSocketFactoryEx", ex);
+ }
+ }
+ }
}
diff --git a/pom.xml b/pom.xml
index 0576d574c..3df61fcb1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long
org.owasp
dependency-check-parent
- 1.4.1-SNAPSHOT
+ 1.4.3-SNAPSHOT
pom
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 81273af65..81a187625 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -28,11 +28,12 @@ More information about dependency-check can be found here:
OWASP dependency-check's core analysis engine can be used as:
-- [Command Line Tool](dependency-check-cli/index.html)
-- [Maven Plugin](dependency-check-maven/index.html)
- [Ant Task](dependency-check-ant/index.html)
+- [Command Line Tool](dependency-check-cli/index.html)
- [Gradle Plugin](dependency-check-gradle/index.html)
- [Jenkins Plugin](dependency-check-jenkins/index.html)
+- [Maven Plugin](dependency-check-maven/index.html)
+- [SBT Plugin](https://github.com/albuch/sbt-dependency-check)
For help with dependency-check the following resource can be used:
diff --git a/src/site/markdown/modules.md b/src/site/markdown/modules.md
index 1a0d027fc..012988c08 100644
--- a/src/site/markdown/modules.md
+++ b/src/site/markdown/modules.md
@@ -3,10 +3,12 @@ Modules
OWASP dependency-check's core analysis engine was designed to fit into an applications normal
build and reporting process:
-- [Maven Plugin](dependency-check-maven/index.html)
-- [Ant Task](dependency-check-ant/index.html)
-- [Gradle Plugin](dependency-check-gradle/index.html)
-- [Jenkins Plugin](dependency-check-jenkins/index.html)
+- [Ant Task](dependency-check-ant/index.html)
+- [Command Line Tool](dependency-check-cli/index.html)
+- [Gradle Plugin](dependency-check-gradle/index.html)
+- [Jenkins Plugin](dependency-check-jenkins/index.html)
+- [Maven Plugin](dependency-check-maven/index.html)
+- [SBT Plugin](https://github.com/albuch/sbt-dependency-check)
In addition, dependency-check can be executed from the [command line](dependency-check-cli/index.html).