DependencyCheckScanAgent.java

  1. /*
  2.  * This file is part of dependency-check-core.
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *     http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  *
  16.  * Copyright (c) 2014 Steve Springett. All Rights Reserved.
  17.  */
  18. package org.owasp.dependencycheck.agent;

  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.util.List;
  22. import java.util.stream.Collectors;
  23. import java.util.stream.Stream;
  24. import javax.annotation.concurrent.NotThreadSafe;
  25. import org.owasp.dependencycheck.Engine;
  26. import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
  27. import org.owasp.dependencycheck.data.update.exception.UpdateException;
  28. import org.owasp.dependencycheck.dependency.Dependency;
  29. import org.owasp.dependencycheck.dependency.Vulnerability;
  30. import org.owasp.dependencycheck.dependency.naming.Identifier;
  31. import org.owasp.dependencycheck.exception.ExceptionCollection;
  32. import org.owasp.dependencycheck.exception.ReportException;
  33. import org.owasp.dependencycheck.exception.ScanAgentException;
  34. import org.owasp.dependencycheck.reporting.ReportGenerator;
  35. import org.owasp.dependencycheck.utils.Settings;
  36. import org.owasp.dependencycheck.utils.SeverityUtil;
  37. import org.slf4j.Logger;
  38. import org.slf4j.LoggerFactory;

  39. /**
  40.  * This class provides a way to easily conduct a scan solely based on existing
  41.  * evidence metadata rather than collecting evidence from the files themselves.
  42.  * This class is based on the Ant task and Maven plugin with the exception that
  43.  * it takes a list of dependencies that can be programmatically added from data
  44.  * in a spreadsheet, database or some other datasource and conduct a scan based
  45.  * on this pre-defined evidence.
  46.  *
  47.  * <h2>Example:</h2>
  48.  * <pre>
  49.  * List&lt;Dependency&gt; dependencies = new ArrayList&lt;Dependency&gt;();
  50.  * Dependency dependency = new Dependency(new File(FileUtils.getBitBucket()));
  51.  * dependency.addEvidence(EvidenceType.PRODUCT, "my-datasource", "name", "Jetty", Confidence.HIGH);
  52.  * dependency.addEvidence(EvidenceType.VERSION, "my-datasource", "version", "5.1.10", Confidence.HIGH);
  53.  * dependency.addEvidence(EvidenceType.VENDOR, "my-datasource", "vendor", "mortbay", Confidence.HIGH);
  54.  * dependencies.add(dependency);
  55.  *
  56.  * DependencyCheckScanAgent scan = new DependencyCheckScanAgent();
  57.  * scan.setDependencies(dependencies);
  58.  * scan.setReportFormat(ReportGenerator.Format.ALL);
  59.  * scan.setReportOutputDirectory(System.getProperty("user.home"));
  60.  * scan.execute();
  61.  * </pre>
  62.  *
  63.  * @author Steve Springett
  64.  */
  65. @SuppressWarnings("unused")
  66. @NotThreadSafe
  67. public class DependencyCheckScanAgent {

  68.     //<editor-fold defaultstate="collapsed" desc="private fields">
  69.     /**
  70.      * System specific new line character.
  71.      */
  72.     private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
  73.     /**
  74.      * Logger for use throughout the class.
  75.      */
  76.     private static final Logger LOGGER = LoggerFactory.getLogger(DependencyCheckScanAgent.class);
  77.     /**
  78.      * The application name for the report.
  79.      */
  80.     private String applicationName = "Dependency-Check";
  81.     /**
  82.      * The pre-determined dependencies to scan
  83.      */
  84.     private List<Dependency> dependencies;
  85.     /**
  86.      * The location of the data directory that contains
  87.      */
  88.     private String dataDirectory = null;
  89.     /**
  90.      * Specifies the destination directory for the generated Dependency-Check
  91.      * report.
  92.      */
  93.     private String reportOutputDirectory;
  94.     /**
  95.      * Specifies if the build should be failed if a CVSS score above a specified
  96.      * level is identified. The default is 11 which means since the CVSS scores
  97.      * are 0-10, by default the build will never fail and the CVSS score is set
  98.      * to 11. The valid range for the fail build on CVSS is 0 to 11, where
  99.      * anything above 10 will not cause the build to fail.
  100.      */
  101.     private Double failBuildOnCVSS = 11.0;
  102.     /**
  103.      * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
  104.      * recommended that this be turned to false. Default is true.
  105.      */
  106.     private boolean autoUpdate = true;
  107.     /**
  108.      * The NVD API key.
  109.      */
  110.     private String nvdApiKey;

  111.     /**
  112.      * Sets whether the data directory should be updated without performing a
  113.      * scan. Default is false.
  114.      */
  115.     private boolean updateOnly = false;
  116.     /**
  117.      * flag indicating whether to generate a report of findings.
  118.      */
  119.     private boolean generateReport = true;
  120.     /**
  121.      * The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF,
  122.      * JENKINS, GITLAB, ALL). This configuration option has no affect if using
  123.      * this within the Site plugin unless the externalReport is set to true.
  124.      * Default is HTML.
  125.      */
  126.     private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
  127.     /**
  128.      * The Proxy Server.
  129.      */
  130.     private String proxyServer;
  131.     /**
  132.      * The Proxy Port.
  133.      */
  134.     private String proxyPort;
  135.     /**
  136.      * The Proxy username.
  137.      */
  138.     private String proxyUsername;
  139.     /**
  140.      * The Proxy password.
  141.      */
  142.     private String proxyPassword;
  143.     /**
  144.      * The Connection Timeout.
  145.      */
  146.     private String connectionTimeout;
  147.     /**
  148.      * The Connection Read Timeout.
  149.      */
  150.     private String readTimeout;
  151.     /**
  152.      * The file path used for verbose logging.
  153.      */
  154.     private String logFile = null;
  155.     /**
  156.      * flag indicating whether to show a summary of findings.
  157.      */
  158.     private boolean showSummary = true;
  159.     /**
  160.      * The path to the suppression file.
  161.      */
  162.     private String suppressionFile;
  163.     /**
  164.      * The password to use when connecting to the database.
  165.      */
  166.     private String databasePassword;
  167.     /**
  168.      * The starting string that identifies CPEs that are qualified to be
  169.      * imported.
  170.      */
  171.     private String cpeStartsWithFilter;
  172.     /**
  173.      * Whether the Maven Central analyzer is enabled.
  174.      */
  175.     private boolean centralAnalyzerEnabled = true;
  176.     /**
  177.      * Whether the build should fail if there are unused suppression rules.
  178.      */
  179.     private boolean failOnUnusedSuppressionRule = false;
  180.     /**
  181.      * The URL of Maven Central.
  182.      */
  183.     private String centralUrl;
  184.     /**
  185.      * Whether the nexus analyzer is enabled.
  186.      */
  187.     private boolean nexusAnalyzerEnabled = true;
  188.     /**
  189.      * The URL of the Nexus server.
  190.      */
  191.     private String nexusUrl;
  192.     /**
  193.      * Whether the defined proxy should be used when connecting to Nexus.
  194.      */
  195.     private boolean nexusUsesProxy = true;
  196.     /**
  197.      * The database driver name; such as org.h2.Driver.
  198.      */
  199.     private String databaseDriverName;
  200.     /**
  201.      * The path to the database driver JAR file if it is not on the class path.
  202.      */
  203.     private String databaseDriverPath;
  204.     /**
  205.      * The database connection string.
  206.      */
  207.     private String connectionString;
  208.     /**
  209.      * The username for connecting to the database.
  210.      */
  211.     private String databaseUser;
  212.     /**
  213.      * Additional ZIP File extensions to add analyze. This should be a
  214.      * comma-separated list of file extensions to treat like ZIP files.
  215.      */
  216.     private String zipExtensions;
  217.     /**
  218.      * The path to dotnet core for .NET assembly analysis.
  219.      */
  220.     private String pathToCore;
  221.     /**
  222.      * The configured settings.
  223.      */
  224.     private Settings settings;
  225.     /**
  226.      * The path to optional dependency-check properties file. This will be used
  227.      * to side-load additional user-defined properties.
  228.      * {@link Settings#mergeProperties(String)}
  229.      */
  230.     private String propertiesFilePath;
  231.     //</editor-fold>
  232.     //<editor-fold defaultstate="collapsed" desc="getters/setters">

  233.     /**
  234.      * Get the value of applicationName.
  235.      *
  236.      * @return the value of applicationName
  237.      */
  238.     public String getApplicationName() {
  239.         return applicationName;
  240.     }

  241.     /**
  242.      * Set the value of applicationName.
  243.      *
  244.      * @param applicationName new value of applicationName
  245.      */
  246.     public void setApplicationName(String applicationName) {
  247.         this.applicationName = applicationName;
  248.     }

  249.     /**
  250.      * Get the value of nvdApiKey.
  251.      *
  252.      * @return the value of nvdApiKey
  253.      */
  254.     public String getNvdApiKey() {
  255.         return nvdApiKey;
  256.     }

  257.     /**
  258.      * Set the value of nvdApiKey.
  259.      *
  260.      * @param nvdApiKey new value of nvdApiKey
  261.      */
  262.     public void setNvdApiKey(String nvdApiKey) {
  263.         this.nvdApiKey = nvdApiKey;
  264.     }

  265.     /**
  266.      * Returns a list of pre-determined dependencies.
  267.      *
  268.      * @return returns a list of dependencies
  269.      */
  270.     public List<Dependency> getDependencies() {
  271.         return dependencies;
  272.     }

  273.     /**
  274.      * Sets the list of dependencies to scan.
  275.      *
  276.      * @param dependencies new value of dependencies
  277.      */
  278.     public void setDependencies(List<Dependency> dependencies) {
  279.         this.dependencies = dependencies;
  280.     }

  281.     /**
  282.      * Get the value of dataDirectory.
  283.      *
  284.      * @return the value of dataDirectory
  285.      */
  286.     public String getDataDirectory() {
  287.         return dataDirectory;
  288.     }

  289.     /**
  290.      * Set the value of dataDirectory.
  291.      *
  292.      * @param dataDirectory new value of dataDirectory
  293.      */
  294.     public void setDataDirectory(String dataDirectory) {
  295.         this.dataDirectory = dataDirectory;
  296.     }

  297.     /**
  298.      * Get the value of reportOutputDirectory.
  299.      *
  300.      * @return the value of reportOutputDirectory
  301.      */
  302.     public String getReportOutputDirectory() {
  303.         return reportOutputDirectory;
  304.     }

  305.     /**
  306.      * Set the value of reportOutputDirectory.
  307.      *
  308.      * @param reportOutputDirectory new value of reportOutputDirectory
  309.      */
  310.     public void setReportOutputDirectory(String reportOutputDirectory) {
  311.         this.reportOutputDirectory = reportOutputDirectory;
  312.     }

  313.     /**
  314.      * Get the value of failBuildOnCVSS.
  315.      *
  316.      * @return the value of failBuildOnCVSS
  317.      */
  318.     public Double getFailBuildOnCVSS() {
  319.         return failBuildOnCVSS;
  320.     }

  321.     /**
  322.      * Set the value of failBuildOnCVSS.
  323.      *
  324.      * @param failBuildOnCVSS new value of failBuildOnCVSS
  325.      */
  326.     public void setFailBuildOnCVSS(Double failBuildOnCVSS) {
  327.         this.failBuildOnCVSS = failBuildOnCVSS;
  328.     }

  329.     /**
  330.      * Get the value of autoUpdate.
  331.      *
  332.      * @return the value of autoUpdate
  333.      */
  334.     public boolean isAutoUpdate() {
  335.         return autoUpdate;
  336.     }

  337.     /**
  338.      * Set the value of autoUpdate.
  339.      *
  340.      * @param autoUpdate new value of autoUpdate
  341.      */
  342.     public void setAutoUpdate(boolean autoUpdate) {
  343.         this.autoUpdate = autoUpdate;
  344.     }

  345.     /**
  346.      * Get the value of updateOnly.
  347.      *
  348.      * @return the value of updateOnly
  349.      */
  350.     public boolean isUpdateOnly() {
  351.         return updateOnly;
  352.     }

  353.     /**
  354.      * Set the value of updateOnly.
  355.      *
  356.      * @param updateOnly new value of updateOnly
  357.      */
  358.     public void setUpdateOnly(boolean updateOnly) {
  359.         this.updateOnly = updateOnly;
  360.     }

  361.     /**
  362.      * Get the value of generateReport.
  363.      *
  364.      * @return the value of generateReport
  365.      */
  366.     public boolean isGenerateReport() {
  367.         return generateReport;
  368.     }

  369.     /**
  370.      * Set the value of generateReport.
  371.      *
  372.      * @param generateReport new value of generateReport
  373.      */
  374.     public void setGenerateReport(boolean generateReport) {
  375.         this.generateReport = generateReport;
  376.     }

  377.     /**
  378.      * Get the value of reportFormat.
  379.      *
  380.      * @return the value of reportFormat
  381.      */
  382.     public ReportGenerator.Format getReportFormat() {
  383.         return reportFormat;
  384.     }

  385.     /**
  386.      * Set the value of reportFormat.
  387.      *
  388.      * @param reportFormat new value of reportFormat
  389.      */
  390.     public void setReportFormat(ReportGenerator.Format reportFormat) {
  391.         this.reportFormat = reportFormat;
  392.     }

  393.     /**
  394.      * Get the value of proxyServer.
  395.      *
  396.      * @return the value of proxyServer
  397.      */
  398.     public String getProxyServer() {
  399.         return proxyServer;
  400.     }

  401.     /**
  402.      * Set the value of proxyServer.
  403.      *
  404.      * @param proxyServer new value of proxyServer
  405.      */
  406.     public void setProxyServer(String proxyServer) {
  407.         this.proxyServer = proxyServer;
  408.     }

  409.     /**
  410.      * Get the value of proxyServer.
  411.      *
  412.      * @return the value of proxyServer
  413.      * @deprecated use
  414.      * {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()}
  415.      * instead
  416.      */
  417.     @Deprecated
  418.     public String getProxyUrl() {
  419.         return proxyServer;
  420.     }

  421.     /**
  422.      * Set the value of proxyServer.
  423.      *
  424.      * @param proxyUrl new value of proxyServer
  425.      * @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#setProxyServer(java.lang.String)
  426.      * } instead
  427.      */
  428.     @Deprecated
  429.     public void setProxyUrl(String proxyUrl) {
  430.         this.proxyServer = proxyUrl;
  431.     }

  432.     /**
  433.      * Get the value of proxyPort.
  434.      *
  435.      * @return the value of proxyPort
  436.      */
  437.     public String getProxyPort() {
  438.         return proxyPort;
  439.     }

  440.     /**
  441.      * Set the value of proxyPort.
  442.      *
  443.      * @param proxyPort new value of proxyPort
  444.      */
  445.     public void setProxyPort(String proxyPort) {
  446.         this.proxyPort = proxyPort;
  447.     }

  448.     /**
  449.      * Get the value of proxyUsername.
  450.      *
  451.      * @return the value of proxyUsername
  452.      */
  453.     public String getProxyUsername() {
  454.         return proxyUsername;
  455.     }

  456.     /**
  457.      * Set the value of proxyUsername.
  458.      *
  459.      * @param proxyUsername new value of proxyUsername
  460.      */
  461.     public void setProxyUsername(String proxyUsername) {
  462.         this.proxyUsername = proxyUsername;
  463.     }

  464.     /**
  465.      * Get the value of proxyPassword.
  466.      *
  467.      * @return the value of proxyPassword
  468.      */
  469.     public String getProxyPassword() {
  470.         return proxyPassword;
  471.     }

  472.     /**
  473.      * Set the value of proxyPassword.
  474.      *
  475.      * @param proxyPassword new value of proxyPassword
  476.      */
  477.     public void setProxyPassword(String proxyPassword) {
  478.         this.proxyPassword = proxyPassword;
  479.     }

  480.     /**
  481.      * Get the value of connectionTimeout.
  482.      *
  483.      * @return the value of connectionTimeout
  484.      */
  485.     public String getConnectionTimeout() {
  486.         return connectionTimeout;
  487.     }

  488.     /**
  489.      * Set the value of connectionTimeout.
  490.      *
  491.      * @param connectionTimeout new value of connectionTimeout
  492.      */
  493.     public void setConnectionTimeout(String connectionTimeout) {
  494.         this.connectionTimeout = connectionTimeout;
  495.     }

  496.     /**
  497.      * Get the value of readTimeout.
  498.      *
  499.      * @return the value of readTimeout
  500.      */
  501.     public String getReadTimeout() {
  502.         return readTimeout;
  503.     }

  504.     /**
  505.      * Set the value of readTimeout.
  506.      *
  507.      * @param readTimeout new value of readTimeout
  508.      */
  509.     public void setReadTimeout(String readTimeout) {
  510.         this.readTimeout = readTimeout;
  511.     }

  512.     /**
  513.      * Get the value of logFile.
  514.      *
  515.      * @return the value of logFile
  516.      */
  517.     public String getLogFile() {
  518.         return logFile;
  519.     }

  520.     /**
  521.      * Set the value of logFile.
  522.      *
  523.      * @param logFile new value of logFile
  524.      */
  525.     public void setLogFile(String logFile) {
  526.         this.logFile = logFile;
  527.     }

  528.     /**
  529.      * Get the value of suppressionFile.
  530.      *
  531.      * @return the value of suppressionFile
  532.      */
  533.     public String getSuppressionFile() {
  534.         return suppressionFile;
  535.     }

  536.     /**
  537.      * Set the value of suppressionFile.
  538.      *
  539.      * @param suppressionFile new value of suppressionFile
  540.      */
  541.     public void setSuppressionFile(String suppressionFile) {
  542.         this.suppressionFile = suppressionFile;
  543.     }

  544.     /**
  545.      * Get the value of showSummary.
  546.      *
  547.      * @return the value of showSummary
  548.      */
  549.     public boolean isShowSummary() {
  550.         return showSummary;
  551.     }

  552.     /**
  553.      * Set the value of showSummary.
  554.      *
  555.      * @param showSummary new value of showSummary
  556.      */
  557.     public void setShowSummary(boolean showSummary) {
  558.         this.showSummary = showSummary;
  559.     }

  560.     /**
  561.      * Sets starting string that identifies CPEs that are qualified to be
  562.      * imported.
  563.      *
  564.      * @param cpeStartsWithFilter filters CPEs based on this starting string
  565.      * (i.e. cpe:/a: )
  566.      */
  567.     public void setCpeStartsWithFilter(String cpeStartsWithFilter) {
  568.         this.cpeStartsWithFilter = cpeStartsWithFilter;
  569.     }

  570.     /**
  571.      * Returns the starting string that identifies CPEs that are qualified to be
  572.      * imported.
  573.      *
  574.      * @return the CPE starting filter (i.e. cpe:/a: )
  575.      */
  576.     public String getCpeStartsWithFilter() {
  577.         return cpeStartsWithFilter;
  578.     }

  579.     /**
  580.      * Get the value of failOnUnusedSuppressionRule.
  581.      *
  582.      * @return the value of failOnUnusedSuppressionRule
  583.      */
  584.     public boolean isFailOnUnusedSuppressionRule() {
  585.         return failOnUnusedSuppressionRule;
  586.     }

  587.     /**
  588.      * Set the value of failOnUnusedSuppressionRule.
  589.      *
  590.      * @param failOnUnusedSuppressionRule new value of failOnUnusedSuppressionRule
  591.      */
  592.     public void setFailOnUnusedSuppressionRule(boolean failOnUnusedSuppressionRule) {
  593.         this.failOnUnusedSuppressionRule = failOnUnusedSuppressionRule;
  594.     }

  595.     /**
  596.      * Get the value of centralAnalyzerEnabled.
  597.      *
  598.      * @return the value of centralAnalyzerEnabled
  599.      */
  600.     public boolean isCentralAnalyzerEnabled() {
  601.         return centralAnalyzerEnabled;
  602.     }

  603.     /**
  604.      * Set the value of centralAnalyzerEnabled.
  605.      *
  606.      * @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
  607.      */
  608.     public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
  609.         this.centralAnalyzerEnabled = centralAnalyzerEnabled;
  610.     }

  611.     /**
  612.      * Get the value of centralUrl.
  613.      *
  614.      * @return the value of centralUrl
  615.      */
  616.     public String getCentralUrl() {
  617.         return centralUrl;
  618.     }

  619.     /**
  620.      * Set the value of centralUrl.
  621.      *
  622.      * @param centralUrl new value of centralUrl
  623.      */
  624.     public void setCentralUrl(String centralUrl) {
  625.         this.centralUrl = centralUrl;
  626.     }

  627.     /**
  628.      * Get the value of nexusAnalyzerEnabled.
  629.      *
  630.      * @return the value of nexusAnalyzerEnabled
  631.      */
  632.     public boolean isNexusAnalyzerEnabled() {
  633.         return nexusAnalyzerEnabled;
  634.     }

  635.     /**
  636.      * Set the value of nexusAnalyzerEnabled.
  637.      *
  638.      * @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
  639.      */
  640.     public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
  641.         this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
  642.     }

  643.     /**
  644.      * Get the value of nexusUrl.
  645.      *
  646.      * @return the value of nexusUrl
  647.      */
  648.     public String getNexusUrl() {
  649.         return nexusUrl;
  650.     }

  651.     /**
  652.      * Set the value of nexusUrl.
  653.      *
  654.      * @param nexusUrl new value of nexusUrl
  655.      */
  656.     public void setNexusUrl(String nexusUrl) {
  657.         this.nexusUrl = nexusUrl;
  658.     }

  659.     /**
  660.      * Get the value of nexusUsesProxy.
  661.      *
  662.      * @return the value of nexusUsesProxy
  663.      */
  664.     public boolean isNexusUsesProxy() {
  665.         return nexusUsesProxy;
  666.     }

  667.     /**
  668.      * Set the value of nexusUsesProxy.
  669.      *
  670.      * @param nexusUsesProxy new value of nexusUsesProxy
  671.      */
  672.     public void setNexusUsesProxy(boolean nexusUsesProxy) {
  673.         this.nexusUsesProxy = nexusUsesProxy;
  674.     }

  675.     /**
  676.      * Get the value of databaseDriverName.
  677.      *
  678.      * @return the value of databaseDriverName
  679.      */
  680.     public String getDatabaseDriverName() {
  681.         return databaseDriverName;
  682.     }

  683.     /**
  684.      * Set the value of databaseDriverName.
  685.      *
  686.      * @param databaseDriverName new value of databaseDriverName
  687.      */
  688.     public void setDatabaseDriverName(String databaseDriverName) {
  689.         this.databaseDriverName = databaseDriverName;
  690.     }

  691.     /**
  692.      * Get the value of databaseDriverPath.
  693.      *
  694.      * @return the value of databaseDriverPath
  695.      */
  696.     public String getDatabaseDriverPath() {
  697.         return databaseDriverPath;
  698.     }

  699.     /**
  700.      * Set the value of databaseDriverPath.
  701.      *
  702.      * @param databaseDriverPath new value of databaseDriverPath
  703.      */
  704.     public void setDatabaseDriverPath(String databaseDriverPath) {
  705.         this.databaseDriverPath = databaseDriverPath;
  706.     }

  707.     /**
  708.      * Get the value of connectionString.
  709.      *
  710.      * @return the value of connectionString
  711.      */
  712.     public String getConnectionString() {
  713.         return connectionString;
  714.     }

  715.     /**
  716.      * Set the value of connectionString.
  717.      *
  718.      * @param connectionString new value of connectionString
  719.      */
  720.     public void setConnectionString(String connectionString) {
  721.         this.connectionString = connectionString;
  722.     }

  723.     /**
  724.      * Get the value of databaseUser.
  725.      *
  726.      * @return the value of databaseUser
  727.      */
  728.     public String getDatabaseUser() {
  729.         return databaseUser;
  730.     }

  731.     /**
  732.      * Set the value of databaseUser.
  733.      *
  734.      * @param databaseUser new value of databaseUser
  735.      */
  736.     public void setDatabaseUser(String databaseUser) {
  737.         this.databaseUser = databaseUser;
  738.     }

  739.     /**
  740.      * Get the value of databasePassword.
  741.      *
  742.      * @return the value of databasePassword
  743.      */
  744.     public String getDatabasePassword() {
  745.         return databasePassword;
  746.     }

  747.     /**
  748.      * Set the value of databasePassword.
  749.      *
  750.      * @param databasePassword new value of databasePassword
  751.      */
  752.     public void setDatabasePassword(String databasePassword) {
  753.         this.databasePassword = databasePassword;
  754.     }

  755.     /**
  756.      * Get the value of zipExtensions.
  757.      *
  758.      * @return the value of zipExtensions
  759.      */
  760.     public String getZipExtensions() {
  761.         return zipExtensions;
  762.     }

  763.     /**
  764.      * Set the value of zipExtensions.
  765.      *
  766.      * @param zipExtensions new value of zipExtensions
  767.      */
  768.     public void setZipExtensions(String zipExtensions) {
  769.         this.zipExtensions = zipExtensions;
  770.     }

  771.     /**
  772.      * Get the value of pathToCore.
  773.      *
  774.      * @return the value of pathToCore
  775.      */
  776.     public String getPathToDotnetCore() {
  777.         return pathToCore;
  778.     }

  779.     /**
  780.      * Set the value of pathToCore.
  781.      *
  782.      * @param pathToCore new value of pathToCore
  783.      */
  784.     public void setPathToDotnetCore(String pathToCore) {
  785.         this.pathToCore = pathToCore;
  786.     }

  787.     /**
  788.      * Get the value of propertiesFilePath.
  789.      *
  790.      * @return the value of propertiesFilePath
  791.      */
  792.     public String getPropertiesFilePath() {
  793.         return propertiesFilePath;
  794.     }

  795.     /**
  796.      * Set the value of propertiesFilePath.
  797.      *
  798.      * @param propertiesFilePath new value of propertiesFilePath
  799.      */
  800.     public void setPropertiesFilePath(String propertiesFilePath) {
  801.         this.propertiesFilePath = propertiesFilePath;
  802.     }
  803.     //</editor-fold>

  804.     /**
  805.      * Executes the Dependency-Check on the dependent libraries. <b>Note</b>,
  806.      * the engine object returned from this method must be closed by calling
  807.      * `close()`
  808.      *
  809.      * @return the Engine used to scan the dependencies.
  810.      * @throws ExceptionCollection a collection of one or more exceptions that
  811.      * occurred during analysis.
  812.      */
  813.     @SuppressWarnings("squid:S2095")
  814.     private Engine executeDependencyCheck() throws ExceptionCollection {
  815.         populateSettings();
  816.         final Engine engine;
  817.         try {
  818.             engine = new Engine(settings);
  819.         } catch (DatabaseException ex) {
  820.             throw new ExceptionCollection(ex, true);
  821.         }
  822.         if (this.updateOnly) {
  823.             try {
  824.                 engine.doUpdates();
  825.             } catch (UpdateException ex) {
  826.                 throw new ExceptionCollection(ex);
  827.             } finally {
  828.                 engine.close();
  829.             }
  830.         } else {
  831.             engine.setDependencies(this.dependencies);
  832.             engine.analyzeDependencies();
  833.         }
  834.         return engine;
  835.     }

  836.     /**
  837.      * Generates the reports for a given dependency-check engine.
  838.      *
  839.      * @param engine a dependency-check engine
  840.      * @param outDirectory the directory to write the reports to
  841.      * @throws ScanAgentException thrown if there is an error generating the
  842.      * report
  843.      */
  844.     private void generateExternalReports(Engine engine, File outDirectory) throws ScanAgentException {
  845.         try {
  846.             engine.writeReports(applicationName, outDirectory, this.reportFormat.name(), null);
  847.         } catch (ReportException ex) {
  848.             LOGGER.debug("Unexpected exception occurred during analysis; please see the verbose error log for more details.", ex);
  849.             throw new ScanAgentException("Error generating the report", ex);
  850.         }
  851.     }

  852.     /**
  853.      * Takes the properties supplied and updates the dependency-check settings.
  854.      * Additionally, this sets the system properties required to change the
  855.      * proxy server, port, and connection timeout.
  856.      */
  857.     private void populateSettings() {
  858.         settings = new Settings();
  859.         if (dataDirectory != null) {
  860.             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
  861.         } else {
  862.             final File jarPath = new File(DependencyCheckScanAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath());
  863.             final File base = jarPath.getParentFile();
  864.             final String sub = settings.getString(Settings.KEYS.DATA_DIRECTORY);
  865.             final File dataDir = new File(base, sub);
  866.             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
  867.         }
  868.         if (propertiesFilePath != null) {
  869.             try {
  870.                 settings.mergeProperties(propertiesFilePath);
  871.                 LOGGER.info("Successfully loaded user-defined properties");
  872.             } catch (IOException e) {
  873.                 LOGGER.error("Unable to merge user-defined properties", e);
  874.                 LOGGER.error("Continuing execution");
  875.             }
  876.         }

  877.         settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
  878.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
  879.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
  880.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
  881.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
  882.         settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
  883.         settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_READ_TIMEOUT, readTimeout);
  884.         settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
  885.         settings.setStringIfNotEmpty(Settings.KEYS.CVE_CPE_STARTS_WITH_FILTER, cpeStartsWithFilter);
  886.         settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
  887.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
  888.         settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
  889.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
  890.         settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
  891.         settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
  892.         settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
  893.         settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
  894.         settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
  895.         settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
  896.         settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
  897.         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_KEY, nvdApiKey);
  898.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_DOTNET_PATH, pathToCore);
  899.         settings.setBoolean(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, failOnUnusedSuppressionRule);
  900.     }

  901.     /**
  902.      * Executes the dependency-check and generates the report.
  903.      *
  904.      * @return a reference to the engine used to perform the scan.
  905.      * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
  906.      * there is an exception executing the scan.
  907.      */
  908.     public Engine execute() throws ScanAgentException {
  909.         Engine engine = null;
  910.         try {
  911.             engine = executeDependencyCheck();
  912.             if (!this.updateOnly) {
  913.                 if (this.generateReport) {
  914.                     generateExternalReports(engine, new File(this.reportOutputDirectory));
  915.                 }
  916.                 if (this.showSummary) {
  917.                     showSummary(engine.getDependencies());
  918.                 }
  919.                 if (this.failBuildOnCVSS <= 10.0) {
  920.                     checkForFailure(engine.getDependencies());
  921.                 }
  922.             }
  923.         } catch (ExceptionCollection ex) {
  924.             if (ex.isFatal()) {
  925.                 LOGGER.error("A fatal exception occurred during analysis; analysis has stopped. Please see the debug log for more details.");
  926.                 LOGGER.debug("", ex);
  927.             }
  928.             throw new ScanAgentException("One or more exceptions occurred during analysis; please see the debug log for more details.", ex);
  929.         } finally {
  930.             if (engine != null) {
  931.                 engine.close();
  932.             }
  933.             settings.cleanup(true);
  934.         }
  935.         return engine;
  936.     }

  937.     /**
  938.      * Checks to see if a vulnerability has been identified with a CVSS score
  939.      * that is above the threshold set in the configuration.
  940.      *
  941.      * @param dependencies the list of dependency objects
  942.      * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
  943.      * there is an exception executing the scan.
  944.      */
  945.     private void checkForFailure(Dependency[] dependencies) throws ScanAgentException {
  946.         final StringBuilder ids = new StringBuilder();
  947.         for (Dependency d : dependencies) {
  948.             boolean addName = true;
  949.             for (Vulnerability v : d.getVulnerabilities()) {
  950.                 if ((v.getCvssV2() != null && v.getCvssV2().getCvssData().getBaseScore() >= failBuildOnCVSS)
  951.                         || (v.getCvssV3() != null && v.getCvssV3().getCvssData().getBaseScore() >= failBuildOnCVSS)
  952.                         || (v.getCvssV4() != null && v.getCvssV4().getCvssData().getBaseScore() >= failBuildOnCVSS)
  953.                         || (v.getUnscoredSeverity() != null && SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) >= failBuildOnCVSS)
  954.                         //safety net to fail on any if for some reason the above misses on 0
  955.                         || (failBuildOnCVSS <= 0.0f)) {
  956.                     if (addName) {
  957.                         addName = false;
  958.                         ids.append(NEW_LINE).append(d.getFileName()).append(" (")
  959.                            .append(Stream.concat(d.getSoftwareIdentifiers().stream(), d.getVulnerableSoftwareIdentifiers().stream())
  960.                                          .map(Identifier::getValue)
  961.                                          .collect(Collectors.joining(", ")))
  962.                            .append("): ")
  963.                            .append(v.getName());
  964.                     } else {
  965.                         ids.append(", ").append(v.getName());
  966.                     }
  967.                 }
  968.             }
  969.         }
  970.         if (ids.length() > 0) {
  971.             final String msg;
  972.             if (showSummary) {
  973.                 msg = String.format("%n%nDependency-Check Failure:%n"
  974.                         + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater than or equal to '%.1f': %s%n"
  975.                         + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids);
  976.             } else {
  977.                 msg = String.format("%n%nDependency-Check Failure:%n"
  978.                         + "One or more dependencies were identified with vulnerabilities.%n%n"
  979.                         + "See the dependency-check report for more details.%n%n");
  980.             }
  981.             throw new ScanAgentException(msg);
  982.         }
  983.     }

  984.     /**
  985.      * Generates a warning message listing a summary of dependencies and their
  986.      * associated CPE and CVE entries.
  987.      *
  988.      * @param dependencies a list of dependency objects
  989.      */
  990.     public static void showSummary(Dependency[] dependencies) {
  991.         showSummary(null, dependencies);
  992.     }

  993.     /**
  994.      * Generates a warning message listing a summary of dependencies and their
  995.      * associated CPE and CVE entries.
  996.      *
  997.      * @param projectName the name of the project
  998.      * @param dependencies a list of dependency objects
  999.      */
  1000.     public static void showSummary(String projectName, Dependency[] dependencies) {
  1001.         final StringBuilder summary = new StringBuilder();
  1002.         for (Dependency d : dependencies) {
  1003.             final String ids = d.getVulnerabilities(true).stream()
  1004.                     .map(Vulnerability::getName)
  1005.                     .collect(Collectors.joining(", "));
  1006.             if (ids.length() > 0) {
  1007.                 summary.append(d.getFileName()).append(" (");
  1008.                 summary.append(Stream.concat(d.getSoftwareIdentifiers().stream(), d.getVulnerableSoftwareIdentifiers().stream())
  1009.                         .map(Identifier::getValue)
  1010.                         .collect(Collectors.joining(", ")));
  1011.                 summary.append(") : ").append(ids).append(NEW_LINE);
  1012.             }
  1013.         }
  1014.         if (summary.length() > 0) {
  1015.             if (projectName == null || projectName.isEmpty()) {
  1016.                 LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\n"
  1017.                         + "See the dependency-check report for more details.\n\n",
  1018.                         summary);
  1019.             } else {
  1020.                 LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities in {}:\n\n{}\n\n"
  1021.                         + "See the dependency-check report for more details.\n\n",
  1022.                         projectName,
  1023.                         summary);
  1024.             }
  1025.         }
  1026.     }
  1027. }