diff --git a/dependency-check-maven/pom.xml b/dependency-check-maven/pom.xml
index d6f48ff87..f71c5668d 100644
--- a/dependency-check-maven/pom.xml
+++ b/dependency-check-maven/pom.xml
@@ -208,6 +208,10 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
org.sonatype.plexus
plexus-sec-dispatcher
+
+ org.apache.maven.shared
+ maven-dependency-tree
+
org.jmockit
jmockit
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
index d17854dd0..974c6c489 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
@@ -19,10 +19,8 @@ package org.owasp.dependencycheck.maven;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.apache.maven.plugin.MojoExecutionException;
@@ -32,10 +30,7 @@ import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
-import org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer;
-import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
-import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.utils.Settings;
@@ -49,7 +44,7 @@ import org.owasp.dependencycheck.utils.Settings;
@Mojo(
name = "aggregate",
defaultPhase = LifecyclePhase.VERIFY,
- /*aggregator = true,*/
+ aggregator = true,
threadSafe = false,
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
requiresOnline = true
@@ -72,103 +67,87 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
*/
@Override
public void runCheck() throws MojoExecutionException, MojoFailureException {
- final MavenEngine engine = generateDataFile();
+ final MavenEngine engine = loadEngine();
if (engine == null) {
return;
}
- if (getProject() == getLastProject()) {
- //ensure that the .ser file was created for each.
- for (MavenProject current : getReactorProjects()) {
- final File dataFile = getDataFile(current);
- if (dataFile == null && !skipProject(current)) { //dc was never run on this project. write the ser to the target.
- getLog().error(String.format("Module '%s' did not execute dependency-check; an attempt will be made to perform "
- + "the check but dependencies may be missed resulting in false negatives.", current.getName()));
- generateDataFile(engine, current);
- }
- }
- for (MavenProject current : getReactorProjects()) {
- List dependencies = readDataFile(current);
- if (dependencies == null) {
- dependencies = new ArrayList();
- }
- final Set childProjects = getDescendants(current);
- for (MavenProject reportOn : childProjects) {
- final List childDeps = readDataFile(reportOn);
- if (childDeps != null && !childDeps.isEmpty()) {
- if (getLog().isDebugEnabled()) {
- getLog().debug(String.format("Adding %d dependencies from %s", childDeps.size(), reportOn.getName()));
- }
- dependencies.addAll(childDeps);
- } else if (getLog().isDebugEnabled()) {
- getLog().debug(String.format("No dependencies read for %s", reportOn.getName()));
- }
- }
- engine.getDependencies().clear();
- engine.getDependencies().addAll(dependencies);
- final DependencyBundlingAnalyzer bundler = new DependencyBundlingAnalyzer();
- try {
- if (getLog().isDebugEnabled()) {
- getLog().debug(String.format("Dependency count pre-bundler: %s", engine.getDependencies().size()));
- }
- bundler.analyze(null, engine);
- if (getLog().isDebugEnabled()) {
- getLog().debug(String.format("Dependency count post-bundler: %s", engine.getDependencies().size()));
- }
- } catch (AnalysisException ex) {
- getLog().warn("An error occurred grouping the dependencies; duplicate entries may exist in the report", ex);
- getLog().debug("Bundling Exception", ex);
- }
+ ExceptionCollection exCol = scanArtifacts(getProject(), engine);
- File outputDir = getCorrectOutputDirectory(current);
- if (outputDir == null) {
- //in some regards we shouldn't be writting this, but we are anyway.
- //we shouldn't write this because nothing is configured to generate this report.
- outputDir = new File(current.getBuild().getDirectory());
+ for (MavenProject childProject : getDescendants(this.getProject())) {
+ ExceptionCollection ex = scanArtifacts(childProject, engine);
+ if (ex != null) {
+ if (exCol == null) {
+ exCol = ex;
}
- try {
- writeReports(engine, current, outputDir);
- } catch (ReportException ex) {
- ExceptionCollection exCol = (ExceptionCollection) engine.getExecutionRoot().getContextValue(AGGREGATE_EXCEPTIONS);
- if (exCol == null) {
- exCol = new ExceptionCollection("Error writing aggregate report", ex);
- } else {
- exCol.addException(ex);
- }
- if (this.isFailOnError()) {
- throw new MojoExecutionException("One or more exceptions occured during dependency-check analysis", exCol);
- } else {
- getLog().debug("One or more exceptions occured during dependency-check analysis", exCol);
- }
+ exCol.getExceptions().addAll(ex.getExceptions());
+ if (ex.isFatal()) {
+ exCol.setFatal(true);
}
}
}
+
+ try {
+ engine.analyzeDependencies();
+ } catch (ExceptionCollection ex) {
+ if (exCol == null) {
+ exCol = ex;
+ } else if (ex.isFatal()) {
+ exCol.setFatal(true);
+ exCol.getExceptions().addAll(ex.getExceptions());
+ }
+ if (exCol.isFatal()) {
+ final String msg = String.format("Fatal exception(s) analyzing %s", getProject().getName());
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException(msg, exCol);
+ }
+ getLog().error(msg);
+ if (getLog().isDebugEnabled()) {
+ getLog().debug(exCol);
+ }
+ return;
+ } else {
+ final String msg = String.format("Exception(s) analyzing %s", getProject().getName());
+ if (getLog().isDebugEnabled()) {
+ getLog().debug(msg, exCol);
+ }
+ }
+ }
+ File outputDir = getCorrectOutputDirectory(this.getProject());
+ if (outputDir == null) {
+ //in some regards we shouldn't be writting this, but we are anyway.
+ //we shouldn't write this because nothing is configured to generate this report.
+ outputDir = new File(this.getProject().getBuild().getDirectory());
+ }
+ try {
+ writeReports(engine, this.getProject(), outputDir);
+ } catch (ReportException ex) {
+ if (exCol == null) {
+ exCol = new ExceptionCollection("Error writing aggregate report", ex);
+ } else {
+ exCol.addException(ex);
+ }
+ if (this.isFailOnError()) {
+ throw new MojoExecutionException("One or more exceptions occured during dependency-check analysis", exCol);
+ } else {
+ getLog().debug("One or more exceptions occured during dependency-check analysis", exCol);
+ }
+ }
+ showSummary(this.getProject(), engine.getDependencies());
+ checkForFailure(engine.getDependencies());
engine.cleanup();
Settings.cleanup();
}
- /**
- * Gets the last project in the reactor - taking into account skipped
- * projects.
- *
- * @return the last project in the reactor
- */
- private MavenProject getLastProject() {
- for (int x = getReactorProjects().size() - 1; x >= 0; x--) {
- final MavenProject p = getReactorProjects().get(x);
- if (!skipProject(p)) {
- return p;
- }
- }
- return null;
- }
-
/**
* Tests if the project is being skipped in the Maven site report.
*
* @param project a project in the reactor
* @return true if the project is skipped; otherwise false
+ * @deprecated this function is no longer used, keeping this code around for
+ * a little bit longer in case this needs to be used
*/
+ @Deprecated
private boolean skipProject(MavenProject project) {
final String skip = (String) project.getProperties().get("maven.site.skip");
return "true".equalsIgnoreCase(skip) && isGeneratingSite();
@@ -264,16 +243,15 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
}
/**
- * Initializes the engine, runs a scan, and writes the serialized
- * dependencies to disk.
+ * Initializes the engine.
*
* @return the MavenEngine used to execute dependency-check
* @throws MojoExecutionException thrown if there is an exception running
- * the mojo
+ * the Mojo
* @throws MojoFailureException thrown if dependency-check is configured to
* fail the build if severe CVEs are identified.
*/
- protected MavenEngine generateDataFile() throws MojoExecutionException, MojoFailureException {
+ protected MavenEngine loadEngine() throws MojoExecutionException, MojoFailureException {
MavenEngine engine = null;
try {
engine = initializeEngine();
@@ -286,59 +264,7 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
throw new MojoExecutionException(msg, ex);
}
getLog().error(msg, ex);
- return null;
}
- return generateDataFile(engine, getProject());
- }
-
- /**
- * Runs dependency-check's MavenEngine and writes the serialized
- * dependencies to disk.
- *
- * @param engine the MavenEngine to use when scanning.
- * @param project the project to scan and generate the data file for
- * @return the MavenEngine used to execute dependency-check
- * @throws MojoExecutionException thrown if there is an exception running
- * the mojo
- * @throws MojoFailureException thrown if dependency-check is configured to
- * fail the build if severe CVEs are identified.
- */
- protected MavenEngine generateDataFile(MavenEngine engine, MavenProject project) throws MojoExecutionException, MojoFailureException {
- if (getLog().isDebugEnabled()) {
- getLog().debug(String.format("Begin Scanning: %s", project.getName()));
- }
- engine.getDependencies().clear();
- engine.resetFileTypeAnalyzers();
- scanArtifacts(project, engine);
- try {
- engine.analyzeDependencies();
- } catch (ExceptionCollection ex) {
- ExceptionCollection col = (ExceptionCollection) engine.getExecutionRoot().getContextValue(AGGREGATE_EXCEPTIONS);
- if (col == null) {
- col = ex;
- } else if (ex.isFatal()) {
- col.setFatal(true);
- col.getExceptions().addAll(ex.getExceptions());
- }
- if (col.isFatal()) {
- final String msg = String.format("Fatal exception(s) analyzing %s", project.getName());
- if (this.isFailOnError()) {
- throw new MojoExecutionException(msg, ex);
- }
- getLog().error(msg, col);
- return null;
- } else {
- final String msg = String.format("Exception(s) analyzing %s", project.getName());
- if (getLog().isDebugEnabled()) {
- getLog().debug(msg, ex);
- }
- engine.getExecutionRoot().setContextValue(AGGREGATE_EXCEPTIONS, col);
- }
- }
- final File target = new File(project.getBuild().getDirectory());
- writeDataFile(project, target, engine.getDependencies());
- showSummary(project, engine.getDependencies());
- checkForFailure(engine.getDependencies());
return engine;
}
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
index 3df3f6d75..dd3966df5 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
@@ -25,9 +25,11 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import org.apache.maven.artifact.Artifact;
+//import org.apache.maven.artifact.Artifact;
+import org.eclipse.aether.artifact.Artifact;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
@@ -39,6 +41,16 @@ import org.apache.maven.reporting.MavenReport;
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Server;
+import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
+import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
+import org.apache.maven.shared.dependency.graph.DependencyNode;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
@@ -47,6 +59,7 @@ import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
+import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.utils.ExpectedOjectInputStream;
@@ -102,6 +115,30 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
*/
@Parameter(readonly = true, required = true, property = "reactorProjects")
private List reactorProjects;
+ /**
+ * The entry point to Aether, i.e. the component doing all the work.
+ */
+ @Component
+ private RepositorySystem repoSystem;
+
+ /**
+ * The current repository/network configuration of Maven.
+ */
+ @Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
+ private RepositorySystemSession repoSession;
+
+ /**
+ * The project's remote repositories to use for the resolution of plug-ins
+ * and their dependencies.
+ */
+ @Parameter(defaultValue = "${project.remotePluginRepositories}", readonly = true)
+ private List remoteRepos;
+
+ /**
+ * Component within Maven to build the dependency graph.
+ */
+ @Component
+ private DependencyGraphBuilder dependencyGraphBuilder;
/**
* The output directory. This generally maps to "target".
@@ -553,32 +590,121 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
*
* @param project the project to scan the dependencies of
* @param engine the engine to use to scan the dependencies
+ * @return a collection of exceptions that may have occurred while resolving
+ * and scanning the dependencies
*/
- protected void scanArtifacts(MavenProject project, MavenEngine engine) {
- for (Artifact a : project.getArtifacts()) {
+ protected ExceptionCollection scanArtifacts(MavenProject project, MavenEngine engine) {
+ //
+ /*
+ for (Artifact a : project.getArtifacts()) {
if (excludeFromScan(a)) {
- continue;
+ continue;
}
final List deps = engine.scan(a.getFile().getAbsoluteFile());
if (deps != null) {
- if (deps.size() == 1) {
- final Dependency d = deps.get(0);
- if (d != null) {
- final MavenArtifact ma = new MavenArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
- d.addAsEvidence("pom", ma, Confidence.HIGHEST);
- d.addProjectReference(project.getName());
- if (getLog().isDebugEnabled()) {
- getLog().debug(String.format("Adding project reference %s on dependency %s", project.getName(),
- d.getDisplayFileName()));
+ if (deps.size() == 1) {
+ final Dependency d = deps.get(0);
+ if (d != null) {
+ final MavenArtifact ma = new MavenArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
+ d.addAsEvidence("pom", ma, Confidence.HIGHEST);
+ d.addProjectReference(project.getName());
+ if (getLog().isDebugEnabled()) {
+ getLog().debug(String.format("Adding project reference %s on dependency %s", project.getName(),
+ d.getDisplayFileName()));
+ }
+ }
+ } else if (getLog().isDebugEnabled()) {
+ final String msg = String.format("More then 1 dependency was identified in first pass scan of '%s:%s:%s'",
+ a.getGroupId(), a.getArtifactId(), a.getVersion());
+ getLog().debug(msg);
+ }
+ }
+ }
+ */
+ //
+ try {
+ DependencyNode dn = dependencyGraphBuilder.buildDependencyGraph(project, null, reactorProjects);
+ return collectDependencies(engine, project, dn.getChildren());
+ } catch (DependencyGraphBuilderException ex) {
+ final String msg = String.format("Unable to build dependency graph on project %s", project.getName());
+ getLog().debug(msg, ex);
+ return new ExceptionCollection(msg, ex);
+ }
+ }
+
+ /**
+ * Resolves the projects artifacts using Aether and scans the resulting
+ * dependencies.
+ *
+ * @param engine the core dependency-check engine
+ * @param project the project being scanned
+ * @param nodes the list of dependency nodes, generally obtained via the
+ * DependencyGraphBuilder
+ * @return a collection of exceptions that may have occurred while resolving
+ * and scanning the dependencies
+ */
+ private ExceptionCollection collectDependencies(MavenEngine engine, MavenProject project, List nodes) {
+ ExceptionCollection exCol = null;
+ for (DependencyNode dependencyNode : nodes) {
+ exCol = collectDependencies(engine, project, dependencyNode.getChildren());
+ if (excludeFromScan(dependencyNode.getArtifact().getScope())) {
+ continue;
+ }
+ ArtifactRequest request = new ArtifactRequest();
+ request.setArtifact(new DefaultArtifact(dependencyNode.getArtifact().getId()));
+ request.setRepositories(remoteRepos);
+ try {
+ ArtifactResult result = repoSystem.resolveArtifact(repoSession, request);
+ if (result.isResolved() && result.getArtifact() != null && result.getArtifact().getFile() != null) {
+ final List deps = engine.scan(result.getArtifact().getFile().getAbsoluteFile());
+ if (deps != null) {
+ if (deps.size() == 1) {
+ final Dependency d = deps.get(0);
+ if (d != null) {
+ Artifact a = result.getArtifact();
+ final MavenArtifact ma = new MavenArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
+ d.addAsEvidence("pom", ma, Confidence.HIGHEST);
+ d.addProjectReference(project.getName() + ":" + dependencyNode.getArtifact().getScope());
+ if (getLog().isDebugEnabled()) {
+ getLog().debug(String.format("Adding project reference %s on dependency %s",
+ project.getName(), d.getDisplayFileName()));
+ }
+ }
+ } else if (getLog().isDebugEnabled()) {
+ final String msg = String.format("More then 1 dependency was identified in first pass scan of '%s' in project %s",
+ dependencyNode.getArtifact().getId(), project.getName());
+ getLog().debug(msg);
+ }
+ } else {
+ final String msg = String.format("Error resolving '%s' in project %s",
+ dependencyNode.getArtifact().getId(), project.getName());
+ if (exCol == null) {
+ exCol = new ExceptionCollection();
+ }
+ getLog().error(msg);
+ for (Exception ex : result.getExceptions()) {
+ exCol.addException(ex);
}
}
- } else if (getLog().isDebugEnabled()) {
- final String msg = String.format("More then 1 dependency was identified in first pass scan of '%s:%s:%s'",
- a.getGroupId(), a.getArtifactId(), a.getVersion());
+ } else {
+ final String msg = String.format("Unable to resolve '%s' in project %s",
+ dependencyNode.getArtifact().getId(), project.getName());
getLog().debug(msg);
+ if (exCol == null) {
+ exCol = new ExceptionCollection();
+ }
+ for (Exception ex : result.getExceptions()) {
+ exCol.addException(ex);
+ }
}
+ } catch (ArtifactResolutionException ex) {
+ if (exCol == null) {
+ exCol = new ExceptionCollection();
+ }
+ exCol.addException(ex);
}
}
+ return exCol;
}
/**
@@ -669,8 +795,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
*/
protected MavenEngine initializeEngine() throws DatabaseException {
populateSettings();
- return new MavenEngine(this.project,
- this.reactorProjects);
+ return new MavenEngine(this.project, this.reactorProjects);
}
/**
@@ -835,18 +960,18 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
* Tests is the artifact should be included in the scan (i.e. is the
* dependency in a scope that is being scanned).
*
- * @param a the Artifact to test
+ * @param scope the scope of the artifact to test
* @return true if the artifact is in an excluded scope;
* otherwise false
*/
- protected boolean excludeFromScan(Artifact a) {
- if (skipTestScope && Artifact.SCOPE_TEST.equals(a.getScope())) {
+ protected boolean excludeFromScan(String scope) {
+ if (skipTestScope && org.apache.maven.artifact.Artifact.SCOPE_TEST.equals(scope)) {
return true;
}
- if (skipProvidedScope && Artifact.SCOPE_PROVIDED.equals(a.getScope())) {
+ if (skipProvidedScope && org.apache.maven.artifact.Artifact.SCOPE_PROVIDED.equals(scope)) {
return true;
}
- if (skipRuntimeScope && !Artifact.SCOPE_RUNTIME.equals(a.getScope())) {
+ if (skipRuntimeScope && !org.apache.maven.artifact.Artifact.SCOPE_RUNTIME.equals(scope)) {
return true;
}
return false;
@@ -1133,4 +1258,5 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
return ret;
}
//
+
}
diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java
index ccada1b5c..4017a5d93 100644
--- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java
+++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java
@@ -55,7 +55,7 @@ public class CheckMojo extends BaseDependencyCheckMojo {
public boolean canGenerateReport() {
boolean isCapable = false;
for (Artifact a : getProject().getArtifacts()) {
- if (!excludeFromScan(a)) {
+ if (!excludeFromScan(a.getScope())) {
isCapable = true;
break;
}
@@ -88,11 +88,10 @@ public class CheckMojo extends BaseDependencyCheckMojo {
getLog().error(msg);
}
if (engine != null) {
- scanArtifacts(getProject(), engine);
+ ExceptionCollection exCol = scanArtifacts(getProject(), engine);
if (engine.getDependencies().isEmpty()) {
getLog().info("No dependencies were identified that could be analyzed by dependency-check");
} else {
- ExceptionCollection exCol = null;
try {
engine.analyzeDependencies();
} catch (ExceptionCollection ex) {
diff --git a/pom.xml b/pom.xml
index 3df61fcb1..dc275a75d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -671,6 +671,11 @@ Copyright (c) 2012 - Jeremy Long
plexus-sec-dispatcher
1.4
+
+ org.apache.maven.shared
+ maven-dependency-tree
+ 2.2
+
org.glassfish
javax.json