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