updates to allow old suppression file configuration

This commit is contained in:
Jeremy Long
2017-06-22 07:18:14 -04:00
parent 3d5b86d96f
commit dee1ccfd3e
14 changed files with 269 additions and 38 deletions

View File

@@ -64,7 +64,7 @@ public class Check extends Update {
* Whether or not the NSP Analyzer is enabled.
*/
private Boolean nspAnalyzerEnabled;
/**
* Whether or not the Ruby Bundle Audit Analyzer is enabled.
*/
@@ -154,6 +154,10 @@ public class Check extends Update {
* Default is HTML.
*/
private String reportFormat = "HTML";
/**
* Suppression file path.
*/
private String suppressionFile = null;
/**
* Suppression file paths.
*/
@@ -462,11 +466,10 @@ public class Check extends Update {
* Set the value of suppressionFile.
*
* @param suppressionFile new value of suppressionFile
* @deprecated property form of suppressionFile has been replaced by a child element
*/
@Deprecated
public void setSuppressionFile(String suppressionFile) {
throw new BuildException("Definition of a suppression file via a property has been deprecated. Suppression files are now defined as a nested element, please update your configuration.");
this.suppressionFile = suppressionFile;
suppressionFiles.add(suppressionFile);
}
/**
@@ -758,6 +761,7 @@ public class Check extends Update {
public void setNodeAnalyzerEnabled(Boolean nodeAnalyzerEnabled) {
this.nodeAnalyzerEnabled = nodeAnalyzerEnabled;
}
/**
* Get the value of nspAnalyzerEnabled.
*
@@ -766,6 +770,7 @@ public class Check extends Update {
public Boolean isNspAnalyzerEnabled() {
return nspAnalyzerEnabled;
}
/**
* Set the value of nspAnalyzerEnabled.
*

View File

@@ -18,8 +18,10 @@
package org.owasp.dependencycheck.taskdefs;
/**
* Class : {@link SuppressionFile}
* Responsibility : Models a suppression file nested XML element where the simple content is its location.
* Class : {@link SuppressionFile} Responsibility : Models a suppression file
* nested XML element where the simple content is its location.
*
* @author Phillip Whittlesea
*/
public class SuppressionFile {

View File

@@ -127,22 +127,41 @@ public class DependencyCheckTaskTest {
buildFileRule.executeTarget(antTaskName);
// THEN the ant task executed without error
final File report = new File("target/dependency-check-report.html");
final File report = new File("target/suppression-report.html");
assertTrue("Expected the DependencyCheck report to be generated", report.exists());
}
/**
* Test the DependencyCheckTask deprecated suppression property throws an exception with a warning.
* Test the DependencyCheckTask deprecated suppression property throws an
* exception with a warning.
*/
@Test
public void testDeprecatedSuppressingCVE() {
public void testSuppressingSingle() {
// GIVEN an ant task with a vulnerability using the legacy property
final String antTaskName = "deprecated-suppression";
final String antTaskName = "suppression-single";
// WHEN executing the ant task
// THEN an exception with a warning is thrown
expectedException.expect(BuildException.class);
expectedException.expectMessage("Definition of a suppression file via a property has been deprecated. Suppression files are now defined as a nested element, please update your configuration.");
buildFileRule.executeTarget(antTaskName);
// THEN the ant task executed without error
final File report = new File("target/suppression-single-report.html");
assertTrue("Expected the DependencyCheck report to be generated", report.exists());
}
/**
* Test the DependencyCheckTask deprecated suppression property throws an
* exception with a warning.
*/
@Test
public void testSuppressingMultiple() {
// GIVEN an ant task with a vulnerability using multiple was to configure the suppression file
final String antTaskName = "suppression-multiple";
// WHEN executing the ant task
buildFileRule.executeTarget(antTaskName);
// THEN the ant task executed without error
final File report = new File("target/suppression-multiple-report.html");
assertTrue("Expected the DependencyCheck report to be generated", report.exists());
}
}

View File

@@ -72,19 +72,10 @@
</dependency-check>
</target>
<target name="deprecated-suppression">
<dependency-check
applicationName="test suppression"
reportOutputDirectory="${project.build.directory}"
autoupdate="false"
failBuildOnCVSS="3"
suppressionFile="${project.build.directory}/test-classes/test-suppression1.xml"/>
</target>
<target name="suppression">
<dependency-check
applicationName="test suppression"
reportOutputDirectory="${project.build.directory}"
reportOutputDirectory="${project.build.directory}/suppression-report.html"
autoupdate="false"
failBuildOnCVSS="3">
<suppressionfile>${project.build.directory}/test-classes/test-suppression1.xml</suppressionfile>
@@ -97,4 +88,30 @@
files="jetty-6.1.0.jar,org.mortbay.jetty.jar"/>
</dependency-check>
</target>
<target name="suppression-single">
<dependency-check
applicationName="test suppression"
reportOutputDirectory="${project.build.directory}/suppression-single-report.html"
autoupdate="false"
failBuildOnCVSS="3"
suppressionFile="${project.build.directory}/test-classes/test-suppression1.xml">
<fileset dir="${project.build.directory}/test-classes/jars">
<include name="axis-1.4.jar"/>
</fileset>
</dependency-check>
</target>
<target name="suppression-multiple">
<dependency-check
applicationName="test suppression"
reportOutputDirectory="${project.build.directory}/suppression-multiple-report.html"
autoupdate="false"
failBuildOnCVSS="3"
suppressionFile="${project.build.directory}/test-classes/test-suppression1.xml">
<suppressionfile>${project.build.directory}/test-classes/test-suppression2.xml</suppressionfile>
<fileset dir="${project.build.directory}/test-classes/jars">
<include name="axis-1.4.jar"/>
</fileset>
</dependency-check>
</target>
</project>

View File

@@ -274,7 +274,8 @@ public final class CliParser {
.build();
final Option suppressionFile = Option.builder().argName("file").hasArgs().longOpt(ARGUMENT.SUPPRESSION_FILES)
.desc("The file path to the suppression XML file.")
.desc("The file path to the suppression XML file. This can be specified more then once to utilize multiple "
+ "suppression files")
.build();
final Option hintsFile = Option.builder().argName("file").hasArg().longOpt(ARGUMENT.HINTS_FILE)
@@ -735,7 +736,8 @@ public final class CliParser {
public boolean isNodeJsDisabled() {
return hasDisableOption(ARGUMENT.DISABLE_NODE_JS, Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED);
}
/**
/**
* Returns true if the disableNSP command line argument was specified.
*
* @return true if the disableNSP command line argument was specified;

View File

@@ -14,7 +14,7 @@ Short | Argument&nbsp;Name&nbsp;&nbsp; | Parameter | Description | Requir
| \-\-failOnCvss | \<score\> | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
| \-\-suppression | \<files\> | The file paths to the suppression XML files; used to suppress [false positives](../general/suppression.html). | Optional
| \-\-suppression | \<files\> | The file paths to the suppression XML files; used to suppress [false positives](../general/suppression.html). This can be specified more then once to utilize multiple suppression files. | Optional
\-h | \-\-help | | Print the help message. | Optional
| \-\-advancedHelp | | Print the advanced help message. | Optional
\-v | \-\-version | | Print the version information. | Optional

View File

@@ -0,0 +1,18 @@
#
# 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 The OWASP Foundation. All Rights Reserved.
#
invoker.goals = install ${project.groupId}:${project.artifactId}:${project.version}:check

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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 The OWASP Foundation. All Rights Reserved.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.owasp.test</groupId>
<artifactId>test-multiple-suppression-files</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!-- These can be replaced by any other vulnerable dependency -->
<dependency>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
<version>0.0.20131108.vaadin1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.4.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<suppressionFile>${project.basedir}/test-suppression1.xml</suppressionFile>
<suppressionFiles>
<suppressionFile>${project.basedir}/test-suppression2.xml</suppressionFile>
</suppressionFiles>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,35 @@
/*
* 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 The OWASP Foundation. All Rights Reserved.
*/
import org.apache.commons.io.FileUtils
import org.apache.commons.lang.StringUtils
import java.nio.charset.Charset
// Check that suppression worked.
String log = FileUtils.readFileToString(new File(basedir, "build.log"), Charset.defaultCharset().name());
int count = StringUtils.countMatches(log, "CVE-2016-5696");
if (count > 0) {
System.out.println(String.format("CVE-2016-5696 (android-json-0.0.20131108.vaadin1.jar) was identified and should be suppressed"));
return false;
}
count = StringUtils.countMatches(log, "CVE-2016-7051");
if (count > 0) {
System.out.println(String.format("CVE-2016-7051 (jackson-module-jaxb-annotations-2.4.5.jar) was identified and should be suppressed"));
return false;
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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 The OWASP Foundation. All Rights Reserved.
-->
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
<suppress>
<notes><![CDATA[
file name: android-json-0.0.20131108.vaadin1.jar
]]></notes>
<gav regex="true">^com\.vaadin\.external\.google:android-json:.*$</gav>
<cpe>cpe:/a:google:android</cpe>
</suppress>
</suppressions>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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 The OWASP Foundation. All Rights Reserved.
-->
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
<suppress>
<notes><![CDATA[
file name: jackson-dataformat-xml-2.4.5.jar
]]></notes>
<gav regex="true">^com\.fasterxml\.jackson.*:.*:.*$</gav>
<cpe>cpe:/a:fasterxml:jackson</cpe>
</suppress>
</suppressions>

View File

@@ -21,6 +21,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import org.apache.maven.artifact.Artifact;
@@ -203,7 +204,11 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
*/
@Parameter(required = false)
private String[] suppressionFiles;
/**
* The paths to the suppression file.
*/
@Parameter(required = false)
private String suppressionFile;
/**
* The path to the hints file.
*/
@@ -415,7 +420,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
private boolean skipSystemScope = false;
/**
* Skip analysis for dependencies which type matches this regular expression.
* Skip analysis for dependencies which type matches this regular
* expression.
*/
@SuppressWarnings("CanBeFinal")
@Parameter(property = "skipArtifactType", required = false)
@@ -488,7 +494,6 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
*/
private Filter<String> artifactTypeExcluded;
// </editor-fold>
//<editor-fold defaultstate="collapsed" desc="Base Maven implementation">
/**
@@ -660,8 +665,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
List<DependencyNode> nodes, ProjectBuildingRequest buildingRequest) {
ExceptionCollection exCol = null;
for (DependencyNode dependencyNode : nodes) {
if (artifactScopeExcluded.passes(dependencyNode.getArtifact().getScope()) ||
artifactTypeExcluded.passes(dependencyNode.getArtifact().getType())) {
if (artifactScopeExcluded.passes(dependencyNode.getArtifact().getScope())
|| artifactTypeExcluded.passes(dependencyNode.getArtifact().getType())) {
continue;
}
exCol = collectDependencies(engine, project, dependencyNode.getChildren(), buildingRequest);
@@ -686,7 +691,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
}
if (!isResolved) {
getLog().error("Unable to resolve system scoped dependency: " + dependencyNode.toNodeString());
exCol.addException(new DependencyNotFoundException("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());
@@ -924,8 +930,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
Settings.setStringIfNotNull(Settings.KEYS.PROXY_PASSWORD, password);
Settings.setStringIfNotNull(Settings.KEYS.PROXY_NON_PROXY_HOSTS, proxy.getNonProxyHosts());
}
Settings.setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFiles);
final String[] suppressions = determineSuppressions();
Settings.setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressions);
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
Settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
@@ -1015,6 +1021,25 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
artifactTypeExcluded = new ArtifactTypeExcluded(skipArtifactType);
}
/**
* Combines the configured suppressionFile and suppressionFiles into a
* single array.
*
* @return an array of suppression file paths
*/
private String[] determineSuppressions() {
String[] suppressions = suppressionFiles;
if (suppressionFile != null) {
if (suppressions == null) {
suppressions = new String[]{suppressionFile};
} else {
suppressions = Arrays.copyOf(suppressions, suppressions.length + 1);
suppressions[suppressions.length - 1] = suppressionFile;
}
}
return suppressions;
}
/**
* Returns the maven proxy.
*

View File

@@ -151,10 +151,10 @@ public final class FileUtils {
}
/**
* Gets the {@link InputStream} for this resource
* Gets the {@link InputStream} for this resource.
*
* @param resource path
* @return
* @return the input stream for the given resource
*/
public static InputStream getResourceAsStream(String resource) {
return FileUtils.class.getClassLoader() != null

View File

@@ -763,7 +763,7 @@ public final class Settings {
private static File getJarPath() {
String decodedPath = ".";
String jarPath = "";
ProtectionDomain domain = Settings.class.getProtectionDomain();
final ProtectionDomain domain = Settings.class.getProtectionDomain();
if (domain != null && domain.getCodeSource() != null && domain.getCodeSource().getLocation() != null) {
jarPath = Settings.class.getProtectionDomain().getCodeSource().getLocation().getPath();
}