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