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