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