View Javadoc
1   /*
2    * This file is part of dependency-check-ant.
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) 2013 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.taskdefs;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.List;
24  import java.util.logging.Level;
25  import java.util.logging.Logger;
26  import org.apache.tools.ant.BuildException;
27  import org.apache.tools.ant.Task;
28  import org.apache.tools.ant.types.EnumeratedAttribute;
29  import org.apache.tools.ant.types.Reference;
30  import org.apache.tools.ant.types.Resource;
31  import org.apache.tools.ant.types.ResourceCollection;
32  import org.apache.tools.ant.types.resources.FileProvider;
33  import org.apache.tools.ant.types.resources.Resources;
34  import org.owasp.dependencycheck.Engine;
35  import org.owasp.dependencycheck.data.nvdcve.CveDB;
36  import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
37  import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
38  import org.owasp.dependencycheck.dependency.Dependency;
39  import org.owasp.dependencycheck.dependency.Identifier;
40  import org.owasp.dependencycheck.dependency.Vulnerability;
41  import org.owasp.dependencycheck.reporting.ReportGenerator;
42  import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
43  import org.owasp.dependencycheck.utils.LogUtils;
44  import org.owasp.dependencycheck.utils.Settings;
45  
46  /**
47   * An Ant task definition to execute dependency-check during an Ant build.
48   *
49   * @author Jeremy Long <jeremy.long@owasp.org>
50   */
51  public class DependencyCheckTask extends Task {
52  
53      /**
54       * The properties file location.
55       */
56      private static final String PROPERTIES_FILE = "task.properties";
57      /**
58       * Name of the logging properties file.
59       */
60      private static final String LOG_PROPERTIES_FILE = "log.properties";
61      /**
62       * System specific new line character.
63       */
64      private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
65  
66      /**
67       * Construct a new DependencyCheckTask.
68       */
69      public DependencyCheckTask() {
70          super();
71      }
72      //The following code was copied Apache Ant PathConvert
73      //BEGIN COPY from org.apache.tools.ant.taskdefs.PathConvert
74      /**
75       * Path to be converted
76       */
77      private Resources path = null;
78      /**
79       * Reference to path/fileset to convert
80       */
81      private Reference refid = null;
82  
83      /**
84       * Add an arbitrary ResourceCollection.
85       *
86       * @param rc the ResourceCollection to add.
87       * @since Ant 1.7
88       */
89      public void add(ResourceCollection rc) {
90          if (isReference()) {
91              throw new BuildException("Nested elements are not allowed when using the refid attribute.");
92          }
93          getPath().add(rc);
94      }
95  
96      /**
97       * Returns the path. If the path has not been initialized yet, this class is synchronized, and will instantiate the
98       * path object.
99       *
100      * @return the path
101      */
102     private synchronized Resources getPath() {
103         if (path == null) {
104             path = new Resources(getProject());
105             path.setCache(true);
106         }
107         return path;
108     }
109 
110     /**
111      * Learn whether the refid attribute of this element been set.
112      *
113      * @return true if refid is valid.
114      */
115     public boolean isReference() {
116         return refid != null;
117     }
118 
119     /**
120      * Add a reference to a Path, FileSet, DirSet, or FileList defined elsewhere.
121      *
122      * @param r the reference to a path, fileset, dirset or filelist.
123      */
124     public void setRefid(Reference r) {
125         if (path != null) {
126             throw new BuildException("Nested elements are not allowed when using the refid attribute.");
127         }
128         refid = r;
129     }
130 
131     /**
132      * If this is a reference, this method will add the referenced resource collection to the collection of paths.
133      *
134      * @throws BuildException if the reference is not to a resource collection
135      */
136     private void dealWithReferences() throws BuildException {
137         if (isReference()) {
138             final Object o = refid.getReferencedObject(getProject());
139             if (!(o instanceof ResourceCollection)) {
140                 throw new BuildException("refid '" + refid.getRefId()
141                         + "' does not refer to a resource collection.");
142             }
143             getPath().add((ResourceCollection) o);
144         }
145     }
146     // END COPY from org.apache.tools.ant.taskdefs
147     /**
148      * The application name for the report.
149      */
150     private String applicationName = "Dependency-Check";
151 
152     /**
153      * Get the value of applicationName.
154      *
155      * @return the value of applicationName
156      */
157     public String getApplicationName() {
158         return applicationName;
159     }
160 
161     /**
162      * Set the value of applicationName.
163      *
164      * @param applicationName new value of applicationName
165      */
166     public void setApplicationName(String applicationName) {
167         this.applicationName = applicationName;
168     }
169     /**
170      * The location of the data directory that contains
171      */
172     private String dataDirectory = null;
173 
174     /**
175      * Get the value of dataDirectory.
176      *
177      * @return the value of dataDirectory
178      */
179     public String getDataDirectory() {
180         return dataDirectory;
181     }
182 
183     /**
184      * Set the value of dataDirectory.
185      *
186      * @param dataDirectory new value of dataDirectory
187      */
188     public void setDataDirectory(String dataDirectory) {
189         this.dataDirectory = dataDirectory;
190     }
191     /**
192      * Specifies the destination directory for the generated Dependency-Check report.
193      */
194     private String reportOutputDirectory = ".";
195 
196     /**
197      * Get the value of reportOutputDirectory.
198      *
199      * @return the value of reportOutputDirectory
200      */
201     public String getReportOutputDirectory() {
202         return reportOutputDirectory;
203     }
204 
205     /**
206      * Set the value of reportOutputDirectory.
207      *
208      * @param reportOutputDirectory new value of reportOutputDirectory
209      */
210     public void setReportOutputDirectory(String reportOutputDirectory) {
211         this.reportOutputDirectory = reportOutputDirectory;
212     }
213     /**
214      * Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11
215      * which means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11.
216      * The valid range for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
217      */
218     private float failBuildOnCVSS = 11;
219 
220     /**
221      * Get the value of failBuildOnCVSS.
222      *
223      * @return the value of failBuildOnCVSS
224      */
225     public float getFailBuildOnCVSS() {
226         return failBuildOnCVSS;
227     }
228 
229     /**
230      * Set the value of failBuildOnCVSS.
231      *
232      * @param failBuildOnCVSS new value of failBuildOnCVSS
233      */
234     public void setFailBuildOnCVSS(float failBuildOnCVSS) {
235         this.failBuildOnCVSS = failBuildOnCVSS;
236     }
237     /**
238      * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to
239      * false. Default is true.
240      */
241     private boolean autoUpdate = true;
242 
243     /**
244      * Get the value of autoUpdate.
245      *
246      * @return the value of autoUpdate
247      */
248     public boolean isAutoUpdate() {
249         return autoUpdate;
250     }
251 
252     /**
253      * Set the value of autoUpdate.
254      *
255      * @param autoUpdate new value of autoUpdate
256      */
257     public void setAutoUpdate(boolean autoUpdate) {
258         this.autoUpdate = autoUpdate;
259     }
260     /**
261      * The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this
262      * within the Site plugin unless the externalReport is set to true. Default is HTML.
263      */
264     private String reportFormat = "HTML";
265 
266     /**
267      * Get the value of reportFormat.
268      *
269      * @return the value of reportFormat
270      */
271     public String getReportFormat() {
272         return reportFormat;
273     }
274 
275     /**
276      * Set the value of reportFormat.
277      *
278      * @param reportFormat new value of reportFormat
279      */
280     public void setReportFormat(ReportFormats reportFormat) {
281         this.reportFormat = reportFormat.getValue();
282     }
283     /**
284      * The Proxy URL.
285      */
286     private String proxyUrl;
287 
288     /**
289      * Get the value of proxyUrl.
290      *
291      * @return the value of proxyUrl
292      */
293     public String getProxyUrl() {
294         return proxyUrl;
295     }
296 
297     /**
298      * Set the value of proxyUrl.
299      *
300      * @param proxyUrl new value of proxyUrl
301      */
302     public void setProxyUrl(String proxyUrl) {
303         this.proxyUrl = proxyUrl;
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      * The Proxy username.
329      */
330     private String proxyUsername;
331 
332     /**
333      * Get the value of proxyUsername.
334      *
335      * @return the value of proxyUsername
336      */
337     public String getProxyUsername() {
338         return proxyUsername;
339     }
340 
341     /**
342      * Set the value of proxyUsername.
343      *
344      * @param proxyUsername new value of proxyUsername
345      */
346     public void setProxyUsername(String proxyUsername) {
347         this.proxyUsername = proxyUsername;
348     }
349     /**
350      * The Proxy password.
351      */
352     private String proxyPassword;
353 
354     /**
355      * Get the value of proxyPassword.
356      *
357      * @return the value of proxyPassword
358      */
359     public String getProxyPassword() {
360         return proxyPassword;
361     }
362 
363     /**
364      * Set the value of proxyPassword.
365      *
366      * @param proxyPassword new value of proxyPassword
367      */
368     public void setProxyPassword(String proxyPassword) {
369         this.proxyPassword = proxyPassword;
370     }
371     /**
372      * The Connection Timeout.
373      */
374     private String connectionTimeout;
375 
376     /**
377      * Get the value of connectionTimeout.
378      *
379      * @return the value of connectionTimeout
380      */
381     public String getConnectionTimeout() {
382         return connectionTimeout;
383     }
384 
385     /**
386      * Set the value of connectionTimeout.
387      *
388      * @param connectionTimeout new value of connectionTimeout
389      */
390     public void setConnectionTimeout(String connectionTimeout) {
391         this.connectionTimeout = connectionTimeout;
392     }
393     /**
394      * The file path used for verbose logging.
395      */
396     private String logFile = null;
397 
398     /**
399      * Get the value of logFile.
400      *
401      * @return the value of logFile
402      */
403     public String getLogFile() {
404         return logFile;
405     }
406 
407     /**
408      * Set the value of logFile.
409      *
410      * @param logFile new value of logFile
411      */
412     public void setLogFile(String logFile) {
413         this.logFile = logFile;
414     }
415     /**
416      * The path to the suppression file.
417      */
418     private String suppressionFile;
419 
420     /**
421      * Get the value of suppressionFile.
422      *
423      * @return the value of suppressionFile
424      */
425     public String getSuppressionFile() {
426         return suppressionFile;
427     }
428 
429     /**
430      * Set the value of suppressionFile.
431      *
432      * @param suppressionFile new value of suppressionFile
433      */
434     public void setSuppressionFile(String suppressionFile) {
435         this.suppressionFile = suppressionFile;
436     }
437     /**
438      * flag indicating whether or not to show a summary of findings.
439      */
440     private boolean showSummary = true;
441 
442     /**
443      * Get the value of showSummary.
444      *
445      * @return the value of showSummary
446      */
447     public boolean isShowSummary() {
448         return showSummary;
449     }
450 
451     /**
452      * Set the value of showSummary.
453      *
454      * @param showSummary new value of showSummary
455      */
456     public void setShowSummary(boolean showSummary) {
457         this.showSummary = showSummary;
458     }
459 
460     /**
461      * Sets whether or not the analyzer is enabled.
462      *
463      * @param jarAnalyzerEnabled the value of the new setting
464      */
465     public void setJarAnalyzerEnabled(boolean jarAnalyzerEnabled) {
466         this.jarAnalyzerEnabled = jarAnalyzerEnabled;
467     }
468     /**
469      * Whether or not the Archive Analyzer is enabled.
470      */
471     private boolean archiveAnalyzerEnabled = true;
472 
473     /**
474      * Returns whether or not the analyzer is enabled.
475      *
476      * @return true if the analyzer is enabled
477      */
478     public boolean isArchiveAnalyzerEnabled() {
479         return archiveAnalyzerEnabled;
480     }
481     /**
482      * Whether or not the .NET Assembly Analyzer is enabled.
483      */
484     private boolean assemblyAnalyzerEnabled = true;
485 
486     /**
487      * Sets whether or not the analyzer is enabled.
488      *
489      * @param archiveAnalyzerEnabled the value of the new setting
490      */
491     public void setArchiveAnalyzerEnabled(boolean archiveAnalyzerEnabled) {
492         this.archiveAnalyzerEnabled = archiveAnalyzerEnabled;
493     }
494 
495     /**
496      * Returns whether or not the analyzer is enabled.
497      *
498      * @return true if the analyzer is enabled
499      */
500     public boolean isAssemblyAnalyzerEnabled() {
501         return assemblyAnalyzerEnabled;
502     }
503 
504     /**
505      * Sets whether or not the analyzer is enabled.
506      *
507      * @param assemblyAnalyzerEnabled the value of the new setting
508      */
509     public void setAssemblyAnalyzerEnabled(boolean assemblyAnalyzerEnabled) {
510         this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
511     }
512     /**
513      * Whether or not the .NET Nuspec Analyzer is enabled.
514      */
515     private boolean nuspecAnalyzerEnabled = true;
516 
517     /**
518      * Returns whether or not the analyzer is enabled.
519      *
520      * @return true if the analyzer is enabled
521      */
522     public boolean isNuspecAnalyzerEnabled() {
523         return nuspecAnalyzerEnabled;
524     }
525 
526     /**
527      * Sets whether or not the analyzer is enabled.
528      *
529      * @param nuspecAnalyzerEnabled the value of the new setting
530      */
531     public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
532         this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
533     }
534 
535     /**
536      * Whether or not the nexus analyzer is enabled.
537      */
538     private boolean nexusAnalyzerEnabled = true;
539 
540     /**
541      * Get the value of nexusAnalyzerEnabled.
542      *
543      * @return the value of nexusAnalyzerEnabled
544      */
545     public boolean isNexusAnalyzerEnabled() {
546         return nexusAnalyzerEnabled;
547     }
548 
549     /**
550      * Set the value of nexusAnalyzerEnabled.
551      *
552      * @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
553      */
554     public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
555         this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
556     }
557 
558     /**
559      * The URL of the Nexus server.
560      */
561     private String nexusUrl;
562 
563     /**
564      * Get the value of nexusUrl.
565      *
566      * @return the value of nexusUrl
567      */
568     public String getNexusUrl() {
569         return nexusUrl;
570     }
571 
572     /**
573      * Set the value of nexusUrl.
574      *
575      * @param nexusUrl new value of nexusUrl
576      */
577     public void setNexusUrl(String nexusUrl) {
578         this.nexusUrl = nexusUrl;
579     }
580     /**
581      * Whether or not the defined proxy should be used when connecting to Nexus.
582      */
583     private boolean nexusUsesProxy = true;
584 
585     /**
586      * Get the value of nexusUsesProxy.
587      *
588      * @return the value of nexusUsesProxy
589      */
590     public boolean isNexusUsesProxy() {
591         return nexusUsesProxy;
592     }
593 
594     /**
595      * Set the value of nexusUsesProxy.
596      *
597      * @param nexusUsesProxy new value of nexusUsesProxy
598      */
599     public void setNexusUsesProxy(boolean nexusUsesProxy) {
600         this.nexusUsesProxy = nexusUsesProxy;
601     }
602 
603     /**
604      * The database driver name; such as org.h2.Driver.
605      */
606     private String databaseDriverName;
607 
608     /**
609      * Get the value of databaseDriverName.
610      *
611      * @return the value of databaseDriverName
612      */
613     public String getDatabaseDriverName() {
614         return databaseDriverName;
615     }
616 
617     /**
618      * Set the value of databaseDriverName.
619      *
620      * @param databaseDriverName new value of databaseDriverName
621      */
622     public void setDatabaseDriverName(String databaseDriverName) {
623         this.databaseDriverName = databaseDriverName;
624     }
625 
626     /**
627      * The path to the database driver JAR file if it is not on the class path.
628      */
629     private String databaseDriverPath;
630 
631     /**
632      * Get the value of databaseDriverPath.
633      *
634      * @return the value of databaseDriverPath
635      */
636     public String getDatabaseDriverPath() {
637         return databaseDriverPath;
638     }
639 
640     /**
641      * Set the value of databaseDriverPath.
642      *
643      * @param databaseDriverPath new value of databaseDriverPath
644      */
645     public void setDatabaseDriverPath(String databaseDriverPath) {
646         this.databaseDriverPath = databaseDriverPath;
647     }
648     /**
649      * The database connection string.
650      */
651     private String connectionString;
652 
653     /**
654      * Get the value of connectionString.
655      *
656      * @return the value of connectionString
657      */
658     public String getConnectionString() {
659         return connectionString;
660     }
661 
662     /**
663      * Set the value of connectionString.
664      *
665      * @param connectionString new value of connectionString
666      */
667     public void setConnectionString(String connectionString) {
668         this.connectionString = connectionString;
669     }
670     /**
671      * The user name for connecting to the database.
672      */
673     private String databaseUser;
674 
675     /**
676      * Get the value of databaseUser.
677      *
678      * @return the value of databaseUser
679      */
680     public String getDatabaseUser() {
681         return databaseUser;
682     }
683 
684     /**
685      * Set the value of databaseUser.
686      *
687      * @param databaseUser new value of databaseUser
688      */
689     public void setDatabaseUser(String databaseUser) {
690         this.databaseUser = databaseUser;
691     }
692 
693     /**
694      * The password to use when connecting to the database.
695      */
696     private String databasePassword;
697 
698     /**
699      * Get the value of databasePassword.
700      *
701      * @return the value of databasePassword
702      */
703     public String getDatabasePassword() {
704         return databasePassword;
705     }
706 
707     /**
708      * Set the value of databasePassword.
709      *
710      * @param databasePassword new value of databasePassword
711      */
712     public void setDatabasePassword(String databasePassword) {
713         this.databasePassword = databasePassword;
714     }
715 
716     /**
717      * Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat
718      * like ZIP files.
719      */
720     private String zipExtensions;
721 
722     /**
723      * Get the value of zipExtensions.
724      *
725      * @return the value of zipExtensions
726      */
727     public String getZipExtensions() {
728         return zipExtensions;
729     }
730 
731     /**
732      * Set the value of zipExtensions.
733      *
734      * @param zipExtensions new value of zipExtensions
735      */
736     public void setZipExtensions(String zipExtensions) {
737         this.zipExtensions = zipExtensions;
738     }
739 
740     /**
741      * The url for the modified NVD CVE (1.2 schema).
742      */
743     private String cveUrl12Modified;
744 
745     /**
746      * Get the value of cveUrl12Modified.
747      *
748      * @return the value of cveUrl12Modified
749      */
750     public String getCveUrl12Modified() {
751         return cveUrl12Modified;
752     }
753 
754     /**
755      * Set the value of cveUrl12Modified.
756      *
757      * @param cveUrl12Modified new value of cveUrl12Modified
758      */
759     public void setCveUrl12Modified(String cveUrl12Modified) {
760         this.cveUrl12Modified = cveUrl12Modified;
761     }
762 
763     /**
764      * The url for the modified NVD CVE (2.0 schema).
765      */
766     private String cveUrl20Modified;
767 
768     /**
769      * Get the value of cveUrl20Modified.
770      *
771      * @return the value of cveUrl20Modified
772      */
773     public String getCveUrl20Modified() {
774         return cveUrl20Modified;
775     }
776 
777     /**
778      * Set the value of cveUrl20Modified.
779      *
780      * @param cveUrl20Modified new value of cveUrl20Modified
781      */
782     public void setCveUrl20Modified(String cveUrl20Modified) {
783         this.cveUrl20Modified = cveUrl20Modified;
784     }
785 
786     /**
787      * Base Data Mirror URL for CVE 1.2.
788      */
789     private String cveUrl12Base;
790 
791     /**
792      * Get the value of cveUrl12Base.
793      *
794      * @return the value of cveUrl12Base
795      */
796     public String getCveUrl12Base() {
797         return cveUrl12Base;
798     }
799 
800     /**
801      * Set the value of cveUrl12Base.
802      *
803      * @param cveUrl12Base new value of cveUrl12Base
804      */
805     public void setCveUrl12Base(String cveUrl12Base) {
806         this.cveUrl12Base = cveUrl12Base;
807     }
808 
809     /**
810      * Data Mirror URL for CVE 2.0.
811      */
812     private String cveUrl20Base;
813 
814     /**
815      * Get the value of cveUrl20Base.
816      *
817      * @return the value of cveUrl20Base
818      */
819     public String getCveUrl20Base() {
820         return cveUrl20Base;
821     }
822 
823     /**
824      * Set the value of cveUrl20Base.
825      *
826      * @param cveUrl20Base new value of cveUrl20Base
827      */
828     public void setCveUrl20Base(String cveUrl20Base) {
829         this.cveUrl20Base = cveUrl20Base;
830     }
831     /**
832      * The path to Mono for .NET assembly analysis on non-windows systems.
833      */
834     private String pathToMono;
835 
836     /**
837      * Get the value of pathToMono.
838      *
839      * @return the value of pathToMono
840      */
841     public String getPathToMono() {
842         return pathToMono;
843     }
844 
845     /**
846      * Set the value of pathToMono.
847      *
848      * @param pathToMono new value of pathToMono
849      */
850     public void setPathToMono(String pathToMono) {
851         this.pathToMono = pathToMono;
852     }
853 
854     @Override
855     public void execute() throws BuildException {
856         final InputStream in = DependencyCheckTask.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
857         LogUtils.prepareLogger(in, logFile);
858 
859         dealWithReferences();
860         validateConfiguration();
861         populateSettings();
862 
863         Engine engine = null;
864         try {
865             engine = new Engine();
866 
867             for (Resource resource : path) {
868                 final FileProvider provider = resource.as(FileProvider.class);
869                 if (provider != null) {
870                     final File file = provider.getFile();
871                     if (file != null && file.exists()) {
872                         engine.scan(file);
873                     }
874                 }
875             }
876             try {
877                 engine.analyzeDependencies();
878                 DatabaseProperties prop = null;
879                 CveDB cve = null;
880                 try {
881                     cve = new CveDB();
882                     cve.open();
883                     prop = cve.getDatabaseProperties();
884                 } catch (DatabaseException ex) {
885                     Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex);
886                 } finally {
887                     if (cve != null) {
888                         cve.close();
889                     }
890                 }
891                 final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
892                 reporter.generateReports(reportOutputDirectory, reportFormat);
893 
894                 if (this.failBuildOnCVSS <= 10) {
895                     checkForFailure(engine.getDependencies());
896                 }
897                 if (this.showSummary) {
898                     showSummary(engine.getDependencies());
899                 }
900             } catch (IOException ex) {
901                 Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE,
902                         "Unable to generate dependency-check report", ex);
903                 throw new BuildException("Unable to generate dependency-check report", ex);
904             } catch (Exception ex) {
905                 Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE,
906                         "An exception occurred; unable to continue task", ex);
907                 throw new BuildException("An exception occurred; unable to continue task", ex);
908             }
909         } catch (DatabaseException ex) {
910             Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.SEVERE,
911                     "Unable to connect to the dependency-check database; analysis has stopped");
912             Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "", ex);
913         } finally {
914             if (engine != null) {
915                 engine.cleanup();
916             }
917         }
918     }
919 
920     /**
921      * Validate the configuration to ensure the parameters have been properly configured/initialized.
922      *
923      * @throws BuildException if the task was not configured correctly.
924      */
925     private void validateConfiguration() throws BuildException {
926         if (path == null) {
927             throw new BuildException("No project dependencies have been defined to analyze.");
928         }
929         if (failBuildOnCVSS < 0 || failBuildOnCVSS > 11) {
930             throw new BuildException("Invalid configuration, failBuildOnCVSS must be between 0 and 11.");
931         }
932     }
933 
934     /**
935      * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
936      * properties required to change the proxy url, port, and connection timeout.
937      */
938     private void populateSettings() {
939         InputStream taskProperties = null;
940         try {
941             taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
942             Settings.mergeProperties(taskProperties);
943         } catch (IOException ex) {
944             Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.WARNING, "Unable to load the dependency-check ant task.properties file.");
945             Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, null, ex);
946         } finally {
947             if (taskProperties != null) {
948                 try {
949                     taskProperties.close();
950                 } catch (IOException ex) {
951                     Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINEST, null, ex);
952                 }
953             }
954         }
955         if (dataDirectory != null) {
956             Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
957         } else {
958             final File jarPath = new File(DependencyCheckTask.class.getProtectionDomain().getCodeSource().getLocation().getPath());
959             final File base = jarPath.getParentFile();
960             final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
961             final File dataDir = new File(base, sub);
962             Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
963         }
964 
965         Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
966 
967         if (proxyUrl != null && !proxyUrl.isEmpty()) {
968             Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
969         }
970         if (proxyPort != null && !proxyPort.isEmpty()) {
971             Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
972         }
973         if (proxyUsername != null && !proxyUsername.isEmpty()) {
974             Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername);
975         }
976         if (proxyPassword != null && !proxyPassword.isEmpty()) {
977             Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
978         }
979         if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
980             Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
981         }
982         if (suppressionFile != null && !suppressionFile.isEmpty()) {
983             Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
984         }
985 
986         //File Type Analyzer Settings
987         //JAR ANALYZER
988         Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
989         //NUSPEC ANALYZER
990         Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
991         //NEXUS ANALYZER
992         Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
993         if (nexusUrl != null && !nexusUrl.isEmpty()) {
994             Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
995         }
996         Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
997         //ARCHIVE ANALYZER
998         Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
999         if (zipExtensions != null && !zipExtensions.isEmpty()) {
1000             Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
1001         }
1002         //ASSEMBLY ANALYZER
1003         Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
1004         if (pathToMono != null && !pathToMono.isEmpty()) {
1005             Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
1006         }
1007 
1008         if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
1009             Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
1010         }
1011         if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
1012             Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
1013         }
1014         if (connectionString != null && !connectionString.isEmpty()) {
1015             Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
1016         }
1017         if (databaseUser != null && !databaseUser.isEmpty()) {
1018             Settings.setString(Settings.KEYS.DB_USER, databaseUser);
1019         }
1020         if (databasePassword != null && !databasePassword.isEmpty()) {
1021             Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
1022         }
1023         if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
1024             Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
1025         }
1026         if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) {
1027             Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
1028         }
1029         if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) {
1030             Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
1031         }
1032         if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
1033             Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
1034         }
1035     }
1036 
1037     /**
1038      * Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
1039      * configuration.
1040      *
1041      * @param dependencies the list of dependency objects
1042      * @throws BuildException thrown if a CVSS score is found that is higher then the threshold set
1043      */
1044     private void checkForFailure(List<Dependency> dependencies) throws BuildException {
1045         final StringBuilder ids = new StringBuilder();
1046         for (Dependency d : dependencies) {
1047             for (Vulnerability v : d.getVulnerabilities()) {
1048                 if (v.getCvssScore() >= failBuildOnCVSS) {
1049                     if (ids.length() == 0) {
1050                         ids.append(v.getName());
1051                     } else {
1052                         ids.append(", ").append(v.getName());
1053                     }
1054                 }
1055             }
1056         }
1057         if (ids.length() > 0) {
1058             final String msg = String.format("%n%nDependency-Check Failure:%n"
1059                     + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
1060                     + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
1061             throw new BuildException(msg);
1062         }
1063     }
1064 
1065     /**
1066      * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
1067      *
1068      * @param dependencies a list of dependency objects
1069      */
1070     private void showSummary(List<Dependency> dependencies) {
1071         final StringBuilder summary = new StringBuilder();
1072         for (Dependency d : dependencies) {
1073             boolean firstEntry = true;
1074             final StringBuilder ids = new StringBuilder();
1075             for (Vulnerability v : d.getVulnerabilities()) {
1076                 if (firstEntry) {
1077                     firstEntry = false;
1078                 } else {
1079                     ids.append(", ");
1080                 }
1081                 ids.append(v.getName());
1082             }
1083             if (ids.length() > 0) {
1084                 summary.append(d.getFileName()).append(" (");
1085                 firstEntry = true;
1086                 for (Identifier id : d.getIdentifiers()) {
1087                     if (firstEntry) {
1088                         firstEntry = false;
1089                     } else {
1090                         summary.append(", ");
1091                     }
1092                     summary.append(id.getValue());
1093                 }
1094                 summary.append(") : ").append(ids).append(NEW_LINE);
1095             }
1096         }
1097         if (summary.length() > 0) {
1098             final String msg = String.format("%n%n"
1099                     + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
1100                     + "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
1101             Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.WARNING, msg);
1102         }
1103     }
1104 
1105     /**
1106      * An enumeration of supported report formats: "ALL", "HTML", "XML", "VULN", etc..
1107      */
1108     public static class ReportFormats extends EnumeratedAttribute {
1109 
1110         /**
1111          * Returns the list of values for the report format.
1112          *
1113          * @return the list of values for the report format
1114          */
1115         @Override
1116         public String[] getValues() {
1117             int i = 0;
1118             final Format[] formats = Format.values();
1119             final String[] values = new String[formats.length];
1120             for (Format format : formats) {
1121                 values[i++] = format.name();
1122             }
1123             return values;
1124         }
1125     }
1126 
1127     /**
1128      * Whether or not the Jar Analyzer is enabled.
1129      */
1130     private boolean jarAnalyzerEnabled = true;
1131 
1132     /**
1133      * Returns whether or not the analyzer is enabled.
1134      *
1135      * @return true if the analyzer is enabled
1136      */
1137     public boolean isJarAnalyzerEnabled() {
1138         return jarAnalyzerEnabled;
1139     }
1140 }