diff --git a/maven/src/it/3730-classifier-in-dependency-aggregate/childOne/pom.xml b/maven/src/it/3730-classifier-in-dependency-aggregate/childOne/pom.xml
new file mode 100644
index 00000000000..c2554e6ba65
--- /dev/null
+++ b/maven/src/it/3730-classifier-in-dependency-aggregate/childOne/pom.xml
@@ -0,0 +1,40 @@
+
+
+
+ 4.0.0
+
+ org.owasp.test
+ 3730-classifier-in-dependency-aggregate
+ 1.0.0-SNAPSHOT
+
+ 3730-classifier-in-dependency-aggregate-childOne
+ jar
+
+
+ com.google.inject
+ guice
+ no_aop
+
+
+ org.owasp.test
+ 3730-classifier-in-dependency-aggregate-childTwo
+ 1.0.0-SNAPSHOT
+
+
+
diff --git a/maven/src/it/3730-classifier-in-dependency-aggregate/childTwo/pom.xml b/maven/src/it/3730-classifier-in-dependency-aggregate/childTwo/pom.xml
new file mode 100644
index 00000000000..1d11cad7c1d
--- /dev/null
+++ b/maven/src/it/3730-classifier-in-dependency-aggregate/childTwo/pom.xml
@@ -0,0 +1,35 @@
+
+
+
+ 4.0.0
+
+ org.owasp.test
+ 3730-classifier-in-dependency-aggregate
+ 1.0.0-SNAPSHOT
+
+ 3730-classifier-in-dependency-aggregate-childTwo
+ jar
+
+
+ com.google.inject
+ guice
+ classes
+
+
+
diff --git a/maven/src/it/3730-classifier-in-dependency-aggregate/invoker.properties b/maven/src/it/3730-classifier-in-dependency-aggregate/invoker.properties
new file mode 100644
index 00000000000..5cbf9f5f4bd
--- /dev/null
+++ b/maven/src/it/3730-classifier-in-dependency-aggregate/invoker.properties
@@ -0,0 +1,19 @@
+#
+# This file is part of dependency-check-maven.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Copyright (c) 2014 Jeremy Long. All Rights Reserved.
+#
+
+invoker.goals = --no-transfer-progress --batch-mode -Danalyzer.ossindex.enabled=false -Danalyzer.central.enabled=false ${project.groupId}:${project.artifactId}:${project.version}:aggregate -Dformat=XML -Dcve.startyear=2018
diff --git a/maven/src/it/3730-classifier-in-dependency-aggregate/pom.xml b/maven/src/it/3730-classifier-in-dependency-aggregate/pom.xml
new file mode 100644
index 00000000000..04b0b75c0e7
--- /dev/null
+++ b/maven/src/it/3730-classifier-in-dependency-aggregate/pom.xml
@@ -0,0 +1,47 @@
+
+
+
+ 4.0.0
+ org.owasp.test
+ 3730-classifier-in-dependency-aggregate
+ 1.0.0-SNAPSHOT
+ pom
+
+ childOne
+ childTwo
+
+
+
+
+ com.google.inject
+ guice
+ 4.2.2
+ no_aop
+ provided
+
+
+ com.google.inject
+ guice
+ 4.2.2
+ classes
+ provided
+
+
+
+
diff --git a/maven/src/it/3730-classifier-in-dependency-aggregate/postbuild.groovy b/maven/src/it/3730-classifier-in-dependency-aggregate/postbuild.groovy
new file mode 100644
index 00000000000..d264f127797
--- /dev/null
+++ b/maven/src/it/3730-classifier-in-dependency-aggregate/postbuild.groovy
@@ -0,0 +1,43 @@
+/*
+ * This file is part of dependency-check-maven.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (c) 2014 Jeremy Long. All Rights Reserved.
+ */
+
+import org.apache.commons.io.FileUtils;
+import org.w3c.dom.NodeList;
+
+import java.nio.charset.Charset;
+import javax.xml.xpath.*
+import javax.xml.parsers.DocumentBuilderFactory
+
+// Check to see if jackson-databind-2.5.3.jar was identified with a known CVE - using CVE-2018-7489.
+
+def countMatches(String xml, String xpathQuery) {
+ def xpath = XPathFactory.newInstance().newXPath()
+ def builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ def inputStream = new ByteArrayInputStream( xml.bytes )
+ def records = builder.parse(inputStream).documentElement
+ NodeList nodes = xpath.evaluate( xpathQuery, records, XPathConstants.NODESET ) as NodeList
+ nodes.getLength();
+}
+
+String log = FileUtils.readFileToString(new File(basedir, "target/dependency-check-report.xml"), Charset.defaultCharset().name());
+int count = countMatches(log,"/analysis/dependencies/dependency[./fileName = 'guice-4.2.2-no_aop.jar']");
+if (count != 1){
+ System.out.println(String.format("google guice no_aop was identified %s times, expected 1", count));
+ return false;
+}
+return true;
diff --git a/maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java b/maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
index 1a3582423ae..07e78fbb315 100644
--- a/maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
+++ b/maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java
@@ -74,8 +74,9 @@ protected ExceptionCollection scanDependencies(final Engine engine) throws MojoE
if (ex != null) {
if (exCol == null) {
exCol = ex;
+ } else {
+ exCol.getExceptions().addAll(ex.getExceptions());
}
- exCol.getExceptions().addAll(ex.getExceptions());
if (ex.isFatal()) {
exCol.setFatal(true);
final String msg = String.format("Fatal exception(s) analyzing %s", childProject.getName());
diff --git a/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java b/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
index 2c6b515863d..fea0515bc1b 100644
--- a/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
+++ b/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
@@ -1323,7 +1323,7 @@ private ExceptionCollection collectMavenDependencies(Engine engine, MavenProject
}
} else {
final Artifact dependencyArtifact = dependencyNode.getArtifact();
- final Artifact result;
+ Artifact result;
if (dependencyArtifact.isResolved()) {
//All transitive dependencies, excluding reactor and dependencyManagement artifacts should
//have been resolved by Maven prior to invoking the plugin - resolving the dependencies
@@ -1336,14 +1336,23 @@ private ExceptionCollection collectMavenDependencies(Engine engine, MavenProject
final List dependencies = project.getDependencies();
final List managedDependencies
= project.getDependencyManagement() == null ? null : project.getDependencyManagement().getDependencies();
- final ArtifactCoordinate theCoord = TransferUtils.toArtifactCoordinate(dependencyNode.getArtifact());
- if (theCoord.getClassifier() != null) {
+ if (coordinate.getClassifier() != null) {
// This would trigger NPE when using the filter - MSHARED-998
- getLog().debug("Expensive lookup as workaround for MSHARED-998 for " + theCoord);
- final Iterable allDeps
- = dependencyResolver.resolveDependencies(buildingRequest, dependencies, managedDependencies,
- null);
- result = findClassifierArtifactInAllDeps(allDeps, theCoord);
+ getLog().debug("Expensive lookup as workaround for MSHARED-998 for " + coordinate);
+ try {
+ final Iterable allDeps
+ = dependencyResolver.resolveDependencies(buildingRequest, dependencies, managedDependencies,
+ null);
+ result = findClassifierArtifactInAllDeps(allDeps, coordinate, project);
+ } catch (DependencyResolverException dre) {
+ result = Mshared998Util.findArtifactInAetherDREResult(dre, coordinate);
+ if (result == null) {
+ throw new DependencyNotFoundException(
+ String.format("Failed to resolve dependency %s with dependencyResolver for "
+ + "project-artifact %s", coordinate, project.getArtifactId()),
+ dre);
+ }
+ }
} else {
final TransformableFilter filter = new PatternInclusionsFilter(
Collections.singletonList(
@@ -1357,7 +1366,7 @@ private ExceptionCollection collectMavenDependencies(Engine engine, MavenProject
result = first.getArtifact();
} else {
throw new DependencyNotFoundException(String.format("Failed to resolve dependency %s with "
- + "dependencyResolver", coordinate));
+ + "dependencyResolver for project-artifact %s", coordinate, project.getArtifactId()));
}
}
} catch (DependencyNotFoundException | DependencyResolverException ex) {
@@ -1467,11 +1476,13 @@ && addSnapshotReactorDependency(engine, dependencyNode.getArtifact())) {
* dependencies
* @param theCoord The ArtifactCoordinate of the artifact-with-classifier we
* intended to resolve
+ * @param project The project in whose context resolution was attempted
* @return the resolved artifact matching with {@code theCoord}
* @throws DependencyNotFoundException Not expected to be thrown, but will
* be thrown if {@code theCoord} could not be found within {@code allDeps}
*/
- private Artifact findClassifierArtifactInAllDeps(final Iterable allDeps, final ArtifactCoordinate theCoord)
+ private Artifact findClassifierArtifactInAllDeps(final Iterable allDeps, final ArtifactCoordinate theCoord,
+ final MavenProject project)
throws DependencyNotFoundException {
Artifact result = null;
for (final ArtifactResult res : allDeps) {
@@ -1482,7 +1493,7 @@ private Artifact findClassifierArtifactInAllDeps(final Iterable
}
if (result == null) {
throw new DependencyNotFoundException(String.format("Expected dependency not found in resolved artifacts for "
- + "dependency %s", theCoord));
+ + "dependency %s of project-artifact %s", theCoord, project.getArtifactId()));
}
return result;
}
diff --git a/maven/src/main/java/org/owasp/dependencycheck/maven/Mshared998Util.java b/maven/src/main/java/org/owasp/dependencycheck/maven/Mshared998Util.java
new file mode 100644
index 00000000000..f5afe585fb2
--- /dev/null
+++ b/maven/src/main/java/org/owasp/dependencycheck/maven/Mshared998Util.java
@@ -0,0 +1,81 @@
+/*
+ * This file is part of dependency-check-maven.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (c) 2021 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.maven;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.shared.transfer.artifact.ArtifactCoordinate;
+import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolverException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.DependencyResolutionException;
+import org.eclipse.aether.resolution.DependencyResult;
+
+import java.util.Objects;
+
+public final class Mshared998Util {
+ /**
+ * Empty constructor to prevent instantiation of utility-class.
+ */
+ private Mshared998Util() {
+ }
+
+ /**
+ * Find the artifact for the given coordinate among the available succesfull resolution attempts contained within the
+ * DependencyResolverException
+ * @param dre The DependencyResolverException that might have embedded successful resolution results
+ * @param coordinate The coordinates of the artifact we're interested in
+ * @return The resolved artifact matching {@code coordinate} or {@code null} if not found
+ */
+ public static Artifact findArtifactInAetherDREResult(final DependencyResolverException dre,
+ final ArtifactCoordinate coordinate) {
+ Artifact result = null;
+ if (dre.getCause() instanceof DependencyResolutionException) {
+ final DependencyResolutionException adre = (DependencyResolutionException) dre.getCause();
+ final DependencyResult dependencyResult = adre.getResult();
+ if (dependencyResult != null) {
+ for (ArtifactResult artifactResult : dependencyResult.getArtifactResults()) {
+ if (matchesCoordinate(artifactResult, coordinate)) {
+ result = RepositoryUtils.toArtifact(artifactResult.getArtifact());
+ break;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks whether the given ArtifactResult contains an artifact that matches the coordinate
+ * @param artifactResult The ArtifactResult to inspect
+ * @param coordinate The coordinate to match with
+ * @return {@code true} when the artifactresult contains an artifact that matches the coordinate on GAV_C_E,
+ * false otherwise.
+ */ private static boolean matchesCoordinate(final ArtifactResult artifactResult, final ArtifactCoordinate coordinate) {
+ if (artifactResult.getArtifact() == null) {
+ return false;
+ } else {
+ final org.eclipse.aether.artifact.Artifact artifact = artifactResult.getArtifact();
+ boolean result = Objects.equals(artifact.getGroupId(), coordinate.getGroupId());
+ result &= Objects.equals(artifact.getArtifactId(), coordinate.getArtifactId());
+ result &= Objects.equals(artifact.getVersion(), coordinate.getVersion());
+ result &= Objects.equals(artifact.getClassifier(), coordinate.getClassifier());
+ result &= Objects.equals(artifact.getExtension(), coordinate.getExtension());
+ return result;
+ }
+ }
+}