1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.maven;
19
20 import java.io.BufferedOutputStream;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.ObjectOutputStream;
28 import java.util.List;
29 import java.util.Locale;
30 import org.apache.maven.artifact.Artifact;
31 import org.apache.maven.doxia.sink.Sink;
32 import org.apache.maven.plugin.AbstractMojo;
33 import org.apache.maven.plugin.MojoExecutionException;
34 import org.apache.maven.plugin.MojoFailureException;
35 import org.apache.maven.plugins.annotations.Component;
36 import org.apache.maven.plugins.annotations.Parameter;
37 import org.apache.maven.project.MavenProject;
38 import org.apache.maven.reporting.MavenReport;
39 import org.apache.maven.reporting.MavenReportException;
40 import org.apache.maven.settings.Proxy;
41 import org.apache.maven.settings.Server;
42 import org.owasp.dependencycheck.data.nexus.MavenArtifact;
43 import org.owasp.dependencycheck.data.nvdcve.CveDB;
44 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
45 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
46 import org.owasp.dependencycheck.dependency.Confidence;
47 import org.owasp.dependencycheck.dependency.Dependency;
48 import org.owasp.dependencycheck.dependency.Identifier;
49 import org.owasp.dependencycheck.dependency.Vulnerability;
50 import org.owasp.dependencycheck.reporting.ReportGenerator;
51 import org.owasp.dependencycheck.utils.ExpectedOjectInputStream;
52 import org.owasp.dependencycheck.utils.Settings;
53 import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
54 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
55 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
56
57
58
59
60
61 public abstract class BaseDependencyCheckMojo extends AbstractMojo implements MavenReport {
62
63
64
65
66
67 private static final String PROPERTIES_FILE = "mojo.properties";
68
69
70
71 private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
72
73
74
75 @Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
76 private String dataFileName;
77
78
79
80
81
82
83 @Parameter(property = "project", required = true, readonly = true)
84 private MavenProject project;
85
86
87
88 @Parameter(readonly = true, required = true, property = "reactorProjects")
89 private List<MavenProject> reactorProjects;
90
91
92
93
94 @Parameter(defaultValue = "${project.build.directory}", required = true)
95 private File outputDirectory;
96
97
98
99 @Parameter(property = "project.reporting.outputDirectory", required = true)
100 private File reportOutputDirectory;
101
102
103
104
105 @SuppressWarnings("CanBeFinal")
106 @Parameter(property = "failBuildOnCVSS", defaultValue = "11", required = true)
107 private float failBuildOnCVSS = 11;
108
109
110
111
112 @SuppressWarnings("CanBeFinal")
113 @Parameter(property = "autoUpdate")
114 private Boolean autoUpdate;
115
116
117
118
119
120 @Parameter(property = "aggregate")
121 @Deprecated
122 private Boolean aggregate;
123
124
125
126
127 @SuppressWarnings("CanBeFinal")
128 @Parameter(property = "format", defaultValue = "HTML", required = true)
129 private String format = "HTML";
130
131
132
133 @Parameter(property = "mavenSettings", defaultValue = "${settings}", required = false)
134 private org.apache.maven.settings.Settings mavenSettings;
135
136
137
138
139 @SuppressWarnings("CanBeFinal")
140 @Parameter(property = "mavenSettingsProxyId", required = false)
141 private String mavenSettingsProxyId;
142
143
144
145
146 @Parameter(property = "connectionTimeout", defaultValue = "", required = false)
147 private String connectionTimeout;
148
149
150
151 @Parameter(property = "suppressionFile", defaultValue = "", required = false)
152 private String suppressionFile;
153
154
155
156 @Parameter(property = "showSummary", defaultValue = "true", required = false)
157 private boolean showSummary = true;
158
159
160
161
162 @Parameter(property = "jarAnalyzerEnabled", required = false)
163 private Boolean jarAnalyzerEnabled;
164
165
166
167
168 @Parameter(property = "archiveAnalyzerEnabled", required = false)
169 private Boolean archiveAnalyzerEnabled;
170
171
172
173
174 @Parameter(property = "pyDistributionAnalyzerEnabled", required = false)
175 private Boolean pyDistributionAnalyzerEnabled;
176
177
178
179 @Parameter(property = "pyPackageAnalyzerEnabled", required = false)
180 private Boolean pyPackageAnalyzerEnabled;
181
182
183
184 @Parameter(property = "rubygemsAnalyzerEnabled", required = false)
185 private Boolean rubygemsAnalyzerEnabled;
186
187
188
189 @Parameter(property = "opensslAnalyzerEnabled", required = false)
190 private Boolean opensslAnalyzerEnabled;
191
192
193
194 @Parameter(property = "cmakeAnalyzerEnabled", required = false)
195 private Boolean cmakeAnalyzerEnabled;
196
197
198
199 @Parameter(property = "autoconfAnalyzerEnabled", required = false)
200 private Boolean autoconfAnalyzerEnabled;
201
202
203
204 @Parameter(property = "composerAnalyzerEnabled", required = false)
205 private Boolean composerAnalyzerEnabled;
206
207
208
209 @Parameter(property = "nodeAnalyzerEnabled", required = false)
210 private Boolean nodeAnalyzerEnabled;
211
212
213
214
215 @Parameter(property = "assemblyAnalyzerEnabled", required = false)
216 private Boolean assemblyAnalyzerEnabled;
217
218
219
220
221 @Parameter(property = "nuspecAnalyzerEnabled", required = false)
222 private Boolean nuspecAnalyzerEnabled;
223
224
225
226
227 @Parameter(property = "centralAnalyzerEnabled", required = false)
228 private Boolean centralAnalyzerEnabled;
229
230
231
232
233 @Parameter(property = "nexusAnalyzerEnabled", required = false)
234 private Boolean nexusAnalyzerEnabled;
235
236
237
238
239 @Parameter(property = "nexusUrl", required = false)
240 private String nexusUrl;
241
242
243
244 @Parameter(property = "nexusUsesProxy", required = false)
245 private Boolean nexusUsesProxy;
246
247
248
249 @Parameter(property = "connectionString", defaultValue = "", required = false)
250 private String connectionString;
251
252
253
254
255
256
257 protected String getConnectionString() {
258 return connectionString;
259 }
260
261
262
263 @Parameter(property = "databaseDriverName", defaultValue = "", required = false)
264 private String databaseDriverName;
265
266
267
268 @Parameter(property = "databaseDriverPath", defaultValue = "", required = false)
269 private String databaseDriverPath;
270
271
272
273 @Parameter(property = "serverId", defaultValue = "", required = false)
274 private String serverId;
275
276
277
278 @Parameter(defaultValue = "${settings}", readonly = true, required = true)
279 private org.apache.maven.settings.Settings settingsXml;
280
281
282
283 @Component(role = SecDispatcher.class, hint = "default")
284 private SecDispatcher securityDispatcher;
285
286
287
288 @Parameter(property = "databaseUser", defaultValue = "", required = false)
289 private String databaseUser;
290
291
292
293 @Parameter(property = "databasePassword", defaultValue = "", required = false)
294 private String databasePassword;
295
296
297
298 @Parameter(property = "zipExtensions", required = false)
299 private String zipExtensions;
300
301
302
303 @SuppressWarnings("CanBeFinal")
304 @Parameter(property = "dependency-check.skip", defaultValue = "false", required = false)
305 private boolean skip = false;
306
307
308
309 @SuppressWarnings("CanBeFinal")
310 @Parameter(property = "skipTestScope", defaultValue = "true", required = false)
311 private boolean skipTestScope = true;
312
313
314
315 @SuppressWarnings("CanBeFinal")
316 @Parameter(property = "skipRuntimeScope", defaultValue = "false", required = false)
317 private boolean skipRuntimeScope = false;
318
319
320
321 @SuppressWarnings("CanBeFinal")
322 @Parameter(property = "skipProvidedScope", defaultValue = "false", required = false)
323 private boolean skipProvidedScope = false;
324
325
326
327 @Parameter(property = "dataDirectory", defaultValue = "", required = false)
328 private String dataDirectory;
329
330
331
332 @Parameter(property = "cveUrl12Modified", defaultValue = "", required = false)
333 private String cveUrl12Modified;
334
335
336
337 @Parameter(property = "cveUrl20Modified", defaultValue = "", required = false)
338 private String cveUrl20Modified;
339
340
341
342 @Parameter(property = "cveUrl12Base", defaultValue = "", required = false)
343 private String cveUrl12Base;
344
345
346
347 @Parameter(property = "cveUrl20Base", defaultValue = "", required = false)
348 private String cveUrl20Base;
349
350
351
352 @Parameter(property = "cveValidForHours", defaultValue = "", required = false)
353 private Integer cveValidForHours;
354
355
356
357
358 @Parameter(property = "pathToMono", defaultValue = "", required = false)
359 private String pathToMono;
360
361
362
363
364
365
366 @SuppressWarnings("CanBeFinal")
367 @Parameter(property = "proxyUrl", defaultValue = "", required = false)
368 @Deprecated
369 private String proxyUrl = null;
370
371
372
373
374
375 @SuppressWarnings("CanBeFinal")
376 @Parameter(property = "externalReport")
377 @Deprecated
378 private String externalReport = null;
379
380
381
382
383
384
385
386
387
388 @Override
389 public void execute() throws MojoExecutionException, MojoFailureException {
390 if (skip) {
391 getLog().info("Skipping " + getName(Locale.US));
392 } else {
393 validateAggregate();
394 project.setContextValue(getOutputDirectoryContextKey(), this.outputDirectory);
395 runCheck();
396 }
397 }
398
399
400
401
402
403
404
405 private void validateAggregate() throws MojoExecutionException {
406 if (aggregate != null && aggregate) {
407 final String msg = "Aggregate configuration detected - as of dependency-check 1.2.8 this no longer supported. "
408 + "Please use the aggregate goal instead.";
409 throw new MojoExecutionException(msg);
410 }
411 }
412
413
414
415
416
417
418
419
420
421 @Override
422 @Deprecated
423 public final void generate(@SuppressWarnings("deprecation") org.codehaus.doxia.sink.Sink sink, Locale locale) throws MavenReportException {
424 generate((Sink) sink, locale);
425 }
426
427
428
429
430
431
432
433
434 public void generate(Sink sink, Locale locale) throws MavenReportException {
435 try {
436 validateAggregate();
437 } catch (MojoExecutionException ex) {
438 throw new MavenReportException(ex.getMessage());
439 }
440 project.setContextValue(getOutputDirectoryContextKey(), getReportOutputDirectory());
441 try {
442 runCheck();
443 } catch (MojoExecutionException ex) {
444 throw new MavenReportException(ex.getMessage(), ex);
445 } catch (MojoFailureException ex) {
446 getLog().warn("Vulnerabilities were identifies that exceed the CVSS threshold for failing the build");
447 }
448 }
449
450
451
452
453
454
455
456 protected File getCorrectOutputDirectory() throws MojoExecutionException {
457 return getCorrectOutputDirectory(this.project);
458 }
459
460
461
462
463
464
465
466 protected File getCorrectOutputDirectory(MavenProject current) {
467 final Object obj = current.getContextValue(getOutputDirectoryContextKey());
468 if (obj != null && obj instanceof File) {
469 return (File) obj;
470 }
471 File target = new File(current.getBuild().getDirectory());
472 if (target.getParentFile() != null && "target".equals(target.getParentFile().getName())) {
473 target = target.getParentFile();
474 }
475 return target;
476 }
477
478
479
480
481
482
483
484 protected File getDataFile(MavenProject current) {
485 if (getLog().isDebugEnabled()) {
486 getLog().debug(String.format("Getting data filefor %s using key '%s'", current.getName(), getDataFileContextKey()));
487 }
488 final Object obj = current.getContextValue(getDataFileContextKey());
489 if (obj != null) {
490 if (obj instanceof String) {
491 final File f = new File((String) obj);
492 return f;
493 }
494 } else {
495 if (getLog().isDebugEnabled()) {
496 getLog().debug("Context value not found");
497 }
498 }
499 return null;
500 }
501
502
503
504
505
506
507
508 protected void scanArtifacts(MavenProject project, Engine engine) {
509 for (Artifact a : project.getArtifacts()) {
510 if (excludeFromScan(a)) {
511 continue;
512 }
513 final List<Dependency> deps = engine.scan(a.getFile().getAbsoluteFile());
514 if (deps != null) {
515 if (deps.size() == 1) {
516 final Dependency d = deps.get(0);
517 if (d != null) {
518 final MavenArtifact ma = new MavenArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
519 d.addAsEvidence("pom", ma, Confidence.HIGHEST);
520 d.addProjectReference(project.getName());
521 if (getLog().isDebugEnabled()) {
522 getLog().debug(String.format("Adding project reference %s on dependency %s", project.getName(),
523 d.getDisplayFileName()));
524 }
525 }
526 } else {
527 if (getLog().isDebugEnabled()) {
528 final String msg = String.format("More then 1 dependency was identified in first pass scan of '%s:%s:%s'",
529 a.getGroupId(), a.getArtifactId(), a.getVersion());
530 getLog().debug(msg);
531 }
532 }
533 }
534 }
535 }
536
537
538
539
540
541
542
543 public abstract void runCheck() throws MojoExecutionException, MojoFailureException;
544
545
546
547
548
549
550 @Override
551 public void setReportOutputDirectory(File directory) {
552 reportOutputDirectory = directory;
553 }
554
555
556
557
558
559
560 @Override
561 public File getReportOutputDirectory() {
562 return reportOutputDirectory;
563 }
564
565
566
567
568
569
570 public File getOutputDirectory() {
571 return outputDirectory;
572 }
573
574
575
576
577
578
579 @Override
580 public final boolean isExternalReport() {
581 return true;
582 }
583
584
585
586
587
588
589 @Override
590 public String getOutputName() {
591 if ("HTML".equalsIgnoreCase(this.format) || "ALL".equalsIgnoreCase(this.format)) {
592 return "dependency-check-report";
593 } else if ("XML".equalsIgnoreCase(this.format)) {
594 return "dependency-check-report.xml#";
595 } else if ("VULN".equalsIgnoreCase(this.format)) {
596 return "dependency-check-vulnerability";
597 } else {
598 getLog().warn("Unknown report format used during site generation.");
599 return "dependency-check-report";
600 }
601 }
602
603
604
605
606
607
608 @Override
609 public String getCategoryName() {
610 return MavenReport.CATEGORY_PROJECT_REPORTS;
611 }
612
613
614
615
616
617
618
619
620 protected Engine initializeEngine() throws DatabaseException {
621 populateSettings();
622 return new Engine(this.project,
623 this.reactorProjects);
624 }
625
626
627
628
629
630 protected void populateSettings() {
631 Settings.initialize();
632 InputStream mojoProperties = null;
633 try {
634 mojoProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
635 Settings.mergeProperties(mojoProperties);
636 } catch (IOException ex) {
637 getLog().warn("Unable to load the dependency-check ant task.properties file.");
638 if (getLog().isDebugEnabled()) {
639 getLog().debug("", ex);
640 }
641 } finally {
642 if (mojoProperties != null) {
643 try {
644 mojoProperties.close();
645 } catch (IOException ex) {
646 if (getLog().isDebugEnabled()) {
647 getLog().debug("", ex);
648 }
649 }
650 }
651 }
652 Settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
653
654 if (externalReport != null) {
655 getLog().warn("The 'externalReport' option was set; this configuration option has been removed. "
656 + "Please update the dependency-check-maven plugin's configuration");
657 }
658
659 if (proxyUrl != null && !proxyUrl.isEmpty()) {
660 getLog().warn("Deprecated configuration detected, proxyUrl will be ignored; use the maven settings " + "to configure the proxy instead");
661 }
662 final Proxy proxy = getMavenProxy();
663 if (proxy != null) {
664 Settings.setString(Settings.KEYS.PROXY_SERVER, proxy.getHost());
665 Settings.setString(Settings.KEYS.PROXY_PORT, Integer.toString(proxy.getPort()));
666 final String userName = proxy.getUsername();
667 final String password = proxy.getPassword();
668 Settings.setStringIfNotNull(Settings.KEYS.PROXY_USERNAME, userName);
669 Settings.setStringIfNotNull(Settings.KEYS.PROXY_PASSWORD, password);
670 Settings.setStringIfNotNull(Settings.KEYS.PROXY_NON_PROXY_HOSTS, proxy.getNonProxyHosts());
671 }
672
673 Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
674 Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
675
676
677 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
678 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
679 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
680 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
681 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
682 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
683 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
684 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
685 Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
686 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
687
688 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, pyDistributionAnalyzerEnabled);
689 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, pyPackageAnalyzerEnabled);
690 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, rubygemsAnalyzerEnabled);
691 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, opensslAnalyzerEnabled);
692 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CMAKE_ENABLED, cmakeAnalyzerEnabled);
693 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, autoconfAnalyzerEnabled);
694 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, composerAnalyzerEnabled);
695 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, nodeAnalyzerEnabled);
696
697
698 Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
699 Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
700 Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
701
702 if (databaseUser == null && databasePassword == null && serverId != null) {
703 final Server server = settingsXml.getServer(serverId);
704 if (server != null) {
705 databaseUser = server.getUsername();
706 try {
707
708
709
710
711
712
713
714 if (securityDispatcher instanceof DefaultSecDispatcher) {
715 ((DefaultSecDispatcher) securityDispatcher).setConfigurationFile("~/.m2/settings-security.xml");
716 }
717
718 databasePassword = securityDispatcher.decrypt(server.getPassword());
719 } catch (SecDispatcherException ex) {
720 if (ex.getCause() instanceof FileNotFoundException
721 || (ex.getCause() != null && ex.getCause().getCause() instanceof FileNotFoundException)) {
722
723 final String tmp = server.getPassword();
724 if (tmp.startsWith("{") && tmp.endsWith("}")) {
725 getLog().error(String.format(
726 "Unable to decrypt the server password for server id '%s' in settings.xml%n\tCause: %s",
727 serverId, ex.getMessage()));
728 } else {
729 databasePassword = tmp;
730 }
731 } else {
732 getLog().error(String.format(
733 "Unable to decrypt the server password for server id '%s' in settings.xml%n\tCause: %s",
734 serverId, ex.getMessage()));
735 }
736 }
737 } else {
738 getLog().error(String.format("Server '%s' not found in the settings.xml file", serverId));
739 }
740 }
741
742 Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
743 Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
744 Settings.setStringIfNotEmpty(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
745
746 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
747 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
748 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
749 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
750 Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
751
752 }
753
754
755
756
757
758
759 private Proxy getMavenProxy() {
760 if (mavenSettings != null) {
761 final List<Proxy> proxies = mavenSettings.getProxies();
762 if (proxies != null && !proxies.isEmpty()) {
763 if (mavenSettingsProxyId != null) {
764 for (Proxy proxy : proxies) {
765 if (mavenSettingsProxyId.equalsIgnoreCase(proxy.getId())) {
766 return proxy;
767 }
768 }
769 } else if (proxies.size() == 1) {
770 return proxies.get(0);
771 } else {
772 getLog().warn("Multiple proxy definitions exist in the Maven settings. In the dependency-check "
773 + "configuration set the mavenSettingsProxyId so that the correct proxy will be used.");
774 throw new IllegalStateException("Ambiguous proxy definition");
775 }
776 }
777 }
778 return null;
779 }
780
781
782
783
784
785
786
787 protected boolean excludeFromScan(Artifact a) {
788 if (skipTestScope && Artifact.SCOPE_TEST.equals(a.getScope())) {
789 return true;
790 }
791 if (skipProvidedScope && Artifact.SCOPE_PROVIDED.equals(a.getScope())) {
792 return true;
793 }
794 if (skipRuntimeScope && !Artifact.SCOPE_RUNTIME.equals(a.getScope())) {
795 return true;
796 }
797 return false;
798 }
799
800
801
802
803
804
805
806
807
808 protected MavenProject getProject() {
809 return project;
810 }
811
812
813
814
815
816
817 protected List<MavenProject> getReactorProjects() {
818 return reactorProjects;
819 }
820
821
822
823
824
825
826 protected String getFormat() {
827 return format;
828 }
829
830
831
832
833
834
835
836
837 protected void writeReports(Engine engine, MavenProject p, File outputDir) {
838 DatabaseProperties prop = null;
839 CveDB cve = null;
840 try {
841 cve = new CveDB();
842 cve.open();
843 prop = cve.getDatabaseProperties();
844 } catch (DatabaseException ex) {
845 if (getLog().isDebugEnabled()) {
846 getLog().debug("Unable to retrieve DB Properties", ex);
847 }
848 } finally {
849 if (cve != null) {
850 cve.close();
851 }
852 }
853 final ReportGenerator r = new ReportGenerator(p.getName(), engine.getDependencies(), engine.getAnalyzers(), prop);
854 try {
855 r.generateReports(outputDir.getAbsolutePath(), format);
856 } catch (IOException ex) {
857 getLog().error(
858 "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
859 if (getLog().isDebugEnabled()) {
860 getLog().debug("", ex);
861 }
862 } catch (Throwable ex) {
863 getLog().error(
864 "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
865 if (getLog().isDebugEnabled()) {
866 getLog().debug("", ex);
867 }
868 }
869 }
870
871
872
873
874
875
876
877
878
879 protected void checkForFailure(List<Dependency> dependencies) throws MojoFailureException {
880 if (failBuildOnCVSS <= 10) {
881 final StringBuilder ids = new StringBuilder();
882 for (Dependency d : dependencies) {
883 boolean addName = true;
884 for (Vulnerability v : d.getVulnerabilities()) {
885 if (v.getCvssScore() >= failBuildOnCVSS) {
886 if (addName) {
887 addName = false;
888 ids.append(NEW_LINE).append(d.getFileName()).append(": ");
889 ids.append(v.getName());
890 } else {
891 ids.append(", ").append(v.getName());
892 }
893 }
894 }
895 }
896 if (ids.length() > 0) {
897 final String msg = String.format("%n%nDependency-Check Failure:%n"
898 + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
899 + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
900 throw new MojoFailureException(msg);
901 }
902 }
903 }
904
905
906
907
908
909
910
911 protected void showSummary(MavenProject mp, List<Dependency> dependencies) {
912 if (showSummary) {
913 final StringBuilder summary = new StringBuilder();
914 for (Dependency d : dependencies) {
915 boolean firstEntry = true;
916 final StringBuilder ids = new StringBuilder();
917 for (Vulnerability v : d.getVulnerabilities()) {
918 if (firstEntry) {
919 firstEntry = false;
920 } else {
921 ids.append(", ");
922 }
923 ids.append(v.getName());
924 }
925 if (ids.length() > 0) {
926 summary.append(d.getFileName()).append(" (");
927 firstEntry = true;
928 for (Identifier id : d.getIdentifiers()) {
929 if (firstEntry) {
930 firstEntry = false;
931 } else {
932 summary.append(", ");
933 }
934 summary.append(id.getValue());
935 }
936 summary.append(") : ").append(ids).append(NEW_LINE);
937 }
938 }
939 if (summary.length() > 0) {
940 final String msg = String.format("%n%n" + "One or more dependencies were identified with known vulnerabilities in %s:%n%n%s"
941 + "%n%nSee the dependency-check report for more details.%n%n", mp.getName(), summary.toString());
942 getLog().warn(msg);
943 }
944 }
945 }
946
947
948
949
950
951
952
953
954
955 protected String getDataFileContextKey() {
956 return "dependency-check-path-" + dataFileName;
957 }
958
959
960
961
962
963
964
965 protected String getOutputDirectoryContextKey() {
966 return "dependency-output-dir-" + dataFileName;
967 }
968
969
970
971
972
973
974
975
976 protected void writeDataFile(MavenProject mp, File writeTo, List<Dependency> dependencies) {
977 File file;
978
979 if (mp.getContextValue(this.getDataFileContextKey()) == null) {
980 if (writeTo == null) {
981 file = new File(mp.getBuild().getDirectory());
982 file = new File(file, dataFileName);
983 } else {
984 file = new File(writeTo, dataFileName);
985 }
986 final File parent = file.getParentFile();
987 if (!parent.isDirectory() && parent.mkdirs()) {
988 getLog().error(String.format("Directory '%s' does not exist and cannot be created; unable to write data file.",
989 parent.getAbsolutePath()));
990 }
991
992 ObjectOutputStream out = null;
993 try {
994 if (dependencies != null) {
995 out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
996 out.writeObject(dependencies);
997 }
998 if (getLog().isDebugEnabled()) {
999 getLog().debug(String.format("Serialized data file written to '%s' for %s, referenced by key %s",
1000 file.getAbsolutePath(), mp.getName(), this.getDataFileContextKey()));
1001 }
1002 mp.setContextValue(this.getDataFileContextKey(), file.getAbsolutePath());
1003 } catch (IOException ex) {
1004 getLog().warn("Unable to create data file used for report aggregation; "
1005 + "if report aggregation is being used the results may be incomplete.");
1006 if (getLog().isDebugEnabled()) {
1007 getLog().debug(ex.getMessage(), ex);
1008 }
1009 } finally {
1010 if (out != null) {
1011 try {
1012 out.close();
1013 } catch (IOException ex) {
1014 if (getLog().isDebugEnabled()) {
1015 getLog().debug("ignore", ex);
1016 }
1017 }
1018 }
1019 }
1020 }
1021 }
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031 protected List<Dependency> readDataFile(MavenProject project) {
1032 final Object oPath = project.getContextValue(this.getDataFileContextKey());
1033 if (oPath == null) {
1034 return null;
1035 }
1036 List<Dependency> ret = null;
1037 final String path = (String) oPath;
1038
1039 ExpectedOjectInputStream ois = null;
1040 try {
1041
1042 ois = new ExpectedOjectInputStream(new FileInputStream(path),
1043 "java.util.ArrayList",
1044 "java.util.HashSet",
1045 "java.util.TreeSet",
1046 "java.lang.AbstractSet",
1047 "java.lang.AbstractCollection",
1048 "java.lang.Enum",
1049 "org.owasp.dependencycheck.dependency.Confidence",
1050 "org.owasp.dependencycheck.dependency.Dependency",
1051 "org.owasp.dependencycheck.dependency.Evidence",
1052 "org.owasp.dependencycheck.dependency.EvidenceCollection",
1053 "org.owasp.dependencycheck.dependency.Identifier",
1054 "org.owasp.dependencycheck.dependency.Reference",
1055 "org.owasp.dependencycheck.dependency.Vulnerability",
1056 "org.owasp.dependencycheck.dependency.VulnerabilityComparator",
1057 "org.owasp.dependencycheck.dependency.VulnerableSoftware");
1058 ret = (List<Dependency>) ois.readObject();
1059 } catch (FileNotFoundException ex) {
1060
1061 getLog().error("", ex);
1062 } catch (IOException ex) {
1063 getLog().error("", ex);
1064 } catch (ClassNotFoundException ex) {
1065 getLog().error("", ex);
1066 } finally {
1067 if (ois != null) {
1068 try {
1069 ois.close();
1070 } catch (IOException ex) {
1071 getLog().error("", ex);
1072 }
1073 }
1074 }
1075 return ret;
1076 }
1077
1078 }