Issue #730: Allow multiple suppression files in Maven

The core has been extended to handle multiple suppression files
Extended the Ant test to cover multiple suppression files
NOTE: This change is breaking for users of the Maven plugin
This commit is contained in:
Phillip Whittlesea
2017-06-11 23:26:57 +01:00
parent 237dbe7061
commit 584fd2a47b
11 changed files with 289 additions and 66 deletions

View File

@@ -92,6 +92,9 @@
<fileset dir="${project.build.directory}/test-classes/jars">
<include name="axis-1.4.jar"/>
</fileset>
<filelist
dir="${project.build.directory}/test-classes/list"
files="jetty-6.1.0.jar,org.mortbay.jetty.jar"/>
</dependency-check>
</target>
</project>

View File

@@ -1,10 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Test suppression file for the DependencyCheckTaskTest#testSuppressingCVE() test -->
<!--
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: axis-1.4.jar
]]></notes>
file name: axis-1.4.jar
]]></notes>
<gav regex="true">^org\.apache\.axis:axis:.*$</gav>
<cpe>cpe:/a:apache:axis</cpe>
</suppress>

View File

@@ -0,0 +1,41 @@
<?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: org.mortbay.jetty.jar
]]></notes>
<gav regex="true">^jetty:org\.mortbay\.jetty:.*$</gav>
<cpe>cpe:/a:jetty:jetty</cpe>
</suppress>
<suppress>
<notes><![CDATA[
file name: org.mortbay.jetty.jar
]]></notes>
<gav regex="true">^jetty:org\.mortbay\.jetty:.*$</gav>
<cpe>cpe:/a:mortbay:jetty</cpe>
</suppress>
<suppress>
<notes><![CDATA[
file name: org.mortbay.jetty.jar
]]></notes>
<gav regex="true">^jetty:org\.mortbay\.jetty:.*$</gav>
<cpe>cpe:/a:mortbay_jetty:jetty</cpe>
</suppress>
</suppressions>

View File

@@ -117,66 +117,67 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
return;
}
// TODO support more than one file
final String suppressionFilePath = suppressionFilePaths[0];
for (final String suppressionFilePath : suppressionFilePaths) {
LOGGER.debug("Loading suppression rules from '{}'", suppressionFilePath);
boolean deleteTempFile = false;
try {
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
if (uriRx.matcher(suppressionFilePath).matches()) {
deleteTempFile = true;
file = FileUtils.getTempFile("suppression", "xml");
final URL url = new URL(suppressionFilePath);
try {
Downloader.fetchFile(url, file, false);
} catch (DownloadFailedException ex) {
Downloader.fetchFile(url, file, true);
}
} else {
file = new File(suppressionFilePath);
boolean deleteTempFile = false;
try {
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
if (uriRx.matcher(suppressionFilePath).matches()) {
deleteTempFile = true;
file = FileUtils.getTempFile("suppression", "xml");
final URL url = new URL(suppressionFilePath);
try {
Downloader.fetchFile(url, file, false);
} catch (DownloadFailedException ex) {
Downloader.fetchFile(url, file, true);
}
} else {
file = new File(suppressionFilePath);
if (!file.exists()) {
try (InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath)) {
if (suppressionsFromClasspath != null) {
deleteTempFile = true;
file = FileUtils.getTempFile("suppression", "xml");
try {
org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionsFromClasspath, file);
} catch (IOException ex) {
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
if (!file.exists()) {
try (InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath)) {
if (suppressionsFromClasspath != null) {
deleteTempFile = true;
file = FileUtils.getTempFile("suppression", "xml");
try {
org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionsFromClasspath, file);
} catch (IOException ex) {
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
}
}
}
}
}
}
if (file != null) {
if (!file.exists()) {
final String msg = String.format("Suppression file '%s' does not exists", file.getPath());
LOGGER.warn(msg);
throw new SuppressionParseException(msg);
if (file != null) {
if (!file.exists()) {
final String msg = String.format("Suppression file '%s' does not exists", file.getPath());
LOGGER.warn(msg);
throw new SuppressionParseException(msg);
}
try {
rules.addAll(parser.parseSuppressionRules(file));
} catch (SuppressionParseException ex) {
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
LOGGER.warn(ex.getMessage());
throw ex;
}
}
try {
rules.addAll(parser.parseSuppressionRules(file));
LOGGER.debug("{} suppression rules were loaded.", rules.size());
} catch (SuppressionParseException ex) {
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
LOGGER.warn(ex.getMessage());
throw ex;
} catch (DownloadFailedException ex) {
throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
} catch (MalformedURLException ex) {
throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
} catch (SuppressionParseException ex) {
throw ex;
} catch (IOException ex) {
throwSuppressionParseException("Unable to create temp file for suppressions", ex);
} finally {
if (deleteTempFile && file != null) {
FileUtils.delete(file);
}
}
} catch (DownloadFailedException ex) {
throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
} catch (MalformedURLException ex) {
throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
} catch (SuppressionParseException ex) {
throw ex;
} catch (IOException ex) {
throwSuppressionParseException("Unable to create temp file for suppressions", ex);
} finally {
if (deleteTempFile && file != null) {
FileUtils.delete(file);
}
}
LOGGER.debug("{} suppression rules were loaded.", rules.size());
}
/**

View File

@@ -22,8 +22,8 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<artifactId>test-dataformat-jackson</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.5</version>
@@ -38,10 +38,10 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<artifactId>jackson-dataformat-cbor</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.4.5</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.4.5</version>
</dependency>
</dependencies>
</project>

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>
<suppressionFiles>
<param>${project.basedir}/test-suppression1.xml</param>
<param>${project.basedir}/test-suppression2.xml</param>
</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

@@ -199,10 +199,10 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
@Parameter(property = "connectionTimeout", defaultValue = "", required = false)
private String connectionTimeout;
/**
* The path to the suppression file.
* The paths to the suppression files.
*/
@Parameter(property = "suppressionFile", defaultValue = "", required = false)
private String suppressionFile;
@Parameter(required = false)
private String[] suppressionFiles;
/**
* The path to the hints file.
@@ -920,8 +920,9 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
Settings.setStringIfNotNull(Settings.KEYS.PROXY_NON_PROXY_HOSTS, proxy.getNonProxyHosts());
}
Settings.setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFiles);
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
Settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
//File Type Analyzer Settings