diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java index 7cb77038a..5380dae18 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java @@ -57,7 +57,7 @@ public class Engine { /** * The list of dependencies. */ - private final List dependencies; + private List dependencies; /** * A Map of analyzers grouped by Analysis phase. */ @@ -137,6 +137,13 @@ public class Engine { return dependencies; } + public void setDependencies(List dependencies) { + this.dependencies = dependencies; + //for (Dependency dependency: dependencies) { + // dependencies.add(dependency); + //} + } + /** * 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. diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java new file mode 100644 index 000000000..0469f69d9 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java @@ -0,0 +1,968 @@ +/* + * 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) 2014 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.agent; + +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.dependency.Dependency; +import org.owasp.dependencycheck.dependency.Identifier; +import org.owasp.dependencycheck.dependency.Vulnerability; +import org.owasp.dependencycheck.exception.ScanAgentException; +import org.owasp.dependencycheck.reporting.ReportGenerator; +import org.owasp.dependencycheck.utils.Settings; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class provides a way to easily conduct a scan solely based on existing evidence metadata + * rather than collecting evidence from the files themselves. This class is based on the Ant task + * and Maven plugin with the exception that it takes a list of dependencies that can be + * programmatically added from data in a spreadsheet, database or some other datasource and conduct + * a scan based on this pre-defined evidence. + * + *

Example:

+ *
+ * List dependencies = new ArrayList();
+ * Dependency dependency = new Dependency(new File(FileUtils.getBitBucket()));
+ * dependency.getProductEvidence().addEvidence("my-datasource", "name", "Jetty", Confidence.HIGH);
+ * dependency.getVersionEvidence().addEvidence("my-datasource", "version", "5.1.10", Confidence.HIGH);
+ * dependency.getVendorEvidence().addEvidence("my-datasource", "vendor", "mortbay", Confidence.HIGH);
+ * dependencies.add(dependency);
+ *
+ * DependencyCheckScanAgent scan = new DependencyCheckScanAgent();
+ * scan.setDependencies(dependencies);
+ * scan.setReportFormat(ReportGenerator.Format.ALL);
+ * scan.setReportOutputDirectory(System.getProperty("user.home"));
+ * scan.execute();
+ * 
+ * + * @author Steve Springett + */ +@SuppressWarnings("unused") +public class DependencyCheckScanAgent { + + + /** + * System specific new line character. + */ + private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern(); + + /** + * The application name for the report. + */ + private String applicationName = "Dependency-Check"; + + /** + * Get the value of applicationName. + * + * @return the value of applicationName + */ + public String getApplicationName() { + return applicationName; + } + + /** + * Set the value of applicationName. + * + * @param applicationName new value of applicationName + */ + public void setApplicationName(String applicationName) { + this.applicationName = applicationName; + } + + /** + * The pre-determined dependencies to scan + */ + private List dependencies; + + /** + * Returns a list of pre-determined dependencies + */ + public List getDependencies() { + return dependencies; + } + + /** + * Sets the list of dependencies to scan + * + * @param dependencies new value of dependencies + */ + public void setDependencies(List dependencies) { + this.dependencies = dependencies; + } + + /** + * The location of the data directory that contains + */ + private String dataDirectory = null; + + /** + * Get the value of dataDirectory. + * + * @return the value of dataDirectory + */ + public String getDataDirectory() { + return dataDirectory; + } + + /** + * Set the value of dataDirectory. + * + * @param dataDirectory new value of dataDirectory + */ + public void setDataDirectory(String dataDirectory) { + this.dataDirectory = dataDirectory; + } + + /** + * Specifies the destination directory for the generated Dependency-Check report. + */ + private String reportOutputDirectory; + + /** + * Get the value of reportOutputDirectory. + * + * @return the value of reportOutputDirectory + */ + public String getReportOutputDirectory() { + return reportOutputDirectory; + } + + /** + * Set the value of reportOutputDirectory. + * + * @param reportOutputDirectory new value of reportOutputDirectory + */ + public void setReportOutputDirectory(String reportOutputDirectory) { + this.reportOutputDirectory = reportOutputDirectory; + } + + /** + * 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; + + /** + * Get the value of failBuildOnCVSS. + * + * @return the value of failBuildOnCVSS + */ + public float getFailBuildOnCVSS() { + return failBuildOnCVSS; + } + + /** + * Set the value of failBuildOnCVSS. + * + * @param failBuildOnCVSS new value of failBuildOnCVSS + */ + public void setFailBuildOnCVSS(float failBuildOnCVSS) { + this.failBuildOnCVSS = failBuildOnCVSS; + } + + /** + * 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; + + /** + * Get the value of autoUpdate. + * + * @return the value of autoUpdate + */ + public boolean isAutoUpdate() { + return autoUpdate; + } + + /** + * Set the value of autoUpdate. + * + * @param autoUpdate new value of autoUpdate + */ + public void setAutoUpdate(boolean autoUpdate) { + this.autoUpdate = autoUpdate; + } + + /** + * 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; + + /** + * Get the value of reportFormat. + * + * @return the value of reportFormat + */ + public ReportGenerator.Format getReportFormat() { + return reportFormat; + } + + /** + * Set the value of reportFormat. + * + * @param reportFormat new value of reportFormat + */ + public void setReportFormat(ReportGenerator.Format reportFormat) { + this.reportFormat = reportFormat; + } + + /** + * The Proxy URL. + */ + private String proxyUrl; + + /** + * Get the value of proxyUrl. + * + * @return the value of proxyUrl + */ + public String getProxyUrl() { + return proxyUrl; + } + + /** + * Set the value of proxyUrl. + * + * @param proxyUrl new value of proxyUrl + */ + public void setProxyUrl(String proxyUrl) { + this.proxyUrl = proxyUrl; + } + + /** + * The Proxy Port. + */ + private String proxyPort; + + /** + * Get the value of proxyPort. + * + * @return the value of proxyPort + */ + public String getProxyPort() { + return proxyPort; + } + + /** + * Set the value of proxyPort. + * + * @param proxyPort new value of proxyPort + */ + public void setProxyPort(String proxyPort) { + this.proxyPort = proxyPort; + } + + /** + * The Proxy username. + */ + private String proxyUsername; + + /** + * Get the value of proxyUsername. + * + * @return the value of proxyUsername + */ + public String getProxyUsername() { + return proxyUsername; + } + + /** + * Set the value of proxyUsername. + * + * @param proxyUsername new value of proxyUsername + */ + public void setProxyUsername(String proxyUsername) { + this.proxyUsername = proxyUsername; + } + + /** + * The Proxy password. + */ + private String proxyPassword; + + /** + * Get the value of proxyPassword. + * + * @return the value of proxyPassword + */ + public String getProxyPassword() { + return proxyPassword; + } + + /** + * Set the value of proxyPassword. + * + * @param proxyPassword new value of proxyPassword + */ + public void setProxyPassword(String proxyPassword) { + this.proxyPassword = proxyPassword; + } + + /** + * The Connection Timeout. + */ + private String connectionTimeout; + + /** + * Get the value of connectionTimeout. + * + * @return the value of connectionTimeout + */ + public String getConnectionTimeout() { + return connectionTimeout; + } + + /** + * Set the value of connectionTimeout. + * + * @param connectionTimeout new value of connectionTimeout + */ + public void setConnectionTimeout(String connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + /** + * The file path used for verbose logging. + */ + private String logFile = null; + + /** + * Get the value of logFile. + * + * @return the value of logFile + */ + public String getLogFile() { + return logFile; + } + + /** + * Set the value of logFile. + * + * @param logFile new value of logFile + */ + public void setLogFile(String logFile) { + this.logFile = logFile; + } + + /** + * The path to the suppression file. + */ + private String suppressionFile; + + /** + * Get the value of suppressionFile. + * + * @return the value of suppressionFile + */ + public String getSuppressionFile() { + return suppressionFile; + } + + /** + * Set the value of suppressionFile. + * + * @param suppressionFile new value of suppressionFile + */ + public void setSuppressionFile(String suppressionFile) { + this.suppressionFile = suppressionFile; + } + + /** + * flag indicating whether or not to show a summary of findings. + */ + private boolean showSummary = true; + + /** + * Get the value of showSummary. + * + * @return the value of showSummary + */ + public boolean isShowSummary() { + return showSummary; + } + + /** + * Set the value of showSummary. + * + * @param showSummary new value of showSummary + */ + public void setShowSummary(boolean showSummary) { + this.showSummary = showSummary; + } + + /** + * Whether or not the nexus analyzer is enabled. + */ + private boolean nexusAnalyzerEnabled = true; + + /** + * Get the value of nexusAnalyzerEnabled. + * + * @return the value of nexusAnalyzerEnabled + */ + public boolean isNexusAnalyzerEnabled() { + return nexusAnalyzerEnabled; + } + + /** + * Set the value of nexusAnalyzerEnabled. + * + * @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled + */ + public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) { + this.nexusAnalyzerEnabled = nexusAnalyzerEnabled; + } + + /** + * The URL of the Nexus server. + */ + private String nexusUrl; + + /** + * Get the value of nexusUrl. + * + * @return the value of nexusUrl + */ + public String getNexusUrl() { + return nexusUrl; + } + + /** + * Set the value of nexusUrl. + * + * @param nexusUrl new value of nexusUrl + */ + public void setNexusUrl(String nexusUrl) { + this.nexusUrl = nexusUrl; + } + + /** + * Whether or not the defined proxy should be used when connecting to Nexus. + */ + private boolean nexusUsesProxy = true; + + /** + * Get the value of nexusUsesProxy. + * + * @return the value of nexusUsesProxy + */ + public boolean isNexusUsesProxy() { + return nexusUsesProxy; + } + + /** + * Set the value of nexusUsesProxy. + * + * @param nexusUsesProxy new value of nexusUsesProxy + */ + public void setNexusUsesProxy(boolean nexusUsesProxy) { + this.nexusUsesProxy = nexusUsesProxy; + } + + /** + * The database driver name; such as org.h2.Driver. + */ + private String databaseDriverName; + + /** + * Get the value of databaseDriverName. + * + * @return the value of databaseDriverName + */ + public String getDatabaseDriverName() { + return databaseDriverName; + } + + /** + * Set the value of databaseDriverName. + * + * @param databaseDriverName new value of databaseDriverName + */ + public void setDatabaseDriverName(String databaseDriverName) { + this.databaseDriverName = databaseDriverName; + } + + /** + * The path to the database driver JAR file if it is not on the class path. + */ + private String databaseDriverPath; + + /** + * Get the value of databaseDriverPath. + * + * @return the value of databaseDriverPath + */ + public String getDatabaseDriverPath() { + return databaseDriverPath; + } + + /** + * Set the value of databaseDriverPath. + * + * @param databaseDriverPath new value of databaseDriverPath + */ + public void setDatabaseDriverPath(String databaseDriverPath) { + this.databaseDriverPath = databaseDriverPath; + } + + /** + * The database connection string. + */ + private String connectionString; + + /** + * Get the value of connectionString. + * + * @return the value of connectionString + */ + public String getConnectionString() { + return connectionString; + } + + /** + * Set the value of connectionString. + * + * @param connectionString new value of connectionString + */ + public void setConnectionString(String connectionString) { + this.connectionString = connectionString; + } + + /** + * The user name for connecting to the database. + */ + private String databaseUser; + + /** + * Get the value of databaseUser. + * + * @return the value of databaseUser + */ + public String getDatabaseUser() { + return databaseUser; + } + + /** + * Set the value of databaseUser. + * + * @param databaseUser new value of databaseUser + */ + public void setDatabaseUser(String databaseUser) { + this.databaseUser = databaseUser; + } + + /** + * The password to use when connecting to the database. + */ + private String databasePassword; + + /** + * Get the value of databasePassword. + * + * @return the value of databasePassword + */ + public String getDatabasePassword() { + return databasePassword; + } + + /** + * Set the value of databasePassword. + * + * @param databasePassword new value of databasePassword + */ + public void setDatabasePassword(String databasePassword) { + this.databasePassword = databasePassword; + } + + /** + * 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; + + /** + * Get the value of zipExtensions. + * + * @return the value of zipExtensions + */ + public String getZipExtensions() { + return zipExtensions; + } + + /** + * Set the value of zipExtensions. + * + * @param zipExtensions new value of zipExtensions + */ + public void setZipExtensions(String zipExtensions) { + this.zipExtensions = zipExtensions; + } + + /** + * The url for the modified NVD CVE (1.2 schema). + */ + private String cveUrl12Modified; + + /** + * Get the value of cveUrl12Modified. + * + * @return the value of cveUrl12Modified + */ + public String getCveUrl12Modified() { + return cveUrl12Modified; + } + + /** + * Set the value of cveUrl12Modified. + * + * @param cveUrl12Modified new value of cveUrl12Modified + */ + public void setCveUrl12Modified(String cveUrl12Modified) { + this.cveUrl12Modified = cveUrl12Modified; + } + + /** + * The url for the modified NVD CVE (2.0 schema). + */ + private String cveUrl20Modified; + + /** + * Get the value of cveUrl20Modified. + * + * @return the value of cveUrl20Modified + */ + public String getCveUrl20Modified() { + return cveUrl20Modified; + } + + /** + * Set the value of cveUrl20Modified. + * + * @param cveUrl20Modified new value of cveUrl20Modified + */ + public void setCveUrl20Modified(String cveUrl20Modified) { + this.cveUrl20Modified = cveUrl20Modified; + } + + /** + * Base Data Mirror URL for CVE 1.2. + */ + private String cveUrl12Base; + + /** + * Get the value of cveUrl12Base. + * + * @return the value of cveUrl12Base + */ + public String getCveUrl12Base() { + return cveUrl12Base; + } + + /** + * Set the value of cveUrl12Base. + * + * @param cveUrl12Base new value of cveUrl12Base + */ + public void setCveUrl12Base(String cveUrl12Base) { + this.cveUrl12Base = cveUrl12Base; + } + + /** + * Data Mirror URL for CVE 2.0. + */ + private String cveUrl20Base; + + /** + * Get the value of cveUrl20Base. + * + * @return the value of cveUrl20Base + */ + public String getCveUrl20Base() { + return cveUrl20Base; + } + + /** + * Set the value of cveUrl20Base. + * + * @param cveUrl20Base new value of cveUrl20Base + */ + public void setCveUrl20Base(String cveUrl20Base) { + this.cveUrl20Base = cveUrl20Base; + } + + /** + * The path to Mono for .NET assembly analysis on non-windows systems. + */ + private String pathToMono; + + /** + * Get the value of pathToMono. + * + * @return the value of pathToMono + */ + public String getPathToMono() { + return pathToMono; + } + + /** + * Set the value of pathToMono. + * + * @param pathToMono new value of pathToMono + */ + public void setPathToMono(String pathToMono) { + this.pathToMono = pathToMono; + } + + /** + * 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 + */ + private Engine executeDependencyCheck() throws DatabaseException { + populateSettings(); + Engine engine = null; + try { + engine = new Engine(); + engine.setDependencies(this.dependencies); + engine.analyzeDependencies(); + + } finally { + if (engine != null) { + engine.cleanup(); + } + } + return engine; + } + + /** + * Generates the reports for a given dependency-check engine. + * + * @param engine a dependency-check engine + * @param outDirectory the directory to write the reports to + */ + private void generateExternalReports(Engine engine, File outDirectory) { + DatabaseProperties prop = null; + CveDB cve = null; + try { + cve = new CveDB(); + cve.open(); + prop = cve.getDatabaseProperties(); + } catch (DatabaseException ex) { + Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex); + } finally { + if (cve != null) { + cve.close(); + } + } + final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop); + try { + r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name()); + } catch (IOException ex) { + Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.SEVERE, + "Unexpected exception occurred during analysis; please see the verbose error log for more details."); + Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.FINE, null, ex); + } catch (Throwable ex) { + Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.SEVERE, + "Unexpected exception occurred during analysis; please see the verbose error log for more details."); + Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.FINE, null, ex); + } + } + + /** + * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system + * properties required to change the proxy url, port, and connection timeout. + */ + private void populateSettings() { + if (dataDirectory != null) { + Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory); + } else { + final File jarPath = new File(DependencyCheckScanAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath()); + final File base = jarPath.getParentFile(); + final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY); + final File dataDir = new File(base, sub); + Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath()); + } + + Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate); + + if (proxyUrl != null && !proxyUrl.isEmpty()) { + Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl); + } + if (proxyPort != null && !proxyPort.isEmpty()) { + Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort); + } + if (proxyUsername != null && !proxyUsername.isEmpty()) { + Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername); + } + if (proxyPassword != null && !proxyPassword.isEmpty()) { + Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword); + } + if (connectionTimeout != null && !connectionTimeout.isEmpty()) { + Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout); + } + if (suppressionFile != null && !suppressionFile.isEmpty()) { + Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile); + } + Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled); + if (nexusUrl != null && !nexusUrl.isEmpty()) { + Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl); + } + Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy); + if (databaseDriverName != null && !databaseDriverName.isEmpty()) { + Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName); + } + if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) { + Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath); + } + if (connectionString != null && !connectionString.isEmpty()) { + Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString); + } + if (databaseUser != null && !databaseUser.isEmpty()) { + Settings.setString(Settings.KEYS.DB_USER, databaseUser); + } + if (databasePassword != null && !databasePassword.isEmpty()) { + Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword); + } + if (zipExtensions != null && !zipExtensions.isEmpty()) { + Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions); + } + if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) { + Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified); + } + if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) { + Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified); + } + if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) { + Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base); + } + if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) { + Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base); + } + if (pathToMono != null && !pathToMono.isEmpty()) { + Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono); + } + } + + /** + * Executes the dependency-check and generates the report. + */ + public void execute() throws ScanAgentException { + Engine engine = null; + try { + engine = executeDependencyCheck(); + generateExternalReports(engine, new File(this.reportOutputDirectory)); + if (this.showSummary) { + showSummary(engine.getDependencies()); + } + if (this.failBuildOnCVSS <= 10) { + checkForFailure(engine.getDependencies()); + } + } catch (DatabaseException ex) { + Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.SEVERE, + "Unable to connect to the dependency-check database; analysis has stopped"); + Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.FINE, "", ex); + } finally { + if (engine != null) { + engine.cleanup(); + } + } + } + + /** + * 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 + */ + private void checkForFailure(List dependencies) throws ScanAgentException { + final StringBuilder ids = new StringBuilder(); + for (Dependency d : dependencies) { + boolean addName = true; + for (Vulnerability v : d.getVulnerabilities()) { + if (v.getCvssScore() >= failBuildOnCVSS) { + if (addName) { + addName = false; + ids.append(NEW_LINE).append(d.getFileName()).append(": "); + ids.append(v.getName()); + } else { + ids.append(", ").append(v.getName()); + } + } + } + } + if (ids.length() > 0) { + final String msg = String.format("%n%nDependency-Check Failure:%n" + + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n" + + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString()); + + throw new ScanAgentException(msg); + } + } + + /** + * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries. + * + * @param dependencies a list of dependency objects + */ + private void showSummary(List dependencies) { + final StringBuilder summary = new StringBuilder(); + for (Dependency d : dependencies) { + boolean firstEntry = true; + final StringBuilder ids = new StringBuilder(); + for (Vulnerability v : d.getVulnerabilities()) { + if (firstEntry) { + firstEntry = false; + } else { + ids.append(", "); + } + ids.append(v.getName()); + } + if (ids.length() > 0) { + summary.append(d.getFileName()).append(" ("); + firstEntry = true; + for (Identifier id : d.getIdentifiers()) { + if (firstEntry) { + firstEntry = false; + } else { + summary.append(", "); + } + summary.append(id.getValue()); + } + summary.append(") : ").append(ids).append(NEW_LINE); + } + } + if (summary.length() > 0) { + final String msg = String.format("%n%n" + + "One or more dependencies were identified with known vulnerabilities:%n%n%s" + + "%n%nSee the dependency-check report for more details.%n%n", summary.toString()); + Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.WARNING, msg); + } + } + +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ScanAgentException.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ScanAgentException.java new file mode 100644 index 000000000..4b325e234 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/ScanAgentException.java @@ -0,0 +1,68 @@ +/* + * 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) 2014 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.exception; + +import java.io.IOException; + +/** + * An exception used when using @{link DependencyCheckScanAgent} to conduct a scan and the scan fails. + * + * @author Steve Springett + */ +public class ScanAgentException extends IOException { + + /** + * The serial version uid. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new ScanAgentException. + */ + public ScanAgentException() { + super(); + } + + /** + * Creates a new ScanAgentException. + * + * @param msg a message for the exception. + */ + public ScanAgentException(String msg) { + super(msg); + } + + /** + * Creates a new NoDataException. + * + * @param ex the cause of the exception. + */ + public ScanAgentException(Throwable ex) { + super(ex); + } + + /** + * Creates a new ScanAgentException. + * + * @param msg a message for the exception. + * @param ex the cause of the exception. + */ + public ScanAgentException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java index fc3c4a31b..bda2a82c7 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java @@ -40,6 +40,16 @@ import org.owasp.dependencycheck.Engine; */ public final class FileUtils { + /** + * Bit bucket for non-Windows systems + */ + private static final String BIT_BUCKET_UNIX = "/dev/null"; + + /** + * Bit bucket for Windows systems (yes, only one 'L') + */ + private static final String BIT_BUCKET_WIN = "NUL"; + /** * The buffer size to use when extracting files from the archive. */ @@ -239,4 +249,16 @@ public final class FileUtils { } } } + + /** + * Return the bit bucket for the OS. '/dev/null' for Unix and 'NUL' for Windows + * @return a String containing the bit bucket + */ + public static String getBitBucket() { + if (System.getProperty("os.name").startsWith("Windows")) { + return BIT_BUCKET_WIN; + } else { + return BIT_BUCKET_UNIX; + } + } }