mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
278 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f333ef76d9 | ||
|
|
af5ba6854e | ||
|
|
8b7ce06793 | ||
|
|
297a5e516f | ||
|
|
92b11526be | ||
|
|
299350f655 | ||
|
|
127eafc9b3 | ||
|
|
ad1ad3a997 | ||
|
|
82151c5b3f | ||
|
|
90457c89ff | ||
|
|
3f3ac86d38 | ||
|
|
aa126039e5 | ||
|
|
662815b1ee | ||
|
|
243c36849c | ||
|
|
52d5baaf3f | ||
|
|
89217f778e | ||
|
|
9bc9bc9169 | ||
|
|
6b73430473 | ||
|
|
5ca5bca3df | ||
|
|
89ab382a18 | ||
|
|
bad425c0d7 | ||
|
|
cdbbb1b94c | ||
|
|
0a9d8a9b22 | ||
|
|
e662041d06 | ||
|
|
155464bc87 | ||
|
|
06cd811ae4 | ||
|
|
1b31268f59 | ||
|
|
b57ef7291f | ||
|
|
c3bf6aa3f8 | ||
|
|
d2fa14bbe2 | ||
|
|
9b6e55e90c | ||
|
|
afb07b651f | ||
|
|
e6806fdf2b | ||
|
|
e5ff2cff4e | ||
|
|
17d7d47b9a | ||
|
|
64e32061ab | ||
|
|
931110ba6c | ||
|
|
d90e7820cd | ||
|
|
824898dba5 | ||
|
|
761dd61ed4 | ||
|
|
89c63e6d87 | ||
|
|
a2361f9327 | ||
|
|
ea15205be8 | ||
|
|
0a45048535 | ||
|
|
1c51655ce3 | ||
|
|
7749f0da7c | ||
|
|
5695238f95 | ||
|
|
e1feeb7e21 | ||
|
|
84fecaf040 | ||
|
|
da77727673 | ||
|
|
f8c913a3e8 | ||
|
|
2024881ee1 | ||
|
|
35ed3a51e5 | ||
|
|
24b1c4d0a4 | ||
|
|
7ec2458fb5 | ||
|
|
175feaea23 | ||
|
|
dda6cf728b | ||
|
|
a7fd410b01 | ||
|
|
d281c36733 | ||
|
|
dc91e44c0a | ||
|
|
7967a858f4 | ||
|
|
2081407e38 | ||
|
|
976eabd527 | ||
|
|
b6d6a5de2b | ||
|
|
2d58cfe0ce | ||
|
|
9df8bdff5f | ||
|
|
c86b821951 | ||
|
|
4def086bf9 | ||
|
|
885c890d7d | ||
|
|
06060a6694 | ||
|
|
70667814f6 | ||
|
|
766b7a940c | ||
|
|
0c37586357 | ||
|
|
b4aa55ce1f | ||
|
|
109443ce77 | ||
|
|
5f38741831 | ||
|
|
c6f391501d | ||
|
|
d1f3105fbd | ||
|
|
8f88ca9d3d | ||
|
|
f9e4ca0cc2 | ||
|
|
5caf023677 | ||
|
|
35c2f4873c | ||
|
|
1ed7bab375 | ||
|
|
f0d1bfb777 | ||
|
|
42519ac843 | ||
|
|
8869e13385 | ||
|
|
8f9cbfe806 | ||
|
|
6481938626 | ||
|
|
9c7cc2acbf | ||
|
|
89a57d4ed3 | ||
|
|
732378592b | ||
|
|
19dc46660b | ||
|
|
4aad3471af | ||
|
|
92bd305b00 | ||
|
|
f71eb09f74 | ||
|
|
83d4a7bc18 | ||
|
|
29595324c4 | ||
|
|
f9064e526f | ||
|
|
93ec2e8639 | ||
|
|
0e2a31709a | ||
|
|
c785b39eda | ||
|
|
8fab2f58da | ||
|
|
e44ee3bfe1 | ||
|
|
62065c9d28 | ||
|
|
c76275275f | ||
|
|
257f78879d | ||
|
|
894263809c | ||
|
|
c503935d6a | ||
|
|
d4756c9eb8 | ||
|
|
0004767775 | ||
|
|
74908642c7 | ||
|
|
aadfb71c98 | ||
|
|
1244af649d | ||
|
|
7bd48cc811 | ||
|
|
8f3ce38418 | ||
|
|
1b2d9b4245 | ||
|
|
c6b2b34fde | ||
|
|
e58fc13fdb | ||
|
|
922d53d2e4 | ||
|
|
fec53b3951 | ||
|
|
e72e2c6a02 | ||
|
|
08d001ee05 | ||
|
|
99d8a07f4a | ||
|
|
eef565134b | ||
|
|
9d78293437 | ||
|
|
fc0a556e5f | ||
|
|
b6b070584f | ||
|
|
e13225eee6 | ||
|
|
da20fb2922 | ||
|
|
459c2beb12 | ||
|
|
f1cc44dead | ||
|
|
d24cfdc382 | ||
|
|
ae4cc543f6 | ||
|
|
abdb3d17f9 | ||
|
|
4095c5da38 | ||
|
|
78fab728e4 | ||
|
|
52097a6867 | ||
|
|
cb990b55b5 | ||
|
|
5070fe303a | ||
|
|
b4405ebf3e | ||
|
|
d9e6bf5068 | ||
|
|
6822188f52 | ||
|
|
15858d03ff | ||
|
|
814a733258 | ||
|
|
3ce85d8ca9 | ||
|
|
d3bff2f39d | ||
|
|
f2272730ac | ||
|
|
fe19c97d86 | ||
|
|
56b447493e | ||
|
|
e45b68eda7 | ||
|
|
8df1ef5986 | ||
|
|
dac34cda82 | ||
|
|
9925e30c8b | ||
|
|
dc5566b5ae | ||
|
|
8132ee651a | ||
|
|
f49a134a3d | ||
|
|
bd955cda06 | ||
|
|
c6dbc01912 | ||
|
|
fabe1aa940 | ||
|
|
ba5dbb94b8 | ||
|
|
6ccc053d7e | ||
|
|
cf21dfaa3a | ||
|
|
54ceb630de | ||
|
|
0a0c302cb2 | ||
|
|
f6eef54566 | ||
|
|
a69804f84d | ||
|
|
0b06b194b0 | ||
|
|
73f6ce304c | ||
|
|
195818a432 | ||
|
|
47c817de1c | ||
|
|
8b3894f213 | ||
|
|
a411252f07 | ||
|
|
d7626aeb3f | ||
|
|
3565098650 | ||
|
|
803fcf146b | ||
|
|
d9d646c5fb | ||
|
|
034a274b07 | ||
|
|
718d7af8bc | ||
|
|
860d3d9c8b | ||
|
|
f28b566992 | ||
|
|
1c261c7463 | ||
|
|
226b2482b1 | ||
|
|
ff346dc429 | ||
|
|
2dcef25175 | ||
|
|
46702bbb5c | ||
|
|
5600c9bc69 | ||
|
|
d7e46b1693 | ||
|
|
fe8c60ade1 | ||
|
|
288892441f | ||
|
|
e1179a8e22 | ||
|
|
4b06d0fd87 | ||
|
|
464d91f45a | ||
|
|
5cc7aa25cc | ||
|
|
20ec224070 | ||
|
|
9cbcc29ddb | ||
|
|
0badbfc4a0 | ||
|
|
e042148c62 | ||
|
|
d8ba04ae7f | ||
|
|
314d5fdad2 | ||
|
|
5c874cafd1 | ||
|
|
8cafc14d09 | ||
|
|
25ac5033fc | ||
|
|
848be0db6c | ||
|
|
0f9da0731e | ||
|
|
8bc2364cce | ||
|
|
b64916ce3f | ||
|
|
452955667c | ||
|
|
f38bbf4cc7 | ||
|
|
25eaa11a52 | ||
|
|
4b4da8d467 | ||
|
|
13116c5381 | ||
|
|
d2cd406a62 | ||
|
|
acbce05fbf | ||
|
|
bee4d3a338 | ||
|
|
bce226002b | ||
|
|
a417db7c7a | ||
|
|
0ffef12a8b | ||
|
|
4539b040e0 | ||
|
|
f85014a86d | ||
|
|
d90d07c68b | ||
|
|
ce292b84fa | ||
|
|
01690860db | ||
|
|
89fb2d4915 | ||
|
|
5cc3a42832 | ||
|
|
60b0145e04 | ||
|
|
ce48823d38 | ||
|
|
d43fee5585 | ||
|
|
5dc9e51dd4 | ||
|
|
235fcccbd7 | ||
|
|
91c971b8fd | ||
|
|
e43003cadc | ||
|
|
9a96165655 | ||
|
|
994aef411c | ||
|
|
094a180935 | ||
|
|
74e9de6370 | ||
|
|
c7f31b3d79 | ||
|
|
98d0239d03 | ||
|
|
ffeab147ce | ||
|
|
90bdbd6b84 | ||
|
|
e29dd3cd33 | ||
|
|
23b95178ff | ||
|
|
9bde80357f | ||
|
|
1485733715 | ||
|
|
d125a7f09d | ||
|
|
77486dffd4 | ||
|
|
c84bcb433f | ||
|
|
f1e5221257 | ||
|
|
b8bf01acc3 | ||
|
|
65aa7bd1de | ||
|
|
6f511444a7 | ||
|
|
ef5174d89f | ||
|
|
e2a97e75d8 | ||
|
|
9fc6e265eb | ||
|
|
f81c42b1fd | ||
|
|
8594e146eb | ||
|
|
cda0dfdafe | ||
|
|
363568b02c | ||
|
|
443ab02788 | ||
|
|
65784d6dc4 | ||
|
|
da805d037f | ||
|
|
d383776245 | ||
|
|
51eba8da73 | ||
|
|
14b4d64244 | ||
|
|
7cb7f68cda | ||
|
|
83300d028b | ||
|
|
e891ce39c0 | ||
|
|
e58b7782ac | ||
|
|
1ddb468a08 | ||
|
|
95e3f0e0d9 | ||
|
|
0edf017ddc | ||
|
|
ad601fd1ee | ||
|
|
e7eaccb5e0 | ||
|
|
6b201da3ff | ||
|
|
a85a47bc20 | ||
|
|
69b8f51319 | ||
|
|
0d943ba805 | ||
|
|
56fe3b5892 | ||
|
|
c177f12e1d |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,6 +7,9 @@
|
||||
# Eclipse project files
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
maven-eclipse.xml
|
||||
.externalToolBuilders
|
||||
# Netbeans configuration
|
||||
nb-configuration.xml
|
||||
/target/
|
||||
|
||||
@@ -40,7 +40,6 @@ The plugin can be configured using the following:
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@@ -59,7 +58,7 @@ The plugin can be configured using the following:
|
||||
|
||||
### Ant Task
|
||||
|
||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-maven/installation.html).
|
||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/installation.html).
|
||||
|
||||
Development Usage
|
||||
-------------
|
||||
@@ -106,4 +105,4 @@ Dependency-Check makes use of several other open source libraries. Please see th
|
||||
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||
[post]: mailto:dependency-check@googlegroups.com
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
||||
|
||||
@@ -15,20 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2013 - Jeremy Long. 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/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Ant Task</name>
|
||||
<description>Dependency-check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
||||
<description>dependency-check-ant is an Ant Task that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the project's dependencies. The task will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -324,6 +323,9 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -439,6 +441,11 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
|
||||
@@ -285,26 +285,50 @@ public class DependencyCheckTask extends Task {
|
||||
this.reportFormat = reportFormat.getValue();
|
||||
}
|
||||
/**
|
||||
* The Proxy URL.
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyUrl;
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* Get the value of proxyUrl.
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyUrl
|
||||
* @return the value of proxyServer
|
||||
*/
|
||||
public String getProxyUrl() {
|
||||
return proxyUrl;
|
||||
public String getProxyServer() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyUrl.
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyUrl
|
||||
* @param server new value of proxyServer
|
||||
*/
|
||||
public void setProxyServer(String server) {
|
||||
this.proxyServer = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.taskdefs.DependencyCheckTask#getProxyServer()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getProxyUrl() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.taskdefs.DependencyCheckTask#setProxyServer(java.lang.String)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProxyUrl(String proxyUrl) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
LOGGER.warning("A deprecated configuration option 'proxyUrl' was detected; use 'proxyServer' instead.");
|
||||
this.proxyServer = proxyUrl;
|
||||
}
|
||||
/**
|
||||
* The Proxy Port.
|
||||
@@ -866,7 +890,7 @@ public class DependencyCheckTask extends Task {
|
||||
|
||||
Engine engine = null;
|
||||
try {
|
||||
engine = new Engine();
|
||||
engine = new Engine(DependencyCheckTask.class.getClassLoader());
|
||||
|
||||
for (Resource resource : path) {
|
||||
final FileProvider provider = resource.as(FileProvider.class);
|
||||
@@ -912,7 +936,7 @@ public class DependencyCheckTask extends Task {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
@@ -935,7 +959,7 @@ public class DependencyCheckTask extends Task {
|
||||
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
|
||||
* properties required to change the proxy url, port, and connection timeout.
|
||||
* properties required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
private void populateSettings() {
|
||||
Settings.initialize();
|
||||
@@ -967,8 +991,8 @@ public class DependencyCheckTask extends Task {
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
|
||||
if (proxyUrl != null && !proxyUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
|
||||
@@ -32,7 +32,7 @@ failBuildOnCVSS | Specifies if the build should be failed if a CVSS score a
|
||||
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
logFile | The file path to write verbose logging information. |
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) |
|
||||
proxyUrl | The Proxy URL. |
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
@@ -46,17 +46,17 @@ Note, that specific analyzers will automatically disable themselves if no file
|
||||
types that they support are detected - so specifically disabling them may not
|
||||
be needed.
|
||||
|
||||
Property | Description | Default Value
|
||||
------------------------|------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
Property | Description | Default Value
|
||||
------------------------|---------------------------------------------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus Pro URL. If not set the Nexus Analyzer will be disabled. |
|
||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems |
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||
|
||||
Advanced Configuration
|
||||
====================
|
||||
|
||||
@@ -3,7 +3,20 @@ Installation
|
||||
Download dependency-check-ant from [bintray here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-ant-${project.version}.jar).
|
||||
To install dependency-check-ant place the dependency-check-ant-${project.version}.jar into
|
||||
the lib directory of your Ant instalation directory. Once installed you can add
|
||||
the taskdef to you build.xml and add the task to a new or existing target.
|
||||
the taskdef to you build.xml and add the task to a new or existing target:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
|
||||
If you do not want to install dependency-check-ant into your ant's lib directory when you define the task def you
|
||||
must add the classpath to the taskdef:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
It is important to understand that the first time this task is executed it may
|
||||
take 20 minutes or more as it downloads and processes the data from the National
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
Usage
|
||||
====================
|
||||
First, add the dependency-check-ant taskdef to your build.xml:
|
||||
First, add the dependency-check-ant taskdef to your build.xml (see the [installation guide](installation.html):
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
Next, add the task to a target of your choosing:
|
||||
|
||||
```xml
|
||||
@@ -45,7 +45,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
public void tearDown() {
|
||||
//no cleanup...
|
||||
//executeTarget("cleanup");
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,20 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2012 - Jeremy Long. 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/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Command Line</name>
|
||||
<description>Dependency-Check-Maven is a Maven Plugin that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
||||
<description>dependency-check-cli is an command line tool that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the scanned project dependencies. The tool will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -174,6 +173,9 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -284,12 +286,12 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>appassembler-maven-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<version>1.8.1</version>
|
||||
<configuration>
|
||||
<programs>
|
||||
<program>
|
||||
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
||||
<name>dependency-check</name>
|
||||
<id>dependency-check</id>
|
||||
</program>
|
||||
</programs>
|
||||
<assembleDirectory>${project.build.directory}/release</assembleDirectory>
|
||||
@@ -341,5 +343,10 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd
|
||||
"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd"
|
||||
>
|
||||
<id>release</id>
|
||||
<formats>
|
||||
|
||||
@@ -21,15 +21,19 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.owasp.dependencycheck.cli.CliParser;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.DirectoryScanner;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
import org.owasp.dependencycheck.utils.LogUtils;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -57,8 +61,13 @@ public class App {
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final App app = new App();
|
||||
app.run(args);
|
||||
try {
|
||||
Settings.initialize();
|
||||
final App app = new App();
|
||||
app.run(args);
|
||||
} finally {
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,8 +76,8 @@ public class App {
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public void run(String[] args) {
|
||||
|
||||
final CliParser cli = new CliParser();
|
||||
|
||||
try {
|
||||
cli.parse(args);
|
||||
} catch (FileNotFoundException ex) {
|
||||
@@ -88,7 +97,11 @@ public class App {
|
||||
cli.printVersionInfo();
|
||||
} else if (cli.isRunScan()) {
|
||||
populateSettings(cli);
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles());
|
||||
try {
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles(), cli.getExcludeList());
|
||||
} catch (InvalidScanPathException ex) {
|
||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, "An invalid scan path was detected; unable to scan '//*' paths");
|
||||
}
|
||||
} else {
|
||||
cli.printHelp();
|
||||
}
|
||||
@@ -101,18 +114,71 @@ public class App {
|
||||
* @param outputFormat the output format of the report
|
||||
* @param applicationName the application name for the report
|
||||
* @param files the files/directories to scan
|
||||
* @param excludes the patterns for files/directories to exclude
|
||||
*
|
||||
* @throws InvalidScanPathException thrown if the path to scan starts with "//"
|
||||
*/
|
||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files) {
|
||||
Engine scanner = null;
|
||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files,
|
||||
String[] excludes) throws InvalidScanPathException {
|
||||
Engine engine = null;
|
||||
try {
|
||||
scanner = new Engine();
|
||||
|
||||
for (String file : files) {
|
||||
scanner.scan(file);
|
||||
engine = new Engine();
|
||||
List<String> antStylePaths = new ArrayList<String>();
|
||||
if (excludes == null || excludes.length == 0) {
|
||||
for (String file : files) {
|
||||
if (file.contains("*") || file.contains("?")) {
|
||||
antStylePaths.add(file);
|
||||
} else {
|
||||
engine.scan(file);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
antStylePaths = Arrays.asList(files);
|
||||
}
|
||||
|
||||
scanner.analyzeDependencies();
|
||||
final List<Dependency> dependencies = scanner.getDependencies();
|
||||
final Set<File> paths = new HashSet<File>();
|
||||
for (String file : antStylePaths) {
|
||||
final DirectoryScanner scanner = new DirectoryScanner();
|
||||
String include = file.replace('\\', '/');
|
||||
File baseDir;
|
||||
|
||||
if (include.startsWith("//")) {
|
||||
throw new InvalidScanPathException("Unable to scan paths specified by //");
|
||||
} else if (include.startsWith("./")) {
|
||||
baseDir = new File(".");
|
||||
include = include.substring(2);
|
||||
} else if (include.startsWith("/")) {
|
||||
baseDir = new File("/");
|
||||
include = include.substring(1);
|
||||
} else if (include.contains("/")) {
|
||||
final int pos = include.indexOf('/');
|
||||
final String tmp = include.substring(0, pos);
|
||||
if (tmp.contains("*") || tmp.contains("?")) {
|
||||
baseDir = new File(".");
|
||||
} else {
|
||||
baseDir = new File(tmp);
|
||||
include = include.substring(pos + 1);
|
||||
}
|
||||
} else { //no path info - must just be a file in the working directory
|
||||
baseDir = new File(".");
|
||||
}
|
||||
scanner.setBasedir(baseDir);
|
||||
scanner.setIncludes(include);
|
||||
if (excludes != null && excludes.length > 0) {
|
||||
scanner.addExcludes(excludes);
|
||||
}
|
||||
scanner.scan();
|
||||
if (scanner.getIncludedFilesCount() > 0) {
|
||||
for (String s : scanner.getIncludedFiles()) {
|
||||
final File f = new File(baseDir, s);
|
||||
paths.add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
engine.scan(paths);
|
||||
|
||||
engine.analyzeDependencies();
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
@@ -126,7 +192,7 @@ public class App {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop);
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
||||
try {
|
||||
report.generateReports(reportDirectory, outputFormat);
|
||||
} catch (IOException ex) {
|
||||
@@ -140,9 +206,8 @@ public class App {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
if (scanner != null) {
|
||||
scanner.cleanup();
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,11 +220,9 @@ public class App {
|
||||
*/
|
||||
private void populateSettings(CliParser cli) {
|
||||
|
||||
Settings.initialize();
|
||||
|
||||
final boolean autoUpdate = cli.isAutoUpdate();
|
||||
final String connectionTimeout = cli.getConnectionTimeout();
|
||||
final String proxyUrl = cli.getProxyUrl();
|
||||
final String proxyServer = cli.getProxyServer();
|
||||
final String proxyPort = cli.getProxyPort();
|
||||
final String proxyUser = cli.getProxyUsername();
|
||||
final String proxyPass = cli.getProxyPassword();
|
||||
@@ -210,8 +273,8 @@ public class App {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
if (proxyUrl != null && !proxyUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.cli;
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
@@ -39,6 +40,10 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public final class CliParser {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CliParser.class.getName());
|
||||
/**
|
||||
* The command line.
|
||||
*/
|
||||
@@ -85,16 +90,16 @@ public final class CliParser {
|
||||
*/
|
||||
private void validateArgs() throws FileNotFoundException, ParseException {
|
||||
if (isRunScan()) {
|
||||
validatePathExists(getScanFiles(), ArgumentName.SCAN);
|
||||
validatePathExists(getReportDirectory(), ArgumentName.OUT);
|
||||
validatePathExists(getScanFiles(), ARGUMENT.SCAN);
|
||||
validatePathExists(getReportDirectory(), ARGUMENT.OUT);
|
||||
if (getPathToMono() != null) {
|
||||
validatePathExists(getPathToMono(), ArgumentName.PATH_TO_MONO);
|
||||
validatePathExists(getPathToMono(), ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
if (!line.hasOption(ArgumentName.APP_NAME)) {
|
||||
if (!line.hasOption(ARGUMENT.APP_NAME)) {
|
||||
throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
|
||||
}
|
||||
if (line.hasOption(ArgumentName.OUTPUT_FORMAT)) {
|
||||
final String format = line.getOptionValue(ArgumentName.OUTPUT_FORMAT);
|
||||
if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) {
|
||||
final String format = line.getOptionValue(ARGUMENT.OUTPUT_FORMAT);
|
||||
try {
|
||||
Format.valueOf(format);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
@@ -129,14 +134,33 @@ public final class CliParser {
|
||||
* @throws FileNotFoundException is thrown if the path being validated does not exist.
|
||||
*/
|
||||
private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
|
||||
if (!path.contains("*.")) {
|
||||
if (path == null) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: null", argumentName);
|
||||
throw new FileNotFoundException(msg);
|
||||
} else if (!path.contains("*") && !path.contains("?")) {
|
||||
final File f = new File(path);
|
||||
if (!f.exists()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
if ("o".equals(argumentName.substring(0, 1).toLowerCase()) && !"ALL".equals(this.getReportFormat().toUpperCase())) {
|
||||
final String checkPath = path.toLowerCase();
|
||||
if (checkPath.endsWith(".html") || checkPath.endsWith(".xml") || checkPath.endsWith(".htm")) {
|
||||
if (!f.getParentFile().isDirectory()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!f.exists()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
} // else { // TODO add a validation for *.zip extensions rather then relying on the engine to validate it.
|
||||
} else if (path.startsWith("//") || path.startsWith("\\\\")) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'%nUnable to scan paths that start with '//'.", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,11 +170,10 @@ public final class CliParser {
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private Options createCommandLineOptions() {
|
||||
|
||||
final Options options = new Options();
|
||||
addStandardOptions(options);
|
||||
addAdvancedOptions(options);
|
||||
|
||||
addDeprecatedOptions(options);
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -162,44 +185,50 @@ public final class CliParser {
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private void addStandardOptions(final Options options) throws IllegalArgumentException {
|
||||
final Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false,
|
||||
final Option help = new Option(ARGUMENT.HELP_SHORT, ARGUMENT.HELP, false,
|
||||
"Print this message.");
|
||||
|
||||
final Option advancedHelp = OptionBuilder.withLongOpt(ArgumentName.ADVANCED_HELP)
|
||||
final Option advancedHelp = OptionBuilder.withLongOpt(ARGUMENT.ADVANCED_HELP)
|
||||
.withDescription("Print the advanced help message.").create();
|
||||
|
||||
final Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION,
|
||||
final Option version = new Option(ARGUMENT.VERSION_SHORT, ARGUMENT.VERSION,
|
||||
false, "Print the version information.");
|
||||
|
||||
final Option noUpdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
|
||||
final Option noUpdate = new Option(ARGUMENT.DISABLE_AUTO_UPDATE_SHORT, ARGUMENT.DISABLE_AUTO_UPDATE,
|
||||
false, "Disables the automatic updating of the CPE data.");
|
||||
|
||||
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APP_NAME)
|
||||
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ARGUMENT.APP_NAME)
|
||||
.withDescription("The name of the application being scanned. This is a required argument.")
|
||||
.create(ArgumentName.APP_NAME_SHORT);
|
||||
.create(ARGUMENT.APP_NAME_SHORT);
|
||||
|
||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
|
||||
.withDescription("The path to scan - this option can be specified multiple times. To limit the scan"
|
||||
+ " to specific file types *.[ext] can be added to the end of the path.")
|
||||
.create(ArgumentName.SCAN_SHORT);
|
||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
|
||||
.withDescription("The path to scan - this option can be specified multiple times. Ant style"
|
||||
+ " paths are supported (e.g. path/**/*.jar).")
|
||||
.create(ARGUMENT.SCAN_SHORT);
|
||||
|
||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
|
||||
final Option excludes = OptionBuilder.withArgName("pattern").hasArg().withLongOpt(ARGUMENT.EXCLUDE)
|
||||
.withDescription("Specify and exclusion pattern. This option can be specified multiple times"
|
||||
+ " and it accepts Ant style excludsions.")
|
||||
.create();
|
||||
|
||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP)
|
||||
.withDescription("A property file to load.")
|
||||
.create(ArgumentName.PROP_SHORT);
|
||||
.create(ARGUMENT.PROP_SHORT);
|
||||
|
||||
final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
|
||||
.withDescription("The folder to write reports to. This defaults to the current directory.")
|
||||
.create(ArgumentName.OUT_SHORT);
|
||||
final Option out = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.OUT)
|
||||
.withDescription("The folder to write reports to. This defaults to the current directory. "
|
||||
+ "It is possible to set this to a specific file name if the format argument is not set to ALL.")
|
||||
.create(ARGUMENT.OUT_SHORT);
|
||||
|
||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ArgumentName.OUTPUT_FORMAT)
|
||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
|
||||
.withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
|
||||
.create(ArgumentName.OUTPUT_FORMAT_SHORT);
|
||||
.create(ARGUMENT.OUTPUT_FORMAT_SHORT);
|
||||
|
||||
final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.VERBOSE_LOG)
|
||||
final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.VERBOSE_LOG)
|
||||
.withDescription("The file path to write verbose logging information.")
|
||||
.create(ArgumentName.VERBOSE_LOG_SHORT);
|
||||
.create(ARGUMENT.VERBOSE_LOG_SHORT);
|
||||
|
||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.SUPPRESSION_FILE)
|
||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
|
||||
.withDescription("The file path to the suppression XML file.")
|
||||
.create();
|
||||
|
||||
@@ -207,7 +236,11 @@ public final class CliParser {
|
||||
final OptionGroup og = new OptionGroup();
|
||||
og.addOption(path);
|
||||
|
||||
final OptionGroup exog = new OptionGroup();
|
||||
exog.addOption(excludes);
|
||||
|
||||
options.addOptionGroup(og)
|
||||
.addOptionGroup(exog)
|
||||
.addOption(out)
|
||||
.addOption(outputFormat)
|
||||
.addOption(appName)
|
||||
@@ -230,87 +263,87 @@ public final class CliParser {
|
||||
@SuppressWarnings("static-access")
|
||||
private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
|
||||
|
||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DATA_DIRECTORY)
|
||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DATA_DIRECTORY)
|
||||
.withDescription("The location of the H2 Database file. This option should generally not be set.")
|
||||
.create(ArgumentName.DATA_DIRECTORY_SHORT);
|
||||
.create(ARGUMENT.DATA_DIRECTORY_SHORT);
|
||||
|
||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ArgumentName.CONNECTION_TIMEOUT)
|
||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ARGUMENT.CONNECTION_TIMEOUT)
|
||||
.withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
|
||||
.create(ArgumentName.CONNECTION_TIMEOUT_SHORT);
|
||||
.create(ARGUMENT.CONNECTION_TIMEOUT_SHORT);
|
||||
|
||||
final Option proxyUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.PROXY_URL)
|
||||
.withDescription("The proxy url to use when downloading resources.")
|
||||
.create(ArgumentName.PROXY_URL_SHORT);
|
||||
final Option proxyServer = OptionBuilder.withArgName("server").hasArg().withLongOpt(ARGUMENT.PROXY_SERVER)
|
||||
.withDescription("The proxy server to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ArgumentName.PROXY_PORT)
|
||||
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ARGUMENT.PROXY_PORT)
|
||||
.withDescription("The proxy port to use when downloading resources.")
|
||||
.create(ArgumentName.PROXY_PORT_SHORT);
|
||||
.create();
|
||||
|
||||
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.PROXY_USERNAME)
|
||||
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.PROXY_USERNAME)
|
||||
.withDescription("The proxy username to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ArgumentName.PROXY_PASSWORD)
|
||||
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ARGUMENT.PROXY_PASSWORD)
|
||||
.withDescription("The proxy password to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ArgumentName.CONNECTION_STRING)
|
||||
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ARGUMENT.CONNECTION_STRING)
|
||||
.withDescription("The connection string to the database.")
|
||||
.create();
|
||||
|
||||
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.DB_NAME)
|
||||
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.DB_NAME)
|
||||
.withDescription("The username used to connect to the database.")
|
||||
.create();
|
||||
|
||||
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ArgumentName.DB_PASSWORD)
|
||||
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ARGUMENT.DB_PASSWORD)
|
||||
.withDescription("The password for connecting to the database.")
|
||||
.create();
|
||||
|
||||
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ArgumentName.DB_DRIVER)
|
||||
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ARGUMENT.DB_DRIVER)
|
||||
.withDescription("The database driver name.")
|
||||
.create();
|
||||
|
||||
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DB_DRIVER_PATH)
|
||||
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DB_DRIVER_PATH)
|
||||
.withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
|
||||
.create();
|
||||
|
||||
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_JAR)
|
||||
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_JAR)
|
||||
.withDescription("Disable the Jar Analyzer.")
|
||||
.create();
|
||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_ARCHIVE)
|
||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ARCHIVE)
|
||||
.withDescription("Disable the Archive Analyzer.")
|
||||
.create();
|
||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NUSPEC)
|
||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NUSPEC)
|
||||
.withDescription("Disable the Nuspec Analyzer.")
|
||||
.create();
|
||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_ASSEMBLY)
|
||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ASSEMBLY)
|
||||
.withDescription("Disable the .NET Assembly Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NEXUS)
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
|
||||
.withDescription("Disable the Nexus Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.NEXUS_URL)
|
||||
.withDescription("The url to the Nexus Server.")
|
||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
|
||||
.withDescription("The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled.")
|
||||
.create();
|
||||
|
||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ArgumentName.NEXUS_USES_PROXY)
|
||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ARGUMENT.NEXUS_USES_PROXY)
|
||||
.withDescription("Whether or not the configured proxy should be used when connecting to Nexus.")
|
||||
.create();
|
||||
|
||||
final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
|
||||
.withLongOpt(ArgumentName.ADDITIONAL_ZIP_EXTENSIONS)
|
||||
.withLongOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
|
||||
.withDescription("A comma separated list of additional extensions to be scanned as ZIP files "
|
||||
+ "(ZIP, EAR, WAR are already treated as zip files)")
|
||||
.create();
|
||||
|
||||
final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.PATH_TO_MONO)
|
||||
final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.PATH_TO_MONO)
|
||||
.withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
|
||||
.create();
|
||||
|
||||
options.addOption(proxyPort)
|
||||
.addOption(proxyUrl)
|
||||
.addOption(proxyServer)
|
||||
.addOption(proxyUsername)
|
||||
.addOption(proxyPassword)
|
||||
.addOption(connectionTimeout)
|
||||
@@ -331,13 +364,30 @@ public final class CliParser {
|
||||
.addOption(pathToMono);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the deprecated command line options to the given options collection. These are split out for purposes of not
|
||||
* including them in the help message. We need to add the deprecated options so as not to break existing scripts.
|
||||
*
|
||||
* @param options a collection of command line arguments
|
||||
* @throws IllegalArgumentException thrown if there is an exception
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private void addDeprecatedOptions(final Options options) throws IllegalArgumentException {
|
||||
|
||||
final Option proxyServer = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.PROXY_URL)
|
||||
.withDescription("The proxy url argument is deprecated, use proxyserver instead.")
|
||||
.create();
|
||||
|
||||
options.addOption(proxyServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the 'version' command line argument was passed in.
|
||||
*
|
||||
* @return whether or not the 'version' command line argument was passed in
|
||||
*/
|
||||
public boolean isGetVersion() {
|
||||
return (line != null) && line.hasOption(ArgumentName.VERSION);
|
||||
return (line != null) && line.hasOption(ARGUMENT.VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,7 +396,7 @@ public final class CliParser {
|
||||
* @return whether or not the 'help' command line argument was passed in
|
||||
*/
|
||||
public boolean isGetHelp() {
|
||||
return (line != null) && line.hasOption(ArgumentName.HELP);
|
||||
return (line != null) && line.hasOption(ARGUMENT.HELP);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,7 +405,7 @@ public final class CliParser {
|
||||
* @return whether or not the 'scan' command line argument was passed in
|
||||
*/
|
||||
public boolean isRunScan() {
|
||||
return (line != null) && isValid && line.hasOption(ArgumentName.SCAN);
|
||||
return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,7 +414,7 @@ public final class CliParser {
|
||||
* @return true if the disableJar command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isJarDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_JAR);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,7 +423,7 @@ public final class CliParser {
|
||||
* @return true if the disableArchive command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isArchiveDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_ARCHIVE);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,7 +432,7 @@ public final class CliParser {
|
||||
* @return true if the disableNuspec command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isNuspecDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_NUSPEC);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,7 +441,7 @@ public final class CliParser {
|
||||
* @return true if the disableAssembly command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isAssemblyDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_ASSEMBLY);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,7 +450,7 @@ public final class CliParser {
|
||||
* @return true if the disableNexus command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isNexusDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_NEXUS);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,10 +459,10 @@ public final class CliParser {
|
||||
* @return the url to the nexus server; if none was specified this will return null;
|
||||
*/
|
||||
public String getNexusUrl() {
|
||||
if (line == null || !line.hasOption(ArgumentName.NEXUS_URL)) {
|
||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_URL)) {
|
||||
return null;
|
||||
} else {
|
||||
return line.getOptionValue(ArgumentName.NEXUS_URL);
|
||||
return line.getOptionValue(ARGUMENT.NEXUS_URL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,14 +475,14 @@ public final class CliParser {
|
||||
public boolean isNexusUsesProxy() {
|
||||
// If they didn't specify whether Nexus needs to use the proxy, we should
|
||||
// still honor the property if it's set.
|
||||
if (line == null || !line.hasOption(ArgumentName.NEXUS_USES_PROXY)) {
|
||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) {
|
||||
try {
|
||||
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY);
|
||||
} catch (InvalidSettingException ise) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return Boolean.parseBoolean(line.getOptionValue(ArgumentName.NEXUS_USES_PROXY));
|
||||
return Boolean.parseBoolean(line.getOptionValue(ARGUMENT.NEXUS_USES_PROXY));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +493,7 @@ public final class CliParser {
|
||||
final HelpFormatter formatter = new HelpFormatter();
|
||||
final Options options = new Options();
|
||||
addStandardOptions(options);
|
||||
if (line != null && line.hasOption(ArgumentName.ADVANCED_HELP)) {
|
||||
if (line != null && line.hasOption(ARGUMENT.ADVANCED_HELP)) {
|
||||
addAdvancedOptions(options);
|
||||
}
|
||||
final String helpMsg = String.format("%n%s"
|
||||
@@ -457,7 +507,6 @@ public final class CliParser {
|
||||
options,
|
||||
"",
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,7 +515,16 @@ public final class CliParser {
|
||||
* @return the file paths specified on the command line for scan
|
||||
*/
|
||||
public String[] getScanFiles() {
|
||||
return line.getOptionValues(ArgumentName.SCAN);
|
||||
return line.getOptionValues(ARGUMENT.SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of excluded file patterns specified by the 'exclude' argument.
|
||||
*
|
||||
* @return the excluded file patterns
|
||||
*/
|
||||
public String[] getExcludeList() {
|
||||
return line.getOptionValues(ARGUMENT.EXCLUDE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,7 +533,7 @@ public final class CliParser {
|
||||
* @return the path to the reports directory.
|
||||
*/
|
||||
public String getReportDirectory() {
|
||||
return line.getOptionValue(ArgumentName.OUT, ".");
|
||||
return line.getOptionValue(ARGUMENT.OUT, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -484,7 +542,7 @@ public final class CliParser {
|
||||
* @return the path to Mono
|
||||
*/
|
||||
public String getPathToMono() {
|
||||
return line.getOptionValue(ArgumentName.PATH_TO_MONO);
|
||||
return line.getOptionValue(ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,7 +551,7 @@ public final class CliParser {
|
||||
* @return the output format name.
|
||||
*/
|
||||
public String getReportFormat() {
|
||||
return line.getOptionValue(ArgumentName.OUTPUT_FORMAT, "HTML");
|
||||
return line.getOptionValue(ARGUMENT.OUTPUT_FORMAT, "HTML");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -502,7 +560,7 @@ public final class CliParser {
|
||||
* @return the application name.
|
||||
*/
|
||||
public String getApplicationName() {
|
||||
return line.getOptionValue(ArgumentName.APP_NAME);
|
||||
return line.getOptionValue(ARGUMENT.APP_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -511,16 +569,24 @@ public final class CliParser {
|
||||
* @return the connection timeout
|
||||
*/
|
||||
public String getConnectionTimeout() {
|
||||
return line.getOptionValue(ArgumentName.CONNECTION_TIMEOUT);
|
||||
return line.getOptionValue(ARGUMENT.CONNECTION_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the proxy url.
|
||||
* Returns the proxy server.
|
||||
*
|
||||
* @return the proxy url
|
||||
* @return the proxy server
|
||||
*/
|
||||
public String getProxyUrl() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_URL);
|
||||
public String getProxyServer() {
|
||||
|
||||
String server = line.getOptionValue(ARGUMENT.PROXY_SERVER);
|
||||
if (server == null) {
|
||||
server = line.getOptionValue(ARGUMENT.PROXY_URL);
|
||||
if (server != null) {
|
||||
LOGGER.warning("An old command line argument 'proxyurl' was detected; use proxyserver instead");
|
||||
}
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -529,7 +595,7 @@ public final class CliParser {
|
||||
* @return the proxy port
|
||||
*/
|
||||
public String getProxyPort() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_PORT);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,7 +604,7 @@ public final class CliParser {
|
||||
* @return the proxy username
|
||||
*/
|
||||
public String getProxyUsername() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_USERNAME);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,7 +613,7 @@ public final class CliParser {
|
||||
* @return the proxy password
|
||||
*/
|
||||
public String getProxyPassword() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_PASSWORD);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,7 +622,7 @@ public final class CliParser {
|
||||
* @return the value of dataDirectory
|
||||
*/
|
||||
public String getDataDirectory() {
|
||||
return line.getOptionValue(ArgumentName.DATA_DIRECTORY);
|
||||
return line.getOptionValue(ARGUMENT.DATA_DIRECTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,7 +631,7 @@ public final class CliParser {
|
||||
* @return the properties file specified on the command line
|
||||
*/
|
||||
public File getPropertiesFile() {
|
||||
final String path = line.getOptionValue(ArgumentName.PROP);
|
||||
final String path = line.getOptionValue(ARGUMENT.PROP);
|
||||
if (path != null) {
|
||||
return new File(path);
|
||||
}
|
||||
@@ -578,7 +644,7 @@ public final class CliParser {
|
||||
* @return the path to the verbose log file
|
||||
*/
|
||||
public String getVerboseLog() {
|
||||
return line.getOptionValue(ArgumentName.VERBOSE_LOG);
|
||||
return line.getOptionValue(ARGUMENT.VERBOSE_LOG);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -587,7 +653,7 @@ public final class CliParser {
|
||||
* @return the path to the suppression file
|
||||
*/
|
||||
public String getSuppressionFile() {
|
||||
return line.getOptionValue(ArgumentName.SUPPRESSION_FILE);
|
||||
return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -610,7 +676,7 @@ public final class CliParser {
|
||||
* @return if auto-update is allowed.
|
||||
*/
|
||||
public boolean isAutoUpdate() {
|
||||
return (line == null) || !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE);
|
||||
return (line == null) || !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -619,7 +685,7 @@ public final class CliParser {
|
||||
* @return the database driver name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseDriverName() {
|
||||
return line.getOptionValue(ArgumentName.DB_DRIVER);
|
||||
return line.getOptionValue(ARGUMENT.DB_DRIVER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -628,7 +694,7 @@ public final class CliParser {
|
||||
* @return the database driver name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseDriverPath() {
|
||||
return line.getOptionValue(ArgumentName.DB_DRIVER_PATH);
|
||||
return line.getOptionValue(ARGUMENT.DB_DRIVER_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -637,7 +703,7 @@ public final class CliParser {
|
||||
* @return the database connection string if specified; otherwise null is returned
|
||||
*/
|
||||
public String getConnectionString() {
|
||||
return line.getOptionValue(ArgumentName.CONNECTION_STRING);
|
||||
return line.getOptionValue(ARGUMENT.CONNECTION_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -646,7 +712,7 @@ public final class CliParser {
|
||||
* @return the database database user name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseUser() {
|
||||
return line.getOptionValue(ArgumentName.DB_NAME);
|
||||
return line.getOptionValue(ARGUMENT.DB_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,7 +721,7 @@ public final class CliParser {
|
||||
* @return the database database password if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabasePassword() {
|
||||
return line.getOptionValue(ArgumentName.DB_PASSWORD);
|
||||
return line.getOptionValue(ARGUMENT.DB_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -664,13 +730,13 @@ public final class CliParser {
|
||||
* @return the additional Extensions; otherwise null is returned
|
||||
*/
|
||||
public String getAdditionalZipExtensions() {
|
||||
return line.getOptionValue(ArgumentName.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
return line.getOptionValue(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of static final strings that represent the possible command line arguments.
|
||||
*/
|
||||
public static class ArgumentName {
|
||||
public static class ARGUMENT {
|
||||
|
||||
/**
|
||||
* The long CLI argument name specifying the directory/file to scan.
|
||||
@@ -732,21 +798,20 @@ public final class CliParser {
|
||||
* The short CLI argument name asking for the version.
|
||||
*/
|
||||
public static final String VERSION = "version";
|
||||
/**
|
||||
* The short CLI argument name indicating the proxy port.
|
||||
*/
|
||||
public static final String PROXY_PORT_SHORT = "p";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy port.
|
||||
*/
|
||||
public static final String PROXY_PORT = "proxyport";
|
||||
/**
|
||||
* The short CLI argument name indicating the proxy url.
|
||||
* The CLI argument name indicating the proxy server.
|
||||
*/
|
||||
public static final String PROXY_URL_SHORT = "u";
|
||||
public static final String PROXY_SERVER = "proxyserver";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy url.
|
||||
*
|
||||
* @deprecated use {@link org.owasp.dependencycheck.cli.CliParser.ArgumentName#PROXY_SERVER} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String PROXY_URL = "proxyurl";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy username.
|
||||
@@ -848,5 +913,9 @@ public final class CliParser {
|
||||
* The CLI argument name for setting extra extensions.
|
||||
*/
|
||||
public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions";
|
||||
/**
|
||||
* Exclude path argument.
|
||||
*/
|
||||
public static final String EXCLUDE = "exclude";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2014 OWASP.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
/**
|
||||
* Thrown if an invalid path is encountered.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
class InvalidScanPathException extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*/
|
||||
public InvalidScanPathException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param msg a message for the exception
|
||||
*/
|
||||
public InvalidScanPathException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param ex the cause of the exception
|
||||
*/
|
||||
public InvalidScanPathException(Throwable ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param msg a message for the exception
|
||||
* @param ex the cause of the exception
|
||||
*/
|
||||
public InvalidScanPathException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.cli</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* Includes utility classes such as the CLI Parser,
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.cli;
|
||||
@@ -3,11 +3,12 @@ Command Line Arguments
|
||||
|
||||
The following table lists the command line arguments:
|
||||
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
-------|-----------------------|-----------------|-------------|------------
|
||||
\-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. | Required
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify specific file types that should be scanned by supplying a scan path of '[path]/[to]/[scan]/*.zip'. The wild card can only be used to denote any file-name with a specific extension. | Required
|
||||
\-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
|
||||
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**) . | Optional
|
||||
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
|
||||
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required
|
||||
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||
@@ -18,26 +19,25 @@ Short | Argument Name | Parameter | Description | Requirement
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-------------|---------------
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-----------------------------------------------------------------------------|---------------
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
| \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
| \-\-disableJar | | Sets whether Jar Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Disable the Nexus Analyzer. |
|
||||
| \-\-nexus | \<url\> | The url to the Nexus Server. | https://repository.sonatype.org/service/local/
|
||||
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
||||
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
||||
| \-\-pathToMono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||
| \-\-proxyurl | \<url\> | The proxy url to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-disableJar | | Sets whether Jar Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
|
||||
| \-\-nexus | \<url\> | The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled. |
|
||||
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
||||
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
||||
| \-\-pathToMono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
||||
| \-\-dbDriverPath | \<path\> | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. |
|
||||
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
||||
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
||||
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. |
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.cli;
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import org.owasp.dependencycheck.CliParser;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -44,7 +45,7 @@ public class CliParserTest {
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -15,19 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2012 Jeremy Long. 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/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Core</name>
|
||||
<description>dependency-check-core is the engine and reporting tool used to identify and report if there are any known, publicly disclosed vulnerabilities in the scanned project's dependencies. The engine extracts meta-data from the dependencies and uses this to do fuzzy key-word matching against the Common Platfrom Enumeration (CPE), if any CPE identifiers are found the associated Common Vulnerability and Exposure (CVE) entries are added to the generated report.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -220,6 +220,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<name>data.directory</name>
|
||||
<value>${project.build.directory}/data</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*IntegrationTest.java</include>
|
||||
@@ -267,6 +272,9 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -392,6 +400,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
@@ -399,12 +408,23 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-test-framework</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--dependency>
|
||||
<groupId>org.jmockit</groupId>
|
||||
<artifactId>jmockit</artifactId>
|
||||
<version>1.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency-->
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
@@ -419,7 +439,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.8</version>
|
||||
<version>1.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
@@ -451,50 +471,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>velocity</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-tools</artifactId>
|
||||
<version>2.0</version>
|
||||
<!-- very limited use of the velocity-tools, not all of the dependencies are needed-->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-chain</groupId>
|
||||
<artifactId>commons-chain</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>sslext</groupId>
|
||||
<artifactId>sslext</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>antlr</groupId>
|
||||
<artifactId>antlr</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-taglib</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-tiles</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
@@ -521,6 +497,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hazelcast</groupId>
|
||||
<artifactId>hazelcast</artifactId>
|
||||
@@ -601,6 +584,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<version>1.1.0.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
@@ -662,11 +652,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
Additionally, these are only added when using "allTests" to
|
||||
make the build slightly faster in most cases. -->
|
||||
<id>False Positive Tests</id>
|
||||
<!--activation>
|
||||
<activation>
|
||||
<property>
|
||||
<name>allTests</name>
|
||||
</property>
|
||||
</activation-->
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
@@ -689,6 +679,56 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ganyo</groupId>
|
||||
<artifactId>gcm-server</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.python</groupId>
|
||||
<artifactId>jython-standalone</artifactId>
|
||||
<version>2.7-b1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby-complete</artifactId>
|
||||
<version>1.7.4</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby</artifactId>
|
||||
<version>1.6.3</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>2.12</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.faces</groupId>
|
||||
<artifactId>jsf-impl</artifactId>
|
||||
<version>2.2.8-02</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
@@ -52,7 +53,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Engine {
|
||||
public class Engine implements Serializable {
|
||||
|
||||
/**
|
||||
* The list of dependencies.
|
||||
@@ -61,19 +62,19 @@ public class Engine {
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers;
|
||||
private final transient EnumMap<AnalysisPhase, List<Analyzer>> analyzers;
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final Set<FileTypeAnalyzer> fileTypeAnalyzers;
|
||||
private final transient Set<FileTypeAnalyzer> fileTypeAnalyzers;
|
||||
/**
|
||||
* The ClassLoader to use when dynamically loading Analyzer and Update services.
|
||||
*/
|
||||
private ClassLoader serviceClassLoader;
|
||||
private transient ClassLoader serviceClassLoader;
|
||||
/**
|
||||
* The Logger for use throughout the class.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
||||
private static final transient Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
||||
|
||||
/**
|
||||
* Creates a new Engine.
|
||||
@@ -167,142 +168,171 @@ public class Engine {
|
||||
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param paths an array of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param paths an array of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(String[] paths) {
|
||||
public List<Dependency> scan(String[] paths) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (String path : paths) {
|
||||
final File file = new File(path);
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* identified are added to the dependency collection.
|
||||
*
|
||||
* @param path the path to a file or directory to be analyzed.
|
||||
* @param path the path to a file or directory to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*/
|
||||
public void scan(String path) {
|
||||
if (path.matches("^.*[\\/]\\*\\.[^\\/:*|?<>\"]+$")) {
|
||||
final String[] parts = path.split("\\*\\.");
|
||||
final String[] ext = new String[]{parts[parts.length - 1]};
|
||||
final File dir = new File(path.substring(0, path.length() - ext[0].length() - 2));
|
||||
if (dir.isDirectory()) {
|
||||
final List<File> files = (List<File>) org.apache.commons.io.FileUtils.listFiles(dir, ext, true);
|
||||
scan(files);
|
||||
} else {
|
||||
final String msg = String.format("Invalid file path provided to scan '%s'", path);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
}
|
||||
} else {
|
||||
final File file = new File(path);
|
||||
scan(file);
|
||||
}
|
||||
public List<Dependency> scan(String path) {
|
||||
final File file = new File(path);
|
||||
return scan(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
*
|
||||
* @param files an array of paths to files or directories to be analyzed.
|
||||
* @return the list of dependencies
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(File[] files) {
|
||||
public List<Dependency> scan(File[] files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param files a set of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param files a set of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(Set<File> files) {
|
||||
public List<Dependency> scan(Set<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param files a set of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param files a set of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(List<File> files) {
|
||||
public List<Dependency> scan(List<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* identified are added to the dependency collection.
|
||||
*
|
||||
* @param file the path to a file or directory to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @since v0.3.2.4
|
||||
*
|
||||
* @param file the path to a file or directory to be analyzed.
|
||||
*/
|
||||
public void scan(File file) {
|
||||
public List<Dependency> scan(File file) {
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
scanDirectory(file);
|
||||
return scanDirectory(file);
|
||||
} else {
|
||||
scanFile(file);
|
||||
final Dependency d = scanFile(file);
|
||||
if (d != null) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
deps.add(d);
|
||||
return deps;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively scans files and directories. Any dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @param dir the directory to scan.
|
||||
* @param dir the directory to scan
|
||||
* @return the list of Dependency objects scanned
|
||||
*/
|
||||
protected void scanDirectory(File dir) {
|
||||
protected List<Dependency> scanDirectory(File dir) {
|
||||
final File[] files = dir.listFiles();
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
scanDirectory(f);
|
||||
final List<Dependency> d = scanDirectory(f);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
} else {
|
||||
scanFile(f);
|
||||
final Dependency d = scanFile(f);
|
||||
deps.add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a specified file. If a dependency is identified it is added to the dependency collection.
|
||||
*
|
||||
* @param file The file to scan.
|
||||
* @param file The file to scan
|
||||
* @return the scanned dependency
|
||||
*/
|
||||
protected void scanFile(File file) {
|
||||
protected Dependency scanFile(File file) {
|
||||
if (!file.isFile()) {
|
||||
final String msg = String.format("Path passed to scanFile(File) is not a file: %s. Skipping the file.", file.toString());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
final String fileName = file.getName();
|
||||
final String extension = FileUtils.getFileExtension(fileName);
|
||||
Dependency dependency = null;
|
||||
if (extension != null) {
|
||||
if (supportsExtension(extension)) {
|
||||
final Dependency dependency = new Dependency(file);
|
||||
dependency = new Dependency(file);
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
} else {
|
||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.",
|
||||
file.toString());
|
||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.", file.toString());
|
||||
LOGGER.log(Level.FINEST, msg);
|
||||
}
|
||||
return dependency;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -438,8 +468,7 @@ public class Engine {
|
||||
} catch (UpdateException ex) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
|
||||
LOGGER.log(Level.FINE,
|
||||
String.format("Unable to update details for %s", source.getClass().getName()), ex);
|
||||
LOGGER.log(Level.FINE, String.format("Unable to update details for %s", source.getClass().getName()), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
* Copyright (c) 2014 Steve Springett. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.agent;
|
||||
|
||||
@@ -234,26 +234,49 @@ public class DependencyCheckScanAgent {
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy URL.
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyUrl;
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* Get the value of proxyUrl.
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyUrl
|
||||
* @return the value of proxyServer
|
||||
*/
|
||||
public String getProxyUrl() {
|
||||
return proxyUrl;
|
||||
public String getProxyServer() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyUrl.
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyUrl
|
||||
* @param proxyServer new value of proxyServer
|
||||
*/
|
||||
public void setProxyServer(String proxyServer) {
|
||||
this.proxyServer = proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getProxyUrl() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#setProxyServer(java.lang.String)
|
||||
* } instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProxyUrl(String proxyUrl) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
this.proxyServer = proxyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -792,7 +815,7 @@ public class DependencyCheckScanAgent {
|
||||
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
|
||||
* properties required to change the proxy url, port, and connection timeout.
|
||||
* properties required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
private void populateSettings() {
|
||||
Settings.initialize();
|
||||
@@ -808,8 +831,8 @@ public class DependencyCheckScanAgent {
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
|
||||
if (proxyUrl != null && !proxyUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
@@ -888,7 +911,7 @@ public class DependencyCheckScanAgent {
|
||||
"Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
|
||||
@@ -98,11 +98,17 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
* @throws SuppressionParseException thrown if the XML cannot be parsed.
|
||||
*/
|
||||
private void loadSuppressionData() throws SuppressionParseException {
|
||||
final SuppressionParser parser = new SuppressionParser();
|
||||
File file = null;
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
|
||||
} catch (SuppressionParseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to parse the base suppression data file", ex);
|
||||
}
|
||||
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
||||
if (suppressionFilePath == null) {
|
||||
return;
|
||||
}
|
||||
File file = null;
|
||||
boolean deleteTempFile = false;
|
||||
try {
|
||||
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
|
||||
@@ -132,9 +138,9 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
if (file != null) {
|
||||
final SuppressionParser parser = new SuppressionParser();
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(file);
|
||||
//rules = parser.parseSuppressionRules(file);
|
||||
rules.addAll(parser.parseSuppressionRules(file));
|
||||
LOGGER.log(Level.FINE, rules.size() + " suppression rules were loaded.");
|
||||
} catch (SuppressionParseException ex) {
|
||||
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -35,7 +36,9 @@ import java.util.logging.Logger;
|
||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
import org.apache.commons.compress.compressors.CompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipUtils;
|
||||
@@ -99,10 +102,15 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz");
|
||||
|
||||
/**
|
||||
* The set of file extensions to remove from the engine's collection of dependencies.
|
||||
*/
|
||||
private static final Set<String> REMOVE_FROM_ANALYSIS = newHashSet("zip", "tar", "gz", "tgz"); //TODO add nupkg, apk, sar?
|
||||
|
||||
static {
|
||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
if (additionalZipExt != null) {
|
||||
final HashSet ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||
final HashSet<String> ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||
ZIPPABLES.addAll(ext);
|
||||
}
|
||||
EXTENSIONS.addAll(ZIPPABLES);
|
||||
@@ -178,7 +186,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
||||
final boolean success = FileUtils.delete(tempFileLocation);
|
||||
if (!success) {
|
||||
if (!success && tempFileLocation != null && tempFileLocation.exists() && tempFileLocation.list().length > 0) {
|
||||
LOGGER.log(Level.WARNING, "Failed to delete some temporary files, see the log for more details");
|
||||
}
|
||||
}
|
||||
@@ -199,9 +207,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
extractFiles(f, tmpDir, engine);
|
||||
|
||||
//make a copy
|
||||
final List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(tmpDir);
|
||||
final List<Dependency> newDependencies = engine.getDependencies();
|
||||
List<Dependency> newDependencies = engine.getDependencies();
|
||||
if (dependencies.size() != newDependencies.size()) {
|
||||
//get the new dependencies
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
@@ -213,9 +221,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String displayPath = String.format("%s%s",
|
||||
dependency.getFilePath(),
|
||||
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||
final String displayName = String.format("%s%s%s",
|
||||
final String displayName = String.format("%s: %s",
|
||||
dependency.getFileName(),
|
||||
File.separator,
|
||||
d.getFileName());
|
||||
d.setFilePath(displayPath);
|
||||
d.setFileName(displayName);
|
||||
@@ -229,6 +236,40 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
|
||||
if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) {
|
||||
final File tdir = getNextTempDirectory();
|
||||
final String fileName = dependency.getFileName();
|
||||
|
||||
LOGGER.info(String.format("The zip file '%s' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName));
|
||||
|
||||
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc);
|
||||
dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(tmpLoc);
|
||||
newDependencies = engine.getDependencies();
|
||||
if (dependencies.size() != newDependencies.size()) {
|
||||
//get the new dependencies
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
dependencySet.addAll(newDependencies);
|
||||
dependencySet.removeAll(dependencies);
|
||||
if (dependencySet.size() != 1) {
|
||||
LOGGER.info("Deep copy of ZIP to JAR file resulted in more then one dependency?");
|
||||
}
|
||||
for (Dependency d : dependencySet) {
|
||||
//fix the dependency's display name and path
|
||||
d.setFilePath(dependency.getFilePath());
|
||||
d.setDisplayFileName(dependency.getFileName());
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to perform deep copy on '%s'", dependency.getActualFile().getPath());
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
}
|
||||
}
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
Collections.sort(engine.getDependencies());
|
||||
}
|
||||
|
||||
@@ -411,4 +452,38 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to determine if a zip file is actually a JAR file.
|
||||
*
|
||||
* @param dependency the dependency to check
|
||||
* @return true if the dependency appears to be a JAR file; otherwise false
|
||||
*/
|
||||
private boolean isZipFileActuallyJarFile(Dependency dependency) {
|
||||
boolean isJar = false;
|
||||
ZipFile zip = null;
|
||||
try {
|
||||
zip = new ZipFile(dependency.getActualFilePath());
|
||||
if (zip.getEntry("META-INF/MANIFEST.MF") != null
|
||||
|| zip.getEntry("META-INF/maven") != null) {
|
||||
final Enumeration<ZipArchiveEntry> entries = zip.getEntries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final ZipArchiveEntry entry = entries.nextElement();
|
||||
if (!entry.isDirectory()) {
|
||||
final String name = entry.getName().toLowerCase();
|
||||
if (name.endsWith(".class")) {
|
||||
isJar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, String.format("Unable to unzip zip file '%s'", dependency.getFilePath()), ex);
|
||||
} finally {
|
||||
ZipFile.closeQuietly(zip);
|
||||
}
|
||||
|
||||
return isJar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName(), "dependencycheck-resources");
|
||||
|
||||
/**
|
||||
* Builds the beginnings of a List for ProcessBuilder
|
||||
@@ -106,7 +106,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
public void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
if (grokAssemblyExe == null) {
|
||||
LOGGER.warning("GrokAssembly didn't get deployed");
|
||||
LOGGER.warning("analyzer.AssemblyAnalyzer.notdeployed");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -114,16 +114,32 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
args.add(dependency.getActualFilePath());
|
||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||
BufferedReader rdr = null;
|
||||
Document doc = null;
|
||||
try {
|
||||
final Process proc = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
|
||||
String line = null;
|
||||
// CheckStyle:VisibilityModifier OFF
|
||||
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
||||
LOGGER.log(Level.WARNING, "Error from GrokAssembly: {0}", line);
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.stderr", line);
|
||||
}
|
||||
// CheckStyle:VisibilityModifier ON
|
||||
int rc = 0;
|
||||
final Document doc = builder.parse(proc.getInputStream());
|
||||
doc = builder.parse(proc.getInputStream());
|
||||
|
||||
try {
|
||||
rc = proc.waitFor();
|
||||
} catch (InterruptedException ie) {
|
||||
return;
|
||||
}
|
||||
if (rc == 3) {
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.notassembly", dependency.getActualFilePath());
|
||||
return;
|
||||
} else if (rc != 0) {
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.rc", rc);
|
||||
}
|
||||
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
|
||||
// First, see if there was an error
|
||||
@@ -150,18 +166,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
product, Confidence.HIGH));
|
||||
}
|
||||
|
||||
try {
|
||||
rc = proc.waitFor();
|
||||
} catch (InterruptedException ie) {
|
||||
return;
|
||||
}
|
||||
if (rc == 3) {
|
||||
LOGGER.log(Level.INFO, "{0} is not a valid assembly", dependency.getActualFilePath());
|
||||
return;
|
||||
} else if (rc != 0) {
|
||||
LOGGER.log(Level.WARNING, "Return code {0} from GrokAssembly", rc);
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
throw new AnalysisException(ioe);
|
||||
} catch (SAXException saxe) {
|
||||
@@ -201,9 +205,10 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
grokAssemblyExe = tempFile;
|
||||
// Set the temp file to get deleted when we're done
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
LOGGER.log(Level.FINE, "Extracted GrokAssembly.exe to {0}", grokAssemblyExe.getPath());
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.deployed", grokAssemblyExe.getPath());
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.log(Level.WARNING, "Could not extract GrokAssembly.exe: {0}", ioe.getMessage());
|
||||
this.setEnabled(false);
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.notdeployed", ioe.getMessage());
|
||||
throw new AnalysisException("Could not extract GrokAssembly.exe", ioe);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
@@ -230,9 +235,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final Process p = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream(), "UTF-8"));
|
||||
// CheckStyle:VisibilityModifier OFF
|
||||
while (rdr.ready() && rdr.readLine() != null) {
|
||||
// We expect this to complain
|
||||
}
|
||||
// CheckStyle:VisibilityModifier ON
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String error = xpath.evaluate("/assembly/error", doc);
|
||||
@@ -240,15 +247,16 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.warning("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
||||
LOGGER.fine("GrokAssembly.exe is not working properly");
|
||||
grokAssemblyExe = null;
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("Could not execute .NET AssemblyAnalyzer");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof AnalysisException) {
|
||||
throw (AnalysisException) e;
|
||||
} else {
|
||||
LOGGER.warning("An error occured with the .NET AssemblyAnalyzer; "
|
||||
+ "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.");
|
||||
LOGGER.log(Level.FINE, "Could not execute GrokAssembly {0}", e.getMessage());
|
||||
LOGGER.warning("analyzer.AssemblyAnalyzer.grokassembly.initialization.failed");
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.initialization.message", e.getMessage());
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
|
||||
}
|
||||
} finally {
|
||||
@@ -260,7 +268,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
}
|
||||
|
||||
@@ -272,7 +279,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
}
|
||||
} catch (SecurityException se) {
|
||||
LOGGER.fine("Can't delete temporary GrokAssembly.exe");
|
||||
LOGGER.fine("analyzer.AssemblyAnalyzer.grokassembly.notdeleted");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class CPEAnalyzer implements Analyzer {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
@@ -90,6 +91,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
*/
|
||||
private CveDB cve;
|
||||
|
||||
/**
|
||||
* The URL to perform a search of the NVD CVE data at NIST.
|
||||
*/
|
||||
public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
|
||||
|
||||
/**
|
||||
* Returns the name of this analyzer.
|
||||
*
|
||||
@@ -164,29 +170,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
||||
*/
|
||||
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
||||
Confidence confidence = Confidence.HIGHEST;
|
||||
|
||||
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), confidence);
|
||||
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), confidence);
|
||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
|
||||
int ctr = 0;
|
||||
do {
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
|
||||
for (IndexEntry e : entries) {
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
determineIdentifiers(dependency, vendor, product);
|
||||
}
|
||||
}
|
||||
}
|
||||
confidence = reduceConfidence(confidence);
|
||||
//TODO test dojo-war against this. we shold get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
|
||||
String vendors = "";
|
||||
String products = "";
|
||||
for (Confidence confidence : Confidence.values()) {
|
||||
if (dependency.getVendorEvidence().contains(confidence)) {
|
||||
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
||||
}
|
||||
@@ -195,10 +182,28 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
||||
if (dependency.getVersionEvidence().contains(confidence)) {
|
||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
// if (dependency.getVersionEvidence().contains(confidence)) {
|
||||
// addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
// }
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
if (entries == null) {
|
||||
continue;
|
||||
}
|
||||
boolean identifierAdded = false;
|
||||
for (IndexEntry e : entries) {
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
|
||||
}
|
||||
}
|
||||
if (identifierAdded) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((++ctr) < 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,22 +238,6 @@ public class CPEAnalyzer implements Analyzer {
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the given confidence by one level. This returns LOW if the confidence passed in is not HIGH.
|
||||
*
|
||||
* @param c the confidence to reduce.
|
||||
* @return One less then the confidence passed in.
|
||||
*/
|
||||
private Confidence reduceConfidence(final Confidence c) {
|
||||
if (c == Confidence.HIGHEST) {
|
||||
return Confidence.HIGH;
|
||||
} else if (c == Confidence.HIGH) {
|
||||
return Confidence.MEDIUM;
|
||||
} else {
|
||||
return Confidence.LOW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Searches the Lucene CPE index to identify possible CPE entries associated with the supplied vendor, product, and
|
||||
@@ -263,27 +252,24 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @param vendorWeightings a list of strings to use to add weighting factors to the vendor field
|
||||
* @param productWeightings Adds a list of strings that will be used to add weighting factors to the product search
|
||||
* @return a list of possible CPE values
|
||||
* @throws CorruptIndexException when the Lucene index is corrupt
|
||||
* @throws IOException when the Lucene index is not found
|
||||
* @throws ParseException when the generated query is not valid
|
||||
*/
|
||||
protected List<IndexEntry> searchCPE(String vendor, String product,
|
||||
Set<String> vendorWeightings, Set<String> productWeightings)
|
||||
throws CorruptIndexException, IOException, ParseException {
|
||||
Set<String> vendorWeightings, Set<String> productWeightings) {
|
||||
|
||||
final ArrayList<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
|
||||
|
||||
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
||||
if (searchString == null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
||||
for (ScoreDoc d : docs.scoreDocs) {
|
||||
if (d.score >= 0.08) {
|
||||
final Document doc = cpe.getDocument(d.doc);
|
||||
final IndexEntry entry = new IndexEntry();
|
||||
entry.setVendor(doc.get(Fields.VENDOR));
|
||||
entry.setProduct(doc.get(Fields.PRODUCT));
|
||||
try {
|
||||
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
||||
for (ScoreDoc d : docs.scoreDocs) {
|
||||
if (d.score >= 0.08) {
|
||||
final Document doc = cpe.getDocument(d.doc);
|
||||
final IndexEntry entry = new IndexEntry();
|
||||
entry.setVendor(doc.get(Fields.VENDOR));
|
||||
entry.setProduct(doc.get(Fields.PRODUCT));
|
||||
// if (d.score < 0.08) {
|
||||
// System.out.print(entry.getVendor());
|
||||
// System.out.print(":");
|
||||
@@ -291,13 +277,23 @@ public class CPEAnalyzer implements Analyzer {
|
||||
// System.out.print(":");
|
||||
// System.out.println(d.score);
|
||||
// }
|
||||
entry.setSearchScore(d.score);
|
||||
if (!ret.contains(entry)) {
|
||||
ret.add(entry);
|
||||
entry.setSearchScore(d.score);
|
||||
if (!ret.contains(entry)) {
|
||||
ret.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} catch (ParseException ex) {
|
||||
final String msg = String.format("Unable to parse: %s", searchString);
|
||||
LOGGER.log(Level.WARNING, "An error occured querying the CPE data. See the log for more details.");
|
||||
LOGGER.log(Level.INFO, msg, ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("IO Error with search string: %s", searchString);
|
||||
LOGGER.log(Level.WARNING, "An error occured reading CPE data. See the log for more details.");
|
||||
LOGGER.log(Level.INFO, msg, ex);
|
||||
}
|
||||
return ret;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -502,14 +498,21 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @param dependency the Dependency being analyzed
|
||||
* @param vendor the vendor for the CPE being analyzed
|
||||
* @param product the product for the CPE being analyzed
|
||||
* @param currentConfidence the current confidence being used during analysis
|
||||
* @return <code>true</code> if an identifier was added to the dependency; otherwise <code>false</code>
|
||||
* @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
|
||||
*/
|
||||
private void determineIdentifiers(Dependency dependency, String vendor, String product) throws UnsupportedEncodingException {
|
||||
protected boolean determineIdentifiers(Dependency dependency, String vendor, String product,
|
||||
Confidence currentConfidence) throws UnsupportedEncodingException {
|
||||
final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
|
||||
DependencyVersion bestGuess = new DependencyVersion("-");
|
||||
Confidence bestGuessConf = null;
|
||||
boolean hasBroadMatch = false;
|
||||
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
||||
for (Confidence conf : Confidence.values()) {
|
||||
// if (conf.compareTo(currentConfidence) > 0) {
|
||||
// break;
|
||||
// }
|
||||
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
||||
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
||||
if (evVer == null) {
|
||||
@@ -522,9 +525,13 @@ public class CPEAnalyzer implements Analyzer {
|
||||
} else {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||
}
|
||||
if (dbVer == null //special case, no version specified - everything is vulnerable
|
||||
|| evVer.equals(dbVer)) { //yeah! exact match
|
||||
final String url = String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
if (dbVer == null) { //special case, no version specified - everything is vulnerable
|
||||
hasBroadMatch = true;
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.BROAD_MATCH, conf);
|
||||
collected.add(match);
|
||||
} else if (evVer.equals(dbVer)) { //yeah! exact match
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
|
||||
collected.add(match);
|
||||
} else {
|
||||
@@ -549,7 +556,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
}
|
||||
final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
|
||||
final String url = null; //String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(cpeName, "UTF-8"));
|
||||
String url = null;
|
||||
if (hasBroadMatch) { //if we have a broad match we can add the URL to the best guess.
|
||||
final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
|
||||
url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
|
||||
}
|
||||
if (bestGuessConf == null) {
|
||||
bestGuessConf = Confidence.LOW;
|
||||
}
|
||||
@@ -559,6 +570,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
Collections.sort(collected);
|
||||
final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
|
||||
final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
|
||||
boolean identifierAdded = false;
|
||||
for (IdentifierMatch m : collected) {
|
||||
if (bestIdentifierQuality.equals(m.getConfidence())
|
||||
&& bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
|
||||
@@ -569,8 +581,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
i.setConfidence(bestEvidenceQuality);
|
||||
}
|
||||
dependency.addIdentifier(i);
|
||||
identifierAdded = true;
|
||||
}
|
||||
}
|
||||
return identifierAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -585,7 +599,12 @@ public class CPEAnalyzer implements Analyzer {
|
||||
/**
|
||||
* A best guess for the CPE.
|
||||
*/
|
||||
BEST_GUESS
|
||||
BEST_GUESS,
|
||||
/**
|
||||
* The entire vendor/product group must be added (without a guess at version) because there is a CVE with a VS
|
||||
* that only specifies vendor/product.
|
||||
*/
|
||||
BROAD_MATCH
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.central.CentralSearch;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* Analyzer which will attempt to locate a dependency, and the GAV information, by querying Central for the dependency's
|
||||
* SHA-1 digest.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralAnalyzer.class.getName());
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Central Analyzer";
|
||||
|
||||
/**
|
||||
* The phase in which this analyzer runs.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
/**
|
||||
* The types of files on which this will work.
|
||||
*/
|
||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
|
||||
|
||||
/**
|
||||
* The analyzer should be disabled if there are errors, so this is a flag to determine if such an error has
|
||||
* occurred.
|
||||
*/
|
||||
private boolean errorFlag = false;
|
||||
|
||||
/**
|
||||
* The searcher itself.
|
||||
*/
|
||||
private CentralSearch searcher;
|
||||
|
||||
/**
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
private final boolean enabled = checkEnabled();
|
||||
|
||||
/**
|
||||
* Determine whether to enable this analyzer or not.
|
||||
*
|
||||
* @return whether the analyzer should be enabled
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this analyzer is enabled.
|
||||
*
|
||||
* @return <code>true</code> if the analyzer is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
private boolean checkEnabled() {
|
||||
boolean retval = false;
|
||||
|
||||
try {
|
||||
if (Settings.getBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED)) {
|
||||
if (!Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)
|
||||
|| NexusAnalyzer.DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))) {
|
||||
LOGGER.info("Enabling the Central analyzer");
|
||||
retval = true;
|
||||
} else {
|
||||
LOGGER.info("Nexus analyzer is enabled, disabling the Central Analyzer");
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("Central analyzer disabled");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warning("Invalid setting. Disabling the Central analyzer");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the analyzer once before any analysis is performed.
|
||||
*
|
||||
* @throws Exception if there's an error during initialization
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
LOGGER.fine("Initializing Central analyzer");
|
||||
LOGGER.fine(String.format("Central analyzer enabled: %s", isEnabled()));
|
||||
if (isEnabled()) {
|
||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||
LOGGER.fine(String.format("Central Analyzer URL: %s", searchUrl));
|
||||
searcher = new CentralSearch(new URL(searchUrl));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analyzer's name.
|
||||
*
|
||||
* @return the name of the analyzer
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used in the properties file to to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key.
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_CENTRAL_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis phase under which the analyzer runs.
|
||||
*
|
||||
* @return the phase under which the analyzer runs
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extensions for which this Analyzer runs.
|
||||
*
|
||||
* @return the extensions for which this Analyzer runs
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the analysis.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine
|
||||
* @throws AnalysisException when there's an exception during analysis
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (errorFlag || !isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final List<MavenArtifact> mas = searcher.searchSha1(dependency.getSha1sum());
|
||||
final Confidence confidence = mas.size() > 1 ? Confidence.HIGH : Confidence.HIGHEST;
|
||||
for (MavenArtifact ma : mas) {
|
||||
LOGGER.fine(String.format("Central analyzer found artifact (%s) for dependency (%s)", ma.toString(), dependency.getFileName()));
|
||||
dependency.addAsEvidence("central", ma, confidence);
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
LOGGER.info(String.format("invalid sha1-hash on %s", dependency.getFileName()));
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
LOGGER.fine(String.format("Artifact not found in repository: '%s", dependency.getFileName()));
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.log(Level.FINE, "Could not connect to Central search", ioe);
|
||||
errorFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
while (subIterator.hasNext()) {
|
||||
final Dependency nextDependency = subIterator.next();
|
||||
if (hashesMatch(dependency, nextDependency)) {
|
||||
if (isCore(dependency, nextDependency)) {
|
||||
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
@@ -390,4 +390,43 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which path is shortest; if path lengths are equal then we use compareTo of the string method to
|
||||
* determine if the first path is smaller.
|
||||
*
|
||||
* @param left the first path to compare
|
||||
* @param right the second path to compare
|
||||
* @return <code>true</code> if the leftPath is the shortest; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean firstPathIsShortest(String left, String right) {
|
||||
final String leftPath = left.replace('\\', '/');
|
||||
final String rightPath = right.replace('\\', '/');
|
||||
|
||||
final int leftCount = countChar(leftPath, '/');
|
||||
final int rightCount = countChar(rightPath, '/');
|
||||
if (leftCount == rightCount) {
|
||||
return leftPath.compareTo(rightPath) <= 0;
|
||||
} else {
|
||||
return leftCount < rightCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of times the character is present in the string.
|
||||
*
|
||||
* @param string the string to count the characters in
|
||||
* @param c the character to count
|
||||
* @return the number of times the character is present in the string
|
||||
*/
|
||||
private int countChar(String string, char c) {
|
||||
int count = 0;
|
||||
final int max = string.length();
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (c == string.charAt(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,46 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
removeJreEntries(dependency);
|
||||
removeBadMatches(dependency);
|
||||
removeBadSpringMatches(dependency);
|
||||
removeWrongVersionMatches(dependency);
|
||||
removeSpuriousCPE(dependency);
|
||||
removeDuplicativeEntriesFromJar(dependency, engine);
|
||||
addFalseNegativeCPEs(dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes inaccurate matches on springframework CPEs.
|
||||
*
|
||||
* @param dependency the dependency to test for and remove known inaccurate CPE matches
|
||||
*/
|
||||
private void removeBadSpringMatches(Dependency dependency) {
|
||||
String mustContain = null;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("maven".contains(i.getType())) {
|
||||
if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||
final int endPoint = i.getValue().indexOf(":", 19);
|
||||
if (endPoint >= 0) {
|
||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mustContain != null) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
if ("cpe".contains(i.getType())
|
||||
&& i.getValue() != null
|
||||
&& i.getValue().startsWith("cpe:/a:springsource:")
|
||||
&& !i.getValue().toLowerCase().contains(mustContain)) {
|
||||
itr.remove();
|
||||
//dependency.getIdentifiers().remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
|
||||
@@ -160,11 +195,20 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
|
||||
+ "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
|
||||
+ "jdk|jre|jsf|jsse)($|:.*)");
|
||||
+ "jdk|jre|jsse)($|:.*)");
|
||||
|
||||
/**
|
||||
* Regex to identify core jsf libraries.
|
||||
*/
|
||||
public static final Pattern CORE_JAVA_JSF = Pattern.compile("^cpe:/a:(sun|oracle|ibm):jsf($|:.*)");
|
||||
/**
|
||||
* Regex to identify core java library files. This is currently incomplete.
|
||||
*/
|
||||
public static final Pattern CORE_FILES = Pattern.compile("^((alt[-])?rt|jsf[-].*|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
||||
public static final Pattern CORE_FILES = Pattern.compile("(^|/)((alt[-])?rt|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
||||
/**
|
||||
* Regex to identify core jsf java library files. This is currently incomplete.
|
||||
*/
|
||||
public static final Pattern CORE_JSF_FILES = Pattern.compile("(^|/)jsf[-][^/]*\\.jar$");
|
||||
|
||||
/**
|
||||
* Removes any CPE entries for the JDK/JRE unless the filename ends with rt.jar
|
||||
@@ -181,27 +225,11 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
if (coreCPE.matches() && !coreFiles.matches()) {
|
||||
itr.remove();
|
||||
}
|
||||
|
||||
//replaced with the regex above.
|
||||
// if (("cpe:/a:sun:java".equals(i.getValue())
|
||||
// || "cpe:/a:oracle:java".equals(i.getValue())
|
||||
// || "cpe:/a:ibm:java".equals(i.getValue())
|
||||
// || "cpe:/a:sun:j2se".equals(i.getValue())
|
||||
// || "cpe:/a:oracle:j2se".equals(i.getValue())
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:j2se:")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:jre")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:jdk")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java_se")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:java_se")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:java:")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:j2se:")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:jre")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:jdk")
|
||||
// || i.getValue().startsWith("cpe:/a:ibm:java:"))
|
||||
// && !dependency.getFileName().toLowerCase().endsWith("rt.jar")) {
|
||||
// itr.remove();
|
||||
// }
|
||||
final Matcher coreJsfCPE = CORE_JAVA_JSF.matcher(i.getValue());
|
||||
final Matcher coreJsfFiles = CORE_JSF_FILES.matcher(dependency.getFileName());
|
||||
if (coreJsfCPE.matches() && !coreJsfFiles.matches()) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,14 +276,33 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
//TODO move this startsWith expression to a configuration file?
|
||||
if ("cpe".equals(i.getType())) {
|
||||
if ((i.getValue().matches(".*c\\+\\+.*")
|
||||
|| i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||
|| i.getValue().startsWith("cpe:/a:yahoo:yui")
|
||||
|| i.getValue().startsWith("cpe:/a:file:file")
|
||||
|| i.getValue().startsWith("cpe:/a:mozilla:mozilla")
|
||||
|| i.getValue().startsWith("cpe:/a:cvs:cvs")
|
||||
|| i.getValue().startsWith("cpe:/a:ftp:ftp")
|
||||
|| i.getValue().startsWith("cpe:/a:ssh:ssh"))
|
||||
|| i.getValue().startsWith("cpe:/a:tcp:tcp")
|
||||
|| i.getValue().startsWith("cpe:/a:ssh:ssh")
|
||||
|| i.getValue().startsWith("cpe:/a:lookup:lookup"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".nuspec")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".nupkg"))) {
|
||||
itr.remove();
|
||||
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||
|| i.getValue().startsWith("cpe:/a:yahoo:yui"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".exe"))) {
|
||||
itr.remove();
|
||||
} else if ((i.getValue().startsWith("cpe:/a:microsoft:excel")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:word")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:visio")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:office"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|
||||
itr.remove();
|
||||
@@ -266,7 +313,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
&& !dependency.getEvidenceUsed().containsUsedString("m-core")) {
|
||||
itr.remove();
|
||||
} else if (i.getValue().startsWith("cpe:/a:jboss:jboss")
|
||||
&& !dependency.getFileName().toLowerCase().matches("jboss-[\\d\\.]+(GA)?\\.jar")) {
|
||||
&& !dependency.getFileName().toLowerCase().matches("jboss-?[\\d\\.-]+(GA)?\\.jar")) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
@@ -314,6 +361,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
* @param dependency the dependency being analyzed
|
||||
*/
|
||||
private void addFalseNegativeCPEs(Dependency dependency) {
|
||||
//TODO move this to the hint analyzer
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
@@ -329,20 +377,92 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe2,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe2, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe2, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe3,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe3, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe3, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe4,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe4, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM
|
||||
* entries or other types of files (such as DLLs and EXEs) being contained within the JAR.
|
||||
*
|
||||
* @param dependency the dependency that might be a duplicate
|
||||
* @param engine the engine used to scan all dependencies
|
||||
*/
|
||||
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| "dll".equals(dependency.getFileExtension())
|
||||
|| "exe".equals(dependency.getFileExtension())) {
|
||||
String parentPath = dependency.getFilePath().toLowerCase();
|
||||
if (parentPath.contains(".jar")) {
|
||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||
final Dependency parent = findDependency(parentPath, engine.getDependencies());
|
||||
if (parent != null) {
|
||||
boolean remove = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(i.getType())) {
|
||||
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
||||
for (Identifier parentId : parent.getIdentifiers()) {
|
||||
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
||||
remove |= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!remove) { //we can escape early
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a given dependency, based on a given path, from a list of dependencies.
|
||||
*
|
||||
* @param dependencyPath the path of the dependency to return
|
||||
* @param dependencies the collection of dependencies to search
|
||||
* @return the dependency object for the given path, otherwise null
|
||||
*/
|
||||
private Dependency findDependency(String dependencyPath, List<Dependency> dependencies) {
|
||||
for (Dependency d : dependencies) {
|
||||
if (d.getFilePath().equalsIgnoreCase(dependencyPath)) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a full CPE and returns the CPE trimmed to include only vendor and product.
|
||||
*
|
||||
* @param value the CPE value to trim
|
||||
* @return a CPE value that only includes the vendor and product
|
||||
*/
|
||||
private String trimCpeToVendor(String value) {
|
||||
//cpe:/a:jruby:jruby:1.0.8
|
||||
final int pos1 = value.indexOf(":", 7); //right of vendor
|
||||
final int pos2 = value.indexOf(":", pos1 + 1); //right of product
|
||||
if (pos2 < 0) {
|
||||
return value;
|
||||
} else {
|
||||
return value.substring(0, pos2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
|
||||
//strip any path information that may get added by ArchiveAnalyzer, etc.
|
||||
final File f = new File(dependency.getFileName());
|
||||
final File f = dependency.getActualFile();
|
||||
String fileName = f.getName();
|
||||
|
||||
//remove file extension
|
||||
|
||||
@@ -64,7 +64,6 @@ import org.owasp.dependencycheck.jaxb.pom.MavenNamespaceFilter;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.License;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Model;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Organization;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Parent;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.NonClosingStream;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -74,7 +73,6 @@ import org.xml.sax.XMLFilter;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
*
|
||||
* Used to load a JAR file and collect information that can be used to determine the associated CPE.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
@@ -138,7 +136,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
"include-resource",
|
||||
"embed-dependency",
|
||||
"ipojo-components",
|
||||
"ipojo-extension");
|
||||
"ipojo-extension",
|
||||
"eclipse-sourcereferences");
|
||||
/**
|
||||
* item in some manifest, should be considered medium confidence.
|
||||
*/
|
||||
@@ -170,7 +169,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
public JarAnalyzer() {
|
||||
try {
|
||||
final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated");
|
||||
//final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated");
|
||||
final JAXBContext jaxbContext = JAXBContext.newInstance(Model.class);
|
||||
pomUnmarshaller = jaxbContext.createUnmarshaller();
|
||||
} catch (JAXBException ex) { //guess we will just have a null pointer exception later...
|
||||
LOGGER.log(Level.SEVERE, "Unable to load parser. See the log for more details.");
|
||||
@@ -293,13 +293,27 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
return false;
|
||||
}
|
||||
File externalPom = null;
|
||||
if (pomEntries.isEmpty()) {
|
||||
return false;
|
||||
if (dependency.getActualFilePath().matches(".*\\.m2.repository\\b.*")) {
|
||||
String pomPath = dependency.getActualFilePath();
|
||||
pomPath = pomPath.substring(0, pomPath.lastIndexOf('.')) + ".pom";
|
||||
externalPom = new File(pomPath);
|
||||
if (externalPom.isFile()) {
|
||||
pomEntries.add(pomPath);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (String path : pomEntries) {
|
||||
Properties pomProperties = null;
|
||||
try {
|
||||
pomProperties = retrievePomProperties(path, jar);
|
||||
if (externalPom == null) {
|
||||
pomProperties = retrievePomProperties(path, jar);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore this, failed reading a non-existent pom.properties", ex);
|
||||
}
|
||||
@@ -313,19 +327,23 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String displayPath = String.format("%s%s%s",
|
||||
dependency.getFilePath(),
|
||||
File.separator,
|
||||
path); //.replaceAll("[\\/]", File.separator));
|
||||
path);
|
||||
final String displayName = String.format("%s%s%s",
|
||||
dependency.getFileName(),
|
||||
File.separator,
|
||||
path); //.replaceAll("[\\/]", File.separator));
|
||||
path);
|
||||
|
||||
newDependency.setFileName(displayName);
|
||||
newDependency.setFilePath(displayPath);
|
||||
addPomEvidence(newDependency, pom, pomProperties);
|
||||
setPomEvidence(newDependency, pom, pomProperties, null);
|
||||
engine.getDependencies().add(newDependency);
|
||||
Collections.sort(engine.getDependencies());
|
||||
} else {
|
||||
pom = retrievePom(path, jar);
|
||||
if (externalPom == null) {
|
||||
pom = retrievePom(path, jar);
|
||||
} else {
|
||||
pom = retrievePom(externalPom);
|
||||
}
|
||||
foundSomething |= setPomEvidence(dependency, pom, pomProperties, classes);
|
||||
}
|
||||
} catch (AnalysisException ex) {
|
||||
@@ -345,16 +363,25 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @return a Properties object or null if no pom.properties was found
|
||||
* @throws IOException thrown if there is an exception reading the pom.properties
|
||||
*/
|
||||
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "OS_OPEN_STREAM",
|
||||
justification = "The reader is closed by closing the zipEntry")
|
||||
private Properties retrievePomProperties(String path, final JarFile jar) throws IOException {
|
||||
Properties pomProperties = null;
|
||||
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
||||
final ZipEntry propEntry = jar.getEntry(propPath);
|
||||
if (propEntry != null) {
|
||||
final Reader reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||
pomProperties = new Properties();
|
||||
pomProperties.load(reader);
|
||||
Reader reader = null;
|
||||
try {
|
||||
reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||
pomProperties = new Properties();
|
||||
pomProperties.load(reader);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "close error", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pomProperties;
|
||||
}
|
||||
@@ -514,6 +541,41 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the specified POM and converts it to a Model.
|
||||
*
|
||||
* @param file the pom.xml file
|
||||
* @return returns a
|
||||
* @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
|
||||
* {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
|
||||
*/
|
||||
private Model retrievePom(File file) throws AnalysisException {
|
||||
Model model = null;
|
||||
try {
|
||||
final FileInputStream stream = new FileInputStream(file);
|
||||
final InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
|
||||
final InputSource xml = new InputSource(reader);
|
||||
final SAXSource source = new SAXSource(xml);
|
||||
model = readPom(source);
|
||||
} catch (SecurityException ex) {
|
||||
final String msg = String.format("Unable to parse pom '%s'; invalid signature", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new AnalysisException(ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to parse pom '%s'(IO Exception)", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
throw new AnalysisException(ex);
|
||||
} catch (Throwable ex) {
|
||||
final String msg = String.format("Unexpected error during parsing of the pom '%s'", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
throw new AnalysisException(ex);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the specified POM from a jar file and converts it to a Model.
|
||||
*
|
||||
@@ -558,37 +620,90 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private boolean setPomEvidence(Dependency dependency, Model pom, Properties pomProperties, ArrayList<ClassNameInformation> classes) {
|
||||
boolean foundSomething = false;
|
||||
boolean addAsIdentifier = true;
|
||||
if (pom == null) {
|
||||
return foundSomething;
|
||||
}
|
||||
String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
||||
groupid = groupid.substring(4);
|
||||
String parentGroupId = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentGroupId = interpolateString(pom.getParent().getGroupId(), pomProperties);
|
||||
if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
groupid = parentGroupId;
|
||||
}
|
||||
}
|
||||
final String originalGroupID = groupid;
|
||||
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
foundSomething = true;
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGHEST);
|
||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||
addMatchingValues(classes, groupid, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, groupid, dependency.getProductEvidence());
|
||||
if (parentGroupId != null && !parentGroupId.isEmpty() && !parentGroupId.equals(groupid)) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.MEDIUM);
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.LOW);
|
||||
addMatchingValues(classes, parentGroupId, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, parentGroupId, dependency.getProductEvidence());
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
|
||||
String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
||||
String parentArtifactId = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentArtifactId = interpolateString(pom.getParent().getArtifactId(), pomProperties);
|
||||
if ((artifactid == null || artifactid.isEmpty()) && parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||
artifactid = parentArtifactId;
|
||||
}
|
||||
}
|
||||
final String originalArtifactID = artifactid;
|
||||
if (artifactid != null && !artifactid.isEmpty()) {
|
||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
foundSomething = true;
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGH);
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGHEST);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
addMatchingValues(classes, artifactid, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, artifactid, dependency.getProductEvidence());
|
||||
if (parentArtifactId != null && !parentArtifactId.isEmpty() && !parentArtifactId.equals(artifactid)) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.MEDIUM);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.LOW);
|
||||
addMatchingValues(classes, parentArtifactId, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, parentArtifactId, dependency.getProductEvidence());
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
//version
|
||||
final String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
String parentVersion = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentVersion = interpolateString(pom.getParent().getVersion(), pomProperties);
|
||||
if ((version == null || version.isEmpty()) && parentVersion != null && !parentVersion.isEmpty()) {
|
||||
version = parentVersion;
|
||||
}
|
||||
}
|
||||
|
||||
if (version != null && !version.isEmpty()) {
|
||||
foundSomething = true;
|
||||
dependency.getVersionEvidence().addEvidence("pom", "version", version, Confidence.HIGHEST);
|
||||
if (parentVersion != null && !parentVersion.isEmpty() && !parentVersion.equals(version)) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent-version", version, Confidence.LOW);
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
|
||||
if (addAsIdentifier) {
|
||||
dependency.addIdentifier("maven", String.format("%s:%s:%s", originalGroupID, originalArtifactID, version), null, Confidence.LOW);
|
||||
}
|
||||
|
||||
// org name
|
||||
final Organization org = pom.getOrganization();
|
||||
if (org != null && org.getName() != null) {
|
||||
@@ -647,7 +762,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
//TODO remove weighting
|
||||
vendor.addWeighting(entry.getKey());
|
||||
if (addPackagesAsEvidence && entry.getKey().length() > 1) {
|
||||
vendor.addEvidence("jar", "package", entry.getKey(), Confidence.LOW);
|
||||
vendor.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,7 +771,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (ratio > 0.5) {
|
||||
product.addWeighting(entry.getKey());
|
||||
if (addPackagesAsEvidence && entry.getKey().length() > 1) {
|
||||
product.addEvidence("jar", "package", entry.getKey(), Confidence.LOW);
|
||||
product.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -690,7 +805,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-src.jar")
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
|
||||
LOGGER.log(Level.INFO,
|
||||
LOGGER.log(Level.FINE,
|
||||
String.format("Jar file '%s' does not contain a manifest.",
|
||||
dependency.getFileName()));
|
||||
}
|
||||
@@ -764,6 +879,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
&& !key.endsWith("class-path")
|
||||
&& !key.endsWith("-scm") //todo change this to a regex?
|
||||
&& !key.startsWith("scm-")
|
||||
&& !value.trim().startsWith("scm:")
|
||||
&& !isImportPackage(key, value)
|
||||
&& !isPackage(key, value)) {
|
||||
|
||||
@@ -1111,7 +1227,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param evidence the evidence collection to add new entries too
|
||||
*/
|
||||
private void addMatchingValues(ArrayList<ClassNameInformation> classes, String value, EvidenceCollection evidence) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
if (value == null || value.isEmpty() || classes == null || classes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final String text = value.toLowerCase();
|
||||
@@ -1138,93 +1254,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds evidence from the POM to the dependency. This includes the GAV and in some situations the parent GAV if
|
||||
* specified.
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
* @param pom the POM data
|
||||
* @param pomProperties the properties file associated with the pom
|
||||
*/
|
||||
private void addPomEvidence(Dependency dependency, Model pom, Properties pomProperties) {
|
||||
if (pom == null) {
|
||||
return;
|
||||
}
|
||||
String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
||||
groupid = groupid.substring(4);
|
||||
}
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGH);
|
||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||
}
|
||||
String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
||||
if (artifactid != null && !artifactid.isEmpty()) {
|
||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
}
|
||||
final String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
if (version != null && !version.isEmpty()) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "version", version, Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
final Parent parent = pom.getParent(); //grab parent GAV
|
||||
if (parent != null) {
|
||||
final String parentGroupId = interpolateString(parent.getGroupId(), pomProperties);
|
||||
if (parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
if (groupid == null || groupid.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.MEDIUM);
|
||||
}
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.LOW);
|
||||
}
|
||||
final String parentArtifactId = interpolateString(parent.getArtifactId(), pomProperties);
|
||||
if (parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||
if (artifactid == null || artifactid.isEmpty()) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.MEDIUM);
|
||||
}
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.LOW);
|
||||
}
|
||||
final String parentVersion = interpolateString(parent.getVersion(), pomProperties);
|
||||
if (parentVersion != null && !parentVersion.isEmpty()) {
|
||||
if (version == null || version.isEmpty()) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent.version", parentVersion, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent.version", parentVersion, Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
// org name
|
||||
final Organization org = pom.getOrganization();
|
||||
if (org != null && org.getName() != null) {
|
||||
final String orgName = interpolateString(org.getName(), pomProperties);
|
||||
if (orgName != null && !orgName.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Confidence.HIGH);
|
||||
}
|
||||
}
|
||||
//pom name
|
||||
final String pomName = interpolateString(pom.getName(), pomProperties);
|
||||
if (pomName != null && !pomName.isEmpty()) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
}
|
||||
|
||||
//Description
|
||||
if (pom.getDescription() != null) {
|
||||
final String description = interpolateString(pom.getDescription(), pomProperties);
|
||||
if (description != null && !description.isEmpty()) {
|
||||
addDescription(dependency, description, "pom", "description");
|
||||
}
|
||||
}
|
||||
extractLicense(pom, pomProperties, dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the license information from the pom and adds it to the dependency.
|
||||
*
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
@@ -48,6 +49,11 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The default URL - this will be used by the CentralAnalyzer to determine whether to enable this.
|
||||
*/
|
||||
public static final String DEFAULT_URL = "https://repository.sonatype.org/service/local/";
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -73,6 +79,47 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private NexusSearch searcher;
|
||||
|
||||
/**
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
private final boolean enabled = checkEnabled();
|
||||
|
||||
/**
|
||||
* Determines if this analyzer is enabled
|
||||
*
|
||||
* @return <code>true</code> if the analyzer is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
private boolean checkEnabled() {
|
||||
/* Enable this analyzer ONLY if the Nexus URL has been set to something
|
||||
other than the default one (if it's the default one, we'll use the
|
||||
central one) and it's enabled by the user.
|
||||
*/
|
||||
boolean retval = false;
|
||||
try {
|
||||
if ((!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL)))
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
|
||||
LOGGER.info("Enabling Nexus analyzer");
|
||||
retval = true;
|
||||
} else {
|
||||
LOGGER.info("Nexus analyzer disabled, using Central instead");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warning("Invalid setting. Disabling Nexus analyzer");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether to enable this analyzer or not.
|
||||
*
|
||||
* @return whether the analyzer should be enabled
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the analyzer once before any analysis is performed.
|
||||
*
|
||||
@@ -149,20 +196,12 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
|
||||
if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) {
|
||||
dependency.getVendorEvidence().addEvidence("nexus", "groupid", ma.getGroupId(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getArtifactId() != null && !"".equals(ma.getArtifactId())) {
|
||||
dependency.getProductEvidence().addEvidence("nexus", "artifactid", ma.getArtifactId(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getVersion() != null && !"".equals(ma.getVersion())) {
|
||||
dependency.getVersionEvidence().addEvidence("nexus", "version", ma.getVersion(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getArtifactUrl() != null && !"".equals(ma.getArtifactUrl())) {
|
||||
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl(), Confidence.HIGHEST);
|
||||
}
|
||||
dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
|
||||
LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Class of methods to search Maven Central via Central.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class CentralSearch {
|
||||
|
||||
/**
|
||||
* The URL for the Central service
|
||||
*/
|
||||
private final URL rootURL;
|
||||
|
||||
/**
|
||||
* Whether to use the Proxy when making requests
|
||||
*/
|
||||
private boolean useProxy;
|
||||
|
||||
/**
|
||||
* Used for logging.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralSearch.class.getName());
|
||||
|
||||
/**
|
||||
* Creates a NexusSearch for the given repository URL.
|
||||
*
|
||||
* @param rootURL the URL of the repository on which searches should execute. Only parameters are added to this (so
|
||||
* it should end in /select)
|
||||
*/
|
||||
public CentralSearch(URL rootURL) {
|
||||
this.rootURL = rootURL;
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)) {
|
||||
useProxy = true;
|
||||
LOGGER.fine("Using proxy");
|
||||
} else {
|
||||
useProxy = false;
|
||||
LOGGER.fine("Not using proxy");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the configured Central URL for the given sha1 hash. If the artifact is found, a
|
||||
* <code>MavenArtifact</code> is populated with the GAV.
|
||||
*
|
||||
* @param sha1 the SHA-1 hash string for which to search
|
||||
* @return the populated Maven GAV.
|
||||
* @throws IOException if it's unable to connect to the specified repository or if the specified artifact is not
|
||||
* found.
|
||||
*/
|
||||
public List<MavenArtifact> searchSha1(String sha1) throws IOException {
|
||||
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
||||
throw new IllegalArgumentException("Invalid SHA1 format");
|
||||
}
|
||||
|
||||
final URL url = new URL(rootURL + String.format("?q=1:\"%s\"&wt=xml", sha1));
|
||||
|
||||
LOGGER.fine(String.format("Searching Central url %s", url.toString()));
|
||||
|
||||
// Determine if we need to use a proxy. The rules:
|
||||
// 1) If the proxy is set, AND the setting is set to true, use the proxy
|
||||
// 2) Otherwise, don't use the proxy (either the proxy isn't configured,
|
||||
// or proxy is specifically set to false)
|
||||
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
|
||||
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// JSON would be more elegant, but there's not currently a dependency
|
||||
// on JSON, so don't want to add one just for this
|
||||
conn.addRequestProperty("Accept", "application/xml");
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == 200) {
|
||||
boolean missing = false;
|
||||
try {
|
||||
final DocumentBuilder builder = DocumentBuilderFactory
|
||||
.newInstance().newDocumentBuilder();
|
||||
final Document doc = builder.parse(conn.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String numFound = xpath.evaluate("/response/result/@numFound", doc);
|
||||
if ("0".equals(numFound)) {
|
||||
missing = true;
|
||||
} else {
|
||||
final ArrayList<MavenArtifact> result = new ArrayList<MavenArtifact>();
|
||||
final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
|
||||
for (int i = 0; i < docs.getLength(); i++) {
|
||||
final String g = xpath.evaluate("./str[@name='g']", docs.item(i));
|
||||
LOGGER.finest(String.format("GroupId: %s", g));
|
||||
final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
|
||||
LOGGER.finest(String.format("ArtifactId: %s", a));
|
||||
final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
|
||||
LOGGER.finest(String.format("Version: %s", v));
|
||||
result.add(new MavenArtifact(g, a, v, url.toString()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Anything else is jacked up XML stuff that we really can't recover
|
||||
// from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (missing) {
|
||||
throw new FileNotFoundException("Artifact not found in Central");
|
||||
}
|
||||
} else {
|
||||
final String msg = String.format("Could not connect to Central received response code: %d %s",
|
||||
conn.getResponseCode(), conn.getResponseMessage());
|
||||
LOGGER.fine(msg);
|
||||
throw new IOException(msg);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.data.central</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* <p>
|
||||
* Contains classes related to searching Maven Central.</p>
|
||||
* <p>
|
||||
* These are used to abstract Maven Central searching away from OWASP Dependency Check so they can be reused elsewhere.</p>
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
@@ -54,6 +54,7 @@ import org.owasp.dependencycheck.utils.Pair;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class CpeMemoryIndex {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -160,7 +161,7 @@ public final class CpeMemoryIndex {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Analyzer createSearchingAnalyzer() {
|
||||
final Map fieldAnalyzers = new HashMap();
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||
productSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||
vendorSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||
|
||||
@@ -22,7 +22,7 @@ package org.owasp.dependencycheck.data.cpe;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class Fields {
|
||||
public final class Fields {
|
||||
|
||||
/**
|
||||
* The key for the name document id.
|
||||
@@ -36,7 +36,10 @@ public abstract class Fields {
|
||||
* The key for the product field.
|
||||
*/
|
||||
public static final String PRODUCT = "product";
|
||||
|
||||
/**
|
||||
* The key for the version field.
|
||||
* Private constructor as this is more of an enumeration rather then a full class.
|
||||
*/
|
||||
private Fields() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,12 @@ import java.util.logging.Logger;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class CweDB {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CweDB.class.getName());
|
||||
|
||||
/**
|
||||
* Empty private constructor as this is a utility class.
|
||||
*/
|
||||
@@ -55,7 +57,9 @@ public final class CweDB {
|
||||
final String filePath = "data/cwe.hashmap.serialized";
|
||||
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
||||
oin = new ObjectInputStream(input);
|
||||
return (HashMap<String, String>) oin.readObject();
|
||||
@SuppressWarnings("unchecked")
|
||||
final HashMap<String, String> ret = (HashMap<String, String>) oin.readObject();
|
||||
return ret;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
|
||||
@@ -64,7 +64,7 @@ public class NexusSearch {
|
||||
public NexusSearch(URL rootURL) {
|
||||
this.rootURL = rootURL;
|
||||
try {
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_URL)
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
||||
useProxy = true;
|
||||
LOGGER.fine("Using proxy");
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class ConnectionFactory {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
@@ -49,7 +50,7 @@ public final class ConnectionFactory {
|
||||
/**
|
||||
* The version of the current DB Schema.
|
||||
*/
|
||||
public static final String DB_SCHEMA_VERSION = "2.9";
|
||||
public static final String DB_SCHEMA_VERSION = Settings.getString(Settings.KEYS.DB_VERSION);
|
||||
/**
|
||||
* Resource location for SQL file used to create the database schema.
|
||||
*/
|
||||
@@ -111,7 +112,10 @@ public final class ConnectionFactory {
|
||||
//yes, yes - hard-coded password - only if there isn't one in the properties file.
|
||||
password = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
|
||||
try {
|
||||
connectionString = getConnectionString();
|
||||
connectionString = Settings.getConnectionString(
|
||||
Settings.KEYS.DB_CONNECTION_STRING,
|
||||
Settings.KEYS.DB_FILE_NAME,
|
||||
Settings.KEYS.DB_VERSION);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE,
|
||||
"Unable to retrieve the database connection string", ex);
|
||||
@@ -120,7 +124,7 @@ public final class ConnectionFactory {
|
||||
boolean shouldCreateSchema = false;
|
||||
try {
|
||||
if (connectionString.startsWith("jdbc:h2:file:")) { //H2
|
||||
shouldCreateSchema = !dbSchemaExists();
|
||||
shouldCreateSchema = !h2DataFileExists();
|
||||
LOGGER.log(Level.FINE, "Need to create DB Structure: {0}", shouldCreateSchema);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
@@ -217,51 +221,17 @@ public final class ConnectionFactory {
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured connection string. If using the embedded H2 database this function will also ensure the
|
||||
* data directory exists and if not create it.
|
||||
*
|
||||
* @return the connection string
|
||||
* @throws IOException thrown the data directory cannot be created
|
||||
*/
|
||||
private static String getConnectionString() throws IOException {
|
||||
final String connStr = Settings.getString(Settings.KEYS.DB_CONNECTION_STRING, "jdbc:h2:file:%s;AUTO_SERVER=TRUE");
|
||||
if (connStr.contains("%s")) {
|
||||
final String directory = getDataDirectory().getCanonicalPath();
|
||||
final File dataFile = new File(directory, "cve." + DB_SCHEMA_VERSION);
|
||||
LOGGER.log(Level.FINE, String.format("File path for H2 file: '%s'", dataFile.toString()));
|
||||
return String.format(connStr, dataFile.getAbsolutePath());
|
||||
}
|
||||
return connStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the directory that the JAR file exists in so that we can ensure we always use a common data directory
|
||||
* for the embedded H2 database. This is public solely for some unit tests; otherwise this should be private.
|
||||
*
|
||||
* @return the data directory to store data files
|
||||
* @throws IOException is thrown if an IOException occurs of course...
|
||||
*/
|
||||
public static File getDataDirectory() throws IOException {
|
||||
final File path = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
|
||||
if (!path.exists()) {
|
||||
if (!path.mkdirs()) {
|
||||
throw new IOException("Unable to create NVD CVE Data directory");
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the H2 database file exists. If it does not exist then the data structure will need to be created.
|
||||
*
|
||||
* @return true if the H2 database file does not exist; otherwise false
|
||||
* @throws IOException thrown if the data directory does not exist and cannot be created
|
||||
*/
|
||||
private static boolean dbSchemaExists() throws IOException {
|
||||
final File dir = getDataDirectory();
|
||||
final String name = String.format("cve.%s.h2.db", DB_SCHEMA_VERSION);
|
||||
final File file = new File(dir, name);
|
||||
private static boolean h2DataFileExists() throws IOException {
|
||||
final File dir = Settings.getDataDirectory();
|
||||
final String name = Settings.getString(Settings.KEYS.DB_FILE_NAME);
|
||||
final String fileName = String.format(name, DB_SCHEMA_VERSION);
|
||||
final File file = new File(dir, fileName);
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.owasp.dependencycheck.utils.Pair;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class CveDB {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -247,6 +248,7 @@ public class CveDB {
|
||||
/**
|
||||
* SQL Statement to retrieve a property from the database.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static final String SELECT_PROPERTY = "SELECT id, value FROM properties WHERE id = ?";
|
||||
/**
|
||||
* SQL Statement to insert a new property.
|
||||
@@ -259,6 +261,7 @@ public class CveDB {
|
||||
/**
|
||||
* SQL Statement to delete a property.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static final String DELETE_PROPERTY = "DELETE FROM properties WHERE id = ?";
|
||||
|
||||
//</editor-fold>
|
||||
@@ -303,14 +306,14 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown when there is an error retrieving the data from the DB
|
||||
*/
|
||||
public Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
||||
final HashSet data = new HashSet<Pair<String, String>>();
|
||||
final Set<Pair<String, String>> data = new HashSet<Pair<String, String>>();
|
||||
ResultSet rs = null;
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
|
||||
rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
data.add(new Pair(rs.getString(1), rs.getString(2)));
|
||||
data.add(new Pair<String, String>(rs.getString(1), rs.getString(2)));
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||
@@ -728,13 +731,15 @@ public class CveDB {
|
||||
* @param previous a flag indicating if previous versions of the product are vulnerable
|
||||
* @return true if the identified version is affected, otherwise false
|
||||
*/
|
||||
private boolean isAffected(String vendor, String product, DependencyVersion identifiedVersion, String cpeId, String previous) {
|
||||
protected boolean isAffected(String vendor, String product, DependencyVersion identifiedVersion, String cpeId, String previous) {
|
||||
boolean affected = false;
|
||||
final boolean isStruts = "apache".equals(vendor) && "struts".equals(product);
|
||||
final DependencyVersion v = parseDependencyVersion(cpeId);
|
||||
final boolean prevAffected = previous != null && !previous.isEmpty();
|
||||
if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
|
||||
if (v == null || "-".equals(v.toString())) {
|
||||
if (v == null || "-".equals(v.toString())) { //all versions
|
||||
affected = true;
|
||||
} else if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
|
||||
if (prevAffected) {
|
||||
affected = true;
|
||||
}
|
||||
} else if (identifiedVersion.equals(v) || (prevAffected && identifiedVersion.compareTo(v) < 0)) {
|
||||
|
||||
@@ -142,8 +142,8 @@ public class DatabaseProperties {
|
||||
*
|
||||
* @return a map of the database meta data
|
||||
*/
|
||||
public Map getMetaData() {
|
||||
final TreeMap map = new TreeMap();
|
||||
public Map<String, String> getMetaData() {
|
||||
final TreeMap<String, String> map = new TreeMap<String, String>();
|
||||
for (Entry<Object, Object> entry : properties.entrySet()) {
|
||||
final String key = (String) entry.getKey();
|
||||
if (!"version".equals(key)) {
|
||||
@@ -156,10 +156,10 @@ public class DatabaseProperties {
|
||||
map.put(key, formatted);
|
||||
} catch (Throwable ex) { //deliberately being broad in this catch clause
|
||||
LOGGER.log(Level.FINE, "Unable to parse timestamp from DB", ex);
|
||||
map.put(key, entry.getValue());
|
||||
map.put(key, (String) entry.getValue());
|
||||
}
|
||||
} else {
|
||||
map.put(key, entry.getValue());
|
||||
map.put(key, (String) entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* Class responsible for updating the NVD CVE and CPE data stores.
|
||||
@@ -54,7 +55,11 @@ public class NvdCveUpdater implements CachedWebDataSource {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (DownloadFailedException ex) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unable to download the NVD CVE data, unable to update the data to use the most current data.");
|
||||
"Unable to download the NVD CVE data; the results may not include the most recent CPE/CVEs from the NVD.");
|
||||
if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"If you are behind a proxy you may need to configure dependency-check to use the proxy.");
|
||||
}
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED;
|
||||
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.data.update.task.CallableDownloadTask;
|
||||
import org.owasp.dependencycheck.data.update.task.DownloadTask;
|
||||
import org.owasp.dependencycheck.data.update.task.ProcessTask;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
@@ -122,7 +122,7 @@ public class StandardUpdate {
|
||||
final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<Future<Future<ProcessTask>>>(maxUpdates);
|
||||
for (NvdCveInfo cve : updateable) {
|
||||
if (cve.getNeedsUpdate()) {
|
||||
final CallableDownloadTask call = new CallableDownloadTask(cve, processExecutor, cveDB, Settings.getInstance());
|
||||
final DownloadTask call = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance());
|
||||
downloadFutures.add(downloadExecutors.submit(call));
|
||||
}
|
||||
}
|
||||
@@ -178,7 +178,9 @@ public class StandardUpdate {
|
||||
|
||||
if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
|
||||
properties.save(updateable.get(MODIFIED));
|
||||
LOGGER.log(Level.INFO, "Begin database maintenance.");
|
||||
cveDB.cleanupDatabase();
|
||||
LOGGER.log(Level.INFO, "End database maintenance.");
|
||||
}
|
||||
} finally {
|
||||
closeDataStores();
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
package org.owasp.dependencycheck.data.update.task;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -25,6 +28,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.update.NvdCveInfo;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
@@ -37,12 +42,12 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CallableDownloadTask.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(DownloadTask.class.getName());
|
||||
|
||||
/**
|
||||
* Simple constructor for the callable download task.
|
||||
@@ -54,7 +59,7 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
* the dependencies have a correct reference to the global settings.
|
||||
* @throws UpdateException thrown if temporary files could not be created
|
||||
*/
|
||||
public CallableDownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
|
||||
public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
|
||||
this.nvdCveInfo = nvdCveInfo;
|
||||
this.processorService = processor;
|
||||
this.cveDB = cveDB;
|
||||
@@ -188,13 +193,25 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
} catch (DownloadFailedException ex) {
|
||||
msg = String.format("Download Failed for NVD CVE - %s%nSome CVEs may not be reported.", nvdCveInfo.getId());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"If you are behind a proxy you may need to configure dependency-check to use the proxy.");
|
||||
}
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
return null;
|
||||
}
|
||||
if (url1.toExternalForm().endsWith(".xml.gz")) {
|
||||
extractGzip(first);
|
||||
}
|
||||
if (url2.toExternalForm().endsWith(".xml.gz")) {
|
||||
extractGzip(second);
|
||||
}
|
||||
|
||||
msg = String.format("Download Complete for NVD CVE - %s", nvdCveInfo.getId());
|
||||
LOGGER.log(Level.INFO, msg);
|
||||
|
||||
if (this.processorService == null) {
|
||||
return null;
|
||||
}
|
||||
final ProcessTask task = new ProcessTask(cveDB, this, settings);
|
||||
return this.processorService.submit(task);
|
||||
|
||||
@@ -203,7 +220,7 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "Download Task Failed", ex);
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -233,4 +250,48 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file
|
||||
* specified.
|
||||
*
|
||||
* @param file the archive file
|
||||
* @throws FileNotFoundException thrown if the file does not exist
|
||||
* @throws IOException thrown if there is an error extracting the file.
|
||||
*/
|
||||
private void extractGzip(File file) throws FileNotFoundException, IOException {
|
||||
final String originalPath = file.getPath();
|
||||
File gzip = new File(originalPath + ".gz");
|
||||
if (gzip.isFile()) {
|
||||
gzip.delete();
|
||||
}
|
||||
if (!file.renameTo(gzip)) {
|
||||
throw new IOException("Unable to rename '" + file.getPath() + "'");
|
||||
}
|
||||
final File newfile = new File(originalPath);
|
||||
|
||||
final byte[] buffer = new byte[4096];
|
||||
|
||||
GZIPInputStream cin = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
cin = new GZIPInputStream(new FileInputStream(gzip));
|
||||
out = new FileOutputStream(newfile);
|
||||
|
||||
int len;
|
||||
while ((len = cin.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
} finally {
|
||||
if (cin != null) {
|
||||
cin.close();
|
||||
}
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
if (gzip.isFile()) {
|
||||
FileUtils.deleteQuietly(gzip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
/**
|
||||
* A reference to the callable download task.
|
||||
*/
|
||||
private final CallableDownloadTask filePair;
|
||||
private final DownloadTask filePair;
|
||||
/**
|
||||
* A reference to the properties.
|
||||
*/
|
||||
@@ -97,7 +97,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
* @param settings a reference to the global settings object; this is necessary so that when the thread is started
|
||||
* the dependencies have a correct reference to the global settings.
|
||||
*/
|
||||
public ProcessTask(final CveDB cveDB, final CallableDownloadTask filePair, Settings settings) {
|
||||
public ProcessTask(final CveDB cveDB, final DownloadTask filePair, Settings settings) {
|
||||
this.cveDB = cveDB;
|
||||
this.filePair = filePair;
|
||||
this.properties = cveDB.getDatabaseProperties();
|
||||
@@ -119,7 +119,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
} catch (UpdateException ex) {
|
||||
this.exception = ex;
|
||||
} finally {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(false);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@ package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Checksum;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
|
||||
@@ -35,7 +37,7 @@ import org.owasp.dependencycheck.utils.FileUtils;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Dependency implements Comparable<Dependency> {
|
||||
public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
@@ -177,6 +179,33 @@ public class Dependency implements Comparable<Dependency> {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file name to display in reports.
|
||||
*/
|
||||
private String displayName = null;
|
||||
|
||||
/**
|
||||
* Sets the file name to display in reports.
|
||||
*
|
||||
* @param displayName the name to display
|
||||
*/
|
||||
public void setDisplayFileName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name to display in reports; if no display file name has been set it will default to the actual
|
||||
* file name.
|
||||
*
|
||||
* @return the file name to display
|
||||
*/
|
||||
public String getDisplayFileName() {
|
||||
if (displayName == null) {
|
||||
return this.fileName;
|
||||
}
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the file path of the dependency.</p>
|
||||
@@ -288,6 +317,41 @@ public class Dependency implements Comparable<Dependency> {
|
||||
this.identifiers.add(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the maven artifact as evidence.
|
||||
*
|
||||
* @param source The source of the evidence
|
||||
* @param mavenArtifact The maven artifact
|
||||
* @param confidence The confidence level of this evidence
|
||||
*/
|
||||
public void addAsEvidence(String source, MavenArtifact mavenArtifact, Confidence confidence) {
|
||||
if (mavenArtifact.getGroupId() != null && !mavenArtifact.getGroupId().isEmpty()) {
|
||||
this.getVendorEvidence().addEvidence(source, "groupid", mavenArtifact.getGroupId(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getArtifactId() != null && !mavenArtifact.getArtifactId().isEmpty()) {
|
||||
this.getProductEvidence().addEvidence(source, "artifactid", mavenArtifact.getArtifactId(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getVersion() != null && !mavenArtifact.getVersion().isEmpty()) {
|
||||
this.getVersionEvidence().addEvidence(source, "version", mavenArtifact.getVersion(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getArtifactUrl() != null && !mavenArtifact.getArtifactUrl().isEmpty()) {
|
||||
boolean found = false;
|
||||
for (Identifier i : this.getIdentifiers()) {
|
||||
if ("maven".equals(i.getType()) && i.getValue().equals(mavenArtifact.toString())) {
|
||||
found = true;
|
||||
i.setConfidence(Confidence.HIGHEST);
|
||||
i.setUrl(mavenArtifact.getArtifactUrl());
|
||||
LOGGER.fine(String.format("Already found identifier %s. Confidence set to highest", i.getValue()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LOGGER.fine(String.format("Adding new maven identifier %s", mavenArtifact.toString()));
|
||||
this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the list of detected Identifiers for the dependency file.
|
||||
*
|
||||
@@ -296,6 +360,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void addIdentifier(Identifier identifier) {
|
||||
this.identifiers.add(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of identifiers that have been suppressed.
|
||||
*/
|
||||
@@ -369,6 +434,15 @@ public class Dependency implements Comparable<Dependency> {
|
||||
return EvidenceCollection.merge(this.productEvidence, this.vendorEvidence, this.versionEvidence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evidence used to identify this dependency.
|
||||
*
|
||||
* @return an EvidenceCollection.
|
||||
*/
|
||||
public Set<Evidence> getEvidenceForDisplay() {
|
||||
return EvidenceCollection.mergeForDisplay(this.productEvidence, this.vendorEvidence, this.versionEvidence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evidence used to identify this dependency.
|
||||
*
|
||||
@@ -404,6 +478,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public EvidenceCollection getVersionEvidence() {
|
||||
return this.versionEvidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of the JAR file.
|
||||
*/
|
||||
@@ -426,6 +501,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* The license that this dependency uses.
|
||||
*/
|
||||
@@ -448,6 +524,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void setLicense(String license) {
|
||||
this.license = license;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of vulnerabilities for this dependency.
|
||||
*/
|
||||
@@ -503,6 +580,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void addVulnerability(Vulnerability vulnerability) {
|
||||
this.vulnerabilities.add(vulnerability);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of related dependencies.
|
||||
*/
|
||||
@@ -542,7 +620,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
* @return an integer representing the natural ordering
|
||||
*/
|
||||
public int compareTo(Dependency o) {
|
||||
return this.getFileName().compareToIgnoreCase(o.getFileName());
|
||||
return this.getFilePath().compareToIgnoreCase(o.getFilePath());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Evidence is a piece of information about a Dependency.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Evidence implements Comparable<Evidence> {
|
||||
public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
|
||||
/**
|
||||
* Creates a new Evidence object.
|
||||
@@ -220,22 +222,95 @@ public class Evidence implements Comparable<Evidence> {
|
||||
* @return an integer indicating the ordering of the two objects
|
||||
*/
|
||||
public int compareTo(Evidence o) {
|
||||
if (source.equals(o.source)) {
|
||||
if (name.equals(o.name)) {
|
||||
if (value.equals(o.value)) {
|
||||
if (confidence.equals(o.confidence)) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
if (equalsWithNullCheck(source, o.source)) {
|
||||
if (equalsWithNullCheck(name, o.name)) {
|
||||
if (equalsWithNullCheck(value, o.value)) {
|
||||
if (equalsWithNullCheck(confidence, o.confidence)) {
|
||||
return 0; //they are equal
|
||||
} else {
|
||||
return confidence.compareTo(o.confidence);
|
||||
return compareToWithNullCheck(confidence, o.confidence);
|
||||
}
|
||||
} else {
|
||||
return value.compareToIgnoreCase(o.value);
|
||||
return compareToIgnoreCaseWithNullCheck(value, o.value);
|
||||
}
|
||||
} else {
|
||||
return name.compareToIgnoreCase(o.name);
|
||||
return compareToIgnoreCaseWithNullCheck(name, o.name);
|
||||
}
|
||||
} else {
|
||||
return source.compareToIgnoreCase(o.source);
|
||||
return compareToIgnoreCaseWithNullCheck(source, o.source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality check with an exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private boolean equalsWithNullCheck(String me, String other) {
|
||||
if (me == null && other == null) {
|
||||
return true;
|
||||
} else if (me == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return me.equals(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality check with an exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private boolean equalsWithNullCheck(Confidence me, Confidence other) {
|
||||
if (me == null && other == null) {
|
||||
return true;
|
||||
} else if (me == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return me.equals(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link java.lang.String#compareToIgnoreCase(java.lang.String) String.compareToIgnoreCase} with an
|
||||
* exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private int compareToIgnoreCaseWithNullCheck(String me, String other) {
|
||||
if (me == null && other == null) {
|
||||
return 0;
|
||||
} else if (me == null) {
|
||||
return -1; //the other string is greater then me
|
||||
} else if (other == null) {
|
||||
return 1; //me is greater then the other string
|
||||
}
|
||||
return me.compareToIgnoreCase(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link java.lang.Enum#compareTo(java.lang.Enum) Enum.compareTo} with an exhaustive, possibly
|
||||
* duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private int compareToWithNullCheck(Confidence me, Confidence other) {
|
||||
if (me == null && other == null) {
|
||||
return 0;
|
||||
} else if (me == null) {
|
||||
return -1; //the other string is greater then me
|
||||
} else if (other == null) {
|
||||
return 1; //me is greater then the other string
|
||||
}
|
||||
return me.compareTo(other);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -36,7 +37,7 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class EvidenceCollection implements Iterable<Evidence> {
|
||||
public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
@@ -311,6 +312,26 @@ public class EvidenceCollection implements Iterable<Evidence> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple EvidenceCollections together; flattening all of the evidence items by removing the confidence.
|
||||
*
|
||||
* @param ec One or more EvidenceCollections
|
||||
* @return new set of evidence resulting from merging the evidence in the collections
|
||||
*/
|
||||
public static Set<Evidence> mergeForDisplay(EvidenceCollection... ec) {
|
||||
final Set<Evidence> ret = new TreeSet<Evidence>();
|
||||
for (EvidenceCollection col : ec) {
|
||||
for (Evidence e : col) {
|
||||
if (e.isUsed()) {
|
||||
final Evidence newEvidence = new Evidence(e.getSource(), e.getName(), e.getValue(), null);
|
||||
newEvidence.setUsed(true);
|
||||
ret.add(newEvidence);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string of evidence 'values'.
|
||||
*
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Identifier implements Comparable<Identifier> {
|
||||
public class Identifier implements Serializable, Comparable<Identifier> {
|
||||
|
||||
/**
|
||||
* Constructs a new Identifier with the specified data.
|
||||
|
||||
@@ -77,19 +77,19 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
if (cpeName != null && cpeName.length() > 7) {
|
||||
final String[] data = cpeName.substring(7).split(":");
|
||||
if (data.length >= 1) {
|
||||
this.setVendor(URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8"));
|
||||
this.setVendor(urlDecode(data[0]));
|
||||
}
|
||||
if (data.length >= 2) {
|
||||
this.setProduct(URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8"));
|
||||
this.setProduct(urlDecode(data[1]));
|
||||
}
|
||||
if (data.length >= 3) {
|
||||
version = URLDecoder.decode(data[2].replace("+", "%2B"), "UTF-8");
|
||||
version = urlDecode(data[2]);
|
||||
}
|
||||
if (data.length >= 4) {
|
||||
revision = URLDecoder.decode(data[3].replace("+", "%2B"), "UTF-8");
|
||||
revision = urlDecode(data[3]);
|
||||
}
|
||||
if (data.length >= 5) {
|
||||
edition = URLDecoder.decode(data[4].replace("+", "%2B"), "UTF-8");
|
||||
edition = urlDecode(data[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,4 +341,25 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
public void setEdition(String edition) {
|
||||
this.edition = edition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces '+' with '%2B' and then URL Decodes the string attempting first UTF-8, then ASCII, then default.
|
||||
*
|
||||
* @param string the string to URL Decode
|
||||
* @return the URL Decoded string
|
||||
*/
|
||||
private String urlDecode(String string) {
|
||||
final String text = string.replace("+", "%2B");
|
||||
String result;
|
||||
try {
|
||||
result = URLDecoder.decode(text, "UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
try {
|
||||
result = URLDecoder.decode(text, "ASCII");
|
||||
} catch (UnsupportedEncodingException ex1) {
|
||||
result = URLDecoder.decode(text);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class ScanAgentException extends IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NoDataException.
|
||||
* Creates a new ScanAgentException.
|
||||
*
|
||||
* @param ex the cause of the exception.
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -167,15 +167,28 @@ public class ReportGenerator {
|
||||
*/
|
||||
public void generateReports(String outputDir, String outputFormat) throws IOException, Exception {
|
||||
final String format = outputFormat.toUpperCase();
|
||||
final String pathToCheck = outputDir.toLowerCase();
|
||||
if (format.matches("^(XML|HTML|VULN|ALL)$")) {
|
||||
if ("XML".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.XML);
|
||||
if (pathToCheck.endsWith(".xml")) {
|
||||
generateReport("XmlReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.XML);
|
||||
}
|
||||
}
|
||||
if ("HTML".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.HTML);
|
||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
||||
generateReport("HtmlReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.HTML);
|
||||
}
|
||||
}
|
||||
if ("VULN".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.VULN);
|
||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
||||
generateReport("VulnReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.VULN);
|
||||
}
|
||||
}
|
||||
if ("ALL".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.ALL);
|
||||
|
||||
@@ -54,6 +54,10 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
* The CWE element name.
|
||||
*/
|
||||
public static final String CWE = "cwe";
|
||||
/**
|
||||
* The GAV element name.
|
||||
*/
|
||||
public static final String GAV = "gav";
|
||||
/**
|
||||
* The cvssBelow element name.
|
||||
*/
|
||||
@@ -95,13 +99,16 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
*/
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
currentAttributes = null;
|
||||
currentAttributes = attributes;
|
||||
currentText = new StringBuffer();
|
||||
|
||||
if (SUPPRESS.equals(qName)) {
|
||||
rule = new SuppressionRule();
|
||||
} else if (FILE_PATH.equals(qName)) {
|
||||
currentAttributes = attributes;
|
||||
final String base = currentAttributes.getValue("base");
|
||||
if (base != null) {
|
||||
rule.setBase(Boolean.parseBoolean(base));
|
||||
} else {
|
||||
rule.setBase(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +130,9 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
rule.setFilePath(pt);
|
||||
} else if (SHA1.equals(qName)) {
|
||||
rule.setSha1(currentText.toString());
|
||||
} else if (GAV.equals(qName)) {
|
||||
final PropertyType pt = processPropertyType();
|
||||
rule.setGav(pt);
|
||||
} else if (CPE.equals(qName)) {
|
||||
final PropertyType pt = processPropertyType();
|
||||
rule.addCpe(pt);
|
||||
|
||||
@@ -26,11 +26,6 @@ import java.io.IOException;
|
||||
*/
|
||||
public class SuppressionParseException extends IOException {
|
||||
|
||||
/**
|
||||
* The serial version UID.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SuppressionParseException.
|
||||
*/
|
||||
@@ -50,7 +45,7 @@ public class SuppressionParseException extends IOException {
|
||||
/**
|
||||
* Creates a new SuppressionParseException.
|
||||
*
|
||||
* @param ex the cause of the download failure.
|
||||
* @param ex the cause of the parse exception
|
||||
*/
|
||||
public SuppressionParseException(Throwable ex) {
|
||||
super(ex);
|
||||
@@ -60,7 +55,7 @@ public class SuppressionParseException extends IOException {
|
||||
* Creates a new SuppressionParseException.
|
||||
*
|
||||
* @param msg a message for the exception.
|
||||
* @param ex the cause of the download failure.
|
||||
* @param ex the cause of the parse exception
|
||||
*/
|
||||
public SuppressionParseException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
|
||||
@@ -66,10 +66,35 @@ public class SuppressionParser {
|
||||
* @throws SuppressionParseException thrown if the xml file cannot be parsed
|
||||
*/
|
||||
public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
return parseSuppressionRules(fis);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new SuppressionParseException(ex);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to close stream", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given xml stream and returns a list of the suppression rules contained.
|
||||
*
|
||||
* @param inputStream an InputStream containing suppression rues
|
||||
* @return a list of suppression rules
|
||||
* @throws SuppressionParseException if the xml cannot be parsed
|
||||
*/
|
||||
public List<SuppressionRule> parseSuppressionRules(InputStream inputStream) throws SuppressionParseException {
|
||||
try {
|
||||
final InputStream schemaStream = this.getClass().getClassLoader().getResourceAsStream("schema/suppression.xsd");
|
||||
final SuppressionHandler handler = new SuppressionHandler();
|
||||
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
@@ -80,7 +105,6 @@ public class SuppressionParser {
|
||||
xmlReader.setErrorHandler(new SuppressionErrorHandler());
|
||||
xmlReader.setContentHandler(handler);
|
||||
|
||||
final InputStream inputStream = new FileInputStream(file);
|
||||
final Reader reader = new InputStreamReader(inputStream, "UTF-8");
|
||||
final InputSource in = new InputSource(reader);
|
||||
//in.setEncoding("UTF-8");
|
||||
|
||||
@@ -234,6 +234,61 @@ public class SuppressionRule {
|
||||
public boolean hasCve() {
|
||||
return cve.size() > 0;
|
||||
}
|
||||
/**
|
||||
* A Maven GAV to suppression.
|
||||
*/
|
||||
private PropertyType gav = null;
|
||||
|
||||
/**
|
||||
* Get the value of Maven GAV.
|
||||
*
|
||||
* @return the value of gav
|
||||
*/
|
||||
public PropertyType getGav() {
|
||||
return gav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of Maven GAV.
|
||||
*
|
||||
* @param gav new value of Maven gav
|
||||
*/
|
||||
public void setGav(PropertyType gav) {
|
||||
this.gav = gav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this suppression rule as GAV entries.
|
||||
*
|
||||
* @return whether or not this suppression rule as GAV entries
|
||||
*/
|
||||
public boolean hasGav() {
|
||||
return gav != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A flag indicating whether or not the suppression rule is a core/base rule that should not be included in the
|
||||
* resulting report in the "suppressed" section.
|
||||
*/
|
||||
private boolean base;
|
||||
|
||||
/**
|
||||
* Get the value of base.
|
||||
*
|
||||
* @return the value of base
|
||||
*/
|
||||
public boolean isBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of base.
|
||||
*
|
||||
* @param base new value of base
|
||||
*/
|
||||
public void setBase(boolean base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a given dependency to determine if any CPE, CVE, CWE, or CVSS scores should be suppressed. If any
|
||||
@@ -248,13 +303,30 @@ public class SuppressionRule {
|
||||
if (sha1 != null && !sha1.equalsIgnoreCase(dependency.getSha1sum())) {
|
||||
return;
|
||||
}
|
||||
if (gav != null) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
boolean gavFound = false;
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
if (identifierMatches("maven", this.gav, i)) {
|
||||
gavFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gavFound) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hasCpe()) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
for (PropertyType c : this.cpe) {
|
||||
if (cpeMatches(c, i)) {
|
||||
dependency.addSuppressedIdentifier(i);
|
||||
if (identifierMatches("cpe", c, i)) {
|
||||
if (!isBase()) {
|
||||
dependency.addSuppressedIdentifier(i);
|
||||
}
|
||||
itr.remove();
|
||||
break;
|
||||
}
|
||||
@@ -293,7 +365,9 @@ public class SuppressionRule {
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
dependency.addSuppressedVulnerability(v);
|
||||
if (!isBase()) {
|
||||
dependency.addSuppressedVulnerability(v);
|
||||
}
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
@@ -309,7 +383,7 @@ public class SuppressionRule {
|
||||
boolean cpeHasNoVersion(PropertyType c) {
|
||||
if (c.isRegex()) {
|
||||
return false;
|
||||
} // cpe:/a:jboss:jboss:1.0.0:
|
||||
}
|
||||
if (countCharacter(c.getValue(), ':') == 3) {
|
||||
return true;
|
||||
}
|
||||
@@ -336,26 +410,75 @@ public class SuppressionRule {
|
||||
/**
|
||||
* Determines if the cpeEntry specified as a PropertyType matches the given Identifier.
|
||||
*
|
||||
* @param cpeEntry a suppression rule entry
|
||||
* @param identifierType the type of identifier ("cpe", "maven", etc.)
|
||||
* @param suppressionEntry a suppression rule entry
|
||||
* @param identifier a CPE identifier to check
|
||||
* @return true if the entry matches; otherwise false
|
||||
*/
|
||||
boolean cpeMatches(PropertyType cpeEntry, Identifier identifier) {
|
||||
if (cpeEntry.matches(identifier.getValue())) {
|
||||
return true;
|
||||
} else if (cpeHasNoVersion(cpeEntry)) {
|
||||
if (cpeEntry.isCaseSensitive()) {
|
||||
if (identifier.getValue().startsWith(cpeEntry.getValue())) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
final String id = identifier.getValue().toLowerCase();
|
||||
final String check = cpeEntry.getValue().toLowerCase();
|
||||
if (id.startsWith(check)) {
|
||||
return true;
|
||||
boolean identifierMatches(String identifierType, PropertyType suppressionEntry, Identifier identifier) {
|
||||
if (identifierType.equals(identifier.getType())) {
|
||||
if (suppressionEntry.matches(identifier.getValue())) {
|
||||
return true;
|
||||
} else if ("cpe".equals(identifierType) && cpeHasNoVersion(suppressionEntry)) {
|
||||
if (suppressionEntry.isCaseSensitive()) {
|
||||
return identifier.getValue().startsWith(suppressionEntry.getValue());
|
||||
} else {
|
||||
final String id = identifier.getValue().toLowerCase();
|
||||
final String check = suppressionEntry.getValue().toLowerCase();
|
||||
return id.startsWith(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard toString implementation.
|
||||
*
|
||||
* @return a string representation of this object
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("SuppressionRule{");
|
||||
if (filePath != null) {
|
||||
sb.append("filePath=").append(filePath).append(",");
|
||||
}
|
||||
if (sha1 != null) {
|
||||
sb.append("sha1=").append(sha1).append(",");
|
||||
}
|
||||
if (gav != null) {
|
||||
sb.append("gav=").append(gav).append(",");
|
||||
}
|
||||
if (cpe != null && cpe.size() > 0) {
|
||||
sb.append("cpe={");
|
||||
for (PropertyType pt : cpe) {
|
||||
sb.append(pt).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cwe != null && cwe.size() > 0) {
|
||||
sb.append("cwe={");
|
||||
for (String s : cwe) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cve != null && cve.size() > 0) {
|
||||
sb.append("cve={");
|
||||
for (String s : cve) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cvssBelow != null && cvssBelow.size() > 0) {
|
||||
sb.append("cvssBelow={");
|
||||
for (Float s : cvssBelow) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,9 @@ public final class DBUtils {
|
||||
int id = 0;
|
||||
try {
|
||||
rs = statement.getGeneratedKeys();
|
||||
rs.next();
|
||||
if (!rs.next()) {
|
||||
throw new DatabaseException("Unable to get primary key for inserted row");
|
||||
}
|
||||
id = rs.getInt(1);
|
||||
} catch (SQLException ex) {
|
||||
throw new DatabaseException("Unable to get primary key for inserted row");
|
||||
|
||||
@@ -65,7 +65,7 @@ public class DependencyVersion implements Iterable, Comparable<DependencyVersion
|
||||
public final void parseVersion(String version) {
|
||||
versionParts = new ArrayList<String>();
|
||||
if (version != null) {
|
||||
final Pattern rx = Pattern.compile("(\\d+|[a-z]+\\d+|(release|beta|alpha)$)");
|
||||
final Pattern rx = Pattern.compile("(\\d+[a-z]{1,3}$|[a-z]+\\d+|\\d+|(release|beta|alpha)$)");
|
||||
final Matcher matcher = rx.matcher(version.toLowerCase());
|
||||
while (matcher.find()) {
|
||||
versionParts.add(matcher.group());
|
||||
@@ -189,17 +189,23 @@ public class DependencyVersion implements Iterable, Comparable<DependencyVersion
|
||||
if (version == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean ret = true;
|
||||
int max = (this.versionParts.size() < version.versionParts.size())
|
||||
? this.versionParts.size() : version.versionParts.size();
|
||||
|
||||
if (max > 3) {
|
||||
max = 3;
|
||||
if (Math.abs(this.versionParts.size() - version.versionParts.size()) >= 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int max = (this.versionParts.size() < version.versionParts.size())
|
||||
? this.versionParts.size() : version.versionParts.size();
|
||||
|
||||
boolean ret = true;
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (this.versionParts.get(i) == null || !this.versionParts.get(i).equals(version.versionParts.get(i))) {
|
||||
final String thisVersion = this.versionParts.get(i);
|
||||
final String otherVersion = version.getVersionParts().get(i);
|
||||
if (i >= 3) {
|
||||
if (thisVersion.compareToIgnoreCase(otherVersion) >= 0) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
} else if (!thisVersion.equals(otherVersion)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public final class DependencyVersionUtil {
|
||||
/**
|
||||
* Regular expression to extract version numbers from file names.
|
||||
*/
|
||||
private static final Pattern RX_VERSION = Pattern.compile("\\d+(\\.\\d{1,6})+(\\.?([_-](release|beta|alpha)|[a-zA-Z_-]{1,3}\\d{1,8}))?");
|
||||
private static final Pattern RX_VERSION = Pattern.compile("\\d+(\\.\\d{1,6})+(\\.?([_-](release|beta|alpha|\\d+)|[a-zA-Z_-]{1,3}\\d{0,8}))?");
|
||||
/**
|
||||
* Regular expression to extract a single version number without periods. This is a last ditch effort just to check
|
||||
* in case we are missing a version number using the previous regex.
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import static org.owasp.dependencycheck.utils.FileUtils.getFileExtension;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class ExtractionUtil {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ExtractionUtil.class.getName());
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
/**
|
||||
* Private constructor for a utility class.
|
||||
*/
|
||||
private ExtractionUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of an archive into the specified directory.
|
||||
*
|
||||
* @param archive an archive file such as a WAR or EAR
|
||||
* @param extractTo a directory to extract the contents to
|
||||
* @throws ExtractionException thrown if an exception occurs while extracting the files
|
||||
*/
|
||||
public static void extractFiles(File archive, File extractTo) throws ExtractionException {
|
||||
extractFiles(archive, extractTo, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of an archive into the specified directory. The files are only extracted if they are
|
||||
* supported by the analyzers loaded into the specified engine. If the engine is specified as null then all files
|
||||
* are extracted.
|
||||
*
|
||||
* @param archive an archive file such as a WAR or EAR
|
||||
* @param extractTo a directory to extract the contents to
|
||||
* @param engine the scanning engine
|
||||
* @throws ExtractionException thrown if there is an error extracting the files
|
||||
*/
|
||||
public static void extractFiles(File archive, File extractTo, Engine engine) throws ExtractionException {
|
||||
if (archive == null || extractTo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
ZipInputStream zis = null;
|
||||
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new ExtractionException("Archive file was not found.", ex);
|
||||
}
|
||||
zis = new ZipInputStream(new BufferedInputStream(fis));
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.isDirectory()) {
|
||||
final File d = new File(extractTo, entry.getName());
|
||||
if (!d.exists() && !d.mkdirs()) {
|
||||
final String msg = String.format("Unable to create '%s'.", d.getAbsolutePath());
|
||||
throw new ExtractionException(msg);
|
||||
}
|
||||
} else {
|
||||
final File file = new File(extractTo, entry.getName());
|
||||
final String ext = getFileExtension(file.getName());
|
||||
if (engine == null || engine.supportsExtension(ext)) {
|
||||
BufferedOutputStream bos = null;
|
||||
FileOutputStream fos;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||
int count;
|
||||
final byte data[] = new byte[BUFFER_SIZE];
|
||||
while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
bos.write(data, 0, count);
|
||||
}
|
||||
bos.flush();
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
if (bos != null) {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
try {
|
||||
zis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
dependency-check-core/src/main/resources/GrokAssembly.exe
Executable file → Normal file
BIN
dependency-check-core/src/main/resources/GrokAssembly.exe
Executable file → Normal file
Binary file not shown.
@@ -8,6 +8,7 @@ org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NvdCveAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.CentralAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NexusAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NuspecAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.AssemblyAnalyzer
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses false positives identified on spring security.
|
||||
]]></notes>
|
||||
<gav regex="true">org\.springframework\.security:spring.*</gav>
|
||||
<cpe>cpe:/a:mod_security:mod_security</cpe>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses false positives identified on spring security.
|
||||
]]></notes>
|
||||
<filePath regex="true">.*spring-security-[^\\/]*\.jar$</filePath>
|
||||
<cpe>cpe:/a:mod_security:mod_security</cpe>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppreses additional false positives for the xstream library that occur because spring has a copy of this library.
|
||||
com.springsource.com.thoughtworks.xstream-1.3.1.jar
|
||||
]]></notes>
|
||||
<gav regex="true">com\.thoughtworks\.xstream:xstream:.*</gav>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on velocity tools.
|
||||
]]></notes>
|
||||
<gav regex="true">org\.apache\.velocity:velocity-tools:.*</gav>
|
||||
<cpe>cpe:/a:apache:struts</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Sandbox is a php blog platform and should not be flagged as a CPE for java or .net dependencies.
|
||||
]]></notes>
|
||||
<filePath regex="true">.*\.(jar|dll|exe|ear|war|pom)</filePath>
|
||||
<cpe>cpe:/a:sandbox:sandbox</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on Jersey core client.
|
||||
]]></notes>
|
||||
<gav regex="true">(com\.sun\.jersey|org\.glassfish\.jersey\.core):jersey-(client|common):.*</gav>
|
||||
<cpe>cpe:/a:oracle:glassfish</cpe>
|
||||
<cpe>cpe:/a:oracle:oracle_client</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on the grizzly-framework
|
||||
]]></notes>
|
||||
<gav regex="true">org\.glassfish\.grizzly:grizzly-framework:.*</gav>
|
||||
<cpe>cpe:/a:oracle:glassfish</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on the grizzly-framework
|
||||
]]></notes>
|
||||
<gav regex="true">org\.forgerock\.opendj:opendj-ldap-sdk:.*</gav>
|
||||
<cpe>cpe:/a:ldap_project:ldap</cpe>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -0,0 +1,10 @@
|
||||
analyzer.AssemblyAnalyzer.notdeployed=GrokAssembly didn't get deployed
|
||||
analyzer.AssemblyAnalyzer.grokassembly.stderr=Error from GrokAssembly: {0}
|
||||
analyzer.AssemblyAnalyzer.notassembly={0} is not a .NET assembly or executable and as such cannot be analyzed by dependency-check
|
||||
analyzer.AssemblyAnalyzer.grokassembly.rc=Return code {0} from GrokAssembly
|
||||
analyzer.AssemblyAnalyzer.grokassembly.deployed=Extracted GrokAssembly.exe to {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.notdeployed=Could not extract GrokAssembly.exe: {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.initialization.failed=An error occurred with the .NET AssemblyAnalyzer; \
|
||||
this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.
|
||||
analyzer.AssemblyAnalyzer.grokassembly.initialization.message=Could not execute GrokAssembly {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.notdeleted=Can't delete temporary GrokAssembly.exe
|
||||
@@ -13,8 +13,10 @@ max.download.threads=3
|
||||
# will not be used. The data.directory will be resolved and if the connection string
|
||||
# below contains a %s then the data.directory will replace the %s.
|
||||
data.directory=[JAR]/data
|
||||
#if the filename has a %s it will be replaced with the current expected version
|
||||
data.file_name=cve.%s.h2.db
|
||||
data.version=2.9
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
|
||||
|
||||
# user name and password for the database connection. The inherent case is to use H2.
|
||||
@@ -38,11 +40,16 @@ data.driver_path=
|
||||
cve.url.modified.validfordays=7
|
||||
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.url-1.2.modified=https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
#cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
#cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.startyear=2002
|
||||
cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
#cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
|
||||
|
||||
# file type analyzer settings:
|
||||
analyzer.archive.enabled=true
|
||||
@@ -56,3 +63,7 @@ analyzer.nexus.url=https://repository.sonatype.org/service/local/
|
||||
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||
# are configured
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
# the URL for searching search.maven.org for SHA-1 and whether it's enabled
|
||||
analyzer.central.enabled=true
|
||||
analyzer.central.url=http://search.maven.org/solrsearch/select
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
<xs:element name="filePath" type="dc:regexStringType"/>
|
||||
<xs:element name="sha1" type="dc:sha1Type"/>
|
||||
<xs:element name="gav" type="dc:regexStringType"/>
|
||||
</xs:choice>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cpe" type="dc:regexStringType"/>
|
||||
@@ -49,6 +50,7 @@
|
||||
<xs:element name="cvssBelow" type="dc:cvssScoreType"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="base" use="optional" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
|
||||
@@ -33,8 +33,8 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$(".expandable").click(function (e) {
|
||||
e = e || window.event;
|
||||
$(".expandable").click(function (event) {
|
||||
e = event || window.event;
|
||||
var h = e.target || e.srcElement;
|
||||
var content = "#content" + h.id.substr(6);
|
||||
var header = "#" + h.id;
|
||||
@@ -56,6 +56,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
$(header).addClass("expandablesubsection");
|
||||
$(header).removeClass("collaspablesubsection");
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -84,13 +85,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
$('#modal-text').focus();
|
||||
$('#modal-text').select();
|
||||
}
|
||||
function toggleDisplay(el, clzName) {
|
||||
function toggleDisplay(el, clzName, all, some) {
|
||||
$(clzName).toggle();
|
||||
if (el.innerHTML == 'show all') {
|
||||
el.innerHTML = 'less';
|
||||
if (el.innerHTML == all) {
|
||||
el.innerHTML = some;
|
||||
} else {
|
||||
el.innerHTML = 'show all';
|
||||
el.innerHTML = all;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
@@ -427,15 +429,24 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
.indent {
|
||||
margin-left:20px;
|
||||
}
|
||||
td, th {
|
||||
td{
|
||||
vertical-align:text-top;
|
||||
padding:6px;
|
||||
margin:0px;
|
||||
}
|
||||
th {
|
||||
text-align:left
|
||||
vertical-align:text-top;
|
||||
padding:6px;
|
||||
margin:0px;
|
||||
border-bottom:1px;
|
||||
border-color: black;
|
||||
}
|
||||
table {
|
||||
border: 0px;
|
||||
}
|
||||
table.lined tr:nth-child(even) {
|
||||
background-color: #fbfbfb;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
.fullwidth {
|
||||
width:100%;
|
||||
@@ -448,10 +459,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
margin-bottom:3px;
|
||||
}
|
||||
.vulnerable {
|
||||
color: #f00;
|
||||
}
|
||||
.vulnerable li {
|
||||
color: #000;
|
||||
color: #000;
|
||||
}
|
||||
.notvulnerable {
|
||||
display:none;
|
||||
@@ -481,7 +489,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<div id="modal-content">
|
||||
<div>Press CTR-C to copy XML <a href="http://jeremylong.github.io/DependencyCheck/suppression.html" class="infolink" target="_blank" title="Help with suppressing false positives">[help]</a></div>
|
||||
<textarea id="modal-text" cols="50" rows="10"></textarea><br/>
|
||||
<button id="modal-add-header" class="modal-button">Complete XML Doc</button><button id="modal-close" class="modal-button-right">Close</button>
|
||||
<button id="modal-add-header" title="Add the parent XML nodes to create the complete XML file that can be used to suppress this finding" class="modal-button">Complete XML Doc</button><button id="modal-close" class="modal-button-right">Close</button>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<h1>Dependency-Check Report</h1>
|
||||
@@ -513,7 +521,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#set($vulnSuppressedCount=$vulnSuppressedCount+$dependency.getSuppressedVulnerabilities().size())
|
||||
#end
|
||||
#end
|
||||
Scan Information (<a href="#" onclick="toggleDisplay(this, '.scaninfo'); return false;">show all</a>):<br/>
|
||||
Scan Information (<a href="#" title="Click to toggle display" onclick="return toggleDisplay(this, '.scaninfo', 'show all', 'show less'); return false;">show all</a>):<br/>
|
||||
<ul class="indent">
|
||||
<li><i>dependency-check version</i>: $version</li>
|
||||
<li><i>Report Generated On</i>: $scanDate</li>
|
||||
@@ -526,30 +534,101 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<li class="scaninfo hidden"><i>$enc.html($prop.key)</i>: $enc.html($prop.value)</li>
|
||||
#end
|
||||
</ul><br/>
|
||||
Dependency Display: <a href="#" onclick="toggleDisplay(this,'.notvulnerable'); return false;">show all</a><br/><br/>
|
||||
<ul class="indent">
|
||||
Display: <a href="#" title="Click to toggle display" onclick="return toggleDisplay(this, '.notvulnerable', 'Showing Vulnerable Dependencies', 'Showing All Dependencies'); return false;">Showing Vulnerable Dependencies</a><br/><br/>
|
||||
#set($lnkcnt=0)
|
||||
#foreach($dependency in $dependencies)
|
||||
<table class="lined">
|
||||
<tr style="text-align:left">
|
||||
<th title="The name of the dependency">Dependency</th>
|
||||
<th title="The Common Platform Enumeration">CPE</th>
|
||||
<th title="The Maven GAV Coordinates">GAV</th>
|
||||
<th title="The highest CVE Severity">Highest Severity</th>
|
||||
<th title="The number of Common Vulnerability and Exposure (CVE) entries">CVE Count</th>
|
||||
<th title="The confidence rating dependency-check has for the identified CPE">CPE Confidence</th>
|
||||
<th title="The count of evidence used to identify the CPE">Evidence Count</th>
|
||||
</tr>
|
||||
#foreach($dependency in $dependencies)
|
||||
#set($lnkcnt=$lnkcnt+1)
|
||||
<li class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
<a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.FileName)</a>
|
||||
#if($dependency.getRelatedDependencies().size()>0)
|
||||
<ul>
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
<li>$enc.html($related.FileName)</li>
|
||||
<tr class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
<td><a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a></td>
|
||||
#set($mavenlink="")
|
||||
#set($cpeIdCount=0)
|
||||
#set($cpeIdConf="")
|
||||
<td>
|
||||
#foreach($id in $dependency.getIdentifiers())
|
||||
#if ($id.type=="maven")
|
||||
#if ($mavenlink=="" || !$mavenlink.url)
|
||||
#set($mavenlink=$id)
|
||||
#end
|
||||
#else
|
||||
#if ($cpeIdCount>=1)
|
||||
<br/>
|
||||
#end
|
||||
#if( $id.url )
|
||||
<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>
|
||||
#else
|
||||
$enc.html($id.value)
|
||||
#end
|
||||
#if ($cpeIdConf == "")
|
||||
#set($cpeIdConf=$id.confidence)
|
||||
#elseif ($cpeIdConf.compareTo($id.confidence)>0)
|
||||
#set($cpeIdConf=$id.confidence)
|
||||
#end
|
||||
#set($cpeIdCount=$cpeIdCount+1)
|
||||
#end
|
||||
#end
|
||||
</ul>
|
||||
</td>
|
||||
<td>#if( $mavenlink.url )
|
||||
##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here...
|
||||
<a href="$enc.html($mavenlink.url)" target="_blank">$enc.html($mavenlink.value)</a>
|
||||
#elseif ($mavenlink.value)
|
||||
$enc.html($mavenlink.value)
|
||||
#end</td>
|
||||
#set($cveImpact=-1)
|
||||
#foreach($vuln in $dependency.getVulnerabilities())
|
||||
#if ($cveImpact<$vuln.cvssScore)
|
||||
#set($cveImpact=$vuln.cvssScore)
|
||||
#end
|
||||
#end
|
||||
<td>
|
||||
#if ($cveImpact<0)
|
||||
|
||||
#elseif ($cveImpact<4.0)
|
||||
Low
|
||||
#elseif ($cveImpact>=7.0)
|
||||
High
|
||||
#else
|
||||
Medium
|
||||
#end
|
||||
</td>
|
||||
<td>$dependency.getVulnerabilities().size()</td>
|
||||
<td>$cpeIdConf</td>
|
||||
<td>$dependency.getEvidenceForDisplay().size()</td>
|
||||
</tr>
|
||||
#end
|
||||
</li>
|
||||
#end
|
||||
</ul>
|
||||
</table>
|
||||
## <ul class="indent">
|
||||
## #set($lnkcnt=0)
|
||||
## #foreach($dependency in $dependencies)
|
||||
## #set($lnkcnt=$lnkcnt+1)
|
||||
## <li class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
## <a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a>
|
||||
## #if($dependency.getRelatedDependencies().size()>0)
|
||||
## <ul>
|
||||
## #foreach($related in $dependency.getRelatedDependencies())
|
||||
## <li>$enc.html($related.DisplayFileName)</li>
|
||||
## #end
|
||||
## </ul>
|
||||
## #end
|
||||
## </li>
|
||||
## #end
|
||||
## </ul>
|
||||
<h2>Dependencies</h2>
|
||||
#set($lnkcnt=0)
|
||||
#set($cnt=0)
|
||||
#set($vsctr=0) ##counter to create unique groups for vulnerable software
|
||||
#foreach($dependency in $dependencies)
|
||||
#set($lnkcnt=$lnkcnt+1)
|
||||
<h3 class="subsectionheader standardsubsection#if($dependency.getVulnerabilities().size()==0) notvulnerable#end"><a name="l${lnkcnt}_$enc.html($dependency.Sha1sum)"></a>$enc.html($dependency.FileName)</h3>
|
||||
<h3 class="subsectionheader standardsubsection#if($dependency.getVulnerabilities().size()==0) notvulnerable#end"><a name="l${lnkcnt}_$enc.html($dependency.Sha1sum)"></a>$enc.html($dependency.DisplayFileName)</h3>
|
||||
<div class="subsectioncontent#if($dependency.getVulnerabilities().size()==0) notvulnerable#end">
|
||||
#if ($dependency.description)
|
||||
<p><b>Description:</b> $enc.html($dependency.description)<br/></p>
|
||||
@@ -571,7 +650,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||
<table class="lined fullwidth" border="0">
|
||||
<tr><th class="left" style="width:10%;">Source</th><th class="left" style="width:20%;">Name</th><th class="left" style="width:70%;">Value</th></tr>
|
||||
#foreach($evidence in $dependency.getEvidenceUsed())
|
||||
#foreach($evidence in $dependency.getEvidenceForDisplay())
|
||||
<tr><td>$enc.html($evidence.getSource())</td><td>$enc.html($evidence.getName())</td><td>$enc.html($evidence.getValue())</td></tr>
|
||||
#end
|
||||
</table>
|
||||
@@ -582,7 +661,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||
<ul>
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
<li>$enc.html($related.FileName)
|
||||
<li>$enc.html($related.DisplayFileName)
|
||||
<ul>
|
||||
<li>File Path: $enc.html($related.FilePath)</li>
|
||||
<li>SHA1: $enc.html($related.Sha1sum)</li>
|
||||
@@ -612,7 +691,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#end
|
||||
<h4 id="header$cnt" class="subsectionheader white">Identifiers</h4>
|
||||
##: <a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
|
||||
##: <a href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||
#if ($dependency.getIdentifiers().size()==0)
|
||||
<ul><li><b>None</b></li></ul>
|
||||
@@ -630,7 +709,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#if ($id.type=="cpe")
|
||||
##yes, we are HTML Encoding into JavaScript... the escape utils don't have a JS Encode and I haven't written one yet
|
||||
<button class="copybutton" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cpe', '$enc.html($id.value)')">suppress</button>
|
||||
<button class="copybutton" title="Generate Suppression XML for this CPE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cpe', '$enc.html($id.value)')">suppress</button>
|
||||
#end
|
||||
#if ($id.description)
|
||||
<br/>$enc.html($id.description)
|
||||
@@ -646,7 +725,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||
#foreach($vuln in $dependency.getVulnerabilities())
|
||||
#set($vsctr=$vsctr+1)
|
||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" title="Generate Suppression XML for this CCE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||
<p>Severity:
|
||||
#if ($vuln.cvssScore<4.0)
|
||||
Low
|
||||
@@ -668,13 +747,20 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
</ul>
|
||||
#end
|
||||
</p>
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
<li class="vs$vsctr hidden"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||
|
||||
#if ($vuln.getVulnerableSoftware().size()<2)
|
||||
<p>Vulnerable Software & Versions:<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
</ul></p>
|
||||
#else
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
<li class="vs$vsctr hidden"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||
#end
|
||||
</ul></p>
|
||||
#end
|
||||
</ul></p>
|
||||
#end
|
||||
</div>
|
||||
#end
|
||||
@@ -692,7 +778,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#foreach($dependency in $dependencies)
|
||||
#if ($dependency.getSuppressedIdentifiers().size()>0 || $dependency.getSuppressedVulnerabilities().size()>0)
|
||||
#set($lnkcnt=$lnkcnt+1)
|
||||
<h3 class="subsectionheader standardsubsection">$enc.html($dependency.FileName)</h3>
|
||||
<h3 class="subsectionheader standardsubsection">$enc.html($dependency.DisplayFileName)</h3>
|
||||
<div class="subsectioncontent">
|
||||
#if ($dependency.description)
|
||||
<p><b>Description:</b> $enc.html($dependency.description)<br/></p>
|
||||
@@ -714,7 +800,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||
<table class="lined fullwidth" border="0">
|
||||
<tr><th class="left" style="width:10%;">Source</th><th class="left" style="width:20%;">Name</th><th class="left" style="width:70%;">Value</th></tr>
|
||||
#foreach($evidence in $dependency.getEvidenceUsed())
|
||||
#foreach($evidence in $dependency.getEvidenceForDisplay())
|
||||
<tr><td>$enc.html($evidence.getSource())</td><td>$enc.html($evidence.getName())</td><td>$enc.html($evidence.getValue())</td></tr>
|
||||
#end
|
||||
</table>
|
||||
@@ -725,7 +811,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
|
||||
<ul>
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
<li>$enc.html($related.FileName)
|
||||
<li>$enc.html($related.DisplayFileName)
|
||||
<ul>
|
||||
<li>File Path: $enc.html($related.FilePath)</li>
|
||||
<li>SHA1: $enc.html($related.Sha1sum)</li>
|
||||
@@ -744,7 +830,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#end
|
||||
<h4 id="header$cnt" class="subsectionheader white">Suppressed Identifiers</h4>
|
||||
##: <a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
|
||||
##: <a href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||
#if ($dependency.getSuppressedIdentifiers().size()==0)
|
||||
<ul><li><b>None</b></li></ul>
|
||||
@@ -796,13 +882,19 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
</ul>
|
||||
#end
|
||||
</p>
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
<li class="vs$vsctr hidden"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||
#if ($vuln.getVulnerableSoftware().size()<2)
|
||||
<p>Vulnerable Software & Versions:<ul>
|
||||
git st<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
</ul></p>
|
||||
#else
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
<li class="vs$vsctr hidden"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||
#end
|
||||
</ul></p>
|
||||
#end
|
||||
</ul></p>
|
||||
#end
|
||||
</div>
|
||||
#end
|
||||
@@ -814,6 +906,6 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
## END SUPPRESSED VULNERABILITIES
|
||||
</div>
|
||||
</div>
|
||||
<div><br/><br/>This report contains data retrieved from the <a href="nvd.nist.gov">National Vulnerability Database</a>.</div>
|
||||
<div><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -222,10 +222,10 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
($vuln.cvssScore)
|
||||
<td>#set($cnt=$cnt+1)
|
||||
#if($dependency.getRelatedDependencies().size()>0)<span id="header$cnt" class="expandable collapsedList">#end
|
||||
$enc.html($dependency.FileName)
|
||||
$enc.html($dependency.DisplayFileName)
|
||||
#if($dependency.getRelatedDependencies().size()>0) </span><div id="content$cnt" class="hidden">#end
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
$enc.html($related.FileName)<br/>
|
||||
$enc.html($related.DisplayFileName)<br/>
|
||||
#end
|
||||
#if($dependency.getRelatedDependencies().size()>0)</div#end
|
||||
</td>
|
||||
@@ -236,6 +236,6 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p><br/><br/>This report contains data retrieved from the <a href="nvd.nist.gov">National Vulnerability Database</a>.</p>
|
||||
<p><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -36,7 +36,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<dependencies>
|
||||
#foreach($dependency in $dependencies)
|
||||
<dependency>
|
||||
<fileName>$enc.xml($dependency.FileName)</fileName>
|
||||
<fileName>$enc.xml($dependency.DisplayFileName)</fileName>
|
||||
<filePath>$enc.xml($dependency.FilePath)</filePath>
|
||||
<md5>$enc.xml($dependency.Md5sum)</md5>
|
||||
<sha1>$enc.xml($dependency.Sha1sum)</sha1>
|
||||
@@ -68,7 +68,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</relatedDependencies>
|
||||
#end
|
||||
<evidenceCollected>
|
||||
#foreach($evidence in $dependency.getEvidenceUsed())
|
||||
#foreach($evidence in $dependency.getEvidenceForDisplay())
|
||||
<evidence>
|
||||
<source>$enc.xml($evidence.getSource())</source>
|
||||
<name>$enc.xml($evidence.getName())</name>
|
||||
|
||||
@@ -32,6 +32,6 @@ public class BaseTest {
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
Settings.cleanup();
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
@@ -42,26 +41,6 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of scan method, of class Engine.
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testScan() throws Exception {
|
||||
String testClasses = "target/test-classes/*.zip";
|
||||
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Engine instance = new Engine();
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
instance.scan(testClasses);
|
||||
assertTrue(instance.getDependencies().size() > 0);
|
||||
for (Dependency d : instance.getDependencies()) {
|
||||
assertTrue("non-zip file collected " + d.getFileName(), d.getFileName().toLowerCase().endsWith(".zip"));
|
||||
}
|
||||
instance.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test running the entire engine.
|
||||
*
|
||||
@@ -70,10 +49,10 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
@Test
|
||||
public void testEngine() throws Exception {
|
||||
String testClasses = "target/test-classes";
|
||||
// boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
// Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Engine instance = new Engine();
|
||||
// Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
instance.scan(testClasses);
|
||||
assertTrue(instance.getDependencies().size() > 0);
|
||||
instance.analyzeDependencies();
|
||||
@@ -81,8 +60,7 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
cveDB.open();
|
||||
DatabaseProperties dbProp = cveDB.getDatabaseProperties();
|
||||
cveDB.close();
|
||||
ReportGenerator rg = new ReportGenerator("DependencyCheck",
|
||||
instance.getDependencies(), instance.getAnalyzers(), dbProp);
|
||||
ReportGenerator rg = new ReportGenerator("DependencyCheck", instance.getDependencies(), instance.getAnalyzers(), dbProp);
|
||||
rg.generateReports("./target/", "ALL");
|
||||
instance.cleanup();
|
||||
}
|
||||
|
||||
@@ -17,31 +17,78 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionParseException;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class AbstractSuppressionAnalyzerTest extends BaseTest {
|
||||
|
||||
private AbstractSuppressionAnalyzer instance;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
public void createObjectUnderTest() throws Exception {
|
||||
instance = new AbstractSuppressionAnalyzerImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getSupportedExtensions method, of class AbstractSuppressionAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
Set<String> result = instance.getSupportedExtensions();
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getRules method, of class AbstractSuppressionAnalyzer for suppression file declared as URL.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRulesFromSuppressionFileFromURL() throws Exception {
|
||||
setSupressionFileFromURL();
|
||||
instance.initialize();
|
||||
int expCount = 5;
|
||||
List<SuppressionRule> result = instance.getRules();
|
||||
assertTrue(expCount <= result.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getRules method, of class AbstractSuppressionAnalyzer for suppression file declared as URL.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRulesFromSuppressionFileInClasspath() throws Exception {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, "suppressions.xml");
|
||||
instance.initialize();
|
||||
int expCount = 5;
|
||||
List<SuppressionRule> result = instance.getRules();
|
||||
assertTrue(expCount <= result.size());
|
||||
}
|
||||
|
||||
@Test(expected = SuppressionParseException.class)
|
||||
public void testFailureToLocateSuppressionFileAnywhere() throws Exception {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, "doesnotexist.xml");
|
||||
instance.initialize();
|
||||
}
|
||||
|
||||
private void setSupressionFileFromURL() throws Exception {
|
||||
try {
|
||||
final String uri = this.getClass().getClassLoader().getResource("suppressions.xml").toURI().toURL().toString();
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, uri);
|
||||
@@ -52,37 +99,6 @@ public class AbstractSuppressionAnalyzerTest extends BaseTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getSupportedExtensions method, of class AbstractSuppressionAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
|
||||
Set<String> result = instance.getSupportedExtensions();
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of initialize method, of class AbstractSuppressionAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testInitialize() throws Exception {
|
||||
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
|
||||
instance.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getRules method, of class AbstractSuppressionAnalyzer.
|
||||
*/
|
||||
@Test
|
||||
public void testGetRules() throws Exception {
|
||||
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
|
||||
instance.initialize();
|
||||
int expCount = 5;
|
||||
List<SuppressionRule> result = instance.getRules();
|
||||
assertEquals(expCount, result.size());
|
||||
}
|
||||
|
||||
public class AbstractSuppressionAnalyzerImpl extends AbstractSuppressionAnalyzer {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
ArchiveAnalyzer instance = new ArchiveAnalyzer();
|
||||
Set expResult = new HashSet<String>();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("zip");
|
||||
expResult.add("war");
|
||||
expResult.add("ear");
|
||||
|
||||
@@ -25,9 +25,11 @@ import java.util.Set;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.queryparser.classic.ParseException;
|
||||
import org.junit.Assert;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
|
||||
import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
|
||||
@@ -81,12 +83,24 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*/
|
||||
@Test
|
||||
public void testDetermineCPE_full() throws Exception {
|
||||
callDetermineCPE_full("hazelcast-2.5.jar", null);
|
||||
callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5");
|
||||
callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0");
|
||||
callDetermineCPE_full("org.mortbay.jetty.jar", "cpe:/a:mortbay_jetty:jetty:4.2");
|
||||
callDetermineCPE_full("jaxb-xercesImpl-1.5.jar", null);
|
||||
callDetermineCPE_full("ehcache-core-2.2.0.jar", null);
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
FileNameAnalyzer fnAnalyzer = new FileNameAnalyzer();
|
||||
JarAnalyzer jarAnalyzer = new JarAnalyzer();
|
||||
HintAnalyzer hAnalyzer = new HintAnalyzer();
|
||||
FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer();
|
||||
|
||||
try {
|
||||
//callDetermineCPE_full("struts2-core-2.3.16.3.jar", "cpe:/a:apache:struts:2.3.16.3", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("hazelcast-2.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("org.mortbay.jetty.jar", "cpe:/a:mortbay_jetty:jetty:4.2", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("jaxb-xercesImpl-1.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("ehcache-core-2.2.0.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
} finally {
|
||||
instance.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,37 +108,25 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs
|
||||
*/
|
||||
public void callDetermineCPE_full(String depName, String expResult) throws Exception {
|
||||
public void callDetermineCPE_full(String depName, String expResult, CPEAnalyzer instance, FileNameAnalyzer fnAnalyzer, JarAnalyzer jarAnalyzer, HintAnalyzer hAnalyzer, FalsePositiveAnalyzer fp) throws Exception {
|
||||
|
||||
File file = new File(this.getClass().getClassLoader().getResource(depName).getPath());
|
||||
|
||||
Dependency dep = new Dependency(file);
|
||||
|
||||
FileNameAnalyzer fnAnalyzer = new FileNameAnalyzer();
|
||||
fnAnalyzer.analyze(dep, null);
|
||||
|
||||
JarAnalyzer jarAnalyzer = new JarAnalyzer();
|
||||
jarAnalyzer.analyze(dep, null);
|
||||
HintAnalyzer hAnalyzer = new HintAnalyzer();
|
||||
hAnalyzer.analyze(dep, null);
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
instance.analyze(dep, null);
|
||||
instance.close();
|
||||
FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer();
|
||||
fp.analyze(dep, null);
|
||||
|
||||
// for (Identifier i : dep.getIdentifiers()) {
|
||||
// System.out.println(i.getValue());
|
||||
// }
|
||||
if (expResult != null) {
|
||||
Identifier expIdentifier = new Identifier("cpe", expResult, expResult);
|
||||
Assert.assertTrue("Incorrect match: { dep:'" + dep.getFileName() + "' }", dep.getIdentifiers().contains(expIdentifier));
|
||||
} else if (dep.getIdentifiers().isEmpty()) {
|
||||
Assert.assertTrue("Match found when an Identifier should not have been found: { dep:'" + dep.getFileName() + "' }", dep.getIdentifiers().isEmpty());
|
||||
} else {
|
||||
Assert.assertTrue("Match found when an Identifier should not have been found: { dep:'" + dep.getFileName() + "', identifier:'" + dep.getIdentifiers().iterator().next().getValue() + "' }", dep.getIdentifiers().isEmpty());
|
||||
for (Identifier i : dep.getIdentifiers()) {
|
||||
Assert.assertFalse(String.format("%s - found a CPE identifier when should have been none (found '%s')", dep.getFileName(), i.getValue()), "cpe".equals(i.getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +172,10 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
String expResultSpring = "cpe:/a:springsource:spring_framework:2.5.5";
|
||||
String expResultSpring3 = "cpe:/a:vmware:springsource_spring_framework:3.0.0";
|
||||
|
||||
Assert.assertTrue("Apache Common Validator - found an identifier?", commonValidator.getIdentifiers().isEmpty());
|
||||
for (Identifier i : commonValidator.getIdentifiers()) {
|
||||
Assert.assertFalse("Apache Common Validator - found a CPE identifier?", "cpe".equals(i.getType()));
|
||||
}
|
||||
|
||||
Assert.assertTrue("Incorrect match size - struts", struts.getIdentifiers().size() >= 1);
|
||||
Assert.assertTrue("Incorrect match - struts", struts.getIdentifiers().contains(expIdentifier));
|
||||
Assert.assertTrue("Incorrect match size - spring3 - " + spring3.getIdentifiers().size(), spring3.getIdentifiers().size() >= 1);
|
||||
@@ -180,6 +185,30 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
//Assert.assertTrue("Incorrect match - spring", spring.getIdentifiers().get(0).getValue().equals(expResultSpring));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of determineIdentifiers method, of class CPEAnalyzer.
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs
|
||||
*/
|
||||
@Test
|
||||
public void testDetermineIdentifiers() throws Exception {
|
||||
Dependency openssl = new Dependency();
|
||||
openssl.getVendorEvidence().addEvidence("test", "vendor", "openssl", Confidence.HIGHEST);
|
||||
openssl.getProductEvidence().addEvidence("test", "product", "openssl", Confidence.HIGHEST);
|
||||
openssl.getVersionEvidence().addEvidence("test", "version", "1.0.1c", Confidence.HIGHEST);
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
instance.determineIdentifiers(openssl, "openssl", "openssl", Confidence.HIGHEST);
|
||||
instance.close();
|
||||
|
||||
String expResult = "cpe:/a:openssl:openssl:1.0.1c";
|
||||
Identifier expIdentifier = new Identifier("cpe", expResult, expResult);
|
||||
|
||||
assertTrue(openssl.getIdentifiers().contains(expIdentifier));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of searchCPE method, of class CPEAnalyzer.
|
||||
*
|
||||
@@ -190,12 +219,12 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
String vendor = "apache software foundation";
|
||||
String product = "struts 2 core";
|
||||
String version = "2.1.2";
|
||||
String expResult = "cpe:/a:apache:struts:2.1.2";
|
||||
String expVendor = "apache";
|
||||
String expProduct = "struts";
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
|
||||
//TODO - yeah, not a very good test as the results are the same with or without weighting...
|
||||
Set<String> productWeightings = new HashSet<String>(1);
|
||||
productWeightings.add("struts2");
|
||||
|
||||
@@ -203,9 +232,16 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
vendorWeightings.add("apache");
|
||||
|
||||
List<IndexEntry> result = instance.searchCPE(vendor, product, productWeightings, vendorWeightings);
|
||||
//TODO fix this assert
|
||||
//Assert.assertEquals(expResult, result.get(0).getName());
|
||||
|
||||
instance.close();
|
||||
|
||||
boolean found = false;
|
||||
for (IndexEntry entry : result) {
|
||||
if (expVendor.equals(entry.getVendor()) && expProduct.equals(entry.getProduct())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("apache:struts was not identified", found);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,4 +86,40 @@ public class DependencyBundlingAnalyzerTest extends BaseTest {
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFirstPathIsShortest() {
|
||||
DependencyBundlingAnalyzer instance = new DependencyBundlingAnalyzer();
|
||||
|
||||
String left = "./a/c.jar";
|
||||
String right = "./d/e/f.jar";
|
||||
boolean expResult = true;
|
||||
boolean result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./d/e/f.jar";
|
||||
expResult = true;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./d/b/c.jar";
|
||||
right = "./a/e/f.jar";
|
||||
expResult = false;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./d/f.jar";
|
||||
expResult = false;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./a/b/c.jar";
|
||||
expResult = true;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ public class FalsePositiveAnalyzerTest {
|
||||
public void testAnalyze() throws Exception {
|
||||
Dependency dependency = new Dependency();
|
||||
dependency.setFileName("pom.xml");
|
||||
dependency.setFilePath("pom.xml");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:file:file:1.2.1", "http://some.org/url");
|
||||
Engine engine = null;
|
||||
FalsePositiveAnalyzer instance = new FalsePositiveAnalyzer();
|
||||
|
||||
@@ -85,7 +85,7 @@ public class HintAnalyzerTest extends BaseTest {
|
||||
for (Dependency d : engine.getDependencies()) {
|
||||
if (d.getActualFile().equals(guice)) {
|
||||
gdep = d;
|
||||
} else {
|
||||
} else if (d.getActualFile().equals(spring)) {
|
||||
sdep = d;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public class JarAnalyzerTest extends BaseTest {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
JarAnalyzer instance = new JarAnalyzer();
|
||||
Set expResult = new HashSet();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("jar");
|
||||
expResult.add("war");
|
||||
Set result = instance.getSupportedExtensions();
|
||||
|
||||
@@ -38,7 +38,7 @@ public class JavaScriptAnalyzerTest extends BaseTest {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
JavaScriptAnalyzer instance = new JavaScriptAnalyzer();
|
||||
Set expResult = new HashSet<String>();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("js");
|
||||
Set result = instance.getSupportedExtensions();
|
||||
assertEquals(expResult, result);
|
||||
|
||||
@@ -61,19 +61,26 @@ public class VulnerabilitySuppressionAnalyzerIntegrationTest extends AbstractDat
|
||||
@Test
|
||||
public void testAnalyze() throws Exception {
|
||||
|
||||
File file = new File(this.getClass().getClassLoader().getResource("FileHelpers.2.0.0.0.nupkg").getPath());
|
||||
File suppression = new File(this.getClass().getClassLoader().getResource("FileHelpers.2.0.0.0.suppression.xml").getPath());
|
||||
File file = new File(this.getClass().getClassLoader().getResource("commons-fileupload-1.2.1.jar").getPath());
|
||||
File suppression = new File(this.getClass().getClassLoader().getResource("commons-fileupload-1.2.1.suppression.xml").getPath());
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, false);
|
||||
Engine engine = new Engine();
|
||||
engine.scan(file);
|
||||
engine.analyzeDependencies();
|
||||
Dependency dependency = getDependency(engine, file);
|
||||
assertTrue(dependency.getVulnerabilities().size() > 0);
|
||||
int cveSize = dependency.getVulnerabilities().size();
|
||||
int cpeSize = dependency.getIdentifiers().size();
|
||||
assertTrue(cveSize > 0);
|
||||
assertTrue(cpeSize > 0);
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppression.getAbsolutePath());
|
||||
VulnerabilitySuppressionAnalyzer instance = new VulnerabilitySuppressionAnalyzer();
|
||||
instance.initialize();
|
||||
instance.analyze(dependency, engine);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 0);
|
||||
cveSize = cveSize > 1 ? cveSize - 2 : 0;
|
||||
cpeSize = cpeSize > 0 ? cpeSize - 1 : 0;
|
||||
assertTrue(dependency.getVulnerabilities().size() == cveSize);
|
||||
assertTrue(dependency.getIdentifiers().size() == cpeSize);
|
||||
engine.cleanup();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Created by colezlaw on 10/13/14.
|
||||
*/
|
||||
public class CentralSearchTest extends BaseTest {
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralSearchTest.class.getName());
|
||||
private CentralSearch searcher;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
String centralUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||
LOGGER.fine(centralUrl);
|
||||
searcher = new CentralSearch(new URL(centralUrl));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNullSha1() throws Exception { searcher.searchSha1(null); }
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testMalformedSha1() throws Exception {
|
||||
searcher.searchSha1("invalid");
|
||||
}
|
||||
|
||||
// This test does generate network traffic and communicates with a host
|
||||
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
||||
// test it anyway
|
||||
@Test
|
||||
public void testValidSha1() throws Exception {
|
||||
List<MavenArtifact> ma = searcher.searchSha1("9977a8d04e75609cf01badc4eb6a9c7198c4c5ea");
|
||||
assertEquals("Incorrect group", "org.apache.maven.plugins", ma.get(0).getGroupId());
|
||||
assertEquals("Incorrect artifact", "maven-compiler-plugin", ma.get(0).getArtifactId());
|
||||
assertEquals("Incorrect version", "3.1", ma.get(0).getVersion());
|
||||
}
|
||||
|
||||
// This test does generate network traffic and communicates with a host
|
||||
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
||||
// test it anyway
|
||||
@Test(expected = FileNotFoundException.class)
|
||||
public void testMissingSha1() throws Exception {
|
||||
searcher.searchSha1("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
|
||||
}
|
||||
|
||||
// This test should give us multiple results back from Central
|
||||
@Test
|
||||
public void testMultipleReturns() throws Exception {
|
||||
List<MavenArtifact> ma = searcher.searchSha1("94A9CE681A42D0352B3AD22659F67835E560D107");
|
||||
assertTrue(ma.size() > 1);
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,10 @@ public abstract class BaseDBTestCase extends BaseTest {
|
||||
|
||||
public static void ensureDBExists() throws Exception {
|
||||
|
||||
java.io.File dataPath = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
|
||||
if (!dataPath.exists() || (dataPath.isDirectory() && dataPath.listFiles().length < 3)) {
|
||||
java.io.File dataPath = Settings.getDataDirectory();
|
||||
String fileName = String.format(Settings.getString(Settings.KEYS.DB_FILE_NAME), Settings.getString(Settings.KEYS.DB_VERSION));
|
||||
java.io.File dataFile = new File(dataPath, fileName);
|
||||
if (!dataPath.exists() || !dataFile.exists()) {
|
||||
dataPath.mkdirs();
|
||||
FileInputStream fis = null;
|
||||
ZipInputStream zin = null;
|
||||
|
||||
@@ -19,9 +19,11 @@ package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -72,4 +74,21 @@ public class CveDBIntegrationTest extends BaseDBTestCase {
|
||||
instance.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of isAffected method, of class CveDB.
|
||||
*/
|
||||
@Test
|
||||
public void testIsAffected() throws Exception {
|
||||
String vendor = "openssl";
|
||||
String product = "openssl";
|
||||
DependencyVersion identifiedVersion = new DependencyVersion("1.0.1o");
|
||||
String cpeId = "cpe:/a:openssl:openssl:1.0.1e";
|
||||
String previous = "y";
|
||||
|
||||
CveDB instance = new CveDB();
|
||||
assertFalse(instance.isAffected(vendor, product, identifiedVersion, cpeId, previous));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,8 +17,12 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Calendar;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -26,6 +30,32 @@ import org.owasp.dependencycheck.BaseTest;
|
||||
*/
|
||||
public class NvdCveUpdaterIntegrationTest extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
int year = Calendar.getInstance().get(Calendar.YEAR);
|
||||
if (year <= 2014) {
|
||||
File f = new File(NvdCveUpdaterIntegrationTest.class.getClassLoader().getResource("nvdcve-2.0-2014.xml").getPath());
|
||||
String baseURL = f.toURI().toURL().toString();
|
||||
String modified12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-modified.xml");
|
||||
String modified20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-modified.xml");
|
||||
String full12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-%d.xml");
|
||||
String full20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-%d.xml");
|
||||
// cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
// cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
// cve.startyear=2014
|
||||
// cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
// cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, modified12);
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, modified20);
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, full12);
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, full20);
|
||||
Settings.setString(Settings.KEYS.CVE_START_YEAR, "2014");
|
||||
} else {
|
||||
System.err.println("Consider updating the local data files to make the NvdCveUpdaterIntegrationTest perform faster");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of update method, of class NvdCveUpdater.
|
||||
*/
|
||||
|
||||
@@ -67,16 +67,16 @@ public class StandardUpdateIntegrationTest extends BaseTest {
|
||||
result = instance.withinRange(lastRun, current, range);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of update method, of class StandardUpdate.
|
||||
*/
|
||||
@Test
|
||||
public void testUpdate() throws Exception {
|
||||
StandardUpdate instance = getStandardUpdateTask();
|
||||
instance.update();
|
||||
//TODO make this an actual test
|
||||
}
|
||||
// test removed as it is duplicative of the EngineIntegrationTest and the NvdCveUpdaterIntergraionTest
|
||||
// /**
|
||||
// * Test of update method, of class StandardUpdate.
|
||||
// */
|
||||
// @Test
|
||||
// public void testUpdate() throws Exception {
|
||||
// StandardUpdate instance = getStandardUpdateTask();
|
||||
// instance.update();
|
||||
// //TODO make this an actual test
|
||||
// }
|
||||
|
||||
/**
|
||||
* Test of updatesNeeded method, of class StandardUpdate.
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update.task;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.update.NvdCveInfo;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class DownloadTaskTest {
|
||||
|
||||
public DownloadTaskTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Settings.initialize();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Settings.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of call method, of class DownloadTask.
|
||||
*/
|
||||
@Test
|
||||
public void testCall() throws Exception {
|
||||
NvdCveInfo cve = new NvdCveInfo();
|
||||
cve.setId("modified");
|
||||
cve.setNeedsUpdate(true);
|
||||
cve.setUrl(Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL));
|
||||
cve.setOldSchemaVersionUrl(Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL));
|
||||
ExecutorService processExecutor = null;
|
||||
CveDB cveDB = null;
|
||||
DownloadTask instance = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance());;
|
||||
Future<ProcessTask> result = instance.call();
|
||||
assertNull(result);
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,12 @@ import java.util.Set;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -152,7 +154,7 @@ public class DependencyTest {
|
||||
public void testGetMd5sum() {
|
||||
File file = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
|
||||
Dependency instance = new Dependency(file);
|
||||
// assertEquals("89CE9E36AA9A9E03F1450936D2F4F8DD0F961F8B", result.getSha1sum());
|
||||
//assertEquals("89CE9E36AA9A9E03F1450936D2F4F8DD0F961F8B", result.getSha1sum());
|
||||
String expResult = "C30B57142E1CCBC1EFD5CD15F307358F";
|
||||
String result = instance.getMd5sum();
|
||||
assertEquals(expResult, result);
|
||||
@@ -294,4 +296,34 @@ public class DependencyTest {
|
||||
EvidenceCollection result = instance.getVersionEvidence();
|
||||
assertTrue(true); //this is just a getter setter pair.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addAsEvidence method, of class Dependency.
|
||||
*/
|
||||
@Test
|
||||
public void testAddAsEvidence() {
|
||||
Dependency instance = new Dependency();
|
||||
MavenArtifact mavenArtifact = new MavenArtifact("group", "artifact", "version", "url");
|
||||
instance.addAsEvidence("pom", mavenArtifact, Confidence.HIGH);
|
||||
assertTrue(instance.getEvidence().contains(Confidence.HIGH));
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "groupid").isEmpty());
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "artifactid").isEmpty());
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "version").isEmpty());
|
||||
assertFalse(instance.getIdentifiers().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addAsEvidence method, of class Dependency.
|
||||
*/
|
||||
@Test
|
||||
public void testAddAsEvidenceWithEmptyArtefact() {
|
||||
Dependency instance = new Dependency();
|
||||
MavenArtifact mavenArtifact = new MavenArtifact(null, null, null, null);
|
||||
instance.addAsEvidence("pom", mavenArtifact, Confidence.HIGH);
|
||||
assertFalse(instance.getEvidence().contains(Confidence.HIGH));
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "groupid").isEmpty());
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "artifactid").isEmpty());
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "version").isEmpty());
|
||||
assertTrue(instance.getIdentifiers().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,15 @@ public class SuppressionHandlerTest {
|
||||
|
||||
xmlReader.parse(in);
|
||||
|
||||
List result = handler.getSuppressionRules();
|
||||
List<SuppressionRule> result = handler.getSuppressionRules();
|
||||
assertTrue(result.size() > 3);
|
||||
int baseCount = 0;
|
||||
for (SuppressionRule r : result) {
|
||||
if (r.isBase()) {
|
||||
baseCount++;
|
||||
}
|
||||
}
|
||||
assertTrue(baseCount > 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,17 @@ public class SuppressionRuleTest {
|
||||
List<String> result = instance.getCve();
|
||||
assertEquals(cve, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of base property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testBase() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
assertFalse(instance.isBase());
|
||||
instance.setBase(true);
|
||||
assertTrue(instance.isBase());
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Ignored duplicate tests, left in, as empty tests, so IDE doesn't re-generate them">
|
||||
@@ -339,55 +350,70 @@ public class SuppressionRuleTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of cpeMatches method, of class SuppressionRule.
|
||||
* Test of identifierMatches method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCpeMatches() {
|
||||
Identifier identifier = new Identifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
Identifier identifier = new Identifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
|
||||
PropertyType cpe = new PropertyType();
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework:4.5");
|
||||
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
boolean expResult = true;
|
||||
boolean result = instance.cpeMatches(cpe, identifier);
|
||||
boolean result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework:4.0");
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("CPE:/a:microsoft:.net_framework:4.5");
|
||||
cpe.setCaseSensitive(true);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework");
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = true;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.*");
|
||||
cpe.setRegex(true);
|
||||
expResult = true;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("CPE:/a:microsoft:.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(true);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:apache:.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
identifier = new Identifier("maven", "org.springframework:spring-core:2.5.5", "https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.springframework&a=spring-core&v=2.5.5&e=jar");
|
||||
cpe.setValue("org.springframework:spring-core:2.5.5");
|
||||
cpe.setRegex(false);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = true;
|
||||
result = instance.identifierMatches("maven", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("org\\.springframework\\.security:spring.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = false;
|
||||
result = instance.identifierMatches("maven", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
@@ -398,7 +424,7 @@ public class SuppressionRuleTest {
|
||||
public void testProcess() {
|
||||
File struts = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
|
||||
Dependency dependency = new Dependency(struts);
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
String sha1 = dependency.getSha1sum();
|
||||
dependency.setSha1sum("384FAA82E193D4E4B0546059CA09572654BC3970");
|
||||
Vulnerability v = createVulnerability();
|
||||
@@ -409,33 +435,33 @@ public class SuppressionRuleTest {
|
||||
instance.setSha1(sha1);
|
||||
instance.addCwe("287");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
dependency.setSha1sum(sha1);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cvss
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCvssBelow(5f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
instance.addCvssBelow(8f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cve
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCve("CVE-2012-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
instance.addCve("CVE-2013-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cpe
|
||||
instance = new SuppressionRule();
|
||||
@@ -453,18 +479,58 @@ public class SuppressionRuleTest {
|
||||
instance.setFilePath(pt);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
assertTrue(dependency.getSuppressedIdentifiers().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
|
||||
instance = new SuppressionRule();
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:microsoft:.net_framework");
|
||||
instance.addCpe(pt);
|
||||
assertTrue(dependency.getIdentifiers().size() == 3);
|
||||
instance.setBase(true);
|
||||
assertEquals(3, dependency.getIdentifiers().size());
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
assertTrue(dependency.getSuppressedIdentifiers().size() == 3);
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of process method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testProcessGAV() {
|
||||
File spring = new File(this.getClass().getClassLoader().getResource("spring-security-web-3.0.0.RELEASE.jar").getPath());
|
||||
Dependency dependency = new Dependency(spring);
|
||||
dependency.addIdentifier("cpe", "cpe:/a:vmware:springsource_spring_framework:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:springsource:spring_framework:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:mod_security:mod_security:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:vmware:springsource_spring_security:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("maven", "org.springframework.security:spring-security-web:3.0.0.RELEASE", "some url not needed for this test");
|
||||
|
||||
//cpe
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
PropertyType pt = new PropertyType();
|
||||
|
||||
pt.setValue("org\\.springframework\\.security:spring.*");
|
||||
pt.setRegex(true);
|
||||
pt.setCaseSensitive(false);
|
||||
instance.setGav(pt);
|
||||
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:mod_security:mod_security");
|
||||
instance.addCpe(pt);
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:springsource:spring_framework");
|
||||
instance.addCpe(pt);
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:vmware:springsource_spring_framework");
|
||||
instance.addCpe(pt);
|
||||
|
||||
instance.process(dependency);
|
||||
assertEquals(2, dependency.getIdentifiers().size());
|
||||
|
||||
}
|
||||
|
||||
private Vulnerability createVulnerability() {
|
||||
|
||||
@@ -134,14 +134,14 @@ public class DependencyVersionTest {
|
||||
@Test
|
||||
public void testMatchesAtLeastThreeLevels() {
|
||||
|
||||
DependencyVersion instance = new DependencyVersion("1.2.3.4");
|
||||
DependencyVersion version = new DependencyVersion("1.2.3.5");
|
||||
DependencyVersion instance = new DependencyVersion("2.3.16.3");
|
||||
DependencyVersion version = new DependencyVersion("2.3.16.4");
|
||||
//true tests
|
||||
assertEquals(true, instance.matchesAtLeastThreeLevels(version));
|
||||
version = new DependencyVersion("1.2");
|
||||
version = new DependencyVersion("2.3");
|
||||
assertEquals(true, instance.matchesAtLeastThreeLevels(version));
|
||||
//false tests
|
||||
version = new DependencyVersion("1.2.2.5");
|
||||
version = new DependencyVersion("2.3.16.1");
|
||||
assertEquals(false, instance.matchesAtLeastThreeLevels(version));
|
||||
version = new DependencyVersion("2");
|
||||
assertEquals(false, instance.matchesAtLeastThreeLevels(version));
|
||||
@@ -165,6 +165,14 @@ public class DependencyVersionTest {
|
||||
version = new DependencyVersion("1.2.3.1");
|
||||
assertEquals(-1, instance.compareTo(version));
|
||||
|
||||
instance = new DependencyVersion("1.0.1n");
|
||||
version = new DependencyVersion("1.0.1m");
|
||||
assertEquals(1, instance.compareTo(version));
|
||||
version = new DependencyVersion("1.0.1n");
|
||||
assertEquals(0, instance.compareTo(version));
|
||||
version = new DependencyVersion("1.0.1o");
|
||||
assertEquals(-1, instance.compareTo(version));
|
||||
|
||||
DependencyVersion[] dv = new DependencyVersion[7];
|
||||
dv[0] = new DependencyVersion("2.1.3");
|
||||
dv[1] = new DependencyVersion("2.1.3.r2");
|
||||
|
||||
@@ -54,13 +54,13 @@ public class DependencyVersionUtilTest {
|
||||
* Test of parseVersion method, of class DependencyVersionUtil.
|
||||
*/
|
||||
@Test
|
||||
public void testParseVersionFromFileName() {
|
||||
public void testParseVersion() {
|
||||
final String[] fileName = {"something-0.9.5.jar", "lib2-1.1.jar", "lib1.5r4-someflag-R26.jar",
|
||||
"lib-1.2.5-dev-20050313.jar", "testlib_V4.4.0.jar", "lib-core-2.0.0-RC1-SNAPSHOT.jar",
|
||||
"lib-jsp-2.0.1_R114940.jar", "dev-api-2.3.11_R121413.jar", "lib-api-3.7-SNAPSHOT.jar",
|
||||
"-", "", "1.3-beta", "6"};
|
||||
"-", "", "1.3-beta", "6", "openssl1.0.1c", "jsf-impl-2.2.8-02.jar"};
|
||||
final String[] expResult = {"0.9.5", "1.1", "1.5.r4", "1.2.5", "4.4.0", "2.0.0.rc1",
|
||||
"2.0.1.r114940", "2.3.11.r121413", "3.7", "-", null, "1.3.beta", "6"};
|
||||
"2.0.1.r114940", "2.3.11.r121413", "3.7", "-", null, "1.3.beta", "6", "1.0.1c", "2.2.8.02"};
|
||||
|
||||
for (int i = 0; i < fileName.length; i++) {
|
||||
final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName[i]);
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
file name: FileHelpers.2.0.0.0.nupkg
|
||||
]]></notes>
|
||||
<sha1>30FB37D6163CF16E3BA740343BECDD14D5457619</sha1>
|
||||
<cve>CVE-2007-1536</cve>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
file name: commons-fileupload-1.2.1.jar
|
||||
]]></notes>
|
||||
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
|
||||
<cpe>cpe:/a:apache:commons_fileupload:1.2.1</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
file name: commons-fileupload-1.2.1.jar
|
||||
]]></notes>
|
||||
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
|
||||
<cve>CVE-2014-0050</cve>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
file name: commons-fileupload-1.2.1.jar
|
||||
]]></notes>
|
||||
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
|
||||
<cve>CVE-2013-0248</cve>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -13,8 +13,12 @@ max.download.threads=3
|
||||
# will not be used. The data.directory will be resolved and if the connection string
|
||||
# below contains a %s then the data.directory will replace the %s.
|
||||
data.directory=[JAR]/data
|
||||
# if the filename has a %s it will be replaced with the current expected version. For file
|
||||
# based databases the below filename will be added to the data directory above and then
|
||||
# if the connection string has a %s it will be replaced by the directory/filename path.
|
||||
data.file_name=cve.%s.h2.db
|
||||
data.version=2.9
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
|
||||
|
||||
# user name and password for the database connection. The inherent case is to use H2.
|
||||
@@ -43,11 +47,16 @@ cpe.meta.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-di
|
||||
cve.url.modified.validfordays=7
|
||||
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.startyear=2014
|
||||
cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-1.2.modified=https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
#cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
#cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
#cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
|
||||
|
||||
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
||||
analyzer.nexus.enabled=true
|
||||
@@ -55,3 +64,7 @@ analyzer.nexus.url=https://repository.sonatype.org/service/local/
|
||||
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||
# are configured
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
# the URL for searching search.maven.org for SHA-1 and whether it's enabled
|
||||
analyzer.central.enabled=true
|
||||
analyzer.central.url=http://search.maven.org/solrsearch/select
|
||||
|
||||
12297
dependency-check-core/src/test/resources/nvdcve-modified.xml
Normal file
12297
dependency-check-core/src/test/resources/nvdcve-modified.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@
|
||||
<filePath>c:\path\to\some.jar</filePath>
|
||||
<cpe>cpe:/a:csv:csv:1.0</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses any jboss:jboss cpe for any test.jar in any directory.
|
||||
]]></notes>
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<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>
|
||||
|
||||
<description>This plug-in can independently execute a Dependency-Check analysis and visualize the results.</description>
|
||||
<url>http://wiki.jenkins-ci.org/display/JENKINS/OWASP+Dependency-Check+Plugin</url>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-jenkins</artifactId>
|
||||
<name>Dependency-Check Jenkins Plugin</name>
|
||||
<url>http://wiki.jenkins-ci.org/display/JENKINS/OWASP+Dependency-Check+Plugin</url>
|
||||
<description>dependency-check-jenkins is a Jenkins plugin that runs dependency-check-core on a project to detect publicly disclosed vulnerabilities associated with the project's dependencies. The plugin will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries. This module is simply a placeholder and does not contain the actual plugin source code. The source code and distribution of the plugin is handled via https://github.com/jenkinsci/dependency-check-jenkins and Jenkin's plugin management.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/dependency-check-jenkins</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
<organization>
|
||||
@@ -31,15 +39,6 @@
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/dependency-check-maven</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:jenkinsci/dependency-check-jenkins.git</connection>
|
||||
<url>https://github.com/jenkinsci/dependency-check-jenkins</url>
|
||||
|
||||
@@ -15,7 +15,6 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2013 Jeremy Long. 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>
|
||||
<url>http://maven.apache.org</url>
|
||||
@@ -23,14 +22,14 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<packaging>maven-plugin</packaging>
|
||||
|
||||
<name>Dependency-Check Maven Plugin</name>
|
||||
<description>Dependency-Check-Maven is a Maven Plugin that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
||||
<description>dependency-check-maven is a Maven Plugin that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the project's dependencies. The plugin will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<inceptionYear>2013</inceptionYear>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
@@ -150,6 +149,9 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -239,7 +241,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
<exclude>**/generated/**/*.java</exclude>
|
||||
<exclude>**/HelpMojo.java</exclude>
|
||||
</excludes>
|
||||
<rulesets>
|
||||
@@ -277,6 +279,11 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-plugin-api</artifactId>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.doxia.sink.Sink;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugins.annotations.Component;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.reporting.MavenReport;
|
||||
import org.apache.maven.reporting.MavenReportException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is an abstract reporting mojo that enables report aggregation. Some of the code in the this class was copied
|
||||
* from the CoberturaReportMojo (http://mojo.codehaus.org/cobertura-maven-plugin/, version 2.6). The authors of the
|
||||
* CoberturaReportMojo were <a href="will.gwaltney@sas.com">Will Gwaltney</a> and
|
||||
* <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>. There working example of how to do report aggregation was
|
||||
* invaluable.</p>
|
||||
* <p>
|
||||
* An important point about using this abstract class is that it is intended for one to write some form of serialized
|
||||
* data (via the {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#writeDataFile() }; note that the
|
||||
* <code>writeDataFile()</code> function is called automatically after either {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeNonAggregateReport(org.apache.maven.doxia.sink.Sink,
|
||||
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
|
||||
* } or {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeAggregateReport(org.apache.maven.doxia.sink.Sink,
|
||||
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
|
||||
* } are called. When <code>executeAggregateReport()</code> is implemented, one can call {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#getChildDataFiles()
|
||||
* } to obtain a list of the data files to aggregate.</p>
|
||||
*
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class ReportAggregationMojo extends AbstractMojo implements MavenReport {
|
||||
|
||||
/**
|
||||
* The Maven Project Object.
|
||||
*/
|
||||
@Component
|
||||
private MavenProject project;
|
||||
|
||||
/**
|
||||
* Logger field reference.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportAggregationMojo.class.getName());
|
||||
|
||||
/**
|
||||
* List of Maven project of the current build
|
||||
*/
|
||||
@Parameter(readonly = true, required = true, property = "reactorProjects")
|
||||
private List<MavenProject> reactorProjects;
|
||||
|
||||
/**
|
||||
* Generate aggregate reports in multi-module projects.
|
||||
*/
|
||||
@Parameter(property = "aggregate", defaultValue = "false")
|
||||
private boolean aggregate;
|
||||
|
||||
/**
|
||||
* Sets whether or not the external report format should be used.
|
||||
*/
|
||||
@Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
|
||||
private String dataFileName;
|
||||
/**
|
||||
* Specifies the destination directory for the generated Dependency-Check report. This generally maps to
|
||||
* "target/site".
|
||||
*/
|
||||
@Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true)
|
||||
private File reportOutputDirectory;
|
||||
|
||||
/**
|
||||
* Sets the Reporting output directory.
|
||||
*
|
||||
* @param directory the output directory
|
||||
*/
|
||||
@Override
|
||||
public void setReportOutputDirectory(File directory) {
|
||||
reportOutputDirectory = directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output directory.
|
||||
*
|
||||
* @return the output directory
|
||||
*/
|
||||
@Override
|
||||
public File getReportOutputDirectory() {
|
||||
return reportOutputDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output directory for the given project.
|
||||
*
|
||||
* @param project the Maven project to get the output directory for
|
||||
* @return the output directory for the given project
|
||||
*/
|
||||
public File getReportOutputDirectory(MavenProject project) {
|
||||
final Object o = project.getContextValue(getOutputDirectoryContextKey());
|
||||
if (o != null && o instanceof File) {
|
||||
return (File) o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is an external report. This method always returns true.
|
||||
*
|
||||
* @return <code>true</code>
|
||||
*/
|
||||
@Override
|
||||
public final boolean isExternalReport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The collection of child projects.
|
||||
*/
|
||||
private final Map<MavenProject, Set<MavenProject>> projectChildren = new HashMap<MavenProject, Set<MavenProject>>();
|
||||
|
||||
/**
|
||||
* Called before execute; allows for any setup that is needed. If this is overridden you must call
|
||||
* </code>super.preExecute()</code>.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected void preExecute() throws MojoExecutionException, MojoFailureException {
|
||||
buildAggregateInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mojo is being executed.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected abstract void performExecute() throws MojoExecutionException, MojoFailureException;
|
||||
|
||||
/**
|
||||
* Runs after the mojo has executed. This implementation will call <code>writeDataFile()</code>. As such, it is
|
||||
* important that if this method is overriden that <code>super.postExecute()</code> is called.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected void postExecute() throws MojoExecutionException, MojoFailureException {
|
||||
final File written = writeDataFile();
|
||||
if (written != null) {
|
||||
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used to store the path to the data file that is saved by <code>writeDataFile()</code>. This key
|
||||
* is used in the <code>MavenProject.(set|get)ContextValue</code>.
|
||||
*
|
||||
* @return the key used to store the path to the data file
|
||||
*/
|
||||
protected String getDataFileContextKey() {
|
||||
return "dependency-check-path-" + this.getDataFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used to store the path to the output directory. When generating the report in the
|
||||
* <code>executeAggregateReport()</code> the output directory should be obtained by using this key.
|
||||
*
|
||||
* @return the key used to store the path to the output directory
|
||||
*/
|
||||
protected String getOutputDirectoryContextKey() {
|
||||
return "dependency-output-dir-" + this.getDataFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called by Maven to execute the mojo.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
public final void execute() throws MojoExecutionException, MojoFailureException {
|
||||
try {
|
||||
preExecute();
|
||||
performExecute();
|
||||
} finally {
|
||||
postExecute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs prior to the site report generation.
|
||||
*
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected void preGenerate() throws MavenReportException {
|
||||
buildAggregateInfo();
|
||||
|
||||
project.setContextValue(getOutputDirectoryContextKey(), getReportOutputDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes after the site report has been generated.
|
||||
*
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected void postGenerate() throws MavenReportException {
|
||||
final File written = writeDataFile();
|
||||
if (written != null) {
|
||||
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the non aggregate report.
|
||||
*
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected abstract void executeNonAggregateReport(Locale locale) throws MavenReportException;
|
||||
|
||||
/**
|
||||
* Generates the aggregate Site Report.
|
||||
*
|
||||
* @param project the maven project used to generate the aggregate report
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected abstract void executeAggregateReport(MavenProject project, Locale locale) throws MavenReportException;
|
||||
|
||||
/**
|
||||
* Generates the Dependency-Check Site Report.
|
||||
*
|
||||
* @param sink the sink to write the report to
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
* @deprecated use {@link #generate(org.apache.maven.doxia.sink.Sink, java.util.Locale) instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void generate(@SuppressWarnings("deprecation") org.codehaus.doxia.sink.Sink sink, Locale locale) throws MavenReportException {
|
||||
generate((Sink) sink, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency-Check Site Report.
|
||||
*
|
||||
* @param sink the sink to write the report to
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
public final void generate(Sink sink, Locale locale) throws MavenReportException {
|
||||
try {
|
||||
preGenerate();
|
||||
if (canGenerateNonAggregateReport()) {
|
||||
executeNonAggregateReport(locale);
|
||||
}
|
||||
|
||||
if (canGenerateAggregateReport()) {
|
||||
for (MavenProject proj : reactorProjects) {
|
||||
if (!isMultiModule(proj)) {
|
||||
continue;
|
||||
}
|
||||
executeAggregateReport(proj, locale);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
postGenerate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the mojo can generate a non-aggregate report for this project.
|
||||
*
|
||||
* @return <code>true</code> if a non-aggregate report can be generated, otherwise <code>false</code>
|
||||
*/
|
||||
protected abstract boolean canGenerateNonAggregateReport();
|
||||
|
||||
/**
|
||||
* Returns whether or not we can generate any aggregate reports at this time.
|
||||
*
|
||||
* @return <code>true</code> if an aggregate report can be generated, otherwise <code>false</code>
|
||||
*/
|
||||
protected abstract boolean canGenerateAggregateReport();
|
||||
|
||||
/**
|
||||
* Returns the name of the data file that contains the serialized data.
|
||||
*
|
||||
* @return the name of the data file that contains the serialized data
|
||||
*/
|
||||
protected String getDataFileName() {
|
||||
return dataFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the data file to disk in the target directory.
|
||||
*
|
||||
* @return the File object referencing the data file that was written
|
||||
*/
|
||||
protected abstract File writeDataFile();
|
||||
|
||||
/**
|
||||
* Collects the information needed for building aggregate reports.
|
||||
*/
|
||||
private void buildAggregateInfo() {
|
||||
// build parent-child map
|
||||
for (MavenProject proj : reactorProjects) {
|
||||
Set<MavenProject> depList = projectChildren.get(proj.getParent());
|
||||
if (depList == null) {
|
||||
depList = new HashSet<MavenProject>();
|
||||
projectChildren.put(proj.getParent(), depList);
|
||||
}
|
||||
depList.add(proj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
|
||||
*
|
||||
* @return a list of child projects
|
||||
*/
|
||||
protected List<MavenProject> getAllChildren() {
|
||||
return getAllChildren(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
|
||||
*
|
||||
* @param parentProject the parent project to collect the child project references
|
||||
* @return a list of child projects
|
||||
*/
|
||||
protected List<MavenProject> getAllChildren(MavenProject parentProject) {
|
||||
final Set<MavenProject> children = projectChildren.get(parentProject);
|
||||
if (children == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<MavenProject> result = new ArrayList<MavenProject>();
|
||||
for (MavenProject child : children) {
|
||||
if (isMultiModule(child)) {
|
||||
result.addAll(getAllChildren(child));
|
||||
} else {
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of data files that were produced by the direct children of the given MavenProject.
|
||||
*
|
||||
* @param project the Maven project to obtain the child data files from
|
||||
* @return a list of the data files
|
||||
*/
|
||||
protected List<File> getAllChildDataFiles(MavenProject project) {
|
||||
final List<MavenProject> children = getAllChildren(project);
|
||||
return getDataFiles(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any existing output files from the given list of projects.
|
||||
*
|
||||
* @param projects the list of projects to obtain the output files from
|
||||
* @return a list of output files
|
||||
*/
|
||||
protected List<File> getDataFiles(List<MavenProject> projects) {
|
||||
final List<File> files = new ArrayList<File>();
|
||||
for (MavenProject proj : projects) {
|
||||
final Object path = project.getContextValue(getDataFileContextKey());
|
||||
if (path == null) {
|
||||
final String msg = String.format("Unable to aggregate data for '%s' - aggregate data file was not generated",
|
||||
proj.getName());
|
||||
LOGGER.warning(msg);
|
||||
} else {
|
||||
final File outputFile = new File((String) path);
|
||||
if (outputFile.exists()) {
|
||||
files.add(outputFile);
|
||||
} else {
|
||||
if (!isMultiModule(project)) {
|
||||
final String msg = String.format("Unable to aggregate data for '%s' - missing data file '%s'",
|
||||
proj.getName(), outputFile.getPath());
|
||||
LOGGER.warning(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the project has pom packaging
|
||||
*
|
||||
* @param mavenProject Project to test
|
||||
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean isMultiModule(MavenProject mavenProject) {
|
||||
return "pom".equals(mavenProject.getPackaging());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the current project has pom packaging
|
||||
*
|
||||
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean isMultiModule() {
|
||||
return isMultiModule(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current project is the last project in a multi-module build. If the maven build is not a
|
||||
* multi-module project then this will always return true.
|
||||
*
|
||||
* @return <code>true</code> if the current project is the last project in a multi-module build; otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
protected boolean isLastProject() {
|
||||
return project.equals(reactorProjects.get(reactorProjects.size() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the mojo is configured to perform report aggregation.
|
||||
*
|
||||
* @return <code>true</code> if report aggregation is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
public boolean isAggregate() {
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the current project. This method is used instead of auto-binding the project via component
|
||||
* annotation in concrete implementations of this. If the child has a <code>@Component MavenProject project;</code>
|
||||
* defined then the abstract class (i.e. this class) will not have access to the current project (just the way Maven
|
||||
* works with the binding).
|
||||
*
|
||||
* @return returns a reference to the current project
|
||||
*/
|
||||
protected MavenProject getProject() {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.owasp.dependencycheck.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.doxia.sink.Sink;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Reference;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
|
||||
/**
|
||||
* A utility class that encapsulates the report generation for dependency-check-maven.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
final class ReportingUtil {
|
||||
|
||||
/**
|
||||
* Logger field reference.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportingUtil.class.getName());
|
||||
|
||||
/**
|
||||
* Empty private constructor for this utility class.
|
||||
*/
|
||||
private ReportingUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the reports for a given dependency-check engine.
|
||||
*
|
||||
* @param engine a dependency-check engine
|
||||
* @param outDirectory the directory to write the reports to
|
||||
* @param projectName the name of the project that a report is being generated for
|
||||
* @param format the format of the report to generate
|
||||
*/
|
||||
static void generateExternalReports(Engine engine, File outDirectory, String projectName, String format) {
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator r = new ReportGenerator(projectName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||
try {
|
||||
r.generateReports(outDirectory.getCanonicalPath(), format);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a dependency-check report using the Maven Site format.
|
||||
*
|
||||
* @param engine the engine used to scan the dependencies
|
||||
* @param sink the sink to write the data to
|
||||
* @param projectName the name of the project
|
||||
*/
|
||||
static void generateMavenSiteReport(final Engine engine, Sink sink, String projectName) {
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
|
||||
writeSiteReportHeader(sink, projectName);
|
||||
writeSiteReportTOC(sink, dependencies);
|
||||
|
||||
int cnt = 0;
|
||||
for (Dependency d : dependencies) {
|
||||
writeSiteReportDependencyHeader(sink, d);
|
||||
cnt = writeSiteReportDependencyEvidenceUsed(d, cnt, sink);
|
||||
cnt = writeSiteReportDependencyRelatedDependencies(d, cnt, sink);
|
||||
writeSiteReportDependencyIdentifiers(d, sink);
|
||||
writeSiteReportDependencyVulnerabilities(d, sink, cnt);
|
||||
}
|
||||
sink.body_();
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="various writeXXXXX methods to generate the Site Report">
|
||||
/**
|
||||
* Writes the vulnerabilities to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
*/
|
||||
private static void writeSiteReportDependencyVulnerabilities(Dependency d, Sink sink, int collapsibleHeaderCount) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
if (d.getVulnerabilities() != null && !d.getVulnerabilities().isEmpty()) {
|
||||
for (Vulnerability v : d.getVulnerabilities()) {
|
||||
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
try {
|
||||
sink.link("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + URLEncoder.encode(v.getName(), "US-ASCII"));
|
||||
sink.text(v.getName());
|
||||
sink.link_();
|
||||
sink.bold_();
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
sink.text(v.getName());
|
||||
sink.bold_();
|
||||
sink.lineBreak();
|
||||
sink.text("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + v.getName());
|
||||
}
|
||||
sink.paragraph_();
|
||||
sink.paragraph();
|
||||
sink.text("Severity: ");
|
||||
if (v.getCvssScore() < 4.0) {
|
||||
sink.text("Low");
|
||||
} else {
|
||||
if (v.getCvssScore() >= 7.0) {
|
||||
sink.text("High");
|
||||
} else {
|
||||
sink.text("Medium");
|
||||
}
|
||||
}
|
||||
sink.lineBreak();
|
||||
sink.text("CVSS Score: " + v.getCvssScore());
|
||||
if (v.getCwe() != null && !v.getCwe().isEmpty()) {
|
||||
sink.lineBreak();
|
||||
sink.text("CWE: ");
|
||||
sink.text(v.getCwe());
|
||||
}
|
||||
sink.paragraph_();
|
||||
sink.paragraph();
|
||||
sink.text(v.getDescription());
|
||||
if (v.getReferences() != null && !v.getReferences().isEmpty()) {
|
||||
sink.list();
|
||||
for (Reference ref : v.getReferences()) {
|
||||
sink.listItem();
|
||||
sink.text(ref.getSource());
|
||||
sink.text(" - ");
|
||||
sink.link(ref.getUrl());
|
||||
sink.text(ref.getName());
|
||||
sink.link_();
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
sink.paragraph_();
|
||||
if (v.getVulnerableSoftware() != null && !v.getVulnerableSoftware().isEmpty()) {
|
||||
sink.paragraph();
|
||||
|
||||
cnt += 1;
|
||||
sink.rawText("Vulnerable Software <a href=\"javascript:toggleElement(this, 'vulnSoft" + cnt + "')\">[-]</a>");
|
||||
sink.rawText("<div id=\"vulnSoft" + cnt + "\" style=\"display:block\">");
|
||||
sink.list();
|
||||
for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
|
||||
sink.listItem();
|
||||
try {
|
||||
sink.link("http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + URLEncoder.encode(vs.getName(), "US-ASCII"));
|
||||
sink.text(vs.getName());
|
||||
sink.link_();
|
||||
if (vs.hasPreviousVersion()) {
|
||||
sink.text(" and all previous versions.");
|
||||
}
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
sink.text(vs.getName());
|
||||
if (vs.hasPreviousVersion()) {
|
||||
sink.text(" and all previous versions.");
|
||||
}
|
||||
sink.text(" (http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + vs.getName() + ")");
|
||||
}
|
||||
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
sink.rawText("</div>");
|
||||
sink.paragraph_();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the identifiers to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
*/
|
||||
private static void writeSiteReportDependencyIdentifiers(Dependency d, Sink sink) {
|
||||
if (d.getIdentifiers() != null && !d.getIdentifiers().isEmpty()) {
|
||||
sink.sectionTitle4();
|
||||
sink.text("Identifiers");
|
||||
sink.sectionTitle4_();
|
||||
sink.list();
|
||||
for (Identifier i : d.getIdentifiers()) {
|
||||
sink.listItem();
|
||||
sink.text(i.getType());
|
||||
sink.text(": ");
|
||||
if (i.getUrl() != null && i.getUrl().length() > 0) {
|
||||
sink.link(i.getUrl());
|
||||
sink.text(i.getValue());
|
||||
sink.link_();
|
||||
} else {
|
||||
sink.text(i.getValue());
|
||||
}
|
||||
if (i.getDescription() != null && i.getDescription().length() > 0) {
|
||||
sink.lineBreak();
|
||||
sink.text(i.getDescription());
|
||||
}
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the related dependencies to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
* @return the collapsible header count
|
||||
*/
|
||||
private static int writeSiteReportDependencyRelatedDependencies(Dependency d, int collapsibleHeaderCount, Sink sink) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
if (d.getRelatedDependencies() != null && !d.getRelatedDependencies().isEmpty()) {
|
||||
cnt += 1;
|
||||
sink.sectionTitle4();
|
||||
sink.rawText("Related Dependencies <a href=\"javascript:toggleElement(this, 'related" + cnt + "')\">[+]</a>");
|
||||
sink.sectionTitle4_();
|
||||
sink.rawText("<div id=\"related" + cnt + "\" style=\"display:none\">");
|
||||
sink.list();
|
||||
for (Dependency r : d.getRelatedDependencies()) {
|
||||
sink.listItem();
|
||||
sink.text(r.getFileName());
|
||||
sink.list();
|
||||
writeListItem(sink, "File Path: " + r.getFilePath());
|
||||
writeListItem(sink, "SHA1: " + r.getSha1sum());
|
||||
writeListItem(sink, "MD5: " + r.getMd5sum());
|
||||
sink.list_();
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
sink.rawText("</div>");
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the evidence used to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
* @return the collapsible header count
|
||||
*/
|
||||
private static int writeSiteReportDependencyEvidenceUsed(Dependency d, int collapsibleHeaderCount, Sink sink) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
final Set<Evidence> evidence = d.getEvidenceForDisplay();
|
||||
if (evidence != null && evidence.size() > 0) {
|
||||
cnt += 1;
|
||||
sink.sectionTitle4();
|
||||
sink.rawText("Evidence Collected <a href=\"javascript:toggleElement(this, 'evidence" + cnt + "')\">[+]</a>");
|
||||
sink.sectionTitle4_();
|
||||
sink.rawText("<div id=\"evidence" + cnt + "\" style=\"display:none\">");
|
||||
sink.table();
|
||||
sink.tableRow();
|
||||
writeTableHeaderCell(sink, "Source");
|
||||
writeTableHeaderCell(sink, "Name");
|
||||
writeTableHeaderCell(sink, "Value");
|
||||
sink.tableRow_();
|
||||
for (Evidence e : evidence) {
|
||||
sink.tableRow();
|
||||
writeTableCell(sink, e.getSource());
|
||||
writeTableCell(sink, e.getName());
|
||||
writeTableCell(sink, e.getValue());
|
||||
sink.tableRow_();
|
||||
}
|
||||
sink.table_();
|
||||
sink.rawText("</div>");
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the dependency header to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
*/
|
||||
private static void writeSiteReportDependencyHeader(Sink sink, Dependency d) {
|
||||
sink.sectionTitle2();
|
||||
sink.anchor("sha1" + d.getSha1sum());
|
||||
sink.text(d.getFileName());
|
||||
sink.anchor_();
|
||||
sink.sectionTitle2_();
|
||||
if (d.getDescription() != null && d.getDescription().length() > 0) {
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
sink.text("Description: ");
|
||||
sink.bold_();
|
||||
sink.text(d.getDescription());
|
||||
sink.paragraph_();
|
||||
}
|
||||
if (d.getLicense() != null && d.getLicense().length() > 0) {
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
sink.text("License: ");
|
||||
sink.bold_();
|
||||
if (d.getLicense().startsWith("http://") && !d.getLicense().contains(" ")) {
|
||||
sink.link(d.getLicense());
|
||||
sink.text(d.getLicense());
|
||||
sink.link_();
|
||||
} else {
|
||||
sink.text(d.getLicense());
|
||||
}
|
||||
sink.paragraph_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list item to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeListItem(Sink sink, String text) {
|
||||
sink.listItem();
|
||||
sink.text(text);
|
||||
sink.listItem_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table cell to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeTableCell(Sink sink, String text) {
|
||||
sink.tableCell();
|
||||
sink.text(text);
|
||||
sink.tableCell_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table header cell to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeTableHeaderCell(Sink sink, String text) {
|
||||
sink.tableHeaderCell();
|
||||
sink.text(text);
|
||||
sink.tableHeaderCell_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the TOC for the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param dependencies the dependencies that are being reported on
|
||||
*/
|
||||
private static void writeSiteReportTOC(Sink sink, final List<Dependency> dependencies) {
|
||||
sink.list();
|
||||
for (Dependency d : dependencies) {
|
||||
sink.listItem();
|
||||
sink.link("#sha1" + d.getSha1sum());
|
||||
sink.text(d.getFileName());
|
||||
sink.link_();
|
||||
if (!d.getVulnerabilities().isEmpty()) {
|
||||
sink.rawText(" <font style=\"color:red\">•</font>");
|
||||
}
|
||||
if (!d.getRelatedDependencies().isEmpty()) {
|
||||
sink.list();
|
||||
for (Dependency r : d.getRelatedDependencies()) {
|
||||
writeListItem(sink, r.getFileName());
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the site report header.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param projectName the name of the project
|
||||
*/
|
||||
private static void writeSiteReportHeader(Sink sink, String projectName) {
|
||||
sink.head();
|
||||
sink.title();
|
||||
sink.text("Dependency-Check Report: " + projectName);
|
||||
sink.title_();
|
||||
sink.head_();
|
||||
sink.body();
|
||||
sink.rawText("<script type=\"text/javascript\">");
|
||||
sink.rawText("function toggleElement(el, targetId) {");
|
||||
sink.rawText("if (el.innerText == '[+]') {");
|
||||
sink.rawText(" el.innerText = '[-]';");
|
||||
sink.rawText(" document.getElementById(targetId).style.display='block';");
|
||||
sink.rawText("} else {");
|
||||
sink.rawText(" el.innerText = '[+]';");
|
||||
sink.rawText(" document.getElementById(targetId).style.display='none';");
|
||||
sink.rawText("}");
|
||||
|
||||
sink.rawText("}");
|
||||
sink.rawText("</script>");
|
||||
sink.section1();
|
||||
sink.sectionTitle1();
|
||||
sink.text("Project: " + projectName);
|
||||
sink.sectionTitle1_();
|
||||
sink.date();
|
||||
final Date now = new Date();
|
||||
sink.text(DateFormat.getDateTimeInstance().format(now));
|
||||
sink.date_();
|
||||
sink.section1_();
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
}
|
||||
@@ -4,8 +4,8 @@ The following properties can be set on the dependency-check-maven plugin.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
aggregate | Sets whether report aggregation will be performed for multi-module site reports. This option only affects the report generation when configured within the reporting section. | false
|
||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
||||
externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
|
||||
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'
|
||||
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
|
||||
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
@@ -23,49 +23,44 @@ Note, that specific analyzers will automatically disable themselves if no file
|
||||
types that they support are detected - so specifically disabling them may not
|
||||
be needed.
|
||||
|
||||
Property | Description | Default Value
|
||||
------------------------|------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
Property | Description | Default Value
|
||||
------------------------|---------------------------------------------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus Pro Server URL. If not set the Nexus Analyzer will be disabled. |
|
||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems |
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||
|
||||
Advanced Configuration
|
||||
====================
|
||||
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
||||
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|-------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
Property | Description | Default Value
|
||||
---------------------|--------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2. | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year. | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
connectionTimeout | Sets the URL Connection Timeout used when downloading external data. |
|
||||
dataDirectory | Sets the data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
databaseDriverName | The name of the database driver. Example: org.h2.Driver. |
|
||||
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
||||
connectionString | The connection string used to connect to the database. |
|
||||
databaseUser | The username used when connecting to the database. |
|
||||
databasePassword | The password used when connecting to the database. |
|
||||
metaFileName | Sets the name of the file to use for storing the metadata about the project. | dependency-check.ser
|
||||
|
||||
|
||||
Deprecated Configuration
|
||||
Proxy Configuration
|
||||
====================
|
||||
The following properties have been deprecated. These can still be set in
|
||||
the dependency-check-maven plugin's configuration. However, future versions
|
||||
will remove these properties. Instead using these properties you should
|
||||
use [Maven's settings](https://maven.apache.org/settings.html#Proxies) to
|
||||
configure a proxy.
|
||||
Use [Maven's settings](https://maven.apache.org/settings.html#Proxies) to configure a proxy server. If multiple proxies
|
||||
are configured in the Maven settings file you must tell dependency-check which proxy to use with the following property:
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|--------------------------------------------------------------------------------------|------------------
|
||||
mavenSettingsProxyId | The id for the proxy, configured via settings.xml, that dependency-check should use. |
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
proxyUrl | The Proxy URL. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user