Merge branch 'master' into swift_support

This commit is contained in:
bjiang
2016-08-12 16:35:12 -04:00
53 changed files with 1778 additions and 536 deletions

18
.github/issue_template.md vendored Normal file
View File

@@ -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
<dependency>
<groupId>org.sample</groupId>
<artifactId>foo</artifactId>
<version>1.0</version>
</dependency>
```

View File

@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.4.1-SNAPSHOT</version>
<version>1.4.3-SNAPSHOT</version>
</parent>
<artifactId>dependency-check-ant</artifactId>

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -24,6 +24,7 @@ proxyPort | The Proxy Port. | &nbsp;
proxyUsername | Defines the proxy user name. | &nbsp;
proxyPassword | Defines the proxy password. | &nbsp;
connectionTimeout | The URL Connection Timeout. | &nbsp;
failOnError | Whether the build should fail if there is an error executing the update | true
Advanced Configuration
====================

View File

@@ -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'

View File

@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.4.1-SNAPSHOT</version>
<version>1.4.3-SNAPSHOT</version>
</parent>
<artifactId>dependency-check-cli</artifactId>

View File

@@ -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<Dependency> 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 &amp; 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 &amp; 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("?")) {

View File

@@ -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);
}

View File

@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.4.1-SNAPSHOT</version>
<version>1.4.3-SNAPSHOT</version>
</parent>
<artifactId>dependency-check-core</artifactId>

View File

@@ -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<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
/**
* 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<Throwable> exceptions = new ArrayList<Throwable>();
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<Analyzer> 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<CachedWebDataSource> 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();

View File

@@ -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.
*
* <h2>Example:</h2>
* <pre>
@@ -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<Dependency> 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
*/

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<Evidence> itr = dependency.getVendorEvidence().iterator();
final List<Evidence> newEntries = new ArrayList<Evidence>();
@@ -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());

View File

@@ -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<ClassNameInformation> classInformation)
throws IOException {
protected boolean parseManifest(Dependency dependency, List<ClassNameInformation> 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<String, Attributes> item : manifest.getEntries().entrySet()) {
final String name = item.getKey();
source = "manifest: " + name;

View File

@@ -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;

View File

@@ -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<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
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()) {

View File

@@ -34,7 +34,7 @@ import org.apache.lucene.util.Version;
* index the CPE fields vendor and product.</p>
*
* @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

View File

@@ -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);

View File

@@ -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 {
// <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
/**
* 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 {

View File

@@ -36,6 +36,9 @@ import org.slf4j.LoggerFactory;
*/
public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveInfo> {
/**
* A reference to the logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(UpdateableNvdCve.class);
/**
* A collection of sources of data.

View File

@@ -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<Throwable> 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<Throwable> 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<Throwable> 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<Throwable> 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<Throwable>();
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<Throwable>();
this.exceptions.add(exception);
this.fatal = false;
}
/**
* Instantiates a new exception collection.
*/
public ExceptionCollection() {
super();
this.exceptions = new ArrayList<Throwable>();
}
/**
* The serial version uid.
*/
private static final long serialVersionUID = 1L;
/**
* A collection of exceptions.
*/
private List<Throwable> exceptions;
/**
* Get the value of exceptions.
*
* @return the value of exceptions
*/
public List<Throwable> 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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<Dependency> dependencies, List<Analyzer> 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 {

View File

@@ -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);
}
/**
* <p>
* 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.</p>
* <pre>
* Example:
* Give the file name: library-name-1.4.1r2-release.jar
* This function would return: library-name</pre>
*
* @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;
}
}

View File

@@ -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

View File

@@ -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<Evidence> getGivenProduct() {
return givenProduct;

View File

@@ -32,7 +32,7 @@ public class Hints {
private List<HintRule> 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<VendorDuplicatingHintRule> 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<VendorDuplicatingHintRule> vendorDuplicatingHintRules) {
this.vendorDuplicatingHintRules = vendorDuplicatingHintRules;
}
}

View File

@@ -70,7 +70,7 @@ public class SuppressionErrorHandler implements ErrorHandler {
*/
@Override
public void warning(SAXParseException ex) throws SAXException {
LOGGER.debug("", ex);
//LOGGER.debug("", ex);
}
/**

View File

@@ -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();

View File

@@ -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<Dependency> dependencies = engine.getDependencies();
LOGGER.info(dependencies.size() + " dependencies found.");

View File

@@ -20,7 +20,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.4.1-SNAPSHOT</version>
<version>1.4.3-SNAPSHOT</version>
</parent>
<artifactId>dependency-check-maven</artifactId>

View File

@@ -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<Dependency> 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 <code>true</code> if it has a pom packaging; otherwise <code>false</code>
* @return <code>true</code> if it has a pom packaging; otherwise
* <code>false</code>
*/
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

View File

@@ -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();
//</editor-fold>
// <editor-fold defaultstate="collapsed" desc="Maven bound parameters and components">
/**
* 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;
}
//</editor-fold>
// <editor-fold defaultstate="collapsed" desc="Maven bound parameters and components">
/**
* 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
//</editor-fold>
/**
* Initializes a new <code>Engine</code> that can be used for scanning.
* Initializes a new <code>MavenEngine</code> that can be used for scanning.
*
* @return a newly instantiated <code>Engine</code>
* @return a newly instantiated <code>MavenEngine</code>
* @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);
}
}
//<editor-fold defaultstate="collapsed" desc="Methods to fail build or show summary">
@@ -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 <code>Engine</code> object populated with dependencies if the
* serialized data file exists; otherwise <code>null</code> is returned
* @return a <code>MavenEngine</code> object populated with dependencies if
* the serialized data file exists; otherwise <code>null</code> is returned
*/
protected List<Dependency> readDataFile(MavenProject project) {
final Object oPath = project.getContextValue(this.getDataFileContextKey());

View File

@@ -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 <code>true</code> if the report can be generated; otherwise <code>false</code>
* @return <code>true</code> if the report can be generated; otherwise
* <code>false</code>
*/
@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

View File

@@ -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<MavenProject> 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<MavenProject> reactorProjects) throws DatabaseException {
public MavenEngine(MavenProject project, List<MavenProject> 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()) {

View File

@@ -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

View File

@@ -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.";
}
}

View File

@@ -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'

View File

@@ -53,18 +53,16 @@ Create an aggregated dependency-check report within the site.
<plugins>
...
<plugin>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>${project.version}</version>
<reportSets>
<reportSet>
<reports>
<report>aggregate</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>${project.version}</version>
<reportSets>
<reportSet>
<reports>
<report>aggregate</report>
</reports>
</reportSet>
</reportSets>
</plugin>
...
</plugins>

View File

@@ -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());

View File

@@ -20,7 +20,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.4.1-SNAPSHOT</version>
<version>1.4.3-SNAPSHOT</version>
</parent>
<artifactId>dependency-check-utils</artifactId>

View File

@@ -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");

View File

@@ -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 <a href="http://stackoverflow.com/users/608639/jww">jww</a>
*/
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<String> aa = new ArrayList<String>();
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<String> aa = new ArrayList<String>();
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;
}

View File

@@ -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.<br><br>
* <b>Note</b>: 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.<br><br>
* <b>Note</b>: 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.<br><br>
* 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.<br><br>
* 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.<br><br>
* <b>Note</b>: 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.<br><br>
* <b>Note</b>: 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
* <code>-Dprop=value</code> 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
* <code>-Dprop=value</code> 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
* <code>-Dprop=value</code> 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
* <code>-Dprop=value</code> 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...

View File

@@ -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);
}
}
}
}

View File

@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.4.1-SNAPSHOT</version>
<version>1.4.3-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>

View File

@@ -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:

View File

@@ -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).