View Javadoc
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  
20  import java.io.File;
21  import java.io.IOException;
22  import java.util.List;
23  import org.owasp.dependencycheck.Engine;
24  import org.owasp.dependencycheck.data.nvdcve.CveDB;
25  import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
26  import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
27  import org.owasp.dependencycheck.dependency.Dependency;
28  import org.owasp.dependencycheck.dependency.Identifier;
29  import org.owasp.dependencycheck.dependency.Vulnerability;
30  import org.owasp.dependencycheck.exception.ScanAgentException;
31  import org.owasp.dependencycheck.reporting.ReportGenerator;
32  import org.owasp.dependencycheck.utils.Settings;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  /**
37   * This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting evidence
38   * from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it takes a list of
39   * dependencies that can be programmatically added from data in a spreadsheet, database or some other datasource and conduct a
40   * scan based on this pre-defined evidence.
41   *
42   * <h2>Example:</h2>
43   * <pre>
44   * List<Dependency> dependencies = new ArrayList<Dependency>();
45   * Dependency dependency = new Dependency(new File(FileUtils.getBitBucket()));
46   * dependency.getProductEvidence().addEvidence("my-datasource", "name", "Jetty", Confidence.HIGH);
47   * dependency.getVersionEvidence().addEvidence("my-datasource", "version", "5.1.10", Confidence.HIGH);
48   * dependency.getVendorEvidence().addEvidence("my-datasource", "vendor", "mortbay", Confidence.HIGH);
49   * dependencies.add(dependency);
50   *
51   * DependencyCheckScanAgent scan = new DependencyCheckScanAgent();
52   * scan.setDependencies(dependencies);
53   * scan.setReportFormat(ReportGenerator.Format.ALL);
54   * scan.setReportOutputDirectory(System.getProperty("user.home"));
55   * scan.execute();
56   * </pre>
57   *
58   * @author Steve Springett <steve.springett@owasp.org>
59   */
60  @SuppressWarnings("unused")
61  public class DependencyCheckScanAgent {
62  
63      /**
64       * System specific new line character.
65       */
66      private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
67      /**
68       * Logger for use throughout the class.
69       */
70      private static final Logger LOGGER = LoggerFactory.getLogger(DependencyCheckScanAgent.class);
71      /**
72       * The application name for the report.
73       */
74      private String applicationName = "Dependency-Check";
75  
76      /**
77       * Get the value of applicationName.
78       *
79       * @return the value of applicationName
80       */
81      public String getApplicationName() {
82          return applicationName;
83      }
84  
85      /**
86       * Set the value of applicationName.
87       *
88       * @param applicationName new value of applicationName
89       */
90      public void setApplicationName(String applicationName) {
91          this.applicationName = applicationName;
92      }
93  
94      /**
95       * The pre-determined dependencies to scan
96       */
97      private List<Dependency> dependencies;
98  
99      /**
100      * Returns a list of pre-determined dependencies.
101      *
102      * @return returns a list of dependencies
103      */
104     public List<Dependency> getDependencies() {
105         return dependencies;
106     }
107 
108     /**
109      * Sets the list of dependencies to scan.
110      *
111      * @param dependencies new value of dependencies
112      */
113     public void setDependencies(List<Dependency> dependencies) {
114         this.dependencies = dependencies;
115     }
116 
117     /**
118      * The location of the data directory that contains
119      */
120     private String dataDirectory = null;
121 
122     /**
123      * Get the value of dataDirectory.
124      *
125      * @return the value of dataDirectory
126      */
127     public String getDataDirectory() {
128         return dataDirectory;
129     }
130 
131     /**
132      * Set the value of dataDirectory.
133      *
134      * @param dataDirectory new value of dataDirectory
135      */
136     public void setDataDirectory(String dataDirectory) {
137         this.dataDirectory = dataDirectory;
138     }
139 
140     /**
141      * Specifies the destination directory for the generated Dependency-Check report.
142      */
143     private String reportOutputDirectory;
144 
145     /**
146      * Get the value of reportOutputDirectory.
147      *
148      * @return the value of reportOutputDirectory
149      */
150     public String getReportOutputDirectory() {
151         return reportOutputDirectory;
152     }
153 
154     /**
155      * Set the value of reportOutputDirectory.
156      *
157      * @param reportOutputDirectory new value of reportOutputDirectory
158      */
159     public void setReportOutputDirectory(String reportOutputDirectory) {
160         this.reportOutputDirectory = reportOutputDirectory;
161     }
162 
163     /**
164      * Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which
165      * 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
166      * for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
167      */
168     private float failBuildOnCVSS = 11;
169 
170     /**
171      * Get the value of failBuildOnCVSS.
172      *
173      * @return the value of failBuildOnCVSS
174      */
175     public float getFailBuildOnCVSS() {
176         return failBuildOnCVSS;
177     }
178 
179     /**
180      * Set the value of failBuildOnCVSS.
181      *
182      * @param failBuildOnCVSS new value of failBuildOnCVSS
183      */
184     public void setFailBuildOnCVSS(float failBuildOnCVSS) {
185         this.failBuildOnCVSS = failBuildOnCVSS;
186     }
187 
188     /**
189      * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
190      * is true.
191      */
192     private boolean autoUpdate = true;
193 
194     /**
195      * Get the value of autoUpdate.
196      *
197      * @return the value of autoUpdate
198      */
199     public boolean isAutoUpdate() {
200         return autoUpdate;
201     }
202 
203     /**
204      * Set the value of autoUpdate.
205      *
206      * @param autoUpdate new value of autoUpdate
207      */
208     public void setAutoUpdate(boolean autoUpdate) {
209         this.autoUpdate = autoUpdate;
210     }
211 
212     /**
213      * flag indicating whether or not to generate a report of findings.
214      */
215     private boolean generateReport = true;
216 
217     /**
218      * Get the value of generateReport.
219      *
220      * @return the value of generateReport
221      */
222     public boolean isGenerateReport() {
223         return generateReport;
224     }
225 
226     /**
227      * Set the value of generateReport.
228      *
229      * @param generateReport new value of generateReport
230      */
231     public void setGenerateReport(boolean generateReport) {
232         this.generateReport = generateReport;
233     }
234 
235     /**
236      * The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the
237      * Site plugin unless the externalReport is set to true. Default is HTML.
238      */
239     private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
240 
241     /**
242      * Get the value of reportFormat.
243      *
244      * @return the value of reportFormat
245      */
246     public ReportGenerator.Format getReportFormat() {
247         return reportFormat;
248     }
249 
250     /**
251      * Set the value of reportFormat.
252      *
253      * @param reportFormat new value of reportFormat
254      */
255     public void setReportFormat(ReportGenerator.Format reportFormat) {
256         this.reportFormat = reportFormat;
257     }
258 
259     /**
260      * The Proxy Server.
261      */
262     private String proxyServer;
263 
264     /**
265      * Get the value of proxyServer.
266      *
267      * @return the value of proxyServer
268      */
269     public String getProxyServer() {
270         return proxyServer;
271     }
272 
273     /**
274      * Set the value of proxyServer.
275      *
276      * @param proxyServer new value of proxyServer
277      */
278     public void setProxyServer(String proxyServer) {
279         this.proxyServer = proxyServer;
280     }
281 
282     /**
283      * Get the value of proxyServer.
284      *
285      * @return the value of proxyServer
286      * @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()} instead
287      */
288     @Deprecated
289     public String getProxyUrl() {
290         return proxyServer;
291     }
292 
293     /**
294      * Set the value of proxyServer.
295      *
296      * @param proxyUrl new value of proxyServer
297      * @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#setProxyServer(java.lang.String)
298      * } instead
299      */
300     @Deprecated
301     public void setProxyUrl(String proxyUrl) {
302         this.proxyServer = proxyUrl;
303     }
304 
305     /**
306      * The Proxy Port.
307      */
308     private String proxyPort;
309 
310     /**
311      * Get the value of proxyPort.
312      *
313      * @return the value of proxyPort
314      */
315     public String getProxyPort() {
316         return proxyPort;
317     }
318 
319     /**
320      * Set the value of proxyPort.
321      *
322      * @param proxyPort new value of proxyPort
323      */
324     public void setProxyPort(String proxyPort) {
325         this.proxyPort = proxyPort;
326     }
327 
328     /**
329      * The Proxy username.
330      */
331     private String proxyUsername;
332 
333     /**
334      * Get the value of proxyUsername.
335      *
336      * @return the value of proxyUsername
337      */
338     public String getProxyUsername() {
339         return proxyUsername;
340     }
341 
342     /**
343      * Set the value of proxyUsername.
344      *
345      * @param proxyUsername new value of proxyUsername
346      */
347     public void setProxyUsername(String proxyUsername) {
348         this.proxyUsername = proxyUsername;
349     }
350 
351     /**
352      * The Proxy password.
353      */
354     private String proxyPassword;
355 
356     /**
357      * Get the value of proxyPassword.
358      *
359      * @return the value of proxyPassword
360      */
361     public String getProxyPassword() {
362         return proxyPassword;
363     }
364 
365     /**
366      * Set the value of proxyPassword.
367      *
368      * @param proxyPassword new value of proxyPassword
369      */
370     public void setProxyPassword(String proxyPassword) {
371         this.proxyPassword = proxyPassword;
372     }
373 
374     /**
375      * The Connection Timeout.
376      */
377     private String connectionTimeout;
378 
379     /**
380      * Get the value of connectionTimeout.
381      *
382      * @return the value of connectionTimeout
383      */
384     public String getConnectionTimeout() {
385         return connectionTimeout;
386     }
387 
388     /**
389      * Set the value of connectionTimeout.
390      *
391      * @param connectionTimeout new value of connectionTimeout
392      */
393     public void setConnectionTimeout(String connectionTimeout) {
394         this.connectionTimeout = connectionTimeout;
395     }
396 
397     /**
398      * The file path used for verbose logging.
399      */
400     private String logFile = null;
401 
402     /**
403      * Get the value of logFile.
404      *
405      * @return the value of logFile
406      */
407     public String getLogFile() {
408         return logFile;
409     }
410 
411     /**
412      * Set the value of logFile.
413      *
414      * @param logFile new value of logFile
415      */
416     public void setLogFile(String logFile) {
417         this.logFile = logFile;
418     }
419 
420     /**
421      * The path to the suppression file.
422      */
423     private String suppressionFile;
424 
425     /**
426      * Get the value of suppressionFile.
427      *
428      * @return the value of suppressionFile
429      */
430     public String getSuppressionFile() {
431         return suppressionFile;
432     }
433 
434     /**
435      * Set the value of suppressionFile.
436      *
437      * @param suppressionFile new value of suppressionFile
438      */
439     public void setSuppressionFile(String suppressionFile) {
440         this.suppressionFile = suppressionFile;
441     }
442 
443     /**
444      * flag indicating whether or not to show a summary of findings.
445      */
446     private boolean showSummary = true;
447 
448     /**
449      * Get the value of showSummary.
450      *
451      * @return the value of showSummary
452      */
453     public boolean isShowSummary() {
454         return showSummary;
455     }
456 
457     /**
458      * Set the value of showSummary.
459      *
460      * @param showSummary new value of showSummary
461      */
462     public void setShowSummary(boolean showSummary) {
463         this.showSummary = showSummary;
464     }
465 
466     /**
467      * Whether or not the Maven Central analyzer is enabled.
468      */
469     private boolean centralAnalyzerEnabled = true;
470 
471     /**
472      * Get the value of centralAnalyzerEnabled.
473      *
474      * @return the value of centralAnalyzerEnabled
475      */
476     public boolean isCentralAnalyzerEnabled() {
477         return centralAnalyzerEnabled;
478     }
479 
480     /**
481      * Set the value of centralAnalyzerEnabled.
482      *
483      * @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
484      */
485     public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
486         this.centralAnalyzerEnabled = centralAnalyzerEnabled;
487     }
488 
489     /**
490      * The URL of Maven Central.
491      */
492     private String centralUrl;
493 
494     /**
495      * Get the value of centralUrl.
496      *
497      * @return the value of centralUrl
498      */
499     public String getCentralUrl() {
500         return centralUrl;
501     }
502 
503     /**
504      * Set the value of centralUrl.
505      *
506      * @param centralUrl new value of centralUrl
507      */
508     public void setCentralUrl(String centralUrl) {
509         this.centralUrl = centralUrl;
510     }
511 
512     /**
513      * Whether or not the nexus analyzer is enabled.
514      */
515     private boolean nexusAnalyzerEnabled = true;
516 
517     /**
518      * Get the value of nexusAnalyzerEnabled.
519      *
520      * @return the value of nexusAnalyzerEnabled
521      */
522     public boolean isNexusAnalyzerEnabled() {
523         return nexusAnalyzerEnabled;
524     }
525 
526     /**
527      * Set the value of nexusAnalyzerEnabled.
528      *
529      * @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
530      */
531     public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
532         this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
533     }
534 
535     /**
536      * The URL of the Nexus server.
537      */
538     private String nexusUrl;
539 
540     /**
541      * Get the value of nexusUrl.
542      *
543      * @return the value of nexusUrl
544      */
545     public String getNexusUrl() {
546         return nexusUrl;
547     }
548 
549     /**
550      * Set the value of nexusUrl.
551      *
552      * @param nexusUrl new value of nexusUrl
553      */
554     public void setNexusUrl(String nexusUrl) {
555         this.nexusUrl = nexusUrl;
556     }
557 
558     /**
559      * Whether or not the defined proxy should be used when connecting to Nexus.
560      */
561     private boolean nexusUsesProxy = true;
562 
563     /**
564      * Get the value of nexusUsesProxy.
565      *
566      * @return the value of nexusUsesProxy
567      */
568     public boolean isNexusUsesProxy() {
569         return nexusUsesProxy;
570     }
571 
572     /**
573      * Set the value of nexusUsesProxy.
574      *
575      * @param nexusUsesProxy new value of nexusUsesProxy
576      */
577     public void setNexusUsesProxy(boolean nexusUsesProxy) {
578         this.nexusUsesProxy = nexusUsesProxy;
579     }
580 
581     /**
582      * The database driver name; such as org.h2.Driver.
583      */
584     private String databaseDriverName;
585 
586     /**
587      * Get the value of databaseDriverName.
588      *
589      * @return the value of databaseDriverName
590      */
591     public String getDatabaseDriverName() {
592         return databaseDriverName;
593     }
594 
595     /**
596      * Set the value of databaseDriverName.
597      *
598      * @param databaseDriverName new value of databaseDriverName
599      */
600     public void setDatabaseDriverName(String databaseDriverName) {
601         this.databaseDriverName = databaseDriverName;
602     }
603 
604     /**
605      * The path to the database driver JAR file if it is not on the class path.
606      */
607     private String databaseDriverPath;
608 
609     /**
610      * Get the value of databaseDriverPath.
611      *
612      * @return the value of databaseDriverPath
613      */
614     public String getDatabaseDriverPath() {
615         return databaseDriverPath;
616     }
617 
618     /**
619      * Set the value of databaseDriverPath.
620      *
621      * @param databaseDriverPath new value of databaseDriverPath
622      */
623     public void setDatabaseDriverPath(String databaseDriverPath) {
624         this.databaseDriverPath = databaseDriverPath;
625     }
626 
627     /**
628      * The database connection string.
629      */
630     private String connectionString;
631 
632     /**
633      * Get the value of connectionString.
634      *
635      * @return the value of connectionString
636      */
637     public String getConnectionString() {
638         return connectionString;
639     }
640 
641     /**
642      * Set the value of connectionString.
643      *
644      * @param connectionString new value of connectionString
645      */
646     public void setConnectionString(String connectionString) {
647         this.connectionString = connectionString;
648     }
649 
650     /**
651      * The user name for connecting to the database.
652      */
653     private String databaseUser;
654 
655     /**
656      * Get the value of databaseUser.
657      *
658      * @return the value of databaseUser
659      */
660     public String getDatabaseUser() {
661         return databaseUser;
662     }
663 
664     /**
665      * Set the value of databaseUser.
666      *
667      * @param databaseUser new value of databaseUser
668      */
669     public void setDatabaseUser(String databaseUser) {
670         this.databaseUser = databaseUser;
671     }
672 
673     /**
674      * The password to use when connecting to the database.
675      */
676     private String databasePassword;
677 
678     /**
679      * Get the value of databasePassword.
680      *
681      * @return the value of databasePassword
682      */
683     public String getDatabasePassword() {
684         return databasePassword;
685     }
686 
687     /**
688      * Set the value of databasePassword.
689      *
690      * @param databasePassword new value of databasePassword
691      */
692     public void setDatabasePassword(String databasePassword) {
693         this.databasePassword = databasePassword;
694     }
695 
696     /**
697      * Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
698      * files.
699      */
700     private String zipExtensions;
701 
702     /**
703      * Get the value of zipExtensions.
704      *
705      * @return the value of zipExtensions
706      */
707     public String getZipExtensions() {
708         return zipExtensions;
709     }
710 
711     /**
712      * Set the value of zipExtensions.
713      *
714      * @param zipExtensions new value of zipExtensions
715      */
716     public void setZipExtensions(String zipExtensions) {
717         this.zipExtensions = zipExtensions;
718     }
719 
720     /**
721      * The url for the modified NVD CVE (1.2 schema).
722      */
723     private String cveUrl12Modified;
724 
725     /**
726      * Get the value of cveUrl12Modified.
727      *
728      * @return the value of cveUrl12Modified
729      */
730     public String getCveUrl12Modified() {
731         return cveUrl12Modified;
732     }
733 
734     /**
735      * Set the value of cveUrl12Modified.
736      *
737      * @param cveUrl12Modified new value of cveUrl12Modified
738      */
739     public void setCveUrl12Modified(String cveUrl12Modified) {
740         this.cveUrl12Modified = cveUrl12Modified;
741     }
742 
743     /**
744      * The url for the modified NVD CVE (2.0 schema).
745      */
746     private String cveUrl20Modified;
747 
748     /**
749      * Get the value of cveUrl20Modified.
750      *
751      * @return the value of cveUrl20Modified
752      */
753     public String getCveUrl20Modified() {
754         return cveUrl20Modified;
755     }
756 
757     /**
758      * Set the value of cveUrl20Modified.
759      *
760      * @param cveUrl20Modified new value of cveUrl20Modified
761      */
762     public void setCveUrl20Modified(String cveUrl20Modified) {
763         this.cveUrl20Modified = cveUrl20Modified;
764     }
765 
766     /**
767      * Base Data Mirror URL for CVE 1.2.
768      */
769     private String cveUrl12Base;
770 
771     /**
772      * Get the value of cveUrl12Base.
773      *
774      * @return the value of cveUrl12Base
775      */
776     public String getCveUrl12Base() {
777         return cveUrl12Base;
778     }
779 
780     /**
781      * Set the value of cveUrl12Base.
782      *
783      * @param cveUrl12Base new value of cveUrl12Base
784      */
785     public void setCveUrl12Base(String cveUrl12Base) {
786         this.cveUrl12Base = cveUrl12Base;
787     }
788 
789     /**
790      * Data Mirror URL for CVE 2.0.
791      */
792     private String cveUrl20Base;
793 
794     /**
795      * Get the value of cveUrl20Base.
796      *
797      * @return the value of cveUrl20Base
798      */
799     public String getCveUrl20Base() {
800         return cveUrl20Base;
801     }
802 
803     /**
804      * Set the value of cveUrl20Base.
805      *
806      * @param cveUrl20Base new value of cveUrl20Base
807      */
808     public void setCveUrl20Base(String cveUrl20Base) {
809         this.cveUrl20Base = cveUrl20Base;
810     }
811 
812     /**
813      * The path to Mono for .NET assembly analysis on non-windows systems.
814      */
815     private String pathToMono;
816 
817     /**
818      * Get the value of pathToMono.
819      *
820      * @return the value of pathToMono
821      */
822     public String getPathToMono() {
823         return pathToMono;
824     }
825 
826     /**
827      * Set the value of pathToMono.
828      *
829      * @param pathToMono new value of pathToMono
830      */
831     public void setPathToMono(String pathToMono) {
832         this.pathToMono = pathToMono;
833     }
834 
835     /**
836      * Executes the Dependency-Check on the dependent libraries.
837      *
838      * @return the Engine used to scan the dependencies.
839      * @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the database
840      */
841     private Engine executeDependencyCheck() throws DatabaseException {
842         populateSettings();
843         final Engine engine = new Engine();
844         engine.setDependencies(this.dependencies);
845         engine.analyzeDependencies();
846         return engine;
847     }
848 
849     /**
850      * Generates the reports for a given dependency-check engine.
851      *
852      * @param engine a dependency-check engine
853      * @param outDirectory the directory to write the reports to
854      */
855     private void generateExternalReports(Engine engine, File outDirectory) {
856         DatabaseProperties prop = null;
857         CveDB cve = null;
858         try {
859             cve = new CveDB();
860             cve.open();
861             prop = cve.getDatabaseProperties();
862         } catch (DatabaseException ex) {
863             LOGGER.debug("Unable to retrieve DB Properties", ex);
864         } finally {
865             if (cve != null) {
866                 cve.close();
867             }
868         }
869         final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
870         try {
871             r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
872         } catch (IOException ex) {
873             LOGGER.error(
874                     "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
875             LOGGER.debug("", ex);
876         } catch (Throwable ex) {
877             LOGGER.error(
878                     "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
879             LOGGER.debug("", ex);
880         }
881     }
882 
883     /**
884      * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
885      * required to change the proxy server, port, and connection timeout.
886      */
887     private void populateSettings() {
888         Settings.initialize();
889         if (dataDirectory != null) {
890             Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
891         } else {
892             final File jarPath = new File(DependencyCheckScanAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath());
893             final File base = jarPath.getParentFile();
894             final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
895             final File dataDir = new File(base, sub);
896             Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
897         }
898 
899         Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
900         Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
901         Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
902         Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
903         Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
904         Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
905         Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
906         Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
907         Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
908         Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
909         Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
910         Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
911         Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
912         Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
913         Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
914         Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
915         Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
916         Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
917         Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
918         Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
919         Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
920         Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
921         Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
922     }
923 
924     /**
925      * Executes the dependency-check and generates the report.
926      *
927      * @return a reference to the engine used to perform the scan.
928      * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
929      */
930     public Engine execute() throws ScanAgentException {
931         Engine engine = null;
932         try {
933             engine = executeDependencyCheck();
934             if (this.generateReport) {
935                 generateExternalReports(engine, new File(this.reportOutputDirectory));
936             }
937             if (this.showSummary) {
938                 showSummary(engine.getDependencies());
939             }
940             if (this.failBuildOnCVSS <= 10) {
941                 checkForFailure(engine.getDependencies());
942             }
943         } catch (DatabaseException ex) {
944             LOGGER.error(
945                     "Unable to connect to the dependency-check database; analysis has stopped");
946             LOGGER.debug("", ex);
947         } finally {
948             Settings.cleanup(true);
949             if (engine != null) {
950                 engine.cleanup();
951             }
952         }
953         return engine;
954     }
955 
956     /**
957      * Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
958      * configuration.
959      *
960      * @param dependencies the list of dependency objects
961      * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
962      */
963     private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
964         final StringBuilder ids = new StringBuilder();
965         for (Dependency d : dependencies) {
966             boolean addName = true;
967             for (Vulnerability v : d.getVulnerabilities()) {
968                 if (v.getCvssScore() >= failBuildOnCVSS) {
969                     if (addName) {
970                         addName = false;
971                         ids.append(NEW_LINE).append(d.getFileName()).append(": ");
972                         ids.append(v.getName());
973                     } else {
974                         ids.append(", ").append(v.getName());
975                     }
976                 }
977             }
978         }
979         if (ids.length() > 0) {
980             final String msg = String.format("%n%nDependency-Check Failure:%n"
981                     + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
982                     + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
983 
984             throw new ScanAgentException(msg);
985         }
986     }
987 
988     /**
989      * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
990      *
991      * @param dependencies a list of dependency objects
992      */
993     private void showSummary(List<Dependency> dependencies) {
994         final StringBuilder summary = new StringBuilder();
995         for (Dependency d : dependencies) {
996             boolean firstEntry = true;
997             final StringBuilder ids = new StringBuilder();
998             for (Vulnerability v : d.getVulnerabilities()) {
999                 if (firstEntry) {
1000                     firstEntry = false;
1001                 } else {
1002                     ids.append(", ");
1003                 }
1004                 ids.append(v.getName());
1005             }
1006             if (ids.length() > 0) {
1007                 summary.append(d.getFileName()).append(" (");
1008                 firstEntry = true;
1009                 for (Identifier id : d.getIdentifiers()) {
1010                     if (firstEntry) {
1011                         firstEntry = false;
1012                     } else {
1013                         summary.append(", ");
1014                     }
1015                     summary.append(id.getValue());
1016                 }
1017                 summary.append(") : ").append(ids).append(NEW_LINE);
1018             }
1019         }
1020         if (summary.length() > 0) {
1021             LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\n"
1022                     + "See the dependency-check report for more details.\n\n",
1023                     summary.toString());
1024         }
1025     }
1026 
1027 }