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