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.ObjectInputStream;
28 import java.io.ObjectOutputStream;
29 import java.util.List;
30 import java.util.Locale;
31 import org.apache.maven.artifact.Artifact;
32 import org.apache.maven.doxia.sink.Sink;
33 import org.apache.maven.plugin.AbstractMojo;
34 import org.apache.maven.plugin.MojoExecutionException;
35 import org.apache.maven.plugin.MojoFailureException;
36 import org.apache.maven.plugins.annotations.Component;
37 import org.apache.maven.plugins.annotations.Parameter;
38 import org.apache.maven.project.MavenProject;
39 import org.apache.maven.reporting.MavenReport;
40 import org.apache.maven.reporting.MavenReportException;
41 import org.apache.maven.settings.Proxy;
42 import org.apache.maven.settings.Server;
43 import org.owasp.dependencycheck.data.nexus.MavenArtifact;
44 import org.owasp.dependencycheck.data.nvdcve.CveDB;
45 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
46 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
47 import org.owasp.dependencycheck.dependency.Confidence;
48 import org.owasp.dependencycheck.dependency.Dependency;
49 import org.owasp.dependencycheck.dependency.Identifier;
50 import org.owasp.dependencycheck.dependency.Vulnerability;
51 import org.owasp.dependencycheck.reporting.ReportGenerator;
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 }
671
672 Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
673 Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
674
675
676 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
677 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
678 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
679 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
680 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
681 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
682 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
683 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
684 Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
685 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
686
687 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, pyDistributionAnalyzerEnabled);
688 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, pyPackageAnalyzerEnabled);
689 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, rubygemsAnalyzerEnabled);
690 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, opensslAnalyzerEnabled);
691 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CMAKE_ENABLED, cmakeAnalyzerEnabled);
692 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, autoconfAnalyzerEnabled);
693 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, composerAnalyzerEnabled);
694 Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, nodeAnalyzerEnabled);
695
696
697 Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
698 Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
699 Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
700
701 if (databaseUser == null && databasePassword == null && serverId != null) {
702 final Server server = settingsXml.getServer(serverId);
703 if (server != null) {
704 databaseUser = server.getUsername();
705 try {
706
707
708
709
710
711
712
713 if (securityDispatcher instanceof DefaultSecDispatcher) {
714 ((DefaultSecDispatcher) securityDispatcher).setConfigurationFile("~/.m2/settings-security.xml");
715 }
716
717 databasePassword = securityDispatcher.decrypt(server.getPassword());
718 } catch (SecDispatcherException ex) {
719 if (ex.getCause() instanceof FileNotFoundException
720 || (ex.getCause() != null && ex.getCause().getCause() instanceof FileNotFoundException)) {
721
722 final String tmp = server.getPassword();
723 if (tmp.startsWith("{") && tmp.endsWith("}")) {
724 getLog().error(String.format(
725 "Unable to decrypt the server password for server id '%s' in settings.xml%n\tCause: %s",
726 serverId, ex.getMessage()));
727 } else {
728 databasePassword = tmp;
729 }
730 } else {
731 getLog().error(String.format(
732 "Unable to decrypt the server password for server id '%s' in settings.xml%n\tCause: %s",
733 serverId, ex.getMessage()));
734 }
735 }
736 } else {
737 getLog().error(String.format("Server '%s' not found in the settings.xml file", serverId));
738 }
739 }
740
741 Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
742 Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
743 Settings.setStringIfNotEmpty(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
744
745 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
746 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
747 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
748 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
749 Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
750
751 }
752
753
754
755
756
757
758 private Proxy getMavenProxy() {
759 if (mavenSettings != null) {
760 final List<Proxy> proxies = mavenSettings.getProxies();
761 if (proxies != null && !proxies.isEmpty()) {
762 if (mavenSettingsProxyId != null) {
763 for (Proxy proxy : proxies) {
764 if (mavenSettingsProxyId.equalsIgnoreCase(proxy.getId())) {
765 return proxy;
766 }
767 }
768 } else if (proxies.size() == 1) {
769 return proxies.get(0);
770 } else {
771 getLog().warn("Multiple proxy definitions exist in the Maven settings. In the dependency-check "
772 + "configuration set the mavenSettingsProxyId so that the correct proxy will be used.");
773 throw new IllegalStateException("Ambiguous proxy definition");
774 }
775 }
776 }
777 return null;
778 }
779
780
781
782
783
784
785
786 protected boolean excludeFromScan(Artifact a) {
787 if (skipTestScope && Artifact.SCOPE_TEST.equals(a.getScope())) {
788 return true;
789 }
790 if (skipProvidedScope && Artifact.SCOPE_PROVIDED.equals(a.getScope())) {
791 return true;
792 }
793 if (skipRuntimeScope && !Artifact.SCOPE_RUNTIME.equals(a.getScope())) {
794 return true;
795 }
796 return false;
797 }
798
799
800
801
802
803
804
805
806
807 protected MavenProject getProject() {
808 return project;
809 }
810
811
812
813
814
815
816 protected List<MavenProject> getReactorProjects() {
817 return reactorProjects;
818 }
819
820
821
822
823
824
825 protected String getFormat() {
826 return format;
827 }
828
829
830
831
832
833
834
835
836 protected void writeReports(Engine engine, MavenProject p, File outputDir) {
837 DatabaseProperties prop = null;
838 CveDB cve = null;
839 try {
840 cve = new CveDB();
841 cve.open();
842 prop = cve.getDatabaseProperties();
843 } catch (DatabaseException ex) {
844 if (getLog().isDebugEnabled()) {
845 getLog().debug("Unable to retrieve DB Properties", ex);
846 }
847 } finally {
848 if (cve != null) {
849 cve.close();
850 }
851 }
852 final ReportGenerator r = new ReportGenerator(p.getName(), engine.getDependencies(), engine.getAnalyzers(), prop);
853 try {
854 r.generateReports(outputDir.getAbsolutePath(), format);
855 } catch (IOException ex) {
856 getLog().error(
857 "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
858 if (getLog().isDebugEnabled()) {
859 getLog().debug("", ex);
860 }
861 } catch (Throwable ex) {
862 getLog().error(
863 "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
864 if (getLog().isDebugEnabled()) {
865 getLog().debug("", ex);
866 }
867 }
868 }
869
870
871
872
873
874
875
876
877
878 protected void checkForFailure(List<Dependency> dependencies) throws MojoFailureException {
879 if (failBuildOnCVSS <= 10) {
880 final StringBuilder ids = new StringBuilder();
881 for (Dependency d : dependencies) {
882 boolean addName = true;
883 for (Vulnerability v : d.getVulnerabilities()) {
884 if (v.getCvssScore() >= failBuildOnCVSS) {
885 if (addName) {
886 addName = false;
887 ids.append(NEW_LINE).append(d.getFileName()).append(": ");
888 ids.append(v.getName());
889 } else {
890 ids.append(", ").append(v.getName());
891 }
892 }
893 }
894 }
895 if (ids.length() > 0) {
896 final String msg = String.format("%n%nDependency-Check Failure:%n"
897 + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
898 + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
899 throw new MojoFailureException(msg);
900 }
901 }
902 }
903
904
905
906
907
908
909
910 protected void showSummary(MavenProject mp, List<Dependency> dependencies) {
911 if (showSummary) {
912 final StringBuilder summary = new StringBuilder();
913 for (Dependency d : dependencies) {
914 boolean firstEntry = true;
915 final StringBuilder ids = new StringBuilder();
916 for (Vulnerability v : d.getVulnerabilities()) {
917 if (firstEntry) {
918 firstEntry = false;
919 } else {
920 ids.append(", ");
921 }
922 ids.append(v.getName());
923 }
924 if (ids.length() > 0) {
925 summary.append(d.getFileName()).append(" (");
926 firstEntry = true;
927 for (Identifier id : d.getIdentifiers()) {
928 if (firstEntry) {
929 firstEntry = false;
930 } else {
931 summary.append(", ");
932 }
933 summary.append(id.getValue());
934 }
935 summary.append(") : ").append(ids).append(NEW_LINE);
936 }
937 }
938 if (summary.length() > 0) {
939 final String msg = String.format("%n%n" + "One or more dependencies were identified with known vulnerabilities in %s:%n%n%s"
940 + "%n%nSee the dependency-check report for more details.%n%n", mp.getName(), summary.toString());
941 getLog().warn(msg);
942 }
943 }
944 }
945
946
947
948
949
950
951
952
953
954 protected String getDataFileContextKey() {
955 return "dependency-check-path-" + dataFileName;
956 }
957
958
959
960
961
962
963
964 protected String getOutputDirectoryContextKey() {
965 return "dependency-output-dir-" + dataFileName;
966 }
967
968
969
970
971
972
973
974
975 protected void writeDataFile(MavenProject mp, File writeTo, List<Dependency> dependencies) {
976 File file;
977
978 if (mp.getContextValue(this.getDataFileContextKey()) == null) {
979 if (writeTo == null) {
980 file = new File(mp.getBuild().getDirectory());
981 file = new File(file, dataFileName);
982 } else {
983 file = new File(writeTo, dataFileName);
984 }
985 final File parent = file.getParentFile();
986 if (!parent.isDirectory() && parent.mkdirs()) {
987 getLog().error(String.format("Directory '%s' does not exist and cannot be created; unable to write data file.",
988 parent.getAbsolutePath()));
989 }
990
991 ObjectOutputStream out = null;
992 try {
993 if (dependencies != null) {
994 out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
995 out.writeObject(dependencies);
996 }
997 if (getLog().isDebugEnabled()) {
998 getLog().debug(String.format("Serialized data file written to '%s' for %s, referenced by key %s",
999 file.getAbsolutePath(), mp.getName(), this.getDataFileContextKey()));
1000 }
1001 mp.setContextValue(this.getDataFileContextKey(), file.getAbsolutePath());
1002 } catch (IOException ex) {
1003 getLog().warn("Unable to create data file used for report aggregation; "
1004 + "if report aggregation is being used the results may be incomplete.");
1005 if (getLog().isDebugEnabled()) {
1006 getLog().debug(ex.getMessage(), ex);
1007 }
1008 } finally {
1009 if (out != null) {
1010 try {
1011 out.close();
1012 } catch (IOException ex) {
1013 if (getLog().isDebugEnabled()) {
1014 getLog().debug("ignore", ex);
1015 }
1016 }
1017 }
1018 }
1019 }
1020 }
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030 protected List<Dependency> readDataFile(MavenProject project) {
1031 final Object oPath = project.getContextValue(this.getDataFileContextKey());
1032 if (oPath == null) {
1033 return null;
1034 }
1035 List<Dependency> ret = null;
1036 final String path = (String) oPath;
1037 ObjectInputStream ois = null;
1038 try {
1039 ois = new ObjectInputStream(new FileInputStream(path));
1040 ret = (List<Dependency>) ois.readObject();
1041 } catch (FileNotFoundException ex) {
1042
1043 getLog().error("", ex);
1044 } catch (IOException ex) {
1045 getLog().error("", ex);
1046 } catch (ClassNotFoundException ex) {
1047 getLog().error("", ex);
1048 } finally {
1049 if (ois != null) {
1050 try {
1051 ois.close();
1052 } catch (IOException ex) {
1053 getLog().error("", ex);
1054 }
1055 }
1056 }
1057 return ret;
1058 }
1059
1060 }