diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/DependencyNotFoundException.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/DependencyNotFoundException.java new file mode 100644 index 000000000..3406b9900 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/DependencyNotFoundException.java @@ -0,0 +1,66 @@ +/* + * This file is part of dependency-check-core. + * + * 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) 2017 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.exception; + +/** + * An exception used when a dependency could not be found. + * + * @author Jeremy Long + */ +public class DependencyNotFoundException extends Exception { + + /** + * The serial version uid. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new DependencyNotFoundException. + */ + public DependencyNotFoundException() { + super(); + } + + /** + * Creates a new DependencyNotFoundException. + * + * @param msg a message for the exception. + */ + public DependencyNotFoundException(String msg) { + super(msg); + } + + /** + * Creates a new DependencyNotFoundException. + * + * @param ex the cause of the exception. + */ + public DependencyNotFoundException(Throwable ex) { + super(ex); + } + + /** + * Creates a new DependencyNotFoundException. + * + * @param msg a message for the exception. + * @param ex the cause of the exception. + */ + public DependencyNotFoundException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/dependency-check-maven/pom.xml b/dependency-check-maven/pom.xml index ec672c570..8f03b9bb0 100644 --- a/dependency-check-maven/pom.xml +++ b/dependency-check-maven/pom.xml @@ -227,6 +227,13 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-invoker-plugin 2.0.0 + + + org.codehaus.groovy + groovy-all + 2.4.11 + + diff --git a/dependency-check-maven/src/it/729-system-scope-resolved/invoker.properties b/dependency-check-maven/src/it/729-system-scope-resolved/invoker.properties new file mode 100644 index 000000000..135fb86f1 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-resolved/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) 2017 Jeremy Long. All Rights Reserved. +# + +invoker.goals = install ${project.groupId}:${project.artifactId}:${project.version}:check -e -Dformat=JSON diff --git a/dependency-check-maven/src/it/729-system-scope-resolved/pom.xml b/dependency-check-maven/src/it/729-system-scope-resolved/pom.xml new file mode 100644 index 000000000..6f2d06950 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-resolved/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + org.owasp.test + test-system-scope + 1.0.0-SNAPSHOT + jar + + + system + com.sun + tools + 1.8 + ${java.home}/../lib/tools.jar + + + \ No newline at end of file diff --git a/dependency-check-maven/src/it/729-system-scope-resolved/postbuild.groovy b/dependency-check-maven/src/it/729-system-scope-resolved/postbuild.groovy new file mode 100644 index 000000000..c1d6476e4 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-resolved/postbuild.groovy @@ -0,0 +1,30 @@ +/* + * 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) 2017 Jeremy Long. All Rights Reserved. + */ + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import java.nio.charset.Charset; +import groovy.json.JsonSlurper; + +def slurper = new JsonSlurper() +def json = slurper.parse(new File(basedir, "target/dependency-check-report.json"), "UTF-8") + +assert json instanceof Map +assert json.analysis.dependencies instanceof List +assert json.analysis.dependencies.size()==1 +return true; diff --git a/dependency-check-maven/src/it/729-system-scope-resolved/prebuild.groovy b/dependency-check-maven/src/it/729-system-scope-resolved/prebuild.groovy new file mode 100644 index 000000000..9ec3a0a91 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-resolved/prebuild.groovy @@ -0,0 +1,17 @@ +/* + * 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) 2017 Jeremy Long. All Rights Reserved. + */ diff --git a/dependency-check-maven/src/it/729-system-scope-skipped/invoker.properties b/dependency-check-maven/src/it/729-system-scope-skipped/invoker.properties new file mode 100644 index 000000000..b41bc60f9 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-skipped/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 = install ${project.groupId}:${project.artifactId}:${project.version}:check -DskipSystemScope=true -Dformat=JSON diff --git a/dependency-check-maven/src/it/729-system-scope-skipped/pom.xml b/dependency-check-maven/src/it/729-system-scope-skipped/pom.xml new file mode 100644 index 000000000..6f2d06950 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-skipped/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + org.owasp.test + test-system-scope + 1.0.0-SNAPSHOT + jar + + + system + com.sun + tools + 1.8 + ${java.home}/../lib/tools.jar + + + \ No newline at end of file diff --git a/dependency-check-maven/src/it/729-system-scope-skipped/postbuild.groovy b/dependency-check-maven/src/it/729-system-scope-skipped/postbuild.groovy new file mode 100644 index 000000000..335aaa589 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-skipped/postbuild.groovy @@ -0,0 +1,30 @@ +/* + * 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) 2017 Jeremy Long. All Rights Reserved. + */ + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import java.nio.charset.Charset; +import groovy.json.JsonSlurper; + +def slurper = new JsonSlurper() +def json = slurper.parse(new File(basedir, "target/dependency-check-report.json"), "UTF-8") + +assert json instanceof Map +assert json.analysis.dependencies instanceof List +assert json.analysis.dependencies.size()==0 +return true; diff --git a/dependency-check-maven/src/it/729-system-scope-skipped/prebuild.groovy b/dependency-check-maven/src/it/729-system-scope-skipped/prebuild.groovy new file mode 100644 index 000000000..9eff4bb5c --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-skipped/prebuild.groovy @@ -0,0 +1,17 @@ +/* + * 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. + */ 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 9dc7dc799..99b3a401f 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 @@ -55,6 +55,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.DependencyNotFoundException; import org.owasp.dependencycheck.exception.ExceptionCollection; import org.owasp.dependencycheck.exception.ReportException; import org.owasp.dependencycheck.reporting.ReportGenerator; @@ -403,6 +404,13 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma @SuppressWarnings("CanBeFinal") @Parameter(property = "skipProvidedScope", defaultValue = "false", required = false) private boolean skipProvidedScope = false; + + /** + * Skip Analysis for Provided Scope Dependencies. + */ + @SuppressWarnings("CanBeFinal") + @Parameter(property = "skipSystemScope", defaultValue = "false", required = false) + private boolean skipSystemScope = false; /** * The data directory, hold DC SQL DB. */ @@ -631,21 +639,50 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma List nodes, ProjectBuildingRequest buildingRequest) { ExceptionCollection exCol = null; for (DependencyNode dependencyNode : nodes) { - exCol = collectDependencies(engine, project, dependencyNode.getChildren(), buildingRequest); if (excludeFromScan(dependencyNode.getArtifact().getScope())) { continue; } + exCol = collectDependencies(engine, project, dependencyNode.getChildren(), buildingRequest); try { - final ArtifactCoordinate coordinate = TransferUtils.toArtifactCoordinate(dependencyNode.getArtifact()); - final Artifact result = artifactResolver.resolveArtifact(buildingRequest, coordinate).getArtifact(); - if (result.isResolved() && result.getFile() != null) { - final List deps = engine.scan(result.getFile().getAbsoluteFile(), + boolean isResolved = false; + File artifactFile = null; + String artifactId = null; + String groupId = null; + String version = null; + if (org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(dependencyNode.getArtifact().getScope())) { + for (org.apache.maven.model.Dependency d : project.getDependencies()) { + Artifact a = dependencyNode.getArtifact(); + if (d.getSystemPath() != null && artifactsMatch(d, a)) { + + artifactFile = new File(d.getSystemPath()); + isResolved = artifactFile.isFile(); + groupId = a.getGroupId(); + artifactId = a.getArtifactId(); + version = a.getVersion(); + break; + } + } + if (!isResolved) { + getLog().error("Unable to resolve system scoped dependency: " + dependencyNode.toNodeString()); + exCol.addException(new DependencyNotFoundException("Unable to resolve system scoped dependency: " + dependencyNode.toNodeString())); + } + } else { + final ArtifactCoordinate coordinate = TransferUtils.toArtifactCoordinate(dependencyNode.getArtifact()); + final Artifact result = artifactResolver.resolveArtifact(buildingRequest, coordinate).getArtifact(); + isResolved = result.isResolved(); + artifactFile = result.getFile(); + groupId = result.getGroupId(); + artifactId = result.getArtifactId(); + version = result.getVersion(); + } + if (isResolved && artifactFile != null) { + final List deps = engine.scan(artifactFile.getAbsoluteFile(), project.getName() + ":" + dependencyNode.getArtifact().getScope()); if (deps != null) { if (deps.size() == 1) { final Dependency d = deps.get(0); if (d != null) { - final MavenArtifact ma = new MavenArtifact(result.getGroupId(), result.getArtifactId(), result.getVersion()); + final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version); d.addAsEvidence("pom", ma, Confidence.HIGHEST); if (getLog().isDebugEnabled()) { getLog().debug(String.format("Adding project reference %s on dependency %s", @@ -683,6 +720,33 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma return exCol; } + /** + * Determines if the groupId, artifactId, and version of the Maven + * dependency and artifact match. + * + * @param d the Maven dependency + * @param a the Maven artifact + * @return true if the groupId, artifactId, and version match + */ + private static boolean artifactsMatch(org.apache.maven.model.Dependency d, Artifact a) { + return (isEqualOrNull(a.getArtifactId(), d.getArtifactId())) + && (isEqualOrNull(a.getGroupId(), d.getGroupId())) + && (isEqualOrNull(a.getVersion(), d.getVersion())); + } + + /** + * Compares two strings for equality; if both strings are null they are + * considered equal. + * + * @param left the first string to compare + * @param right the second string to compare + * @return true if the strings are equal or if they are both null; otherwise + * false. + */ + private static boolean isEqualOrNull(String left, String right) { + return (left != null && left.equals(right)) || (left == null && right == null); + } + /** * @return Returns a new ProjectBuildingRequest populated from the current * session and the current project remote repositories, used to resolve @@ -967,6 +1031,9 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma if (skipProvidedScope && org.apache.maven.artifact.Artifact.SCOPE_PROVIDED.equals(scope)) { return true; } + if (skipSystemScope && org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(scope)) { + return true; + } return skipRuntimeScope && !org.apache.maven.artifact.Artifact.SCOPE_RUNTIME.equals(scope); } 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 b566cc306..cb95628db 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 @@ -108,24 +108,23 @@ public class CheckMojo extends BaseDependencyCheckMojo { } exCol = ex; } - if (exCol == null || !exCol.isFatal()) { - try { - writeReports(engine, getProject(), getCorrectOutputDirectory()); - } catch (ReportException ex) { - if (this.isFailOnError()) { - if (exCol != null) { - exCol.addException(ex); - } else { - exCol = new ExceptionCollection("Unable to write the dependency-check report", ex); - } + } + if (exCol == null || !exCol.isFatal()) { + try { + writeReports(engine, getProject(), getCorrectOutputDirectory()); + } catch (ReportException ex) { + if (this.isFailOnError()) { + if (exCol != null) { + exCol.addException(ex); + } else { + exCol = new ExceptionCollection("Unable to write the dependency-check report", ex); } } - //writeDataFile(getProject(), null, engine.getDependencies()); - showSummary(getProject(), engine.getDependencies()); - checkForFailure(engine.getDependencies()); - if (exCol != null && this.isFailOnError()) { - throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol); - } + } + showSummary(getProject(), engine.getDependencies()); + checkForFailure(engine.getDependencies()); + if (exCol != null && this.isFailOnError()) { + throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol); } } engine.cleanup(); diff --git a/dependency-check-maven/src/site/markdown/configuration.md b/dependency-check-maven/src/site/markdown/configuration.md index c42cfc28b..72168e591 100644 --- a/dependency-check-maven/src/site/markdown/configuration.md +++ b/dependency-check-maven/src/site/markdown/configuration.md @@ -23,9 +23,10 @@ format | The report format to be generated (HTML, XML, CSV, name | The name of the report in the site. | dependency-check or dependency-check:aggregate outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build. | 'target' skip | Skips the dependency-check analysis. | false -skipTestScope | Skip analysis for artifacts with Test Scope. | true skipProvidedScope | Skip analysis for artifacts with Provided Scope. | false skipRuntimeScope | Skip analysis for artifacts with Runtime Scope. | false +skipSystemScope | Skip analysis for artifacts with System Scope. | false +skipTestScope | Skip analysis for artifacts with Test Scope. | true suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). |   hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html). |   enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false