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 URL.
289      */
290     private String proxyUrl;
291 
292     /**
293      * Get the value of proxyUrl.
294      *
295      * @return the value of proxyUrl
296      */
297     public String getProxyUrl() {
298         return proxyUrl;
299     }
300 
301     /**
302      * Set the value of proxyUrl.
303      *
304      * @param proxyUrl new value of proxyUrl
305      */
306     public void setProxyUrl(String proxyUrl) {
307         this.proxyUrl = proxyUrl;
308     }
309     /**
310      * The Proxy Port.
311      */
312     private String proxyPort;
313 
314     /**
315      * Get the value of proxyPort.
316      *
317      * @return the value of proxyPort
318      */
319     public String getProxyPort() {
320         return proxyPort;
321     }
322 
323     /**
324      * Set the value of proxyPort.
325      *
326      * @param proxyPort new value of proxyPort
327      */
328     public void setProxyPort(String proxyPort) {
329         this.proxyPort = proxyPort;
330     }
331     /**
332      * The Proxy username.
333      */
334     private String proxyUsername;
335 
336     /**
337      * Get the value of proxyUsername.
338      *
339      * @return the value of proxyUsername
340      */
341     public String getProxyUsername() {
342         return proxyUsername;
343     }
344 
345     /**
346      * Set the value of proxyUsername.
347      *
348      * @param proxyUsername new value of proxyUsername
349      */
350     public void setProxyUsername(String proxyUsername) {
351         this.proxyUsername = proxyUsername;
352     }
353     /**
354      * The Proxy password.
355      */
356     private String proxyPassword;
357 
358     /**
359      * Get the value of proxyPassword.
360      *
361      * @return the value of proxyPassword
362      */
363     public String getProxyPassword() {
364         return proxyPassword;
365     }
366 
367     /**
368      * Set the value of proxyPassword.
369      *
370      * @param proxyPassword new value of proxyPassword
371      */
372     public void setProxyPassword(String proxyPassword) {
373         this.proxyPassword = proxyPassword;
374     }
375     /**
376      * The Connection Timeout.
377      */
378     private String connectionTimeout;
379 
380     /**
381      * Get the value of connectionTimeout.
382      *
383      * @return the value of connectionTimeout
384      */
385     public String getConnectionTimeout() {
386         return connectionTimeout;
387     }
388 
389     /**
390      * Set the value of connectionTimeout.
391      *
392      * @param connectionTimeout new value of connectionTimeout
393      */
394     public void setConnectionTimeout(String connectionTimeout) {
395         this.connectionTimeout = connectionTimeout;
396     }
397     /**
398      * The file path used for verbose logging.
399      */
400     private String logFile = null;
401 
402     /**
403      * Get the value of logFile.
404      *
405      * @return the value of logFile
406      */
407     public String getLogFile() {
408         return logFile;
409     }
410 
411     /**
412      * Set the value of logFile.
413      *
414      * @param logFile new value of logFile
415      */
416     public void setLogFile(String logFile) {
417         this.logFile = logFile;
418     }
419     /**
420      * The path to the suppression file.
421      */
422     private String suppressionFile;
423 
424     /**
425      * Get the value of suppressionFile.
426      *
427      * @return the value of suppressionFile
428      */
429     public String getSuppressionFile() {
430         return suppressionFile;
431     }
432 
433     /**
434      * Set the value of suppressionFile.
435      *
436      * @param suppressionFile new value of suppressionFile
437      */
438     public void setSuppressionFile(String suppressionFile) {
439         this.suppressionFile = suppressionFile;
440     }
441     /**
442      * flag indicating whether or not to show a summary of findings.
443      */
444     private boolean showSummary = true;
445 
446     /**
447      * Get the value of showSummary.
448      *
449      * @return the value of showSummary
450      */
451     public boolean isShowSummary() {
452         return showSummary;
453     }
454 
455     /**
456      * Set the value of showSummary.
457      *
458      * @param showSummary new value of showSummary
459      */
460     public void setShowSummary(boolean showSummary) {
461         this.showSummary = showSummary;
462     }
463 
464     /**
465      * Sets whether or not the analyzer is enabled.
466      *
467      * @param jarAnalyzerEnabled the value of the new setting
468      */
469     public void setJarAnalyzerEnabled(boolean jarAnalyzerEnabled) {
470         this.jarAnalyzerEnabled = jarAnalyzerEnabled;
471     }
472     /**
473      * Whether or not the Archive Analyzer is enabled.
474      */
475     private boolean archiveAnalyzerEnabled = true;
476 
477     /**
478      * Returns whether or not the analyzer is enabled.
479      *
480      * @return true if the analyzer is enabled
481      */
482     public boolean isArchiveAnalyzerEnabled() {
483         return archiveAnalyzerEnabled;
484     }
485     /**
486      * Whether or not the .NET Assembly Analyzer is enabled.
487      */
488     private boolean assemblyAnalyzerEnabled = true;
489 
490     /**
491      * Sets whether or not the analyzer is enabled.
492      *
493      * @param archiveAnalyzerEnabled the value of the new setting
494      */
495     public void setArchiveAnalyzerEnabled(boolean archiveAnalyzerEnabled) {
496         this.archiveAnalyzerEnabled = archiveAnalyzerEnabled;
497     }
498 
499     /**
500      * Returns whether or not the analyzer is enabled.
501      *
502      * @return true if the analyzer is enabled
503      */
504     public boolean isAssemblyAnalyzerEnabled() {
505         return assemblyAnalyzerEnabled;
506     }
507 
508     /**
509      * Sets whether or not the analyzer is enabled.
510      *
511      * @param assemblyAnalyzerEnabled the value of the new setting
512      */
513     public void setAssemblyAnalyzerEnabled(boolean assemblyAnalyzerEnabled) {
514         this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
515     }
516     /**
517      * Whether or not the .NET Nuspec Analyzer is enabled.
518      */
519     private boolean nuspecAnalyzerEnabled = true;
520 
521     /**
522      * Returns whether or not the analyzer is enabled.
523      *
524      * @return true if the analyzer is enabled
525      */
526     public boolean isNuspecAnalyzerEnabled() {
527         return nuspecAnalyzerEnabled;
528     }
529 
530     /**
531      * Sets whether or not the analyzer is enabled.
532      *
533      * @param nuspecAnalyzerEnabled the value of the new setting
534      */
535     public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
536         this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
537     }
538 
539     /**
540      * Whether or not the nexus analyzer is enabled.
541      */
542     private boolean nexusAnalyzerEnabled = true;
543 
544     /**
545      * Get the value of nexusAnalyzerEnabled.
546      *
547      * @return the value of nexusAnalyzerEnabled
548      */
549     public boolean isNexusAnalyzerEnabled() {
550         return nexusAnalyzerEnabled;
551     }
552 
553     /**
554      * Set the value of nexusAnalyzerEnabled.
555      *
556      * @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
557      */
558     public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
559         this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
560     }
561 
562     /**
563      * The URL of the Nexus server.
564      */
565     private String nexusUrl;
566 
567     /**
568      * Get the value of nexusUrl.
569      *
570      * @return the value of nexusUrl
571      */
572     public String getNexusUrl() {
573         return nexusUrl;
574     }
575 
576     /**
577      * Set the value of nexusUrl.
578      *
579      * @param nexusUrl new value of nexusUrl
580      */
581     public void setNexusUrl(String nexusUrl) {
582         this.nexusUrl = nexusUrl;
583     }
584     /**
585      * Whether or not the defined proxy should be used when connecting to Nexus.
586      */
587     private boolean nexusUsesProxy = true;
588 
589     /**
590      * Get the value of nexusUsesProxy.
591      *
592      * @return the value of nexusUsesProxy
593      */
594     public boolean isNexusUsesProxy() {
595         return nexusUsesProxy;
596     }
597 
598     /**
599      * Set the value of nexusUsesProxy.
600      *
601      * @param nexusUsesProxy new value of nexusUsesProxy
602      */
603     public void setNexusUsesProxy(boolean nexusUsesProxy) {
604         this.nexusUsesProxy = nexusUsesProxy;
605     }
606 
607     /**
608      * The database driver name; such as org.h2.Driver.
609      */
610     private String databaseDriverName;
611 
612     /**
613      * Get the value of databaseDriverName.
614      *
615      * @return the value of databaseDriverName
616      */
617     public String getDatabaseDriverName() {
618         return databaseDriverName;
619     }
620 
621     /**
622      * Set the value of databaseDriverName.
623      *
624      * @param databaseDriverName new value of databaseDriverName
625      */
626     public void setDatabaseDriverName(String databaseDriverName) {
627         this.databaseDriverName = databaseDriverName;
628     }
629 
630     /**
631      * The path to the database driver JAR file if it is not on the class path.
632      */
633     private String databaseDriverPath;
634 
635     /**
636      * Get the value of databaseDriverPath.
637      *
638      * @return the value of databaseDriverPath
639      */
640     public String getDatabaseDriverPath() {
641         return databaseDriverPath;
642     }
643 
644     /**
645      * Set the value of databaseDriverPath.
646      *
647      * @param databaseDriverPath new value of databaseDriverPath
648      */
649     public void setDatabaseDriverPath(String databaseDriverPath) {
650         this.databaseDriverPath = databaseDriverPath;
651     }
652     /**
653      * The database connection string.
654      */
655     private String connectionString;
656 
657     /**
658      * Get the value of connectionString.
659      *
660      * @return the value of connectionString
661      */
662     public String getConnectionString() {
663         return connectionString;
664     }
665 
666     /**
667      * Set the value of connectionString.
668      *
669      * @param connectionString new value of connectionString
670      */
671     public void setConnectionString(String connectionString) {
672         this.connectionString = connectionString;
673     }
674     /**
675      * The user name for connecting to the database.
676      */
677     private String databaseUser;
678 
679     /**
680      * Get the value of databaseUser.
681      *
682      * @return the value of databaseUser
683      */
684     public String getDatabaseUser() {
685         return databaseUser;
686     }
687 
688     /**
689      * Set the value of databaseUser.
690      *
691      * @param databaseUser new value of databaseUser
692      */
693     public void setDatabaseUser(String databaseUser) {
694         this.databaseUser = databaseUser;
695     }
696 
697     /**
698      * The password to use when connecting to the database.
699      */
700     private String databasePassword;
701 
702     /**
703      * Get the value of databasePassword.
704      *
705      * @return the value of databasePassword
706      */
707     public String getDatabasePassword() {
708         return databasePassword;
709     }
710 
711     /**
712      * Set the value of databasePassword.
713      *
714      * @param databasePassword new value of databasePassword
715      */
716     public void setDatabasePassword(String databasePassword) {
717         this.databasePassword = databasePassword;
718     }
719 
720     /**
721      * Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat
722      * like ZIP files.
723      */
724     private String zipExtensions;
725 
726     /**
727      * Get the value of zipExtensions.
728      *
729      * @return the value of zipExtensions
730      */
731     public String getZipExtensions() {
732         return zipExtensions;
733     }
734 
735     /**
736      * Set the value of zipExtensions.
737      *
738      * @param zipExtensions new value of zipExtensions
739      */
740     public void setZipExtensions(String zipExtensions) {
741         this.zipExtensions = zipExtensions;
742     }
743 
744     /**
745      * The url for the modified NVD CVE (1.2 schema).
746      */
747     private String cveUrl12Modified;
748 
749     /**
750      * Get the value of cveUrl12Modified.
751      *
752      * @return the value of cveUrl12Modified
753      */
754     public String getCveUrl12Modified() {
755         return cveUrl12Modified;
756     }
757 
758     /**
759      * Set the value of cveUrl12Modified.
760      *
761      * @param cveUrl12Modified new value of cveUrl12Modified
762      */
763     public void setCveUrl12Modified(String cveUrl12Modified) {
764         this.cveUrl12Modified = cveUrl12Modified;
765     }
766 
767     /**
768      * The url for the modified NVD CVE (2.0 schema).
769      */
770     private String cveUrl20Modified;
771 
772     /**
773      * Get the value of cveUrl20Modified.
774      *
775      * @return the value of cveUrl20Modified
776      */
777     public String getCveUrl20Modified() {
778         return cveUrl20Modified;
779     }
780 
781     /**
782      * Set the value of cveUrl20Modified.
783      *
784      * @param cveUrl20Modified new value of cveUrl20Modified
785      */
786     public void setCveUrl20Modified(String cveUrl20Modified) {
787         this.cveUrl20Modified = cveUrl20Modified;
788     }
789 
790     /**
791      * Base Data Mirror URL for CVE 1.2.
792      */
793     private String cveUrl12Base;
794 
795     /**
796      * Get the value of cveUrl12Base.
797      *
798      * @return the value of cveUrl12Base
799      */
800     public String getCveUrl12Base() {
801         return cveUrl12Base;
802     }
803 
804     /**
805      * Set the value of cveUrl12Base.
806      *
807      * @param cveUrl12Base new value of cveUrl12Base
808      */
809     public void setCveUrl12Base(String cveUrl12Base) {
810         this.cveUrl12Base = cveUrl12Base;
811     }
812 
813     /**
814      * Data Mirror URL for CVE 2.0.
815      */
816     private String cveUrl20Base;
817 
818     /**
819      * Get the value of cveUrl20Base.
820      *
821      * @return the value of cveUrl20Base
822      */
823     public String getCveUrl20Base() {
824         return cveUrl20Base;
825     }
826 
827     /**
828      * Set the value of cveUrl20Base.
829      *
830      * @param cveUrl20Base new value of cveUrl20Base
831      */
832     public void setCveUrl20Base(String cveUrl20Base) {
833         this.cveUrl20Base = cveUrl20Base;
834     }
835     /**
836      * The path to Mono for .NET assembly analysis on non-windows systems.
837      */
838     private String pathToMono;
839 
840     /**
841      * Get the value of pathToMono.
842      *
843      * @return the value of pathToMono
844      */
845     public String getPathToMono() {
846         return pathToMono;
847     }
848 
849     /**
850      * Set the value of pathToMono.
851      *
852      * @param pathToMono new value of pathToMono
853      */
854     public void setPathToMono(String pathToMono) {
855         this.pathToMono = pathToMono;
856     }
857 
858     @Override
859     public void execute() throws BuildException {
860         final InputStream in = DependencyCheckTask.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
861         LogUtils.prepareLogger(in, logFile);
862 
863         dealWithReferences();
864         validateConfiguration();
865         populateSettings();
866 
867         Engine engine = null;
868         try {
869             engine = new Engine(DependencyCheckTask.class.getClassLoader());
870 
871             for (Resource resource : path) {
872                 final FileProvider provider = resource.as(FileProvider.class);
873                 if (provider != null) {
874                     final File file = provider.getFile();
875                     if (file != null && file.exists()) {
876                         engine.scan(file);
877                     }
878                 }
879             }
880             try {
881                 engine.analyzeDependencies();
882                 DatabaseProperties prop = null;
883                 CveDB cve = null;
884                 try {
885                     cve = new CveDB();
886                     cve.open();
887                     prop = cve.getDatabaseProperties();
888                 } catch (DatabaseException ex) {
889                     LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
890                 } finally {
891                     if (cve != null) {
892                         cve.close();
893                     }
894                 }
895                 final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
896                 reporter.generateReports(reportOutputDirectory, reportFormat);
897 
898                 if (this.failBuildOnCVSS <= 10) {
899                     checkForFailure(engine.getDependencies());
900                 }
901                 if (this.showSummary) {
902                     showSummary(engine.getDependencies());
903                 }
904             } catch (IOException ex) {
905                 LOGGER.log(Level.FINE, "Unable to generate dependency-check report", ex);
906                 throw new BuildException("Unable to generate dependency-check report", ex);
907             } catch (Exception ex) {
908                 LOGGER.log(Level.FINE, "An exception occurred; unable to continue task", ex);
909                 throw new BuildException("An exception occurred; unable to continue task", ex);
910             }
911         } catch (DatabaseException ex) {
912             LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
913             LOGGER.log(Level.FINE, "", ex);
914         } finally {
915             Settings.cleanup(true);
916             if (engine != null) {
917                 engine.cleanup();
918             }
919         }
920     }
921 
922     /**
923      * Validate the configuration to ensure the parameters have been properly configured/initialized.
924      *
925      * @throws BuildException if the task was not configured correctly.
926      */
927     private void validateConfiguration() throws BuildException {
928         if (path == null) {
929             throw new BuildException("No project dependencies have been defined to analyze.");
930         }
931         if (failBuildOnCVSS < 0 || failBuildOnCVSS > 11) {
932             throw new BuildException("Invalid configuration, failBuildOnCVSS must be between 0 and 11.");
933         }
934     }
935 
936     /**
937      * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
938      * properties required to change the proxy url, port, and connection timeout.
939      */
940     private void populateSettings() {
941         Settings.initialize();
942         InputStream taskProperties = null;
943         try {
944             taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
945             Settings.mergeProperties(taskProperties);
946         } catch (IOException ex) {
947             LOGGER.log(Level.WARNING, "Unable to load the dependency-check ant task.properties file.");
948             LOGGER.log(Level.FINE, null, ex);
949         } finally {
950             if (taskProperties != null) {
951                 try {
952                     taskProperties.close();
953                 } catch (IOException ex) {
954                     LOGGER.log(Level.FINEST, null, ex);
955                 }
956             }
957         }
958         if (dataDirectory != null) {
959             Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
960         } else {
961             final File jarPath = new File(DependencyCheckTask.class.getProtectionDomain().getCodeSource().getLocation().getPath());
962             final File base = jarPath.getParentFile();
963             final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
964             final File dataDir = new File(base, sub);
965             Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
966         }
967 
968         Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
969 
970         if (proxyUrl != null && !proxyUrl.isEmpty()) {
971             Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
972         }
973         if (proxyPort != null && !proxyPort.isEmpty()) {
974             Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
975         }
976         if (proxyUsername != null && !proxyUsername.isEmpty()) {
977             Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername);
978         }
979         if (proxyPassword != null && !proxyPassword.isEmpty()) {
980             Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
981         }
982         if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
983             Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
984         }
985         if (suppressionFile != null && !suppressionFile.isEmpty()) {
986             Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
987         }
988 
989         //File Type Analyzer Settings
990         //JAR ANALYZER
991         Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
992         //NUSPEC ANALYZER
993         Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
994         //NEXUS ANALYZER
995         Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
996         if (nexusUrl != null && !nexusUrl.isEmpty()) {
997             Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
998         }
999         Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
1000         //ARCHIVE ANALYZER
1001         Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
1002         if (zipExtensions != null && !zipExtensions.isEmpty()) {
1003             Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
1004         }
1005         //ASSEMBLY ANALYZER
1006         Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
1007         if (pathToMono != null && !pathToMono.isEmpty()) {
1008             Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
1009         }
1010 
1011         if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
1012             Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
1013         }
1014         if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
1015             Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
1016         }
1017         if (connectionString != null && !connectionString.isEmpty()) {
1018             Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
1019         }
1020         if (databaseUser != null && !databaseUser.isEmpty()) {
1021             Settings.setString(Settings.KEYS.DB_USER, databaseUser);
1022         }
1023         if (databasePassword != null && !databasePassword.isEmpty()) {
1024             Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
1025         }
1026         if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
1027             Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
1028         }
1029         if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) {
1030             Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
1031         }
1032         if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) {
1033             Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
1034         }
1035         if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
1036             Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
1037         }
1038     }
1039 
1040     /**
1041      * Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
1042      * configuration.
1043      *
1044      * @param dependencies the list of dependency objects
1045      * @throws BuildException thrown if a CVSS score is found that is higher then the threshold set
1046      */
1047     private void checkForFailure(List<Dependency> dependencies) throws BuildException {
1048         final StringBuilder ids = new StringBuilder();
1049         for (Dependency d : dependencies) {
1050             for (Vulnerability v : d.getVulnerabilities()) {
1051                 if (v.getCvssScore() >= failBuildOnCVSS) {
1052                     if (ids.length() == 0) {
1053                         ids.append(v.getName());
1054                     } else {
1055                         ids.append(", ").append(v.getName());
1056                     }
1057                 }
1058             }
1059         }
1060         if (ids.length() > 0) {
1061             final String msg = String.format("%n%nDependency-Check Failure:%n"
1062                     + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
1063                     + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
1064             throw new BuildException(msg);
1065         }
1066     }
1067 
1068     /**
1069      * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
1070      *
1071      * @param dependencies a list of dependency objects
1072      */
1073     private void showSummary(List<Dependency> dependencies) {
1074         final StringBuilder summary = new StringBuilder();
1075         for (Dependency d : dependencies) {
1076             boolean firstEntry = true;
1077             final StringBuilder ids = new StringBuilder();
1078             for (Vulnerability v : d.getVulnerabilities()) {
1079                 if (firstEntry) {
1080                     firstEntry = false;
1081                 } else {
1082                     ids.append(", ");
1083                 }
1084                 ids.append(v.getName());
1085             }
1086             if (ids.length() > 0) {
1087                 summary.append(d.getFileName()).append(" (");
1088                 firstEntry = true;
1089                 for (Identifier id : d.getIdentifiers()) {
1090                     if (firstEntry) {
1091                         firstEntry = false;
1092                     } else {
1093                         summary.append(", ");
1094                     }
1095                     summary.append(id.getValue());
1096                 }
1097                 summary.append(") : ").append(ids).append(NEW_LINE);
1098             }
1099         }
1100         if (summary.length() > 0) {
1101             final String msg = String.format("%n%n"
1102                     + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
1103                     + "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
1104             LOGGER.log(Level.WARNING, msg);
1105         }
1106     }
1107 
1108     /**
1109      * An enumeration of supported report formats: "ALL", "HTML", "XML", "VULN", etc..
1110      */
1111     public static class ReportFormats extends EnumeratedAttribute {
1112 
1113         /**
1114          * Returns the list of values for the report format.
1115          *
1116          * @return the list of values for the report format
1117          */
1118         @Override
1119         public String[] getValues() {
1120             int i = 0;
1121             final Format[] formats = Format.values();
1122             final String[] values = new String[formats.length];
1123             for (Format format : formats) {
1124                 values[i++] = format.name();
1125             }
1126             return values;
1127         }
1128     }
1129 
1130     /**
1131      * Whether or not the Jar Analyzer is enabled.
1132      */
1133     private boolean jarAnalyzerEnabled = true;
1134 
1135     /**
1136      * Returns whether or not the analyzer is enabled.
1137      *
1138      * @return true if the analyzer is enabled
1139      */
1140     public boolean isJarAnalyzerEnabled() {
1141         return jarAnalyzerEnabled;
1142     }
1143 }