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