Compare commits

...

72 Commits

Author SHA1 Message Date
Jeremy Long
3264becdc2 minor correction to unit tests
Former-commit-id: 44829f536b0940ed95750890262a1ab668c57745
2014-03-29 07:28:24 -04:00
Jeremy Long
845bf6ada1 version 1.1.4
Former-commit-id: 9d8e2cc70f7779b99e98aac396475f70980d7147
2014-03-29 06:55:03 -04:00
Jeremy Long
865ef2beb3 FindBugs corrections
Former-commit-id: 3bde1ba8aa05c0007a40be7594a6ded6675f5441
2014-03-29 05:58:56 -04:00
Jeremy Long
ace5353595 find bugs corrections
Former-commit-id: 34820edd6de652dc6f62702de332447d0ba48398
2014-03-29 05:54:53 -04:00
Jeremy Long
56a43fe17b checkstyle corrections
Former-commit-id: c49596f06b497f80dbe6b5b9656a5221312c7e3f
2014-03-29 05:34:46 -04:00
Jeremy Long
46f36dc7ab updated cli help to indicate wild cards can be used to limit scan to specific file extensions
Former-commit-id: 1369c129ee4a774ce22fda28a4e74468b578da40
2014-03-29 05:26:07 -04:00
Jeremy Long
db0ac70b71 checkstyle corrections
Former-commit-id: 2d7107de4141937a5be66c42b170130118c7d613
2014-03-29 05:23:49 -04:00
Jeremy Long
6cfcc903df updated documentation to support wild card file extensions
Former-commit-id: fb64ad0e0997dfb3dc3c607ef6d2818afd0b3606
2014-03-29 05:23:34 -04:00
Jeremy Long
2ccae9f434 added back in scan methods that were removed by mistake
Former-commit-id: c4a26c76c2668a2b635f361a55d3c840a842f6f7
2014-03-28 05:28:17 -04:00
Jeremy Long
139bf0ee35 updated delete file method
Former-commit-id: d5821f9476d9b230633eb0feac20d72f60baf337
2014-03-28 05:21:16 -04:00
Jeremy Long
1ce6e37e78 added support for wildcard extensions in scan path for issue #95
Former-commit-id: d02eaf80664e4525d9b00ba5978bec5cced0970a
2014-03-28 05:03:37 -04:00
Jeremy Long
462026e7e9 fixed bug causing analyzer to hang reading from an empty error input steam
Former-commit-id: 1b474a3376df612a13a62d8a31efb035c421afc5
2014-03-28 04:06:42 -04:00
Jeremy Long
2f180510b8 Merge branch 'master' of github.com:colezlaw/DependencyCheck into colezlaw-master
Former-commit-id: 1eb983f1cbcd44b029b912b7a87f19ee78d6233e
2014-03-28 02:40:26 -04:00
Will Stranathan
53e67dfb27 Updated waitFor semantics
Former-commit-id: 1080c4eca42029535508f2503ac0a76e853a7fcc
2014-03-27 17:34:45 -04:00
Jeremy Long
ff951130b6 added initial version of legal disclaimer - it will need to be updated
Former-commit-id: 776adc94aad64db842ce216f3f88354ffba79091
2014-03-27 15:35:59 -04:00
Will Stranathan
69ebb53a05 Squashed commit of the following:
commit 1d1a06a5ae7ea4f6e3adbf5a4b8163eba50562a3
Author: Will Stranathan <will@thestranathans.com>
Date:   Wed Mar 26 22:59:15 2014 -0400

    Updated unit tests and logging

commit bb00174e62c9657809d6e5a9cde7c7308d905593
Author: Will Stranathan <will@thestranathans.com>
Date:   Wed Mar 26 22:20:28 2014 -0400

    Updated GrokAssembly to not fail if the vendor can't be gotten

commit 27f7c9366acca8abbff9c6e9fa9ce1a1329da887
Author: Will Stranathan <will@thestranathans.com>
Date:   Wed Mar 26 22:18:33 2014 -0400

    Updated unit test to not care about version number


Former-commit-id: e700a5f81b7b0f6d6ccf392e846723e67fff591c
2014-03-26 23:02:17 -04:00
Jeremy Long
1a2a3d1945 added another test jar
Former-commit-id: c1eee9a685aed640be0d3a535f2888bf9e972990
2014-03-26 07:38:13 -04:00
Jeremy Long
c8b967ba37 updated engine to fix bug with archive analyzer prematurely deleting fiels
Former-commit-id: dd4400e3c852f2d9bf7bf3b89f54913be79d6d68
2014-03-26 07:33:52 -04:00
Jeremy Long
83b713a781 updated documentation for PR #98
Former-commit-id: 2121e1d535939646b3c7ce9b9b485c00f5b4bef8
2014-03-24 23:55:36 -04:00
Will Stranathan
c930568df7 Switched default Nexus to SSL to fix 301 issues
Former-commit-id: 231a5f20652fd83123f614881198edf675dd1105
2014-03-24 19:59:13 -04:00
Jeremy Long
95e2c6179f applied PR from Steve to close issue #96 and issue #97
Former-commit-id: d758d881a762c38b27d1a6ef1e17ebdab1efd5a7
2014-03-23 23:27:49 -04:00
Jeremy Long
dfdf690575 added configuration settings to the interfaces to support disabling of specific analyzers per issue #86
Former-commit-id: ce5fe7e4340a4df6f0a59a78acee6429a10ba01b
2014-03-23 23:08:03 -04:00
Jeremy Long
db30517516 various findbug, checkstyle, documentation fixes
Former-commit-id: 436d6de72216aa90360c96b5f2d23adbbd733e7b
2014-03-23 23:07:27 -04:00
Jeremy Long
534b2e59a0 fixed bug where the analyzers were not being closed
Former-commit-id: 50f1859e79cf11a19837a389b4edd3c563d2c7c8
2014-03-23 23:06:14 -04:00
Jeremy Long
5028216058 added enabled properties in support of issue #86
Former-commit-id: e6df3962e1e96b28fad499694b580423cd1cb7b5
2014-03-23 23:05:41 -04:00
Jeremy Long
173947fd7d updated documentation
Former-commit-id: b2036f354cc3d16db7e01bef9aad6aa494650fd2
2014-03-23 23:03:51 -04:00
Jeremy Long
9aa6ad216d updated tests to fix issues with the analyzer disabling themselves
Former-commit-id: 8286f053801efa11e10d3ea07529444a585859b8
2014-03-23 00:36:54 -04:00
Jeremy Long
b2a5963f5a added the ability to have a default value for getBoolean
Former-commit-id: 3768e635a48b42f198fd9e11a248f93cc8662aaa
2014-03-23 00:36:10 -04:00
Jeremy Long
c80fdee99b updated to allow turning off individual file type analyzers via configuration
Former-commit-id: c492d41e1b5ad0c890cb750370dff326c3d0de05
2014-03-23 00:33:00 -04:00
Jeremy Long
270db7829d fixed teest case
Former-commit-id: 7ced3ad498d077c8bed116c161744dd817250d96
2014-03-17 20:42:43 -04:00
Jeremy Long
5ff9ec9942 improved the abstract base class to support enabling/disabling each FileTypeAnalyzer
Former-commit-id: a2464c7041d292e6f3a2ec0d2b1e75f3bcfce425
2014-03-17 00:08:04 -04:00
Jeremy Long
2fc554e1d4 major revision to patch issue #86; file type analyzers will no longer initialize if no files were detected that they can process during the scan phase.
Former-commit-id: 1d9ef39d5f7898de73ac72bbb9573af763368e95
2014-03-16 22:39:44 -04:00
Jeremy Long
7a35c1638b updated initialization of the analyzers to use less looping
Former-commit-id: 517e0b87d6673c44d50ba60e4e4d50693f22ab98
2014-03-16 07:50:41 -04:00
Jeremy Long
916243468f added a vulnerability suppression analyzer test case
Former-commit-id: 415f214241e2ac6e882ea0291e6c11d991d4be8f
2014-03-16 07:05:05 -04:00
Jeremy Long
cb56bbc122 updated class name
Former-commit-id: 7cda28ba656b243a6b64d1101cd81a2868837c2c
2014-03-16 07:04:36 -04:00
Jeremy Long
d1b2d5cb27 renamed class
Former-commit-id: 216b78611cee90c521c36b2c20c9324cb5086f4f
2014-03-16 07:02:58 -04:00
Jeremy Long
884b56a4ef renamed class
Former-commit-id: f27ba73aff027de16b9f950401b4fee125cb19eb
2014-03-16 07:02:34 -04:00
Jeremy Long
eeb8d9cdf5 fixed a bug that caused the suppression file not to load
Former-commit-id: 3cc9ab64b4f9efbc51c497b82d9b63e2edd8376d
2014-03-16 07:02:10 -04:00
Jeremy Long
e8d7bbd280 updated the base class name to be more accurate
Former-commit-id: 38c9eed0e4226ce08d11f95b4e7f2a1ecca1f67c
2014-03-16 07:01:24 -04:00
Jeremy Long
277ee4c4b2 changed the logging level on the "entrance" log
Former-commit-id: 92b0b110cbcf05ca71e22fc244d1daefd5072e26
2014-03-16 07:00:44 -04:00
Jeremy Long
efa6c8135d improved manifest parsing to exclude additional entries per issue #88
Former-commit-id: 0665b1d9967324f6c07e95b593d6b199da5b5ee3
2014-03-16 04:49:09 -04:00
Jeremy Long
cbb705c367 updated so that the Filename was properely escaped in Javascript so that it shows up correctly in the report to fix issue #91
Former-commit-id: ec161508db21c0a3d1f4f6f4130e5fdc63d9b367
2014-03-16 04:13:43 -04:00
Jeremy Long
44326cd8c1 minor update to the generated report names
Former-commit-id: e072df44801e468c7a5d46e2f8eb039a8733865e
2014-03-15 07:48:19 -04:00
Jeremy Long
4592ab4bf5 updated to resolve issue #87
Former-commit-id: 03c12742bbd99b980c605d78b3d25fb1f89ab3cd
2014-03-15 07:46:29 -04:00
Jeremy Long
870849f01a minor update to the generated report names
Former-commit-id: 2319209d909b7350447c91af693f88e57e437a7e
2014-03-15 07:42:55 -04:00
Jeremy Long
a00bcc3df2 patch from davidkarlsen (PR #85) was applied to resolve issue #84
Former-commit-id: ac2f1c66913d08ae2e39293e98a3e7e5b9318b50
2014-03-12 23:40:42 -04:00
Jeremy Long
122dc5baf4 updated logo
Former-commit-id: 4ea34b9862eef2229bd1ba7c2e3868f12c336055
2014-03-11 11:59:54 -04:00
Jeremy Long
a276d2da4f version 1.1.4-SNAPSHOT
Former-commit-id: 969be860afdca6a1e86f6ef03b2218c34cb07114
2014-03-11 11:52:57 -04:00
Jeremy Long
6f04d4d43b version 1.1.3
Former-commit-id: af8a66cf2ecda07b7005d20f9de9dbe14d61e187
2014-03-11 11:49:32 -04:00
Jeremy Long
a966f263a2 created a new getTempFile() to FileUtils that does not create the file, it only generates the file name
Former-commit-id: 04e275caade0deba97b3b03cf41fa48f962c0172
2014-03-10 21:25:53 -04:00
Jeremy Long
ac5a23ef29 minor checkstyle correctionn
Former-commit-id: 72cfe98796cc4b8ba335c1cf6de293b30e111d99
2014-03-10 14:53:06 -04:00
Jeremy Long
b82804018d updated to ignore .LCKpom.xml~
Former-commit-id: f81c6f5c3fb3e8529275ce8db56bb0919aa32953
2014-03-10 11:25:40 -04:00
Jeremy Long
35b0b684df updated to delete newly created file prior to attempting to copy a new file into its location
Former-commit-id: 584dc6abeab388acf65ab3d5379616005746db6b
2014-03-10 10:36:03 -04:00
Jeremy Long
a627ca2127 minor updates for issue #58
Former-commit-id: 6f4d0edc03654c73dc6de29a47d65e6297814613
2014-03-09 12:40:42 -04:00
Jeremy Long
05a1096e25 initial version of test cases
Former-commit-id: 7fc3697e5cf1dd2730ea15c4bf7de568033ef9eb
2014-03-09 12:39:36 -04:00
Will Stranathan
9600e56344 Fixed two discrepancies in the CLI options
1) Proxy port and Properties files were both using -p. Now the
properties file uses -P.
2) Nexus Proxy was defaulting to true, even if the properties said
false, so moved the check for its setting to happen after the properties
were merged and had it default to checking the properties file and
setting it to true if the properties didn't say.


Former-commit-id: 6a4bcb9b457eea5a55e2cc74acc47d69637b7620
2014-03-08 18:58:39 -05:00
Jeremy Long
1bb0871948 updated grokassembly version in the test case
Former-commit-id: 233cf163ecf40331a3ac175e764e16bd8d044273
2014-03-08 06:36:31 -05:00
Jeremy Long
6ff50689e1 updated to resolve issue #58
Former-commit-id: 8787dadc04127169c2ae4d19ee0ac96399b63b62
2014-03-08 06:28:36 -05:00
Jeremy Long
9b025ddece corrected syntax error caused by copy paste
Former-commit-id: cd7b981f94fbc4e2f5124fc791162c1a96e2c7ce
2014-03-08 06:22:03 -05:00
Jeremy Long
12fd77f0b2 updated to correctly use the correctly configured temp directory
Former-commit-id: 1080d1ae37304188818f59fff5234d29857c64f5
2014-03-08 06:21:08 -05:00
Jeremy Long
0e60883b3d updated to correctly use the correctly configured temp directory
Former-commit-id: e470dd805e126a7b2aae56f067c8fbe4bb85613a
2014-03-08 06:20:32 -05:00
Jeremy Long
33b6bfe5be updated to correctly use the correctly configured temp directory
Former-commit-id: 048a7f7464f454810924a61110f0af18ac206c5b
2014-03-08 06:20:12 -05:00
Jeremy Long
8167146372 added validation for pathToMono argument
Former-commit-id: 5a2a58c96ee91b0d0dbf7b5a658a776da8a7141f
2014-03-08 06:19:21 -05:00
Jeremy Long
21bbedaf04 added option to download a file without using the configured proxy
Former-commit-id: 234d9ba35d11459473a2f6311ffe4fc56003a083
2014-03-08 06:18:44 -05:00
Jeremy Long
998aedde33 added the path to mono as a configurable setting
Former-commit-id: e0b0e5eed59f36060c4ad57052fe3e610ff2d637
2014-03-08 05:42:32 -05:00
Will Stranathan
25050da2c9 Merge branch 'master' of github.com:/colezlaw/DependencyCheck
Former-commit-id: c9d90f875ca9fe981d2bb294a7ed416b1e299987
2014-03-05 21:52:56 -05:00
Will Stranathan
a74cf8ec4d Updated GrokAssembly to catch a couple of possible exceptions
Former-commit-id: dfc1b67da43178d3653c35ab80fa244bbfd3e70b
2014-03-05 21:52:19 -05:00
Will Stranathan
e06f0a5d49 Updated GrokAssembly to catch a couple of possible exceptions
Former-commit-id: 52c6ae3bd8ff6acccecd9aa709dceb3c2aed6265
2014-03-04 13:18:04 -05:00
Will Stranathan
9d1ea4b551 Merge remote-tracking branch 'upstream/master'
Former-commit-id: c980e2c3cbcfbebd38bd99b62ffcca60f0153eb0
2014-03-04 13:13:01 -05:00
Jeremy Long
e0410783be updated version to 1.1.3-SNAPSHOT
Former-commit-id: b0d241a5d856244c5dac22f24d2ea135d2e4f545
2014-03-04 07:33:27 -05:00
Jeremy Long
d064337c15 corrected intellij idea link
Former-commit-id: da919f5e5b81328e35e7a91f0f16f0c07f42a1e4
2014-03-03 19:54:46 -05:00
Will Stranathan
4340368e49 Merge remote-tracking branch 'upstream/master'
Former-commit-id: ec7e5a5f328476863cc1d92354268ccf99bc33cf
2014-03-01 15:26:53 -05:00
68 changed files with 3014 additions and 836 deletions

4
.gitignore vendored
View File

@@ -15,4 +15,6 @@ dependency-reduced-pom.xml
#ruby Gemfile, etc. This is a java project, Gemfile is here to check site problem with Jekyll #ruby Gemfile, etc. This is a java project, Gemfile is here to check site problem with Jekyll
Gemfile Gemfile
Gemfile.lock Gemfile.lock
_site/** _site/**
#unknown as to why these are showing up... but need to be ignored.
.LCKpom.xml~

View File

@@ -21,7 +21,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<parent> <parent>
<groupId>org.owasp</groupId> <groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId> <artifactId>dependency-check-parent</artifactId>
<version>1.1.2</version> <version>1.1.4</version>
</parent> </parent>
<artifactId>dependency-check-ant</artifactId> <artifactId>dependency-check-ant</artifactId>

View File

@@ -457,6 +457,81 @@ public class DependencyCheckTask extends Task {
this.showSummary = showSummary; this.showSummary = showSummary;
} }
/**
* Sets whether or not the analyzer is enabled.
*
* @param jarAnalyzerEnabled the value of the new setting
*/
public void setJarAnalyzerEnabled(boolean jarAnalyzerEnabled) {
this.jarAnalyzerEnabled = jarAnalyzerEnabled;
}
/**
* Whether or not the Archive Analyzer is enabled.
*/
private boolean archiveAnalyzerEnabled = true;
/**
* Returns whether or not the analyzer is enabled.
*
* @return true if the analyzer is enabled
*/
public boolean isArchiveAnalyzerEnabled() {
return archiveAnalyzerEnabled;
}
/**
* Whether or not the .NET Assembly Analyzer is enabled.
*/
private boolean assemblyAnalyzerEnabled = true;
/**
* Sets whether or not the analyzer is enabled.
*
* @param archiveAnalyzerEnabled the value of the new setting
*/
public void setArchiveAnalyzerEnabled(boolean archiveAnalyzerEnabled) {
this.archiveAnalyzerEnabled = archiveAnalyzerEnabled;
}
/**
* Returns whether or not the analyzer is enabled.
*
* @return true if the analyzer is enabled
*/
public boolean isAssemblyAnalyzerEnabled() {
return assemblyAnalyzerEnabled;
}
/**
* Sets whether or not the analyzer is enabled.
*
* @param assemblyAnalyzerEnabled the value of the new setting
*/
public void setAssemblyAnalyzerEnabled(boolean assemblyAnalyzerEnabled) {
this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
}
/**
* Whether or not the .NET Nuspec Analyzer is enabled.
*/
private boolean nuspecAnalyzerEnabled = true;
/**
* Returns whether or not the analyzer is enabled.
*
* @return true if the analyzer is enabled
*/
public boolean isNuspecAnalyzerEnabled() {
return nuspecAnalyzerEnabled;
}
/**
* Sets whether or not the analyzer is enabled.
*
* @param nuspecAnalyzerEnabled the value of the new setting
*/
public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
}
/** /**
* Whether or not the nexus analyzer is enabled. * Whether or not the nexus analyzer is enabled.
*/ */
@@ -753,6 +828,28 @@ public class DependencyCheckTask extends Task {
public void setCveUrl20Base(String cveUrl20Base) { public void setCveUrl20Base(String cveUrl20Base) {
this.cveUrl20Base = cveUrl20Base; this.cveUrl20Base = cveUrl20Base;
} }
/**
* The path to Mono for .NET assembly analysis on non-windows systems.
*/
private String pathToMono;
/**
* Get the value of pathToMono.
*
* @return the value of pathToMono
*/
public String getPathToMono() {
return pathToMono;
}
/**
* Set the value of pathToMono.
*
* @param pathToMono new value of pathToMono
*/
public void setPathToMono(String pathToMono) {
this.pathToMono = pathToMono;
}
@Override @Override
public void execute() throws BuildException { public void execute() throws BuildException {
@@ -885,11 +982,29 @@ public class DependencyCheckTask extends Task {
if (suppressionFile != null && !suppressionFile.isEmpty()) { if (suppressionFile != null && !suppressionFile.isEmpty()) {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile); Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
} }
//File Type Analyzer Settings
//JAR ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
//NUSPEC ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
//NEXUS ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled); Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
if (nexusUrl != null && !nexusUrl.isEmpty()) { if (nexusUrl != null && !nexusUrl.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl); Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
} }
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy); Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
//ARCHIVE ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
if (zipExtensions != null && !zipExtensions.isEmpty()) {
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
}
//ASSEMBLY ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
if (pathToMono != null && !pathToMono.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
}
if (databaseDriverName != null && !databaseDriverName.isEmpty()) { if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName); Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
} }
@@ -905,9 +1020,6 @@ public class DependencyCheckTask extends Task {
if (databasePassword != null && !databasePassword.isEmpty()) { if (databasePassword != null && !databasePassword.isEmpty()) {
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword); Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
} }
if (zipExtensions != null && !zipExtensions.isEmpty()) {
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
}
if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) { if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified); Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
} }
@@ -1011,4 +1123,18 @@ public class DependencyCheckTask extends Task {
return values; return values;
} }
} }
/**
* Whether or not the Jar Analyzer is enabled.
*/
private boolean jarAnalyzerEnabled = true;
/**
* Returns whether or not the analyzer is enabled.
*
* @return true if the analyzer is enabled
*/
public boolean isJarAnalyzerEnabled() {
return jarAnalyzerEnabled;
}
} }

View File

@@ -18,33 +18,60 @@ the project's dependencies.
</dependency-check> </dependency-check>
</target> </target>
``` ```
The following table lists the configurable properties:
Property | Description | Requirement | Default Value Configuration
----------------------|-------------|-------------|------------ ====================
applicationName | The name of the application to use in the generated report. | Required | &nbsp; The following properties can be set on the dependency-check-maven plugin.
reportFormat | The format of the report to be generated. Allowed values are: HTML, XML, VULN, or ALL. The default value is HTML.| Optional | HTML
reportOutputDirectory | The directory where dependency-check will store data used for analysis. Defaults to the current working directory. | Optional | &nbsp; Property | Description | Default Value
failBuildOn | If set and a CVE is found that is greater then the specified value the build will fail. The default value is 11 which means that the build will not fail. Valid values are 0-11. | Optional | 11 ---------------------|------------------------------------|------------------
autoUpdate | If set to false the NVD CVE data is not automatically updated. Setting this to false could result in false negatives. However, this may be required in some environments. | Optional | true autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
dataDirectory | The directory where dependency-check will store data used for analysis. Defaults to a folder called, called 'dependency-check-data', that is in the same directory as the dependency-check-ant jar file was installed in. *It is not recommended to change this.* | Optional | &nbsp; externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
logFile | The file path to write verbose logging information. | Optional | &nbsp; 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'
suppressionFile | An XML file conforming to the suppression schema that suppresses findings; this is used to hide [false positives](../suppression.html). | Optional | &nbsp; 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
proxyUrl | Defines the proxy used to connect to the Internet. | Optional | &nbsp; 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
proxyPort | Defines the port for the proxy. | Optional | &nbsp; logFile | The file path to write verbose logging information. | &nbsp;
proxyUsername | Defines the proxy user name. | Optional | &nbsp; suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) | &nbsp;
proxyPassword | Defines the proxy password. | Optional | &nbsp; proxyUrl | The Proxy URL. | &nbsp;
connectionTimeout | The connection timeout used when downloading data files from the Internet. | Optional | &nbsp; proxyPort | The Proxy Port. | &nbsp;
nexusAnalyzerEnabled | The connection timeout used when downloading data files from the Internet. | Optional | &nbsp; proxyUsername | Defines the proxy user name. | &nbsp;
nexusUrl | The connection timeout used when downloading data files from the Internet. | Optional | &nbsp; proxyPassword | Defines the proxy password. | &nbsp;
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | Optional | true connectionTimeout | The URL Connection Timeout. | &nbsp;
databaseDriverName | The name of the database driver. Example: org.h2.Driver. | Optional | &nbsp;
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. | Optional | &nbsp; Analyzer Configuration
connectionString | The connection string used to connect to the database. | Optional | &nbsp; ====================
databaseUser | The username used when connecting to the database. | Optional | dcuser The following properties are used to configure the various file type analyzers.
databasePassword | The password used when connecting to the database. | Optional | &nbsp; These properties can be used to turn off specific analyzers if it is not needed.
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. | Optional | &nbsp; Note, that specific analyzers will automatically disable themselves if no file
cveUrl12Modified | URL for the modified CVE 1.2 | Optional | http://nvd.nist.gov/download/nvdcve-modified.xml types that they support are detected - so specifically disabling them may not
cveUrl20Modified | URL for the modified CVE 2.0 | Optional | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml be needed.
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year | Optional | 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 | Optional | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml 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. | &nbsp;
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/
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 | &nbsp;
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
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. | &nbsp;
databaseDriverName | The name of the database driver. Example: org.h2.Driver. | &nbsp;
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. | &nbsp;
connectionString | The connection string used to connect to the database. | &nbsp;
databaseUser | The username used when connecting to the database. | &nbsp;
databasePassword | The password used when connecting to the database. | &nbsp;

View File

@@ -64,7 +64,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
*/ */
@Test @Test
public void testAddFileSet() throws Exception { public void testAddFileSet() throws Exception {
File report = new File("target/DependencyCheck-Report.html"); File report = new File("target/dependency-check-report.html");
if (report.exists()) { if (report.exists()) {
if (!report.delete()) { if (!report.delete()) {
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test."); throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
@@ -83,7 +83,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
*/ */
@Test @Test
public void testAddFileList() throws Exception { public void testAddFileList() throws Exception {
File report = new File("target/DependencyCheck-Report.xml"); File report = new File("target/dependency-check-report.xml");
if (report.exists()) { if (report.exists()) {
if (!report.delete()) { if (!report.delete()) {
throw new Exception("Unable to delete 'target/DependencyCheck-Report.xml' prior to test."); throw new Exception("Unable to delete 'target/DependencyCheck-Report.xml' prior to test.");
@@ -101,7 +101,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
*/ */
@Test @Test
public void testAddDirSet() throws Exception { public void testAddDirSet() throws Exception {
File report = new File("target/DependencyCheck-Vulnerability.html"); File report = new File("target/dependency-check-vulnerability.html");
if (report.exists()) { if (report.exists()) {
if (!report.delete()) { if (!report.delete()) {
throw new Exception("Unable to delete 'target/DependencyCheck-Vulnerability.html' prior to test."); throw new Exception("Unable to delete 'target/DependencyCheck-Vulnerability.html' prior to test.");

View File

@@ -21,7 +21,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<parent> <parent>
<groupId>org.owasp</groupId> <groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId> <artifactId>dependency-check-parent</artifactId>
<version>1.1.2</version> <version>1.1.4</version>
</parent> </parent>
<artifactId>dependency-check-cli</artifactId> <artifactId>dependency-check-cli</artifactId>

View File

@@ -158,15 +158,19 @@ public class App {
final String dataDirectory = cli.getDataDirectory(); final String dataDirectory = cli.getDataDirectory();
final File propertiesFile = cli.getPropertiesFile(); final File propertiesFile = cli.getPropertiesFile();
final String suppressionFile = cli.getSuppressionFile(); final String suppressionFile = cli.getSuppressionFile();
final boolean jarDisabled = cli.isJarDisabled();
final boolean archiveDisabled = cli.isArchiveDisabled();
final boolean assemblyDisabled = cli.isAssemblyDisabled();
final boolean nuspecDisabled = cli.isNuspecDisabled();
final boolean nexusDisabled = cli.isNexusDisabled(); final boolean nexusDisabled = cli.isNexusDisabled();
final String nexusUrl = cli.getNexusUrl(); final String nexusUrl = cli.getNexusUrl();
final boolean nexusUsesProxy = cli.isNexusUsesProxy();
final String databaseDriverName = cli.getDatabaseDriverName(); final String databaseDriverName = cli.getDatabaseDriverName();
final String databaseDriverPath = cli.getDatabaseDriverPath(); final String databaseDriverPath = cli.getDatabaseDriverPath();
final String connectionString = cli.getConnectionString(); final String connectionString = cli.getConnectionString();
final String databaseUser = cli.getDatabaseUser(); final String databaseUser = cli.getDatabaseUser();
final String databasePassword = cli.getDatabasePassword(); final String databasePassword = cli.getDatabasePassword();
final String additionalZipExtensions = cli.getAdditionalZipExtensions(); final String additionalZipExtensions = cli.getAdditionalZipExtensions();
final String pathToMono = cli.getPathToMono();
if (propertiesFile != null) { if (propertiesFile != null) {
try { try {
@@ -181,6 +185,10 @@ public class App {
Logger.getLogger(App.class.getName()).log(Level.FINE, null, ex); Logger.getLogger(App.class.getName()).log(Level.FINE, null, ex);
} }
} }
// We have to wait until we've merged the properties before attempting to set whether we use
// the proxy for Nexus since it could be disabled in the properties, but not explicitly stated
// on the command line
final boolean nexusUsesProxy = cli.isNexusUsesProxy();
if (dataDirectory != null) { if (dataDirectory != null) {
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory); Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
} else if (System.getProperty("basedir") != null) { } else if (System.getProperty("basedir") != null) {
@@ -212,6 +220,13 @@ public class App {
if (suppressionFile != null && !suppressionFile.isEmpty()) { if (suppressionFile != null && !suppressionFile.isEmpty()) {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile); Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
} }
//File Type Analyzer Settings
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !jarDisabled);
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !archiveDisabled);
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !nuspecDisabled);
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !assemblyDisabled);
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !nexusDisabled); Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !nexusDisabled);
if (nexusUrl != null && !nexusUrl.isEmpty()) { if (nexusUrl != null && !nexusUrl.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl); Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
@@ -235,5 +250,8 @@ public class App {
if (additionalZipExtensions != null && !additionalZipExtensions.isEmpty()) { if (additionalZipExtensions != null && !additionalZipExtensions.isEmpty()) {
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions); Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
} }
if (pathToMono != null && !pathToMono.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
}
} }
} }

View File

@@ -29,6 +29,7 @@ import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser; import org.apache.commons.cli.PosixParser;
import org.owasp.dependencycheck.reporting.ReportGenerator.Format; import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
/** /**
@@ -84,8 +85,11 @@ public final class CliParser {
*/ */
private void validateArgs() throws FileNotFoundException, ParseException { private void validateArgs() throws FileNotFoundException, ParseException {
if (isRunScan()) { if (isRunScan()) {
validatePathExists(getScanFiles(), "scan"); validatePathExists(getScanFiles(), ArgumentName.SCAN);
validatePathExists(getReportDirectory(), "out"); validatePathExists(getReportDirectory(), ArgumentName.OUT);
if (getPathToMono() != null) {
validatePathExists(getPathToMono(), ArgumentName.PATH_TO_MONO);
}
if (!line.hasOption(ArgumentName.APP_NAME)) { if (!line.hasOption(ArgumentName.APP_NAME)) {
throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name."); throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
} }
@@ -121,16 +125,18 @@ public final class CliParser {
* FileNotFoundException is thrown. * FileNotFoundException is thrown.
* *
* @param path the paths to validate if they exists * @param path the paths to validate if they exists
* @param optType the option being validated (e.g. scan, out, etc.) * @param argumentName the argument being validated (e.g. scan, out, etc.)
* @throws FileNotFoundException is thrown if the path being validated does not exist. * @throws FileNotFoundException is thrown if the path being validated does not exist.
*/ */
private void validatePathExists(String path, String optType) throws FileNotFoundException { private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
final File f = new File(path); if (!path.contains("*.")) {
if (!f.exists()) { final File f = new File(path);
isValid = false; if (!f.exists()) {
final String msg = String.format("Invalid '%s' argument: '%s'", optType, path); isValid = false;
throw new FileNotFoundException(msg); 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.
} }
/** /**
@@ -173,7 +179,8 @@ public final class CliParser {
.create(ArgumentName.APP_NAME_SHORT); .create(ArgumentName.APP_NAME_SHORT);
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN) final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
.withDescription("The path to scan - this option can be specified multiple times.") .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); .create(ArgumentName.SCAN_SHORT);
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP) final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
@@ -196,24 +203,6 @@ public final class CliParser {
.withDescription("The file path to the suppression XML file.") .withDescription("The file path to the suppression XML file.")
.create(); .create();
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ArgumentName.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.")
.create();
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ArgumentName.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)
.withDescription("A comma seperated list of additional extensions to be scanned as ZIP files "
+ "(ZIP, EAR, WAR are already treated as zip files)")
.create();
//This is an option group because it can be specified more then once. //This is an option group because it can be specified more then once.
final OptionGroup og = new OptionGroup(); final OptionGroup og = new OptionGroup();
og.addOption(path); og.addOption(path);
@@ -228,11 +217,7 @@ public final class CliParser {
.addOption(noUpdate) .addOption(noUpdate)
.addOption(props) .addOption(props)
.addOption(verboseLog) .addOption(verboseLog)
.addOption(suppressionFile) .addOption(suppressionFile);
.addOption(disableNexusAnalyzer)
.addOption(nexusUrl)
.addOption(nexusUsesProxy)
.addOption(additionalZipExtensions);
} }
/** /**
@@ -272,19 +257,58 @@ public final class CliParser {
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ArgumentName.CONNECTION_STRING) final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ArgumentName.CONNECTION_STRING)
.withDescription("The connection string to the database.") .withDescription("The connection string to the database.")
.create(); .create();
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.DB_NAME) final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.DB_NAME)
.withDescription("The username used to connect to the database.") .withDescription("The username used to connect to the database.")
.create(); .create();
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ArgumentName.DB_PASSWORD) final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ArgumentName.DB_PASSWORD)
.withDescription("The password for connecting to the database.") .withDescription("The password for connecting to the database.")
.create(); .create();
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ArgumentName.DB_DRIVER) final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ArgumentName.DB_DRIVER)
.withDescription("The database driver name.") .withDescription("The database driver name.")
.create(); .create();
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DB_DRIVER_PATH) final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.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.") .withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
.create(); .create();
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_JAR)
.withDescription("Disable the Jar Analyzer.")
.create();
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_ARCHIVE)
.withDescription("Disable the Archive Analyzer.")
.create();
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NUSPEC)
.withDescription("Disable the Nuspec Analyzer.")
.create();
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_ASSEMBLY)
.withDescription("Disable the .NET Assembly Analyzer.")
.create();
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ArgumentName.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.")
.create();
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ArgumentName.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)
.withDescription("A comma seperated 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)
.withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
.create();
options.addOption(proxyPort) options.addOption(proxyPort)
.addOption(proxyUrl) .addOption(proxyUrl)
.addOption(proxyUsername) .addOption(proxyUsername)
@@ -295,7 +319,16 @@ public final class CliParser {
.addOption(data) .addOption(data)
.addOption(dbPassword) .addOption(dbPassword)
.addOption(dbDriver) .addOption(dbDriver)
.addOption(dbDriverPath); .addOption(dbDriverPath)
.addOption(disableJarAnalyzer)
.addOption(disableArchiveAnalyzer)
.addOption(disableAssemblyAnalyzer)
.addOption(disableNuspecAnalyzer)
.addOption(disableNexusAnalyzer)
.addOption(nexusUrl)
.addOption(nexusUsesProxy)
.addOption(additionalZipExtensions)
.addOption(pathToMono);
} }
/** /**
@@ -325,6 +358,42 @@ public final class CliParser {
return (line != null) && isValid && line.hasOption(ArgumentName.SCAN); return (line != null) && isValid && line.hasOption(ArgumentName.SCAN);
} }
/**
* Returns true if the disableJar command line argument was specified.
*
* @return true if the disableJar command line argument was specified; otherwise false
*/
public boolean isJarDisabled() {
return (line != null) && line.hasOption(ArgumentName.DISABLE_JAR);
}
/**
* Returns true if the disableArchive command line argument was specified.
*
* @return true if the disableArchive command line argument was specified; otherwise false
*/
public boolean isArchiveDisabled() {
return (line != null) && line.hasOption(ArgumentName.DISABLE_ARCHIVE);
}
/**
* Returns true if the disableNuspec command line argument was specified.
*
* @return true if the disableNuspec command line argument was specified; otherwise false
*/
public boolean isNuspecDisabled() {
return (line != null) && line.hasOption(ArgumentName.DISABLE_NUSPEC);
}
/**
* Returns true if the disableAssembly command line argument was specified.
*
* @return true if the disableAssembly command line argument was specified; otherwise false
*/
public boolean isAssemblyDisabled() {
return (line != null) && line.hasOption(ArgumentName.DISABLE_ASSEMBLY);
}
/** /**
* Returns true if the disableNexus command line argument was specified. * Returns true if the disableNexus command line argument was specified.
* *
@@ -354,8 +423,14 @@ public final class CliParser {
* @return true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false * @return true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false
*/ */
public boolean isNexusUsesProxy() { 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(ArgumentName.NEXUS_USES_PROXY)) {
return true; try {
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY);
} catch (InvalidSettingException ise) {
return true;
}
} else { } else {
return Boolean.parseBoolean(line.getOptionValue(ArgumentName.NEXUS_USES_PROXY)); return Boolean.parseBoolean(line.getOptionValue(ArgumentName.NEXUS_USES_PROXY));
} }
@@ -403,6 +478,15 @@ public final class CliParser {
return line.getOptionValue(ArgumentName.OUT, "."); return line.getOptionValue(ArgumentName.OUT, ".");
} }
/**
* Returns the path to Mono for .NET Assembly analysis on non-windows systems.
*
* @return the path to Mono
*/
public String getPathToMono() {
return line.getOptionValue(ArgumentName.PATH_TO_MONO);
}
/** /**
* Returns the output format specified on the command line. Defaults to HTML if no format was specified. * Returns the output format specified on the command line. Defaults to HTML if no format was specified.
* *
@@ -683,7 +767,7 @@ public final class CliParser {
/** /**
* The short CLI argument name for setting the location of an additional properties file. * The short CLI argument name for setting the location of an additional properties file.
*/ */
public static final String PROP_SHORT = "p"; public static final String PROP_SHORT = "P";
/** /**
* The CLI argument name for setting the location of an additional properties file. * The CLI argument name for setting the location of an additional properties file.
*/ */
@@ -708,6 +792,22 @@ public final class CliParser {
* The CLI argument name for setting the location of the suppression file. * The CLI argument name for setting the location of the suppression file.
*/ */
public static final String SUPPRESION_FILE = "suppression"; public static final String SUPPRESION_FILE = "suppression";
/**
* Disables the Jar Analyzer.
*/
public static final String DISABLE_JAR = "disableJar";
/**
* Disables the Archive Analyzer.
*/
public static final String DISABLE_ARCHIVE = "disableArchive";
/**
* Disables the Assembly Analyzer.
*/
public static final String DISABLE_ASSEMBLY = "disableAssembly";
/**
* Disables the Nuspec Analyzer.
*/
public static final String DISABLE_NUSPEC = "disableNuspec";
/** /**
* Disables the Nexus Analyzer. * Disables the Nexus Analyzer.
*/ */
@@ -740,6 +840,10 @@ public final class CliParser {
* The CLI argument name for setting the path to the database driver; in case it is not on the class path. * The CLI argument name for setting the path to the database driver; in case it is not on the class path.
*/ */
public static final String DB_DRIVER_PATH = "dbDriverPath"; public static final String DB_DRIVER_PATH = "dbDriverPath";
/**
* The CLI argument name for setting the path to mono for .NET Assembly analysis on non-windows systems.
*/
public static final String PATH_TO_MONO = "mono";
/** /**
* The CLI argument name for setting extra extensions. * The CLI argument name for setting extra extensions.
*/ */

View File

@@ -1,32 +1,43 @@
Command Line Arguments Command Line Arguments
==================== ======================
The following table lists the 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 \-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. | Required
\-c | \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. | Optional \-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
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. | Optional \-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required \-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required
\-h | \-\-help | | Print the help message. | Optional
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional \-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional \-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
\-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
\-p | \-\-proxyport | \<port\> | The proxy port to use when downloading resources. | Optional
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. | Optional
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. | Optional
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. | Required
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../suppression.html). | Optional | \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../suppression.html). | Optional
\-u | \-\-proxyurl | \<url\> | The proxy url to use when downloading resources. | Optional \-h | \-\-help | | Print the help message. | Optional
\-v | \-\-version | | Print the version information. | Optional
| \-\-advancedHelp | | Print the advanced help message. | Optional | \-\-advancedHelp | | Print the advanced help message. | Optional
| \-\-connectionString | \<connStr\> | The connection string to the database. | Optional \-v | \-\-version | | Print the version information. | Optional
| \-\-dbDriverName | \<driver\> | The database driver name. | Optional
| \-\-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. | Optional Advanced Options
| \-\-dbPassword | \<password\> | The password for connecting to the database. | Optional ================
| \-\-dbUser | \<user\> | The username used to connect to the database. | Optional Short | Argument Name | Parameter | Description | Default Value
| \-\-disableNexus | | Disable the Nexus Analyzer. | Optional -------|-----------------------|-----------------|-------------|---------------
| \-\-nexus | \<url\> | The url to the Nexus Server. | Optional | \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | Optional | \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. | &nbsp;
| \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. | Optional | \-\-disableJar | | Sets whether Jar Analyzer will be used. | false
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
| \-\-disableNexus | | Disable the Nexus Analyzer. | &nbsp;
| \-\-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. | &nbsp;
| \-\-proxyurl | \<url\> | The proxy url to use when downloading resources. | &nbsp;
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. | &nbsp;
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. | &nbsp;
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. | &nbsp;
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. | &nbsp;
| \-\-connectionString | \<connStr\> | The connection string to the database. | &nbsp;
| \-\-dbDriverName | \<driver\> | The database driver name. | &nbsp;
| \-\-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. | &nbsp;
| \-\-dbPassword | \<password\> | The password for connecting to the database. | &nbsp;
| \-\-dbUser | \<user\> | The username used to connect to the database. | &nbsp;
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. | &nbsp;

View File

@@ -8,20 +8,18 @@ script executable:
$ chmod +777 dependency-check.sh $ chmod +777 dependency-check.sh
To scan a folder on the system you can run: To scan a folder on the system you can run:
#set( $H = '#' )
Windows $H$H$H Windows
-------
dependency-check.bat --app "My App Name" --scan "c:\java\application\lib" dependency-check.bat --app "My App Name" --scan "c:\java\application\lib"
\*nix $H$H$H *nix
-------
dependency-check.sh --app "My App Name" --scan "/java/application/lib" dependency-check.sh --app "My App Name" --scan "/java/application/lib"
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run: To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
Windows
------- $H$H$H Windows
dependency-check.bat --help dependency-check.bat --help
\*nix $H$H$H *nix
-------
dependency-check.sh --help dependency-check.sh --help

View File

@@ -21,7 +21,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<parent> <parent>
<groupId>org.owasp</groupId> <groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId> <artifactId>dependency-check-parent</artifactId>
<version>1.1.2</version> <version>1.1.4</version>
</parent> </parent>
<artifactId>dependency-check-core</artifactId> <artifactId>dependency-check-core</artifactId>
@@ -581,6 +581,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<scope>provided</scope> <scope>provided</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies> </dependencies>
<profiles> <profiles>
<profile> <profile>

View File

@@ -29,6 +29,7 @@ import java.util.logging.Logger;
import org.owasp.dependencycheck.analyzer.AnalysisPhase; import org.owasp.dependencycheck.analyzer.AnalysisPhase;
import org.owasp.dependencycheck.analyzer.Analyzer; import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.analyzer.AnalyzerService; import org.owasp.dependencycheck.analyzer.AnalyzerService;
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex; import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex;
import org.owasp.dependencycheck.data.cpe.IndexException; import org.owasp.dependencycheck.data.cpe.IndexException;
@@ -56,15 +57,15 @@ public class Engine {
/** /**
* The list of dependencies. * The list of dependencies.
*/ */
private final List<Dependency> dependencies; private List<Dependency> dependencies;
/** /**
* A Map of analyzers grouped by Analysis phase. * A Map of analyzers grouped by Analysis phase.
*/ */
private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers; private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers;
/** /**
* A set of extensions supported by the analyzers. * A Map of analyzers grouped by Analysis phase.
*/ */
private final Set<String> extensions; private final Set<FileTypeAnalyzer> fileTypeAnalyzers;
/** /**
* Creates a new Engine. * Creates a new Engine.
@@ -72,9 +73,10 @@ public class Engine {
* @throws DatabaseException thrown if there is an error connecting to the database * @throws DatabaseException thrown if there is an error connecting to the database
*/ */
public Engine() throws DatabaseException { public Engine() throws DatabaseException {
this.extensions = new HashSet<String>();
this.dependencies = new ArrayList<Dependency>(); this.dependencies = new ArrayList<Dependency>();
this.analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class); this.analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
this.fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
ConnectionFactory.initialize(); ConnectionFactory.initialize();
boolean autoUpdate = true; boolean autoUpdate = true;
@@ -110,8 +112,8 @@ public class Engine {
while (iterator.hasNext()) { while (iterator.hasNext()) {
final Analyzer a = iterator.next(); final Analyzer a = iterator.next();
analyzers.get(a.getAnalysisPhase()).add(a); analyzers.get(a.getAnalysisPhase()).add(a);
if (a.getSupportedExtensions() != null) { if (a instanceof FileTypeAnalyzer) {
extensions.addAll(a.getSupportedExtensions()); this.fileTypeAnalyzers.add((FileTypeAnalyzer) a);
} }
} }
} }
@@ -135,6 +137,13 @@ public class Engine {
return dependencies; return dependencies;
} }
public void setDependencies(List<Dependency> dependencies) {
this.dependencies = dependencies;
//for (Dependency dependency: dependencies) {
// dependencies.add(dependency);
//}
}
/** /**
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any * 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. * dependencies identified are added to the dependency collection.
@@ -157,8 +166,21 @@ public class Engine {
* @param path the path to a file or directory to be analyzed. * @param path the path to a file or directory to be analyzed.
*/ */
public void scan(String path) { public void scan(String path) {
final File file = new File(path); if (path.matches("^.*[\\/]\\*\\.[^\\/:*|?<>\"]+$")) {
scan(file); 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.getLogger(Engine.class.getName()).log(Level.SEVERE, msg);
}
} else {
final File file = new File(path);
scan(file);
}
} }
/** /**
@@ -253,7 +275,7 @@ public class Engine {
final String fileName = file.getName(); final String fileName = file.getName();
final String extension = FileUtils.getFileExtension(fileName); final String extension = FileUtils.getFileExtension(fileName);
if (extension != null) { if (extension != null) {
if (extensions.contains(extension)) { if (supportsExtension(extension)) {
final Dependency dependency = new Dependency(file); final Dependency dependency = new Dependency(file);
dependencies.add(dependency); dependencies.add(dependency);
} }
@@ -291,32 +313,13 @@ public class Engine {
Logger.getLogger(Engine.class.getName()).log(Level.FINE, logHeader); Logger.getLogger(Engine.class.getName()).log(Level.FINE, logHeader);
Logger.getLogger(Engine.class.getName()).log(Level.INFO, "Analysis Starting"); Logger.getLogger(Engine.class.getName()).log(Level.INFO, "Analysis Starting");
//phase one initialize
for (AnalysisPhase phase : AnalysisPhase.values()) {
final List<Analyzer> analyzerList = analyzers.get(phase);
for (Analyzer a : analyzerList) {
try {
final String msg = String.format("Initializing %s", a.getName());
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
a.initialize();
} catch (Throwable ex) {
final String msg = String.format("Exception occurred initializing %s.", a.getName());
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(Engine.class.getName()).log(Level.FINE, null, ex);
try {
a.close();
} catch (Throwable ex1) {
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, null, ex1);
}
}
}
}
// analysis phases // analysis phases
for (AnalysisPhase phase : AnalysisPhase.values()) { for (AnalysisPhase phase : AnalysisPhase.values()) {
final List<Analyzer> analyzerList = analyzers.get(phase); final List<Analyzer> analyzerList = analyzers.get(phase);
for (Analyzer a : analyzerList) { for (Analyzer a : analyzerList) {
initializeAnalyzer(a);
/* need to create a copy of the collection because some of the /* need to create a copy of the collection because some of the
* analyzers may modify it. This prevents ConcurrentModificationExceptions. * analyzers may modify it. This prevents ConcurrentModificationExceptions.
* This is okay for adds/deletes because it happens per analyzer. * This is okay for adds/deletes because it happens per analyzer.
@@ -326,7 +329,12 @@ public class Engine {
final Set<Dependency> dependencySet = new HashSet<Dependency>(); final Set<Dependency> dependencySet = new HashSet<Dependency>();
dependencySet.addAll(dependencies); dependencySet.addAll(dependencies);
for (Dependency d : dependencySet) { for (Dependency d : dependencySet) {
if (a.supportsExtension(d.getFileExtension())) { boolean shouldAnalyze = true;
if (a instanceof FileTypeAnalyzer) {
final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a;
shouldAnalyze = fAnalyzer.supportsExtension(d.getFileExtension());
}
if (shouldAnalyze) {
final String msgFile = String.format("Begin Analysis of '%s'", d.getActualFilePath()); final String msgFile = String.format("Begin Analysis of '%s'", d.getActualFilePath());
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msgFile); Logger.getLogger(Engine.class.getName()).log(Level.FINE, msgFile);
try { try {
@@ -345,18 +353,11 @@ public class Engine {
} }
} }
} }
//close/cleanup
for (AnalysisPhase phase : AnalysisPhase.values()) { for (AnalysisPhase phase : AnalysisPhase.values()) {
final List<Analyzer> analyzerList = analyzers.get(phase); final List<Analyzer> analyzerList = analyzers.get(phase);
for (Analyzer a : analyzerList) { for (Analyzer a : analyzerList) {
final String msg = String.format("Closing Analyzer '%s'", a.getName()); closeAnalyzer(a);
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
try {
a.close();
} catch (Throwable ex) {
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, null, ex);
}
} }
} }
@@ -368,6 +369,43 @@ public class Engine {
Logger.getLogger(Engine.class.getName()).log(Level.INFO, "Analysis Complete"); Logger.getLogger(Engine.class.getName()).log(Level.INFO, "Analysis Complete");
} }
/**
* Initializes the given analyzer.
*
* @param analyzer the analyzer to initialize
*/
private void initializeAnalyzer(Analyzer analyzer) {
try {
final String msg = String.format("Initializing %s", analyzer.getName());
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
analyzer.initialize();
} catch (Throwable ex) {
final String msg = String.format("Exception occurred initializing %s.", analyzer.getName());
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(Engine.class.getName()).log(Level.FINE, null, ex);
try {
analyzer.close();
} catch (Throwable ex1) {
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, null, ex1);
}
}
}
/**
* Closes the given analyzer.
*
* @param analyzer the analyzer to close
*/
private void closeAnalyzer(Analyzer analyzer) {
final String msg = String.format("Closing Analyzer '%s'", analyzer.getName());
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
try {
analyzer.close();
} catch (Throwable ex) {
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, null, ex);
}
}
/** /**
* Cycles through the cached web data sources and calls update on all of them. * Cycles through the cached web data sources and calls update on all of them.
*/ */
@@ -411,15 +449,13 @@ public class Engine {
if (ext == null) { if (ext == null) {
return false; return false;
} }
for (AnalysisPhase phase : AnalysisPhase.values()) { boolean scan = false;
final List<Analyzer> analyzerList = analyzers.get(phase); for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
for (Analyzer a : analyzerList) { /* note, we can't break early on this loop as the analyzers need to know if
if (a.getSupportedExtensions() != null && a.supportsExtension(ext)) { they have files to work on prior to initialization */
return true; scan |= a.supportsExtension(ext);
}
}
} }
return false; return scan;
} }
/** /**
@@ -447,4 +483,5 @@ public class Engine {
throw new NoDataException("No documents exist"); throw new NoDataException("No documents exist");
} }
} }
} }

View File

@@ -0,0 +1,973 @@
/*
* 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.agent;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
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.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.exception.ScanAgentException;
import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.utils.Settings;
/**
* This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting
* evidence from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it
* takes a list of dependencies that can be programmatically added from data in a spreadsheet, database or some other
* datasource and conduct a scan based on this pre-defined evidence.
*
* <h2>Example:</h2>
* <pre>
* List<Dependency> dependencies = new ArrayList<Dependency>();
* Dependency dependency = new Dependency(new File(FileUtils.getBitBucket()));
* dependency.getProductEvidence().addEvidence("my-datasource", "name", "Jetty", Confidence.HIGH);
* dependency.getVersionEvidence().addEvidence("my-datasource", "version", "5.1.10", Confidence.HIGH);
* dependency.getVendorEvidence().addEvidence("my-datasource", "vendor", "mortbay", Confidence.HIGH);
* dependencies.add(dependency);
*
* DependencyCheckScanAgent scan = new DependencyCheckScanAgent();
* scan.setDependencies(dependencies);
* scan.setReportFormat(ReportGenerator.Format.ALL);
* scan.setReportOutputDirectory(System.getProperty("user.home"));
* scan.execute();
* </pre>
*
* @author Steve Springett <steve.springett@owasp.org>
*/
@SuppressWarnings("unused")
public class DependencyCheckScanAgent {
/**
* System specific new line character.
*/
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
/**
* The application name for the report.
*/
private String applicationName = "Dependency-Check";
/**
* Get the value of applicationName.
*
* @return the value of applicationName
*/
public String getApplicationName() {
return applicationName;
}
/**
* Set the value of applicationName.
*
* @param applicationName new value of applicationName
*/
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
/**
* The pre-determined dependencies to scan
*/
private List<Dependency> dependencies;
/**
* Returns a list of pre-determined dependencies.
*
* @return returns a list of dependencies
*/
public List<Dependency> getDependencies() {
return dependencies;
}
/**
* Sets the list of dependencies to scan.
*
* @param dependencies new value of dependencies
*/
public void setDependencies(List<Dependency> dependencies) {
this.dependencies = dependencies;
}
/**
* The location of the data directory that contains
*/
private String dataDirectory = null;
/**
* Get the value of dataDirectory.
*
* @return the value of dataDirectory
*/
public String getDataDirectory() {
return dataDirectory;
}
/**
* Set the value of dataDirectory.
*
* @param dataDirectory new value of dataDirectory
*/
public void setDataDirectory(String dataDirectory) {
this.dataDirectory = dataDirectory;
}
/**
* Specifies the destination directory for the generated Dependency-Check report.
*/
private String reportOutputDirectory;
/**
* Get the value of reportOutputDirectory.
*
* @return the value of reportOutputDirectory
*/
public String getReportOutputDirectory() {
return reportOutputDirectory;
}
/**
* Set the value of reportOutputDirectory.
*
* @param reportOutputDirectory new value of reportOutputDirectory
*/
public void setReportOutputDirectory(String reportOutputDirectory) {
this.reportOutputDirectory = reportOutputDirectory;
}
/**
* 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 and the CVSS score is set to 11.
* The valid range for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
*/
private float failBuildOnCVSS = 11;
/**
* Get the value of failBuildOnCVSS.
*
* @return the value of failBuildOnCVSS
*/
public float getFailBuildOnCVSS() {
return failBuildOnCVSS;
}
/**
* Set the value of failBuildOnCVSS.
*
* @param failBuildOnCVSS new value of failBuildOnCVSS
*/
public void setFailBuildOnCVSS(float failBuildOnCVSS) {
this.failBuildOnCVSS = failBuildOnCVSS;
}
/**
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to
* false. Default is true.
*/
private boolean autoUpdate = true;
/**
* Get the value of autoUpdate.
*
* @return the value of autoUpdate
*/
public boolean isAutoUpdate() {
return autoUpdate;
}
/**
* Set the value of autoUpdate.
*
* @param autoUpdate new value of autoUpdate
*/
public void setAutoUpdate(boolean autoUpdate) {
this.autoUpdate = autoUpdate;
}
/**
* 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. Default is HTML.
*/
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
/**
* Get the value of reportFormat.
*
* @return the value of reportFormat
*/
public ReportGenerator.Format getReportFormat() {
return reportFormat;
}
/**
* Set the value of reportFormat.
*
* @param reportFormat new value of reportFormat
*/
public void setReportFormat(ReportGenerator.Format reportFormat) {
this.reportFormat = reportFormat;
}
/**
* The Proxy URL.
*/
private String proxyUrl;
/**
* Get the value of proxyUrl.
*
* @return the value of proxyUrl
*/
public String getProxyUrl() {
return proxyUrl;
}
/**
* Set the value of proxyUrl.
*
* @param proxyUrl new value of proxyUrl
*/
public void setProxyUrl(String proxyUrl) {
this.proxyUrl = proxyUrl;
}
/**
* The Proxy Port.
*/
private String proxyPort;
/**
* Get the value of proxyPort.
*
* @return the value of proxyPort
*/
public String getProxyPort() {
return proxyPort;
}
/**
* Set the value of proxyPort.
*
* @param proxyPort new value of proxyPort
*/
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
}
/**
* The Proxy username.
*/
private String proxyUsername;
/**
* Get the value of proxyUsername.
*
* @return the value of proxyUsername
*/
public String getProxyUsername() {
return proxyUsername;
}
/**
* Set the value of proxyUsername.
*
* @param proxyUsername new value of proxyUsername
*/
public void setProxyUsername(String proxyUsername) {
this.proxyUsername = proxyUsername;
}
/**
* The Proxy password.
*/
private String proxyPassword;
/**
* Get the value of proxyPassword.
*
* @return the value of proxyPassword
*/
public String getProxyPassword() {
return proxyPassword;
}
/**
* Set the value of proxyPassword.
*
* @param proxyPassword new value of proxyPassword
*/
public void setProxyPassword(String proxyPassword) {
this.proxyPassword = proxyPassword;
}
/**
* The Connection Timeout.
*/
private String connectionTimeout;
/**
* Get the value of connectionTimeout.
*
* @return the value of connectionTimeout
*/
public String getConnectionTimeout() {
return connectionTimeout;
}
/**
* Set the value of connectionTimeout.
*
* @param connectionTimeout new value of connectionTimeout
*/
public void setConnectionTimeout(String connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
/**
* The file path used for verbose logging.
*/
private String logFile = null;
/**
* Get the value of logFile.
*
* @return the value of logFile
*/
public String getLogFile() {
return logFile;
}
/**
* Set the value of logFile.
*
* @param logFile new value of logFile
*/
public void setLogFile(String logFile) {
this.logFile = logFile;
}
/**
* The path to the suppression file.
*/
private String suppressionFile;
/**
* Get the value of suppressionFile.
*
* @return the value of suppressionFile
*/
public String getSuppressionFile() {
return suppressionFile;
}
/**
* Set the value of suppressionFile.
*
* @param suppressionFile new value of suppressionFile
*/
public void setSuppressionFile(String suppressionFile) {
this.suppressionFile = suppressionFile;
}
/**
* flag indicating whether or not to show a summary of findings.
*/
private boolean showSummary = true;
/**
* Get the value of showSummary.
*
* @return the value of showSummary
*/
public boolean isShowSummary() {
return showSummary;
}
/**
* Set the value of showSummary.
*
* @param showSummary new value of showSummary
*/
public void setShowSummary(boolean showSummary) {
this.showSummary = showSummary;
}
/**
* Whether or not the nexus analyzer is enabled.
*/
private boolean nexusAnalyzerEnabled = true;
/**
* Get the value of nexusAnalyzerEnabled.
*
* @return the value of nexusAnalyzerEnabled
*/
public boolean isNexusAnalyzerEnabled() {
return nexusAnalyzerEnabled;
}
/**
* Set the value of nexusAnalyzerEnabled.
*
* @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
*/
public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
}
/**
* The URL of the Nexus server.
*/
private String nexusUrl;
/**
* Get the value of nexusUrl.
*
* @return the value of nexusUrl
*/
public String getNexusUrl() {
return nexusUrl;
}
/**
* Set the value of nexusUrl.
*
* @param nexusUrl new value of nexusUrl
*/
public void setNexusUrl(String nexusUrl) {
this.nexusUrl = nexusUrl;
}
/**
* Whether or not the defined proxy should be used when connecting to Nexus.
*/
private boolean nexusUsesProxy = true;
/**
* Get the value of nexusUsesProxy.
*
* @return the value of nexusUsesProxy
*/
public boolean isNexusUsesProxy() {
return nexusUsesProxy;
}
/**
* Set the value of nexusUsesProxy.
*
* @param nexusUsesProxy new value of nexusUsesProxy
*/
public void setNexusUsesProxy(boolean nexusUsesProxy) {
this.nexusUsesProxy = nexusUsesProxy;
}
/**
* The database driver name; such as org.h2.Driver.
*/
private String databaseDriverName;
/**
* Get the value of databaseDriverName.
*
* @return the value of databaseDriverName
*/
public String getDatabaseDriverName() {
return databaseDriverName;
}
/**
* Set the value of databaseDriverName.
*
* @param databaseDriverName new value of databaseDriverName
*/
public void setDatabaseDriverName(String databaseDriverName) {
this.databaseDriverName = databaseDriverName;
}
/**
* The path to the database driver JAR file if it is not on the class path.
*/
private String databaseDriverPath;
/**
* Get the value of databaseDriverPath.
*
* @return the value of databaseDriverPath
*/
public String getDatabaseDriverPath() {
return databaseDriverPath;
}
/**
* Set the value of databaseDriverPath.
*
* @param databaseDriverPath new value of databaseDriverPath
*/
public void setDatabaseDriverPath(String databaseDriverPath) {
this.databaseDriverPath = databaseDriverPath;
}
/**
* The database connection string.
*/
private String connectionString;
/**
* Get the value of connectionString.
*
* @return the value of connectionString
*/
public String getConnectionString() {
return connectionString;
}
/**
* Set the value of connectionString.
*
* @param connectionString new value of connectionString
*/
public void setConnectionString(String connectionString) {
this.connectionString = connectionString;
}
/**
* The user name for connecting to the database.
*/
private String databaseUser;
/**
* Get the value of databaseUser.
*
* @return the value of databaseUser
*/
public String getDatabaseUser() {
return databaseUser;
}
/**
* Set the value of databaseUser.
*
* @param databaseUser new value of databaseUser
*/
public void setDatabaseUser(String databaseUser) {
this.databaseUser = databaseUser;
}
/**
* The password to use when connecting to the database.
*/
private String databasePassword;
/**
* Get the value of databasePassword.
*
* @return the value of databasePassword
*/
public String getDatabasePassword() {
return databasePassword;
}
/**
* Set the value of databasePassword.
*
* @param databasePassword new value of databasePassword
*/
public void setDatabasePassword(String databasePassword) {
this.databasePassword = databasePassword;
}
/**
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat
* like ZIP files.
*/
private String zipExtensions;
/**
* Get the value of zipExtensions.
*
* @return the value of zipExtensions
*/
public String getZipExtensions() {
return zipExtensions;
}
/**
* Set the value of zipExtensions.
*
* @param zipExtensions new value of zipExtensions
*/
public void setZipExtensions(String zipExtensions) {
this.zipExtensions = zipExtensions;
}
/**
* The url for the modified NVD CVE (1.2 schema).
*/
private String cveUrl12Modified;
/**
* Get the value of cveUrl12Modified.
*
* @return the value of cveUrl12Modified
*/
public String getCveUrl12Modified() {
return cveUrl12Modified;
}
/**
* Set the value of cveUrl12Modified.
*
* @param cveUrl12Modified new value of cveUrl12Modified
*/
public void setCveUrl12Modified(String cveUrl12Modified) {
this.cveUrl12Modified = cveUrl12Modified;
}
/**
* The url for the modified NVD CVE (2.0 schema).
*/
private String cveUrl20Modified;
/**
* Get the value of cveUrl20Modified.
*
* @return the value of cveUrl20Modified
*/
public String getCveUrl20Modified() {
return cveUrl20Modified;
}
/**
* Set the value of cveUrl20Modified.
*
* @param cveUrl20Modified new value of cveUrl20Modified
*/
public void setCveUrl20Modified(String cveUrl20Modified) {
this.cveUrl20Modified = cveUrl20Modified;
}
/**
* Base Data Mirror URL for CVE 1.2.
*/
private String cveUrl12Base;
/**
* Get the value of cveUrl12Base.
*
* @return the value of cveUrl12Base
*/
public String getCveUrl12Base() {
return cveUrl12Base;
}
/**
* Set the value of cveUrl12Base.
*
* @param cveUrl12Base new value of cveUrl12Base
*/
public void setCveUrl12Base(String cveUrl12Base) {
this.cveUrl12Base = cveUrl12Base;
}
/**
* Data Mirror URL for CVE 2.0.
*/
private String cveUrl20Base;
/**
* Get the value of cveUrl20Base.
*
* @return the value of cveUrl20Base
*/
public String getCveUrl20Base() {
return cveUrl20Base;
}
/**
* Set the value of cveUrl20Base.
*
* @param cveUrl20Base new value of cveUrl20Base
*/
public void setCveUrl20Base(String cveUrl20Base) {
this.cveUrl20Base = cveUrl20Base;
}
/**
* The path to Mono for .NET assembly analysis on non-windows systems.
*/
private String pathToMono;
/**
* Get the value of pathToMono.
*
* @return the value of pathToMono
*/
public String getPathToMono() {
return pathToMono;
}
/**
* Set the value of pathToMono.
*
* @param pathToMono new value of pathToMono
*/
public void setPathToMono(String pathToMono) {
this.pathToMono = pathToMono;
}
/**
* Executes the Dependency-Check on the dependent libraries.
*
* @return the Engine used to scan the dependencies.
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the
* database
*/
private Engine executeDependencyCheck() throws DatabaseException {
populateSettings();
Engine engine = null;
try {
engine = new Engine();
engine.setDependencies(this.dependencies);
engine.analyzeDependencies();
} finally {
if (engine != null) {
engine.cleanup();
}
}
return engine;
}
/**
* Generates the reports for a given dependency-check engine.
*
* @param engine a dependency-check engine
* @param outDirectory the directory to write the reports to
*/
private void generateExternalReports(Engine engine, File outDirectory) {
DatabaseProperties prop = null;
CveDB cve = null;
try {
cve = new CveDB();
cve.open();
prop = cve.getDatabaseProperties();
} catch (DatabaseException ex) {
Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex);
} finally {
if (cve != null) {
cve.close();
}
}
final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
try {
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
} catch (IOException ex) {
Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.SEVERE,
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.FINE, null, ex);
} catch (Throwable ex) {
Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.SEVERE,
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.FINE, null, ex);
}
}
/**
* 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.
*/
private void populateSettings() {
if (dataDirectory != null) {
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
} else {
final File jarPath = new File(DependencyCheckScanAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath());
final File base = jarPath.getParentFile();
final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
final File dataDir = new File(base, sub);
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 (proxyPort != null && !proxyPort.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
}
if (proxyUsername != null && !proxyUsername.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername);
}
if (proxyPassword != null && !proxyPassword.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
}
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
}
if (suppressionFile != null && !suppressionFile.isEmpty()) {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
}
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
if (nexusUrl != null && !nexusUrl.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
}
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
}
if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
}
if (connectionString != null && !connectionString.isEmpty()) {
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
}
if (databaseUser != null && !databaseUser.isEmpty()) {
Settings.setString(Settings.KEYS.DB_USER, databaseUser);
}
if (databasePassword != null && !databasePassword.isEmpty()) {
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
}
if (zipExtensions != null && !zipExtensions.isEmpty()) {
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
}
if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
}
if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) {
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
}
if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) {
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
}
if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
}
if (pathToMono != null && !pathToMono.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
}
}
/**
* Executes the dependency-check and generates the report.
*
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the
* scan.
*/
public void execute() throws ScanAgentException {
Engine engine = null;
try {
engine = executeDependencyCheck();
generateExternalReports(engine, new File(this.reportOutputDirectory));
if (this.showSummary) {
showSummary(engine.getDependencies());
}
if (this.failBuildOnCVSS <= 10) {
checkForFailure(engine.getDependencies());
}
} catch (DatabaseException ex) {
Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.SEVERE,
"Unable to connect to the dependency-check database; analysis has stopped");
Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.FINE, "", ex);
} finally {
if (engine != null) {
engine.cleanup();
}
}
}
/**
* Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
* configuration.
*
* @param dependencies the list of dependency objects
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the
* scan.
*/
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
final StringBuilder ids = new StringBuilder();
for (Dependency d : dependencies) {
boolean addName = true;
for (Vulnerability v : d.getVulnerabilities()) {
if (v.getCvssScore() >= failBuildOnCVSS) {
if (addName) {
addName = false;
ids.append(NEW_LINE).append(d.getFileName()).append(": ");
ids.append(v.getName());
} else {
ids.append(", ").append(v.getName());
}
}
}
}
if (ids.length() > 0) {
final String msg = String.format("%n%nDependency-Check Failure:%n"
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
throw new ScanAgentException(msg);
}
}
/**
* Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
*
* @param dependencies a list of dependency objects
*/
private void showSummary(List<Dependency> dependencies) {
final StringBuilder summary = new StringBuilder();
for (Dependency d : dependencies) {
boolean firstEntry = true;
final StringBuilder ids = new StringBuilder();
for (Vulnerability v : d.getVulnerabilities()) {
if (firstEntry) {
firstEntry = false;
} else {
ids.append(", ");
}
ids.append(v.getName());
}
if (ids.length() > 0) {
summary.append(d.getFileName()).append(" (");
firstEntry = true;
for (Identifier id : d.getIdentifiers()) {
if (firstEntry) {
firstEntry = false;
} else {
summary.append(", ");
}
summary.append(id.getValue());
}
summary.append(") : ").append(ids).append(NEW_LINE);
}
}
if (summary.length() > 0) {
final String msg = String.format("%n%n"
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
Logger.getLogger(DependencyCheckScanAgent.class.getName()).log(Level.WARNING, msg);
}
}
}

View File

@@ -0,0 +1,13 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.agent</title>
* </head>
* <body>
* The agent package holds an agent API that can be used by other applications that have information about dependencies;
* but would rather implement something in their code directly rather then spawn a process to run the entire
* dependency-check engine. This basically provides programmatic access to running a scan.
* </body>
* </html>
*/
package org.owasp.dependencycheck.agent;

View File

@@ -17,33 +17,12 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/** /**
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public abstract class AbstractAnalyzer implements Analyzer { public abstract class AbstractAnalyzer implements Analyzer {
/**
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a
* final static declaration.<br/><br/>
*
* This implementation was copied from
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction
*
* @param strings a list of strings to add to the set.
* @return a Set of strings.
*/
protected static Set<String> newHashSet(String... strings) {
final Set<String> set = new HashSet<String>();
Collections.addAll(set, strings);
return set;
}
/** /**
* The initialize method does nothing for this Analyzer. * The initialize method does nothing for this Analyzer.
* *

View File

@@ -0,0 +1,229 @@
/*
* 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.util.Collections;
import java.util.HashSet;
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.dependency.Dependency;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
/**
* The base FileTypeAnalyzer that all analyzers that have specific file types they analyze should extend.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
//<editor-fold defaultstate="collapsed" desc="Constructor">
/**
* Base constructor that all children must call. This checks the configuration to determine if the analyzer is
* enabled.
*/
public AbstractFileTypeAnalyzer() {
final String key = getAnalyzerEnabledSettingKey();
try {
enabled = Settings.getBoolean(key, true);
} catch (InvalidSettingException ex) {
String msg = String.format("Invalid settting for property '%s'", key);
LOGGER.log(Level.WARNING, msg);
LOGGER.log(Level.FINE, "", ex);
msg = String.format("%s has been disabled", getName());
LOGGER.log(Level.WARNING, msg);
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Field defentitions">
/**
* The logger.
*/
private static final Logger LOGGER = Logger.getLogger(AbstractFileTypeAnalyzer.class.getName());
/**
* Whether the file type analyzer detected any files it needs to analyze.
*/
private boolean filesMatched = false;
/**
* Get the value of filesMatched. A flag indicating whether the scan included any file types this analyzer supports.
*
* @return the value of filesMatched
*/
protected boolean isFilesMatched() {
return filesMatched;
}
/**
* Set the value of filesMatched. A flag indicating whether the scan included any file types this analyzer supports.
*
* @param filesMatched new value of filesMatched
*/
protected void setFilesMatched(boolean filesMatched) {
this.filesMatched = filesMatched;
}
/**
* A flag indicating whether or not the analyzer is enabled.
*/
private boolean enabled = true;
/**
* Get the value of enabled.
*
* @return the value of enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* Set the value of enabled.
*
* @param enabled new value of enabled
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
/**
* <p>
* Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The
* getSupportedExtensions function would return a set with a single element "jar".</p>
*
* <p>
* <b>Note:</b> when implementing this the extensions returned MUST be lowercase.</p>
*
* @return The file extensions supported by this analyzer.
*
* <p>
* If the analyzer returns null it will not cause additional files to be analyzed but will be executed against every
* file loaded</p>
*/
protected abstract Set<String> getSupportedExtensions();
/**
* Initializes the file type analyzer.
*
* @throws Exception thrown if there is an exception during initialization
*/
protected abstract void initializeFileTypeAnalyzer() throws Exception;
/**
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
* scanned, and added to the list of dependencies within the engine.
*
* @param dependency the dependency to analyze
* @param engine the engine scanning
* @throws AnalysisException thrown if there is an analysis exception
*/
protected abstract void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException;
/**
* <p>
* Returns the setting key to determine if the analyzer is enabled.</p>
*
* @return the key for the analyzer's enabled property
*/
protected abstract String getAnalyzerEnabledSettingKey();
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Final implementations for the Analyzer interface">
/**
* Initializes the analyzer.
*
* @throws Exception thrown if there is an exception during initialization
*/
@Override
public final void initialize() throws Exception {
if (filesMatched) {
initializeFileTypeAnalyzer();
} else {
enabled = false;
}
}
/**
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
* scanned, and added to the list of dependencies within the engine.
*
* @param dependency the dependency to analyze
* @param engine the engine scanning
* @throws AnalysisException thrown if there is an analysis exception
*/
@Override
public final void analyze(Dependency dependency, Engine engine) throws AnalysisException {
if (enabled) {
analyzeFileType(dependency, engine);
}
}
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
@Override
public final boolean supportsExtension(String extension) {
if (!enabled) {
return false;
}
final Set<String> ext = getSupportedExtensions();
if (ext == null) {
final String msg = String.format("The '%s' analyzer is misconfigured and does not have any file extensions;"
+ " it will be disabled", getName());
Logger.getLogger(AbstractFileTypeAnalyzer.class.getName()).log(Level.SEVERE, msg);
return false;
} else {
final boolean match = ext.contains(extension);
if (match) {
filesMatched = match;
}
return match;
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Static utility methods">
/**
* <p>
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a
* final static declaration.</p>
*
* <p>
* This implementation was copied from
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
*
* @param strings a list of strings to add to the set.
* @return a Set of strings.
*/
protected static Set<String> newHashSet(String... strings) {
final Set<String> set = new HashSet<String>();
Collections.addAll(set, strings);
return set;
}
//</editor-fold>
}

View File

@@ -18,13 +18,20 @@
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.owasp.dependencycheck.suppression.SuppressionParseException; import org.owasp.dependencycheck.suppression.SuppressionParseException;
import org.owasp.dependencycheck.suppression.SuppressionParser; import org.owasp.dependencycheck.suppression.SuppressionParser;
import org.owasp.dependencycheck.suppression.SuppressionRule; import org.owasp.dependencycheck.suppression.SuppressionRule;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
/** /**
@@ -44,17 +51,6 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
return null; return null;
} }
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
@Override
public boolean supportsExtension(String extension) {
return true;
}
//</editor-fold> //</editor-fold>
/** /**
* The initialize method loads the suppression XML file. * The initialize method loads the suppression XML file.
@@ -95,17 +91,58 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
* @throws SuppressionParseException thrown if the XML cannot be parsed. * @throws SuppressionParseException thrown if the XML cannot be parsed.
*/ */
private void loadSuppressionData() throws SuppressionParseException { private void loadSuppressionData() throws SuppressionParseException {
final File file = Settings.getFile(Settings.KEYS.SUPPRESSION_FILE); final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
if (file != null) { if (suppressionFilePath == null) {
final SuppressionParser parser = new SuppressionParser(); return;
try { }
rules = parser.parseSuppressionRules(file); File file = null;
} catch (SuppressionParseException ex) { boolean deleteTempFile = false;
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath()); try {
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, msg); final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, ex.getMessage()); if (uriRx.matcher(suppressionFilePath).matches()) {
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.FINE, null, ex); deleteTempFile = true;
throw ex; file = FileUtils.getTempFile("suppression", "xml");
final URL url = new URL(suppressionFilePath);
try {
Downloader.fetchFile(url, file, false);
} catch (DownloadFailedException ex) {
Downloader.fetchFile(url, file, true);
}
} else {
file = new File(suppressionFilePath);
}
if (file != null) {
final SuppressionParser parser = new SuppressionParser();
try {
rules = parser.parseSuppressionRules(file);
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).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());
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, ex.getMessage());
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.FINE, "", ex);
throw ex;
}
}
} catch (DownloadFailedException ex) {
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING,
"Unable to fetch the configured suppression file");
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.FINE, "", ex);
throw new SuppressionParseException("Unable to fetch the configured suppression file", ex);
} catch (MalformedURLException ex) {
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING,
"Configured suppression file has an invalid URL");
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.FINE, "", ex);
throw new SuppressionParseException("Configured suppression file has an invalid URL", ex);
} catch (IOException ex) {
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING,
"Unable to create temp file for suppressions");
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.FINE, "", ex);
throw new SuppressionParseException("Unable to create temp file for suppressions", ex);
} finally {
if (deleteTempFile && file != null) {
FileUtils.delete(file);
} }
} }
} }

View File

@@ -17,9 +17,8 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import java.util.Set;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
/** /**
@@ -42,22 +41,6 @@ public interface Analyzer {
*/ */
void analyze(Dependency dependency, Engine engine) throws AnalysisException; void analyze(Dependency dependency, Engine engine) throws AnalysisException;
/**
* <p>
* Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The
* getSupportedExtensions function would return a set with a single element "jar".</p>
*
* <p>
* <b>Note:</b> when implementing this the extensions returned MUST be lowercase.</p>
*
* @return The file extensions supported by this analyzer.
*
* <p>
* If the analyzer returns null it will not cause additional files to be analyzed but will be executed against every
* file loaded</p>
*/
Set<String> getSupportedExtensions();
/** /**
* Returns the name of the analyzer. * Returns the name of the analyzer.
* *
@@ -65,14 +48,6 @@ public interface Analyzer {
*/ */
String getName(); String getName();
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
boolean supportsExtension(String extension);
/** /**
* Returns the phase that the analyzer is intended to run in. * Returns the phase that the analyzer is intended to run in.
* *

View File

@@ -53,8 +53,12 @@ import org.owasp.dependencycheck.utils.Settings;
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer { public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The logger.
*/
private static final Logger LOGGER = Logger.getLogger(ArchiveAnalyzer.class.getName());
/** /**
* The buffer size to use when extracting files from the archive. * The buffer size to use when extracting files from the archive.
*/ */
@@ -75,6 +79,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
* Tracks the current scan/extraction depth for nested archives. * Tracks the current scan/extraction depth for nested archives.
*/ */
private int scanDepth = 0; private int scanDepth = 0;
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer"> //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/** /**
* The name of the analyzer. * The name of the analyzer.
@@ -108,6 +113,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
* *
* @return a list of file EXTENSIONS supported by this analyzer. * @return a list of file EXTENSIONS supported by this analyzer.
*/ */
@Override
public Set<String> getSupportedExtensions() { public Set<String> getSupportedExtensions() {
return EXTENSIONS; return EXTENSIONS;
} }
@@ -117,37 +123,39 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
* *
* @return the name of the analyzer. * @return the name of the analyzer.
*/ */
@Override
public String getName() { public String getName() {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
public boolean supportsExtension(String extension) {
return EXTENSIONS.contains(extension);
}
/** /**
* Returns the phase that the analyzer is intended to run in. * Returns the phase that the analyzer is intended to run in.
* *
* @return the phase that the analyzer is intended to run in. * @return the phase that the analyzer is intended to run in.
*/ */
@Override
public AnalysisPhase getAnalysisPhase() { public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE; return ANALYSIS_PHASE;
} }
//</editor-fold> //</editor-fold>
/**
* Returns the key used in the properties file to reference the analyzer's enabled property.
*
* @return the analyzer's enabled property setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_ARCHIVE_ENABLED;
}
/** /**
* The initialize method does nothing for this Analyzer. * The initialize method does nothing for this Analyzer.
* *
* @throws Exception is thrown if there is an exception deleting or creating temporary files * @throws Exception is thrown if there is an exception deleting or creating temporary files
*/ */
@Override @Override
public void initialize() throws Exception { public void initializeFileTypeAnalyzer() throws Exception {
final File baseDir = Settings.getTempDirectory(); final File baseDir = Settings.getTempDirectory();
if (!baseDir.exists()) { if (!baseDir.exists()) {
if (!baseDir.mkdirs()) { if (!baseDir.mkdirs()) {
@@ -174,11 +182,10 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
@Override @Override
public void close() throws Exception { public void close() throws Exception {
if (tempFileLocation != null && tempFileLocation.exists()) { if (tempFileLocation != null && tempFileLocation.exists()) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, "Attempting to delete temporary files"); LOGGER.log(Level.FINE, "Attempting to delete temporary files");
final boolean success = FileUtils.delete(tempFileLocation); final boolean success = FileUtils.delete(tempFileLocation);
if (!success) { if (!success) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, LOGGER.log(Level.WARNING, "Failed to delete some temporary files, see the log for more details");
"Failed to delete some temporary files, see the log for more details");
} }
} }
} }
@@ -192,7 +199,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
* @throws AnalysisException thrown if there is an analysis exception * @throws AnalysisException thrown if there is an analysis exception
*/ */
@Override @Override
public void analyze(Dependency dependency, Engine engine) throws AnalysisException { public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
final File f = new File(dependency.getActualFilePath()); final File f = new File(dependency.getActualFilePath());
final File tmpDir = getNextTempDirectory(); final File tmpDir = getNextTempDirectory();
extractFiles(f, tmpDir, engine); extractFiles(f, tmpDir, engine);
@@ -268,7 +275,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
try { try {
fis = new FileInputStream(archive); fis = new FileInputStream(archive);
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, null, ex);
throw new AnalysisException("Archive file was not found.", ex); throw new AnalysisException("Archive file was not found.", ex);
} }
final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase(); final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase();
@@ -286,17 +293,17 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
} }
} catch (ArchiveExtractionException ex) { } catch (ArchiveExtractionException ex) {
final String msg = String.format("Exception extracting archive '%s'.", archive.getName()); final String msg = String.format("Exception extracting archive '%s'.", archive.getName());
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, null, ex);
} catch (IOException ex) { } catch (IOException ex) {
final String msg = String.format("Exception reading archive '%s'.", archive.getName()); final String msg = String.format("Exception reading archive '%s'.", archive.getName());
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, null, ex);
} finally { } finally {
try { try {
fis.close(); fis.close();
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex); LOGGER.log(Level.FINEST, null, ex);
} }
} }
} }
@@ -375,7 +382,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
try { try {
input.close(); input.close();
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex); LOGGER.log(Level.FINEST, null, ex);
} }
} }
} }
@@ -398,17 +405,17 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
out.write(buffer, 0, n); out.write(buffer, 0, n);
} }
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, null, ex);
throw new ArchiveExtractionException(ex); throw new ArchiveExtractionException(ex);
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, null, ex);
throw new ArchiveExtractionException(ex); throw new ArchiveExtractionException(ex);
} finally { } finally {
if (out != null) { if (out != null) {
try { try {
out.close(); out.close();
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex); LOGGER.log(Level.FINEST, null, ex);
} }
} }
} }

View File

@@ -17,10 +17,12 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -46,7 +48,7 @@ import org.xml.sax.SAXException;
* @author colezlaw * @author colezlaw
* *
*/ */
public class AssemblyAnalyzer extends AbstractAnalyzer { public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
* The analyzer name * The analyzer name
@@ -63,7 +65,7 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
/** /**
* The temp value for GrokAssembly.exe * The temp value for GrokAssembly.exe
*/ */
private File grokAssemblyExe; private File grokAssemblyExe = null;
/** /**
* The DocumentBuilder for parsing the XML * The DocumentBuilder for parsing the XML
*/ */
@@ -71,7 +73,7 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
/** /**
* Logger * Logger
*/ */
private static final Logger LOG = Logger.getLogger(AbstractAnalyzer.class.getName()); private static final Logger LOG = Logger.getLogger(AssemblyAnalyzer.class.getName());
/** /**
* Builds the beginnings of a List for ProcessBuilder * Builds the beginnings of a List for ProcessBuilder
@@ -101,7 +103,7 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
* @throws AnalysisException if anything goes sideways * @throws AnalysisException if anything goes sideways
*/ */
@Override @Override
public void analyze(Dependency dependency, Engine engine) public void analyzeFileType(Dependency dependency, Engine engine)
throws AnalysisException { throws AnalysisException {
if (grokAssemblyExe == null) { if (grokAssemblyExe == null) {
LOG.warning("GrokAssembly didn't get deployed"); LOG.warning("GrokAssembly didn't get deployed");
@@ -111,8 +113,16 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
final List<String> args = buildArgumentList(); final List<String> args = buildArgumentList();
args.add(dependency.getActualFilePath()); args.add(dependency.getActualFilePath());
final ProcessBuilder pb = new ProcessBuilder(args); final ProcessBuilder pb = new ProcessBuilder(args);
BufferedReader rdr = null;
try { try {
final Process proc = pb.start(); final Process proc = pb.start();
// Try evacuating the error stream
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line = null;
while (rdr.ready() && (line = rdr.readLine()) != null) {
LOG.log(Level.WARNING, "Error from GrokAssembly: {0}", line);
}
int rc = 0;
final Document doc = builder.parse(proc.getInputStream()); final Document doc = builder.parse(proc.getInputStream());
final XPath xpath = XPathFactory.newInstance().newXPath(); final XPath xpath = XPathFactory.newInstance().newXPath();
@@ -140,6 +150,18 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
product, Confidence.HIGH)); product, Confidence.HIGH));
} }
try {
rc = proc.waitFor();
} catch (InterruptedException ie) {
return;
}
if (rc == 3) {
LOG.log(Level.INFO, "{0} is not a valid assembly", dependency.getActualFilePath());
return;
} else if (rc != 0) {
LOG.log(Level.WARNING, "Return code {0} from GrokAssembly", rc);
}
} catch (IOException ioe) { } catch (IOException ioe) {
throw new AnalysisException(ioe); throw new AnalysisException(ioe);
} catch (SAXException saxe) { } catch (SAXException saxe) {
@@ -147,6 +169,14 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
} catch (XPathExpressionException xpe) { } catch (XPathExpressionException xpe) {
// This shouldn't happen // This shouldn't happen
throw new AnalysisException(xpe); throw new AnalysisException(xpe);
} finally {
if (rdr != null) {
try {
rdr.close();
} catch (IOException ex) {
Logger.getLogger(AssemblyAnalyzer.class.getName()).log(Level.FINEST, "ignore", ex);
}
}
} }
} }
@@ -156,9 +186,8 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
* @throws Exception if anything goes wrong * @throws Exception if anything goes wrong
*/ */
@Override @Override
public void initialize() throws Exception { public void initializeFileTypeAnalyzer() throws Exception {
super.initialize(); final File tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
final File tempFile = File.createTempFile("GKA", ".exe");
FileOutputStream fos = null; FileOutputStream fos = null;
InputStream is = null; InputStream is = null;
try { try {
@@ -195,8 +224,16 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
// Now, need to see if GrokAssembly actually runs from this location. // Now, need to see if GrokAssembly actually runs from this location.
final List<String> args = buildArgumentList(); final List<String> args = buildArgumentList();
BufferedReader rdr = null;
try { try {
final Process p = new ProcessBuilder(args).start(); final ProcessBuilder pb = new ProcessBuilder(args);
final Process p = pb.start();
// Try evacuating the error stream
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line;
while (rdr.ready() && (line = rdr.readLine()) != null) {
// We expect this to complain
}
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream()); final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
final XPath xpath = XPathFactory.newInstance().newXPath(); final XPath xpath = XPathFactory.newInstance().newXPath();
final String error = xpath.evaluate("/assembly/error", doc); final String error = xpath.evaluate("/assembly/error", doc);
@@ -211,6 +248,14 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
+ "this can be ignored unless you are scanning .NET dlls. Please see the log for more details."); + "this can be ignored unless you are scanning .NET dlls. Please see the log for more details.");
LOG.log(Level.FINE, "Could not execute GrokAssembly {0}", e.getMessage()); LOG.log(Level.FINE, "Could not execute GrokAssembly {0}", e.getMessage());
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e); throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
} finally {
if (rdr != null) {
try {
rdr.close();
} catch (IOException ex) {
Logger.getLogger(AssemblyAnalyzer.class.getName()).log(Level.FINEST, "ignore", ex);
}
}
} }
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
@@ -220,7 +265,9 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
public void close() throws Exception { public void close() throws Exception {
super.close(); super.close();
try { try {
grokAssemblyExe.delete(); if (grokAssemblyExe != null && !grokAssemblyExe.delete()) {
grokAssemblyExe.deleteOnExit();
}
} catch (SecurityException se) { } catch (SecurityException se) {
LOG.fine("Can't delete temporary GrokAssembly.exe"); LOG.fine("Can't delete temporary GrokAssembly.exe");
} }
@@ -246,17 +293,6 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Gets whether the analyzer supports the provided extension.
*
* @param extension the extension to check
* @return whether the analyzer supports the extension
*/
@Override
public boolean supportsExtension(String extension) {
return SUPORTED_EXTENSIONS.contains(extension);
}
/** /**
* Returns the phase this analyzer runs under. * Returns the phase this analyzer runs under.
* *
@@ -266,4 +302,14 @@ public class AssemblyAnalyzer extends AbstractAnalyzer {
public AnalysisPhase getAnalysisPhase() { public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE; return ANALYSIS_PHASE;
} }
/**
* Returns the key used in the properties file to reference the analyzer's enabled property.
*
* @return the analyzer's enabled property setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED;
}
} }

View File

@@ -87,6 +87,36 @@ public class CPEAnalyzer implements Analyzer {
*/ */
private CveDB cve; private CveDB cve;
/**
* Returns the name of this analyzer.
*
* @return the name of this analyzer.
*/
@Override
public String getName() {
return "CPE Analyzer";
}
/**
* Returns the analysis phase that this analyzer should run in.
*
* @return the analysis phase that this analyzer should run in.
*/
@Override
public AnalysisPhase getAnalysisPhase() {
return AnalysisPhase.IDENTIFIER_ANALYSIS;
}
/**
* Creates the CPE Lucene Index.
*
* @throws Exception is thrown if there is an issue opening the index.
*/
@Override
public void initialize() throws Exception {
this.open();
}
/** /**
* Opens the data source. * Opens the data source.
* *
@@ -461,57 +491,6 @@ public class CPEAnalyzer implements Analyzer {
} }
} }
/**
* Returns true because this analyzer supports all dependency types.
*
* @return true.
*/
@Override
public Set<String> getSupportedExtensions() {
return null;
}
/**
* Returns the name of this analyzer.
*
* @return the name of this analyzer.
*/
@Override
public String getName() {
return "CPE Analyzer";
}
/**
* Returns true because this analyzer supports all dependency types.
*
* @param extension the file extension of the dependency being analyzed.
* @return true.
*/
@Override
public boolean supportsExtension(String extension) {
return true;
}
/**
* Returns the analysis phase that this analyzer should run in.
*
* @return the analysis phase that this analyzer should run in.
*/
@Override
public AnalysisPhase getAnalysisPhase() {
return AnalysisPhase.IDENTIFIER_ANALYSIS;
}
/**
* Opens the CPE Lucene Index.
*
* @throws Exception is thrown if there is an issue opening the index.
*/
@Override
public void initialize() throws Exception {
this.open();
}
/** /**
* Retrieves a list of CPE values from the CveDB based on the vendor and product passed in. The list is then * Retrieves a list of CPE values from the CveDB based on the vendor and product passed in. The list is then
* validated to find only CPEs that are valid for the given dependency. It is possible that the CPE identified is a * validated to find only CPEs that are valid for the given dependency. It is possible that the CPE identified is a

View File

@@ -17,7 +17,6 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import java.io.File; import java.io.File;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@@ -28,6 +27,7 @@ import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.utils.DependencyVersion; import org.owasp.dependencycheck.utils.DependencyVersion;
@@ -57,10 +57,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
private boolean analyzed = false; private boolean analyzed = false;
//</editor-fold> //</editor-fold>
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer"> //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/**
* The set of file extensions supported by this analyzer.
*/
private static final Set<String> EXTENSIONS = null;
/** /**
* The name of the analyzer. * The name of the analyzer.
*/ */
@@ -70,15 +66,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
*/ */
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_FINDING_ANALYSIS; private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_FINDING_ANALYSIS;
/**
* Returns a list of file EXTENSIONS supported by this analyzer.
*
* @return a list of file EXTENSIONS supported by this analyzer.
*/
public Set<String> getSupportedExtensions() {
return EXTENSIONS;
}
/** /**
* Returns the name of the analyzer. * Returns the name of the analyzer.
* *
@@ -88,16 +75,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support
* @return whether or not the specified file extension is supported by this analyzer.
*/
public boolean supportsExtension(String extension) {
return true;
}
/** /**
* Returns the phase that the analyzer is intended to run in. * Returns the phase that the analyzer is intended to run in.
* *

View File

@@ -43,10 +43,6 @@ import org.owasp.dependencycheck.dependency.VulnerableSoftware;
public class FalsePositiveAnalyzer extends AbstractAnalyzer { public class FalsePositiveAnalyzer extends AbstractAnalyzer {
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer"> //<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The set of file extensions supported by this analyzer.
*/
private static final Set<String> EXTENSIONS = null;
/** /**
* The name of the analyzer. * The name of the analyzer.
*/ */
@@ -56,15 +52,6 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
*/ */
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS; private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
/**
* Returns a list of file EXTENSIONS supported by this analyzer.
*
* @return a list of file EXTENSIONS supported by this analyzer.
*/
public Set<String> getSupportedExtensions() {
return EXTENSIONS;
}
/** /**
* Returns the name of the analyzer. * Returns the name of the analyzer.
* *
@@ -74,16 +61,6 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support
* @return whether or not the specified file extension is supported by this analyzer.
*/
public boolean supportsExtension(String extension) {
return true;
}
/** /**
* Returns the phase that the analyzer is intended to run in. * Returns the phase that the analyzer is intended to run in.
* *

View File

@@ -17,10 +17,9 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import java.io.File; import java.io.File;
import java.util.Set;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.DependencyVersion; import org.owasp.dependencycheck.utils.DependencyVersion;
@@ -43,19 +42,6 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
* The phase that this analyzer is intended to run in. * The phase that this analyzer is intended to run in.
*/ */
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
/**
* The set of file extensions supported by this analyzer.
*/
private static final Set<String> EXTENSIONS = null;
/**
* Returns a list of file EXTENSIONS supported by this analyzer.
*
* @return a list of file EXTENSIONS supported by this analyzer.
*/
public Set<String> getSupportedExtensions() {
return EXTENSIONS;
}
/** /**
* Returns the name of the analyzer. * Returns the name of the analyzer.
@@ -66,16 +52,6 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
public boolean supportsExtension(String extension) {
return true;
}
/** /**
* Returns the phase that the analyzer is intended to run in. * Returns the phase that the analyzer is intended to run in.
* *

View File

@@ -0,0 +1,34 @@
/*
* 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;
/**
* An Analyzer that scans specific file types.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public interface FileTypeAnalyzer extends Analyzer {
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
boolean supportsExtension(String extension);
}

View File

@@ -17,11 +17,11 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence; import org.owasp.dependencycheck.dependency.Evidence;
@@ -41,44 +41,23 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
* The phase that this analyzer is intended to run in. * The phase that this analyzer is intended to run in.
*/ */
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_IDENTIFIER_ANALYSIS; private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_IDENTIFIER_ANALYSIS;
/**
* The set of file extensions supported by this analyzer.
*/
private static final Set<String> EXTENSIONS = null;
/**
* Returns a list of file EXTENSIONS supported by this analyzer.
*
* @return a list of file EXTENSIONS supported by this analyzer.
*/
public Set<String> getSupportedExtensions() {
return EXTENSIONS;
}
/** /**
* Returns the name of the analyzer. * Returns the name of the analyzer.
* *
* @return the name of the analyzer. * @return the name of the analyzer.
*/ */
@Override
public String getName() { public String getName() {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
public boolean supportsExtension(String extension) {
return true;
}
/** /**
* Returns the phase that the analyzer is intended to run in. * Returns the phase that the analyzer is intended to run in.
* *
* @return the phase that the analyzer is intended to run in. * @return the phase that the analyzer is intended to run in.
*/ */
@Override
public AnalysisPhase getAnalysisPhase() { public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE; return ANALYSIS_PHASE;
} }

View File

@@ -79,9 +79,13 @@ import org.xml.sax.XMLReader;
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public class JarAnalyzer extends AbstractAnalyzer implements Analyzer { public class JarAnalyzer extends AbstractFileTypeAnalyzer {
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables"> //<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
/**
* The logger.
*/
private static final Logger LOGGER = Logger.getLogger(JarAnalyzer.class.getName());
/** /**
* The buffer size to use when extracting files from the archive. * The buffer size to use when extracting files from the archive.
*/ */
@@ -111,9 +115,15 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
"buildjdk", "buildjdk",
"ant-version", "ant-version",
"antversion", "antversion",
"dynamicimportpackage",
"dynamicimport-package",
"dynamic-importpackage",
"dynamic-import-package",
"import-package", "import-package",
"ignore-package",
"export-package", "export-package",
"importpackage", "importpackage",
"ignorepackage",
"exportpackage", "exportpackage",
"sealed", "sealed",
"manifest-version", "manifest-version",
@@ -125,7 +135,10 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
"tool", "tool",
"bundle-manifestversion", "bundle-manifestversion",
"bundlemanifestversion", "bundlemanifestversion",
"include-resource"); "include-resource",
"embed-dependency",
"ipojo-components",
"ipojo-extension");
/** /**
* item in some manifest, should be considered medium confidence. * item in some manifest, should be considered medium confidence.
*/ */
@@ -160,10 +173,11 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated"); final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated");
pomUnmarshaller = jaxbContext.createUnmarshaller(); pomUnmarshaller = jaxbContext.createUnmarshaller();
} catch (JAXBException ex) { //guess we will just have a null pointer exception later... } catch (JAXBException ex) { //guess we will just have a null pointer exception later...
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE, "Unable to load parser. See the log for more details."); LOGGER.log(Level.SEVERE, "Unable to load parser. See the log for more details.");
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, null, ex);
} }
} }
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer"> //<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/** /**
* The name of the analyzer. * The name of the analyzer.
@@ -183,6 +197,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
* *
* @return a list of file EXTENSIONS supported by this analyzer. * @return a list of file EXTENSIONS supported by this analyzer.
*/ */
@Override
public Set<String> getSupportedExtensions() { public Set<String> getSupportedExtensions() {
return EXTENSIONS; return EXTENSIONS;
} }
@@ -192,20 +207,11 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
* *
* @return the name of the analyzer. * @return the name of the analyzer.
*/ */
@Override
public String getName() { public String getName() {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
public boolean supportsExtension(String extension) {
return EXTENSIONS.contains(extension);
}
/** /**
* Returns the phase that the analyzer is intended to run in. * Returns the phase that the analyzer is intended to run in.
* *
@@ -216,6 +222,16 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
} }
//</editor-fold> //</editor-fold>
/**
* Returns the key used in the properties file to reference the analyzer's enabled property.
*
* @return the analyzer's enabled property setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_JAR_ENABLED;
}
/** /**
* Loads a specified JAR file and collects information from the manifest and checksums to identify the correct CPE * Loads a specified JAR file and collects information from the manifest and checksums to identify the correct CPE
* information. * information.
@@ -225,7 +241,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
* @throws AnalysisException is thrown if there is an error reading the JAR file. * @throws AnalysisException is thrown if there is an error reading the JAR file.
*/ */
@Override @Override
public void analyze(Dependency dependency, Engine engine) throws AnalysisException { public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
try { try {
final ArrayList<ClassNameInformation> classNames = collectClassNames(dependency); final ArrayList<ClassNameInformation> classNames = collectClassNames(dependency);
final String fileName = dependency.getFileName().toLowerCase(); final String fileName = dependency.getFileName().toLowerCase();
@@ -263,8 +279,8 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
} catch (IOException ex) { } catch (IOException ex) {
final String msg = String.format("Unable to read JarFile '%s'.", dependency.getActualFilePath()); final String msg = String.format("Unable to read JarFile '%s'.", dependency.getActualFilePath());
//final AnalysisException ax = new AnalysisException(msg, ex); //final AnalysisException ax = new AnalysisException(msg, ex);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, "", ex);
return false; return false;
} }
List<String> pomEntries; List<String> pomEntries;
@@ -273,8 +289,8 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
} catch (IOException ex) { } catch (IOException ex) {
final String msg = String.format("Unable to read Jar file entries in '%s'.", dependency.getActualFilePath()); final String msg = String.format("Unable to read Jar file entries in '%s'.", dependency.getActualFilePath());
//final AnalysisException ax = new AnalysisException(msg, ex); //final AnalysisException ax = new AnalysisException(msg, ex);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ex); LOGGER.log(Level.FINE, msg, ex);
return false; return false;
} }
if (pomEntries.isEmpty()) { if (pomEntries.isEmpty()) {
@@ -285,7 +301,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
try { try {
pomProperties = retrievePomProperties(path, jar); pomProperties = retrievePomProperties(path, jar);
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINEST, "ignore this, failed reading a non-existent pom.properties", ex); LOGGER.log(Level.FINEST, "ignore this, failed reading a non-existent pom.properties", ex);
} }
Model pom = null; Model pom = null;
try { try {
@@ -314,8 +330,8 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
} }
} catch (AnalysisException ex) { } catch (AnalysisException ex) {
final String msg = String.format("An error occured while analyzing '%s'.", dependency.getActualFilePath()); final String msg = String.format("An error occured while analyzing '%s'.", dependency.getActualFilePath());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, "", ex); LOGGER.log(Level.FINE, "", ex);
} }
} }
return foundSomething; return foundSomething;
@@ -392,7 +408,9 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
bos.flush(); bos.flush();
dependency.setActualFilePath(file.getAbsolutePath()); dependency.setActualFilePath(file.getAbsolutePath());
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE, null, ex); final String msg = String.format("An error occured reading '%s' from '%s'.", path, dependency.getFilePath());
LOGGER.warning(msg);
LOGGER.log(Level.SEVERE, "", ex);
} finally { } finally {
closeStream(bos); closeStream(bos);
closeStream(fos); closeStream(fos);
@@ -408,18 +426,18 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
model = readPom(source); model = readPom(source);
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (File Not Found)", path, jar.getName()); final String msg = String.format("Unable to parse pom '%s' in jar '%s' (File Not Found)", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, "", ex);
throw new AnalysisException(ex); throw new AnalysisException(ex);
} catch (UnsupportedEncodingException ex) { } catch (UnsupportedEncodingException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (IO Exception)", path, jar.getName()); final String msg = String.format("Unable to parse pom '%s' in jar '%s' (IO Exception)", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, "", ex);
throw new AnalysisException(ex); throw new AnalysisException(ex);
} catch (AnalysisException ex) { } catch (AnalysisException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s'", path, jar.getName()); final String msg = String.format("Unable to parse pom '%s' in jar '%s'", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, "", ex);
throw ex; throw ex;
} finally { } finally {
closeStream(fis); closeStream(fis);
@@ -437,7 +455,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
try { try {
stream.close(); stream.close();
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINEST, null, ex); LOGGER.log(Level.FINEST, null, ex);
} }
} }
} }
@@ -452,7 +470,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
try { try {
stream.close(); stream.close();
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINEST, null, ex); LOGGER.log(Level.FINEST, null, ex);
} }
} }
} }
@@ -486,13 +504,13 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
throw new AnalysisException(ex); throw new AnalysisException(ex);
} catch (IOException ex) { } catch (IOException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (IO Exception)", path, jar.getName()); final String msg = String.format("Unable to parse pom '%s' in jar '%s' (IO Exception)", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, "", ex);
throw new AnalysisException(ex); throw new AnalysisException(ex);
} catch (Throwable ex) { } catch (Throwable ex) {
final String msg = String.format("Unexpected error during parsing of the pom '%s' in jar '%s'", path, jar.getName()); final String msg = String.format("Unexpected error during parsing of the pom '%s' in jar '%s'", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex); LOGGER.log(Level.FINE, "", ex);
throw new AnalysisException(ex); throw new AnalysisException(ex);
} }
} }
@@ -899,12 +917,12 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
private File tempFileLocation = null; private File tempFileLocation = null;
/** /**
* The initialize method does nothing for this Analyzer. * Initializes the JarAnalyzer.
* *
* @throws Exception is thrown if there is an exception creating a temporary directory * @throws Exception is thrown if there is an exception creating a temporary directory
*/ */
@Override @Override
public void initialize() throws Exception { public void initializeFileTypeAnalyzer() throws Exception {
final File baseDir = Settings.getTempDirectory(); final File baseDir = Settings.getTempDirectory();
if (!baseDir.exists()) { if (!baseDir.exists()) {
if (!baseDir.mkdirs()) { if (!baseDir.mkdirs()) {
@@ -929,10 +947,10 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
@Override @Override
public void close() { public void close() {
if (tempFileLocation != null && tempFileLocation.exists()) { if (tempFileLocation != null && tempFileLocation.exists()) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, "Attempting to delete temporary files"); LOGGER.log(Level.FINE, "Attempting to delete temporary files");
final boolean success = FileUtils.delete(tempFileLocation); final boolean success = FileUtils.delete(tempFileLocation);
if (!success) { if (!success) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, LOGGER.log(Level.WARNING,
"Failed to delete some temporary files, see the log for more details"); "Failed to delete some temporary files, see the log for more details");
} }
} }
@@ -1003,11 +1021,9 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
* @return true or false depending on if it is believed the entry is an "import" entry * @return true or false depending on if it is believed the entry is an "import" entry
*/ */
private boolean isImportPackage(String key, String value) { private boolean isImportPackage(String key, String value) {
final Pattern packageRx = Pattern.compile("^((([a-zA-Z_#\\$0-9]\\.)+)\\s*\\;\\s*)+$"); final Pattern packageRx = Pattern.compile("^([a-zA-Z0-9_#\\$\\*\\.]+\\s*[,;]\\s*)+([a-zA-Z0-9_#\\$\\*\\.]+\\s*)?$");
if (packageRx.matcher(value).matches()) { final boolean matches = packageRx.matcher(value).matches();
return (key.contains("import") || key.contains("include")); return matches && (key.contains("import") || key.contains("include") || value.length() > 10);
}
return false;
} }
/** /**
@@ -1044,7 +1060,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
try { try {
jar.close(); jar.close();
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINEST, null, ex); LOGGER.log(Level.FINEST, null, ex);
} }
} }
} }

View File

@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings;
/** /**
* *
@@ -36,7 +37,12 @@ import org.owasp.dependencycheck.dependency.Dependency;
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer { public class JavaScriptAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The logger.
*/
private static final Logger LOGGER = Logger.getLogger(JavaScriptAnalyzer.class.getName());
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer"> //<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/** /**
@@ -72,17 +78,6 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this analyzer.
*/
@Override
public boolean supportsExtension(String extension) {
return EXTENSIONS.contains(extension);
}
/** /**
* Returns the phase that the analyzer is intended to run in. * Returns the phase that the analyzer is intended to run in.
* *
@@ -93,6 +88,15 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
return ANALYSIS_PHASE; return ANALYSIS_PHASE;
} }
//</editor-fold> //</editor-fold>
/**
* Returns the key used in the properties file to reference the analyzer's enabled property.
*
* @return the analyzer's enabled property setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_JAVASCRIPT_ENABLED;
}
/** /**
* Loads a specified JavaScript file and collects information from the copyright information contained within. * Loads a specified JavaScript file and collects information from the copyright information contained within.
@@ -102,7 +106,7 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
* @throws AnalysisException is thrown if there is an error reading the JavaScript file. * @throws AnalysisException is thrown if there is an error reading the JavaScript file.
*/ */
@Override @Override
public void analyze(Dependency dependency, Engine engine) throws AnalysisException { public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
BufferedReader fin = null;; BufferedReader fin = null;;
try { try {
// /\*([^\*][^/]|[\r\n\f])+?\*/ // /\*([^\*][^/]|[\r\n\f])+?\*/
@@ -118,15 +122,20 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
final String msg = String.format("Dependency file not found: '%s'", dependency.getActualFilePath()); final String msg = String.format("Dependency file not found: '%s'", dependency.getActualFilePath());
throw new AnalysisException(msg, ex); throw new AnalysisException(msg, ex);
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(JavaScriptAnalyzer.class.getName()).log(Level.SEVERE, null, ex); LOGGER.log(Level.SEVERE, null, ex);
} finally { } finally {
if (fin != null) { if (fin != null) {
try { try {
fin.close(); fin.close();
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(JavaScriptAnalyzer.class.getName()).log(Level.FINEST, null, ex); LOGGER.log(Level.FINEST, null, ex);
} }
} }
} }
} }
@Override
protected void initializeFileTypeAnalyzer() throws Exception {
}
} }

View File

@@ -46,20 +46,20 @@ import org.owasp.dependencycheck.utils.Settings;
* *
* @author colezlaw * @author colezlaw
*/ */
public class NexusAnalyzer extends AbstractAnalyzer { public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
* The logger * The logger.
*/ */
private static final Logger LOGGER = Logger.getLogger(NexusAnalyzer.class.getName()); private static final Logger LOGGER = Logger.getLogger(NexusAnalyzer.class.getName());
/** /**
* The name of the analyzer * The name of the analyzer.
*/ */
private static final String ANALYZER_NAME = "Nexus Analyzer"; private static final String ANALYZER_NAME = "Nexus Analyzer";
/** /**
* The phase in which the analyzer runs * The phase in which the analyzer runs.
*/ */
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
@@ -68,11 +68,6 @@ public class NexusAnalyzer extends AbstractAnalyzer {
*/ */
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar"); private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
/**
* Whether this is actually enabled. Will get set during initialization.
*/
private boolean enabled = false;
/** /**
* The Nexus Search to be set up for this analyzer. * The Nexus Search to be set up for this analyzer.
*/ */
@@ -84,24 +79,23 @@ public class NexusAnalyzer extends AbstractAnalyzer {
* @throws Exception if there's an error during initialization * @throws Exception if there's an error during initialization
*/ */
@Override @Override
public void initialize() throws Exception { public void initializeFileTypeAnalyzer() throws Exception {
enabled = Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED);
LOGGER.fine("Initializing Nexus Analyzer"); LOGGER.fine("Initializing Nexus Analyzer");
LOGGER.fine(String.format("Nexus Analyzer enabled: %s", enabled)); LOGGER.fine(String.format("Nexus Analyzer enabled: %s", isEnabled()));
if (enabled) { if (isEnabled()) {
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL); final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
LOGGER.fine(String.format("Nexus Analyzer URL: %s", searchUrl)); LOGGER.fine(String.format("Nexus Analyzer URL: %s", searchUrl));
try { try {
searcher = new NexusSearch(new URL(searchUrl)); searcher = new NexusSearch(new URL(searchUrl));
if (!searcher.preflightRequest()) { if (!searcher.preflightRequest()) {
LOGGER.warning("There was an issue getting Nexus status. Disabling analyzer."); LOGGER.warning("There was an issue getting Nexus status. Disabling analyzer.");
enabled = false; setEnabled(false);
} }
} catch (MalformedURLException mue) { } catch (MalformedURLException mue) {
// I know that initialize can throw an exception, but we'll // I know that initialize can throw an exception, but we'll
// just disable the analyzer if the URL isn't valid // just disable the analyzer if the URL isn't valid
LOGGER.warning(String.format("Property %s not a valid URL. Nexus Analyzer disabled", searchUrl)); LOGGER.warning(String.format("Property %s not a valid URL. Nexus Analyzer disabled", searchUrl));
enabled = false; setEnabled(false);
} }
} }
} }
@@ -116,6 +110,16 @@ public class NexusAnalyzer extends AbstractAnalyzer {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns the key used in the properties file to reference the analyzer's enabled property.
*
* @return the analyzer's enabled property setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_NEXUS_ENABLED;
}
/** /**
* Returns the analysis phase under which the analyzer runs. * Returns the analysis phase under which the analyzer runs.
* *
@@ -136,17 +140,6 @@ public class NexusAnalyzer extends AbstractAnalyzer {
return SUPPORTED_EXTENSIONS; return SUPPORTED_EXTENSIONS;
} }
/**
* Determines whether the incoming extension is supported.
*
* @param extension the extension to check for support
* @return whether the extension is supported
*/
@Override
public boolean supportsExtension(String extension) {
return SUPPORTED_EXTENSIONS.contains(extension);
}
/** /**
* Performs the analysis. * Performs the analysis.
* *
@@ -155,12 +148,7 @@ public class NexusAnalyzer extends AbstractAnalyzer {
* @throws AnalysisException when there's an exception during analysis * @throws AnalysisException when there's an exception during analysis
*/ */
@Override @Override
public void analyze(Dependency dependency, Engine engine) throws AnalysisException { public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
// Make a quick exit if this analyzer is disabled
if (!enabled) {
return;
}
try { try {
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum()); final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) { if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) {
@@ -188,5 +176,3 @@ public class NexusAnalyzer extends AbstractAnalyzer {
} }
} }
} }
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -18,36 +18,40 @@
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nuget.NugetPackage; import org.owasp.dependencycheck.data.nuget.NugetPackage;
import org.owasp.dependencycheck.data.nuget.NuspecParseException;
import org.owasp.dependencycheck.data.nuget.NuspecParser; import org.owasp.dependencycheck.data.nuget.NuspecParser;
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser; import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings;
/** /**
* Analyzer which will parse a Nuspec file to gather module information. * Analyzer which will parse a Nuspec file to gather module information.
* *
* @author colezlaw * @author colezlaw
*/ */
public class NuspecAnalyzer extends AbstractAnalyzer { public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
* The logger * The logger.
*/ */
private static final Logger LOGGER = Logger.getLogger(NuspecAnalyzer.class.getName()); private static final Logger LOGGER = Logger.getLogger(NuspecAnalyzer.class.getName());
/** /**
* The name of the analyzer * The name of the analyzer.
*/ */
private static final String ANALYZER_NAME = "Nuspec Analyzer"; private static final String ANALYZER_NAME = "Nuspec Analyzer";
/** /**
* The phase in which the analyzer runs * The phase in which the analyzer runs.
*/ */
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
@@ -62,7 +66,7 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
* @throws Exception if there's an error during initialization * @throws Exception if there's an error during initialization
*/ */
@Override @Override
public void initialize() throws Exception { public void initializeFileTypeAnalyzer() throws Exception {
} }
/** /**
@@ -75,6 +79,16 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
return ANALYZER_NAME; return ANALYZER_NAME;
} }
/**
* Returns the key used in the properties file to reference the analyzer's enabled property.
*
* @return the analyzer's enabled property setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_NUSPEC_ENABLED;
}
/** /**
* Returns the analysis phase under which the analyzer runs. * Returns the analysis phase under which the analyzer runs.
* *
@@ -95,17 +109,6 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
return SUPPORTED_EXTENSIONS; return SUPPORTED_EXTENSIONS;
} }
/**
* Determines whether the incoming extension is supported.
*
* @param extension the extension to check for support
* @return whether the extension is supported
*/
@Override
public boolean supportsExtension(String extension) {
return SUPPORTED_EXTENSIONS.contains(extension);
}
/** /**
* Performs the analysis. * Performs the analysis.
* *
@@ -114,8 +117,8 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
* @throws AnalysisException when there's an exception during analysis * @throws AnalysisException when there's an exception during analysis
*/ */
@Override @Override
public void analyze(Dependency dependency, Engine engine) throws AnalysisException { public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
LOGGER.log(Level.INFO, "Checking Nuspec file {0}", dependency.toString()); LOGGER.log(Level.FINE, "Checking Nuspec file {0}", dependency.toString());
try { try {
final NuspecParser parser = new XPathNuspecParser(); final NuspecParser parser = new XPathNuspecParser();
NugetPackage np = null; NugetPackage np = null;
@@ -123,11 +126,15 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
try { try {
fis = new FileInputStream(dependency.getActualFilePath()); fis = new FileInputStream(dependency.getActualFilePath());
np = parser.parse(fis); np = parser.parse(fis);
} catch (NuspecParseException ex) {
throw new AnalysisException(ex);
} catch (FileNotFoundException ex) {
throw new AnalysisException(ex);
} finally { } finally {
if (fis != null) { if (fis != null) {
try { try {
fis.close(); fis.close();
} catch (Throwable e) { } catch (IOException e) {
LOGGER.fine("Error closing input stream"); LOGGER.fine("Error closing input stream");
} }
} }
@@ -147,5 +154,3 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
} }
} }
} }
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -17,12 +17,11 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Set;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
@@ -62,6 +61,7 @@ public class NvdCveAnalyzer implements Analyzer {
/** /**
* Closes the data source. * Closes the data source.
*/ */
@Override
public void close() { public void close() {
cveDB.close(); cveDB.close();
cveDB = null; cveDB = null;
@@ -96,6 +96,7 @@ public class NvdCveAnalyzer implements Analyzer {
* @param engine The analysis engine * @param engine The analysis engine
* @throws AnalysisException is thrown if there is an issue analyzing the dependency * @throws AnalysisException is thrown if there is an issue analyzing the dependency
*/ */
@Override
public void analyze(Dependency dependency, Engine engine) throws AnalysisException { public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
for (Identifier id : dependency.getIdentifiers()) { for (Identifier id : dependency.getIdentifiers()) {
if ("cpe".equals(id.getType())) { if ("cpe".equals(id.getType())) {
@@ -110,48 +111,32 @@ public class NvdCveAnalyzer implements Analyzer {
} }
} }
/**
* Returns true because this analyzer supports all dependency types.
*
* @return true.
*/
public Set<String> getSupportedExtensions() {
return null;
}
/** /**
* Returns the name of this analyzer. * Returns the name of this analyzer.
* *
* @return the name of this analyzer. * @return the name of this analyzer.
*/ */
@Override
public String getName() { public String getName() {
return "NVD CVE Analyzer"; return "NVD CVE Analyzer";
} }
/**
* Returns true because this analyzer supports all dependency types.
*
* @param extension the file extension of the dependency being analyzed.
* @return true.
*/
public boolean supportsExtension(String extension) {
return true;
}
/** /**
* Returns the analysis phase that this analyzer should run in. * Returns the analysis phase that this analyzer should run in.
* *
* @return the analysis phase that this analyzer should run in. * @return the analysis phase that this analyzer should run in.
*/ */
@Override
public AnalysisPhase getAnalysisPhase() { public AnalysisPhase getAnalysisPhase() {
return AnalysisPhase.FINDING_ANALYSIS; return AnalysisPhase.FINDING_ANALYSIS;
} }
/** /**
* Opens the NVD CVE Lucene Index. * Opens the database used to gather NVD CVE data.
* *
* @throws Exception is thrown if there is an issue opening the index. * @throws Exception is thrown if there is an issue opening the index.
*/ */
@Override
public void initialize() throws Exception { public void initialize() throws Exception {
this.open(); this.open();
} }

View File

@@ -29,6 +29,7 @@ import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.update.NvdCveInfo; import org.owasp.dependencycheck.data.update.NvdCveInfo;
import org.owasp.dependencycheck.utils.DownloadFailedException; import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.Settings;
/** /**
* A callable object to download two files. * A callable object to download two files.
@@ -53,8 +54,8 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
final File file2; final File file2;
try { try {
file1 = File.createTempFile("cve" + nvdCveInfo.getId() + "_", ".xml"); file1 = File.createTempFile("cve" + nvdCveInfo.getId() + "_", ".xml", Settings.getTempDirectory());
file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + "_", ".xml"); file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + "_", ".xml", Settings.getTempDirectory());
} catch (IOException ex) { } catch (IOException ex) {
return; return;
} }

View File

@@ -106,16 +106,26 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Returns the file name of the dependency. * Returns the file name of the dependency.
* *
* @return the file name of the dependency. * @return the file name of the dependency
*/ */
public String getFileName() { public String getFileName() {
return this.fileName; return this.fileName;
} }
/**
* Returns the file name of the dependency with the backslash escaped for use in JavaScript. This is a complete hack
* as I could not get the replace to work in the template itself.
*
* @return the file name of the dependency with the backslash escaped for use in JavaScript
*/
public String getFileNameForJavaScript() {
return this.fileName.replace("\\", "\\\\");
}
/** /**
* Sets the file name of the dependency. * Sets the file name of the dependency.
* *
* @param fileName the file name of the dependency. * @param fileName the file name of the dependency
*/ */
public void setFileName(String fileName) { public void setFileName(String fileName) {
this.fileName = fileName; this.fileName = fileName;
@@ -124,7 +134,7 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Sets the actual file path of the dependency on disk. * Sets the actual file path of the dependency on disk.
* *
* @param actualFilePath the file path of the dependency. * @param actualFilePath the file path of the dependency
*/ */
public void setActualFilePath(String actualFilePath) { public void setActualFilePath(String actualFilePath) {
this.actualFilePath = actualFilePath; this.actualFilePath = actualFilePath;
@@ -137,7 +147,7 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Gets the file path of the dependency. * Gets the file path of the dependency.
* *
* @return the file path of the dependency. * @return the file path of the dependency
*/ */
public String getActualFilePath() { public String getActualFilePath() {
return this.actualFilePath; return this.actualFilePath;
@@ -146,7 +156,7 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Gets a reference to the File object. * Gets a reference to the File object.
* *
* @return the File object. * @return the File object
*/ */
public File getActualFile() { public File getActualFile() {
return new File(this.actualFilePath); return new File(this.actualFilePath);
@@ -155,7 +165,7 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Sets the file path of the dependency. * Sets the file path of the dependency.
* *
* @param filePath the file path of the dependency. * @param filePath the file path of the dependency
*/ */
public void setFilePath(String filePath) { public void setFilePath(String filePath) {
this.filePath = filePath; this.filePath = filePath;
@@ -168,7 +178,7 @@ public class Dependency implements Comparable<Dependency> {
* <b>NOTE:</b> This may not be the actual path of the file on disk. The actual path of the file on disk can be * <b>NOTE:</b> This may not be the actual path of the file on disk. The actual path of the file on disk can be
* obtained via the getActualFilePath().</p> * obtained via the getActualFilePath().</p>
* *
* @return the file path of the dependency. * @return the file path of the dependency
*/ */
public String getFilePath() { public String getFilePath() {
return this.filePath; return this.filePath;
@@ -177,7 +187,7 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Sets the file name of the dependency. * Sets the file name of the dependency.
* *
* @param fileExtension the file name of the dependency. * @param fileExtension the file name of the dependency
*/ */
public void setFileExtension(String fileExtension) { public void setFileExtension(String fileExtension) {
this.fileExtension = fileExtension; this.fileExtension = fileExtension;
@@ -186,7 +196,7 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Gets the file extension of the dependency. * Gets the file extension of the dependency.
* *
* @return the file extension of the dependency. * @return the file extension of the dependency
*/ */
public String getFileExtension() { public String getFileExtension() {
return this.fileExtension; return this.fileExtension;
@@ -231,7 +241,7 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Returns a List of Identifiers. * Returns a List of Identifiers.
* *
* @return an ArrayList of Identifiers. * @return an ArrayList of Identifiers
*/ */
public Set<Identifier> getIdentifiers() { public Set<Identifier> getIdentifiers() {
return this.identifiers; return this.identifiers;
@@ -240,7 +250,7 @@ public class Dependency implements Comparable<Dependency> {
/** /**
* Sets a List of Identifiers. * Sets a List of Identifiers.
* *
* @param identifiers A list of Identifiers. * @param identifiers A list of Identifiers
*/ */
public void setIdentifiers(Set<Identifier> identifiers) { public void setIdentifiers(Set<Identifier> identifiers) {
this.identifiers = identifiers; this.identifiers = identifiers;

View File

@@ -0,0 +1,68 @@
/*
* 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.exception;
import java.io.IOException;
/**
* An exception used when using @{link DependencyCheckScanAgent} to conduct a scan and the scan fails.
*
* @author Steve Springett <steve.springett@owasp.org>
*/
public class ScanAgentException extends IOException {
/**
* The serial version uid.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new ScanAgentException.
*/
public ScanAgentException() {
super();
}
/**
* Creates a new ScanAgentException.
*
* @param msg a message for the exception.
*/
public ScanAgentException(String msg) {
super(msg);
}
/**
* Creates a new NoDataException.
*
* @param ex the cause of the exception.
*/
public ScanAgentException(Throwable ex) {
super(ex);
}
/**
* Creates a new ScanAgentException.
*
* @param msg a message for the exception.
* @param ex the cause of the exception.
*/
public ScanAgentException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -140,13 +140,13 @@ public class ReportGenerator {
*/ */
public void generateReports(String outputDir, Format format) throws IOException, Exception { public void generateReports(String outputDir, Format format) throws IOException, Exception {
if (format == Format.XML || format == Format.ALL) { if (format == Format.XML || format == Format.ALL) {
generateReport("XmlReport", outputDir + File.separator + "DependencyCheck-Report.xml"); generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
} }
if (format == Format.HTML || format == Format.ALL) { if (format == Format.HTML || format == Format.ALL) {
generateReport("HtmlReport", outputDir + File.separator + "DependencyCheck-Report.html"); generateReport("HtmlReport", outputDir + File.separator + "dependency-check-report.html");
} }
if (format == Format.VULN || format == Format.ALL) { if (format == Format.VULN || format == Format.ALL) {
generateReport("VulnerabilityReport", outputDir + File.separator + "DependencyCheck-Vulnerability.html"); generateReport("VulnerabilityReport", outputDir + File.separator + "dependency-check-vulnerability.html");
} }
} }

View File

@@ -46,68 +46,101 @@ public final class Downloader {
/** /**
* Retrieves a file from a given URL and saves it to the outputPath. * Retrieves a file from a given URL and saves it to the outputPath.
* *
* @param url the URL of the file to download. * @param url the URL of the file to download
* @param outputPath the path to the save the file to. * @param outputPath the path to the save the file to
* @throws DownloadFailedException is thrown if there is an error downloading the file. * @throws DownloadFailedException is thrown if there is an error downloading the file
*/ */
public static void fetchFile(URL url, File outputPath) throws DownloadFailedException { public static void fetchFile(URL url, File outputPath) throws DownloadFailedException {
HttpURLConnection conn = null; fetchFile(url, outputPath, true);
try { }
conn = URLConnectionFactory.createHttpURLConnection(url);
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
conn.connect();
} catch (IOException ex) {
try {
if (conn != null) {
conn.disconnect();
}
} finally {
conn = null;
}
throw new DownloadFailedException("Error downloading file.", ex);
}
final String encoding = conn.getContentEncoding();
BufferedOutputStream writer = null; /**
InputStream reader = null; * Retrieves a file from a given URL and saves it to the outputPath.
try { *
if (encoding != null && "gzip".equalsIgnoreCase(encoding)) { * @param url the URL of the file to download
reader = new GZIPInputStream(conn.getInputStream()); * @param outputPath the path to the save the file to
} else if (encoding != null && "deflate".equalsIgnoreCase(encoding)) { * @param useProxy whether to use the configured proxy when downloading files
reader = new InflaterInputStream(conn.getInputStream()); * @throws DownloadFailedException is thrown if there is an error downloading the file
*/
public static void fetchFile(URL url, File outputPath, boolean useProxy) throws DownloadFailedException {
if ("file".equalsIgnoreCase(url.getProtocol())) {
File file;
try {
file = new File(url.toURI());
} catch (URISyntaxException ex) {
final String msg = String.format("Download failed, unable to locate '%s'", url.toString());
throw new DownloadFailedException(msg);
}
if (file.exists()) {
try {
org.apache.commons.io.FileUtils.copyFile(file, outputPath);
} catch (IOException ex) {
final String msg = String.format("Download failed, unable to copy '%s'", url.toString());
throw new DownloadFailedException(msg);
}
} else { } else {
reader = conn.getInputStream(); final String msg = String.format("Download failed, file does not exist '%s'", url.toString());
} throw new DownloadFailedException(msg);
writer = new BufferedOutputStream(new FileOutputStream(outputPath));
final byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = reader.read(buffer)) > 0) {
writer.write(buffer, 0, bytesRead);
}
} catch (Throwable ex) {
throw new DownloadFailedException("Error saving downloaded file.", ex);
} finally {
if (writer != null) {
try {
writer.close();
} catch (Throwable ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the writer in Downloader.", ex);
}
}
if (reader != null) {
try {
reader.close();
} catch (Throwable ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the reader in Downloader.", ex);
}
} }
} else {
HttpURLConnection conn = null;
try { try {
conn.disconnect(); conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
conn.connect();
} catch (IOException ex) {
try {
if (conn != null) {
conn.disconnect();
}
} finally {
conn = null;
}
throw new DownloadFailedException("Error downloading file.", ex);
}
final String encoding = conn.getContentEncoding();
BufferedOutputStream writer = null;
InputStream reader = null;
try {
if (encoding != null && "gzip".equalsIgnoreCase(encoding)) {
reader = new GZIPInputStream(conn.getInputStream());
} else if (encoding != null && "deflate".equalsIgnoreCase(encoding)) {
reader = new InflaterInputStream(conn.getInputStream());
} else {
reader = conn.getInputStream();
}
writer = new BufferedOutputStream(new FileOutputStream(outputPath));
final byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = reader.read(buffer)) > 0) {
writer.write(buffer, 0, bytesRead);
}
} catch (Throwable ex) {
throw new DownloadFailedException("Error saving downloaded file.", ex);
} finally { } finally {
conn = null; if (writer != null) {
try {
writer.close();
} catch (Throwable ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the writer in Downloader.", ex);
}
}
if (reader != null) {
try {
reader.close();
} catch (Throwable ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
"Error closing the reader in Downloader.", ex);
}
}
try {
conn.disconnect();
} finally {
conn = null;
}
} }
} }
} }
@@ -122,20 +155,11 @@ public final class Downloader {
*/ */
public static long getLastModified(URL url) throws DownloadFailedException { public static long getLastModified(URL url) throws DownloadFailedException {
long timestamp = 0; long timestamp = 0;
//TODO add the FPR protocol? //TODO add the FTP protocol?
if ("file".equalsIgnoreCase(url.getProtocol())) { if ("file".equalsIgnoreCase(url.getProtocol())) {
File lastModifiedFile; File lastModifiedFile;
try { try {
// if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
// String filePath = url.toString();
// if (filePath.matches("file://[a-zA-Z]:.*")) {
// f = new File(filePath.substring(7));
// } else {
// f = new File(url.toURI());
// }
// } else {
lastModifiedFile = new File(url.toURI()); lastModifiedFile = new File(url.toURI());
// }
} catch (URISyntaxException ex) { } catch (URISyntaxException ex) {
final String msg = String.format("Unable to locate '%s'; is the cve.url-2.0.modified property set correctly?", url.toString()); final String msg = String.format("Unable to locate '%s'; is the cve.url-2.0.modified property set correctly?", url.toString());
throw new DownloadFailedException(msg); throw new DownloadFailedException(msg);

View File

@@ -26,6 +26,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
@@ -39,6 +40,16 @@ import org.owasp.dependencycheck.Engine;
*/ */
public final class FileUtils { public final class FileUtils {
/**
* Bit bucket for non-Windows systems
*/
private static final String BIT_BUCKET_UNIX = "/dev/null";
/**
* Bit bucket for Windows systems (yes, only one 'L')
*/
private static final String BIT_BUCKET_WIN = "NUL";
/** /**
* The buffer size to use when extracting files from the archive. * The buffer size to use when extracting files from the archive.
*/ */
@@ -73,19 +84,38 @@ public final class FileUtils {
*/ */
public static boolean delete(File file) { public static boolean delete(File file) {
boolean success = true; boolean success = true;
if (file.isDirectory()) { //some of this may duplicative of deleteQuietly....
for (File f : file.listFiles()) {
success &= delete(f);
}
}
if (!org.apache.commons.io.FileUtils.deleteQuietly(file)) { if (!org.apache.commons.io.FileUtils.deleteQuietly(file)) {
success = false; success = false;
final String msg = String.format("Failed to delete file: %s", file.getPath()); final String msg = String.format("Failed to delete file: %s; attempting to delete on exit.", file.getPath());
Logger.getLogger(FileUtils.class.getName()).log(Level.FINE, msg); Logger.getLogger(FileUtils.class.getName()).log(Level.FINE, msg);
file.deleteOnExit();
} }
return success; return success;
} }
/**
* Generates a new temporary file name that is guaranteed to be unique.
*
* @param prefix the prefix for the file name to generate
* @param extension the extension of the generated file name
* @return a temporary File
* @throws java.io.IOException thrown if the temporary folder could not be created
*/
public static File getTempFile(String prefix, String extension) throws IOException {
final File dir = Settings.getTempDirectory();
if (!dir.exists()) {
if (!dir.mkdirs()) {
throw new IOException("Unable to create temporary folder");
}
}
final String tempFileName = String.format("%s%s.%s", prefix, UUID.randomUUID().toString(), extension);
final File tempFile = new File(dir, tempFileName);
if (tempFile.exists()) {
return getTempFile(prefix, extension);
}
return tempFile;
}
/** /**
* Returns the data directory. If a path was specified in dependencycheck.properties or was specified using the * Returns the data directory. If a path was specified in dependencycheck.properties or was specified using the
* Settings object, and the path exists, that path will be returned as a File object. If it does not exist, then a * Settings object, and the path exists, that path will be returned as a File object. If it does not exist, then a
@@ -218,4 +248,17 @@ public final class FileUtils {
} }
} }
} }
/**
* Return the bit bucket for the OS. '/dev/null' for Unix and 'NUL' for Windows
*
* @return a String containing the bit bucket
*/
public static String getBitBucket() {
if (System.getProperty("os.name").startsWith("Windows")) {
return BIT_BUCKET_WIN;
} else {
return BIT_BUCKET_UNIX;
}
}
} }

View File

@@ -145,6 +145,26 @@ public final class Settings {
* The key for a list of suppression files. * The key for a list of suppression files.
*/ */
public static final String SUPPRESSION_FILE = "suppression.file"; public static final String SUPPRESSION_FILE = "suppression.file";
/**
* The properties key for whether the Jar Analyzer is enabled.
*/
public static final String ANALYZER_JAR_ENABLED = "analyzer.jar.enabled";
/**
* The properties key for whether the Archive analyzer is enabled.
*/
public static final String ANALYZER_ARCHIVE_ENABLED = "analyzer.archive.enabled";
/**
* The properties key for whether the .NET Assembly analyzer is enabled.
*/
public static final String ANALYZER_ASSEMBLY_ENABLED = "analyzer.assembly.enabled";
/**
* The properties key for whether the .NET Nuspec analyzer is enabled.
*/
public static final String ANALYZER_NUSPEC_ENABLED = "analyzer.nuspec.enabled";
/**
* The properties key for whether the JavaScript analyzer is enabled.
*/
public static final String ANALYZER_JAVASCRIPT_ENABLED = "analyzer.javascript.enabled";
/** /**
* The properties key for whether the Nexus analyzer is enabled. * The properties key for whether the Nexus analyzer is enabled.
*/ */
@@ -511,4 +531,28 @@ public final class Settings {
} }
return value; return value;
} }
/**
* Returns a boolean value from the properties file. If the value was specified as a system property or passed in
* via the <code>-Dprop=value</code> argument this method will return the value from the system properties before
* the values in the contained configuration file.
*
* @param key the key to lookup within the properties file
* @param defaultValue the default value to return if the setting does not exist
* @return the property from the properties file
* @throws InvalidSettingException is thrown if there is an error retrieving the setting
*/
public static boolean getBoolean(String key, boolean defaultValue) throws InvalidSettingException {
boolean value;
try {
final String strValue = Settings.getString(key);
if (strValue == null) {
return defaultValue;
}
value = Boolean.parseBoolean(strValue);
} catch (NumberFormatException ex) {
throw new InvalidSettingException("Could not convert property '" + key + "' to an int.", ex);
}
return value;
}
} }

View File

@@ -42,9 +42,15 @@ cve.startyear=2002
cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml 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=http://nvd.nist.gov/download/nvdcve-%d.xml
# file type analyzer settings:
analyzer.archive.enabled=true
analyzer.jar.enabled=true
analyzer.nuspec.enabled=true
analyzer.assembly.enabled=true
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled # the URL for searching Nexus for SHA-1 hashes and whether it's enabled
analyzer.nexus.enabled=true analyzer.nexus.enabled=true
analyzer.nexus.url=http://repository.sonatype.org/service/local/ 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) # If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
# are configured # are configured
analyzer.nexus.proxy=true analyzer.nexus.proxy=true

View File

@@ -448,6 +448,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
color: blue; color: blue;
float:right; float:right;
} }
.disclaimer {
color: #888888;
font: 9px "Droid Sans",Arial,"Helvetica Neue","Lucida Grande",sans-serif
}
</style> </style>
</head> </head>
<body> <body>
@@ -459,6 +464,12 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
</div> </div>
<div class="wrapper"> <div class="wrapper">
<h1>Dependency-Check Report</h1> <h1>Dependency-Check Report</h1>
<p class="disclaimer">Dependency-Check is an open source tool performing a best effort analysis of 3rd party dependencies;
false positives and false negatives may exist in the analysis performed by the tool. Use of the tool and
the reporting provided constitutes acceptance for use in an AS IS condition, and there are NO warranties,
implied or otherwise, with regard to the analysis or its use. Any use of the tool and the reporting provided
is at the users risk. In no event shall the copyright holder or OWASP be held liable for any damages whatsoever
arising out of or in connection with the use of this tool, the analysis performed, or the resulting report.</p>
]]# ]]#
<h2 class="">Project:&nbsp;$esc.html($applicationName)</h2> <h2 class="">Project:&nbsp;$esc.html($applicationName)</h2>
<div class=""> <div class="">
@@ -586,7 +597,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
#end #end
#if ($id.type=="cpe") #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 ##yes, we are HTML Encoding into JavaScript... the escape utils don't have a JS Encode and I haven't written one yet
&nbsp;&nbsp;<button class="copybutton" onclick="copyText('$esc.html($dependency.FileName)', '$esc.html($dependency.Sha1sum)', 'cpe', '$esc.html($id.value)')">suppress</button> &nbsp;&nbsp;<button class="copybutton" onclick="copyText('$esc.html($dependency.FileNameForJavaScript)', '$esc.html($dependency.Sha1sum)', 'cpe', '$esc.html($id.value)')">suppress</button>
#end #end
#if ($id.description) #if ($id.description)
<br/>$esc.html($id.description) <br/>$esc.html($id.description)
@@ -602,7 +613,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<div id="content$cnt" class="subsectioncontent standardsubsection"> <div id="content$cnt" class="subsectioncontent standardsubsection">
#foreach($vuln in $dependency.getVulnerabilities()) #foreach($vuln in $dependency.getVulnerabilities())
#set($vsctr=$vsctr+1) #set($vsctr=$vsctr+1)
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$esc.url($vuln.name)">$esc.html($vuln.name)</a></b>&nbsp;&nbsp;<button class="copybutton" onclick="copyText('$esc.html($dependency.FileName)', '$esc.html($dependency.Sha1sum)', 'cve', '$esc.html($vuln.name)')">suppress</button></p> <p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$esc.url($vuln.name)">$esc.html($vuln.name)</a></b>&nbsp;&nbsp;<button class="copybutton" onclick="copyText('$esc.html($dependency.FileNameForJavaScript)', '$esc.html($dependency.Sha1sum)', 'cve', '$esc.html($vuln.name)')">suppress</button></p>
<p>Severity: <p>Severity:
#if ($vuln.cvssScore<4.0) #if ($vuln.cvssScore<4.0)
Low Low

View File

@@ -161,11 +161,22 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
margin-top:3px; margin-top:3px;
margin-bottom:3px; margin-bottom:3px;
} }
.disclaimer {
color: #888888;
font: 9px "Droid Sans",Arial,"Helvetica Neue","Lucida Grande",sans-serif
}
</style> </style>
</head> </head>
<body> <body>
<div> <div>
<h1 class="sectionheader">Vulnerability Report</h1> <h1 class="sectionheader">Vulnerability Report</h1>
<p class="disclaimer">Dependency-Check is an open source tool performing a best effort analysis of 3rd party dependencies;
false positives and false negatives may exist in the analysis performed by the tool. Use of the tool and
the reporting provided constitutes acceptance for use in an AS IS condition, and there are NO warranties,
implied or otherwise, with regard to the analysis or its use. Any use of the tool and the reporting provided
is at the users risk. In no event shall the copyright holder or OWASP be held liable for any damages whatsoever
arising out of or in connection with the use of this tool, the analysis performed, or the resulting report.</p>
]]# ]]#
<h2 class="sectionheader white">Project:&nbsp;$esc.html($applicationName)</h2> <h2 class="sectionheader white">Project:&nbsp;$esc.html($applicationName)</h2>
<div class="sectioncontent">Report Generated On: $date<br/><br/> <div class="sectioncontent">Report Generated On: $date<br/><br/>

View File

@@ -25,7 +25,9 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.reporting.ReportGenerator; import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.utils.Settings;
/** /**
* *
@@ -57,6 +59,26 @@ public class EngineIntegrationTest {
*/ */
@Test @Test
public void testScan() throws Exception { 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.
*
* @throws Exception is thrown when an exception occurs.
*/
@Test
public void testEngine() throws Exception {
String testClasses = "target/test-classes"; String testClasses = "target/test-classes";
Engine instance = new Engine(); Engine instance = new Engine();
instance.scan(testClasses); instance.scan(testClasses);

View File

@@ -30,9 +30,9 @@ import org.junit.Test;
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public class AbstractAnalyzerTest { public class AbstractFileTypeAnalyzerTest {
public AbstractAnalyzerTest() { public AbstractFileTypeAnalyzerTest() {
} }
@BeforeClass @BeforeClass
@@ -56,7 +56,7 @@ public class AbstractAnalyzerTest {
*/ */
@Test @Test
public void testNewHashSet() { public void testNewHashSet() {
Set result = AbstractAnalyzer.newHashSet("one", "two"); Set result = AbstractFileTypeAnalyzer.newHashSet("one", "two");
assertEquals(2, result.size()); assertEquals(2, result.size());
assertTrue(result.contains("one")); assertTrue(result.contains("one"));
assertTrue(result.contains("two")); assertTrue(result.contains("two"));

View File

@@ -0,0 +1,121 @@
/*
* 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.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 org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.suppression.SuppressionRule;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class AbstractSuppressionAnalyzerTest {
public AbstractSuppressionAnalyzerTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
try {
final String uri = this.getClass().getClassLoader().getResource("suppressions.xml").toURI().toURL().toString();
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, uri);
} catch (URISyntaxException ex) {
Logger.getLogger(AbstractSuppressionAnalyzerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (MalformedURLException ex) {
Logger.getLogger(AbstractSuppressionAnalyzerTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
@After
public void tearDown() {
}
/**
* 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
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public String getName() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public AnalysisPhase getAnalysisPhase() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
}

View File

@@ -18,7 +18,6 @@
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -62,8 +61,7 @@ public class AnalyzerServiceTest {
boolean found = false; boolean found = false;
while (result.hasNext()) { while (result.hasNext()) {
Analyzer a = result.next(); Analyzer a = result.next();
Set<String> e = a.getSupportedExtensions(); if ("Jar Analyzer".equals(a.getName())) {
if (e != null && e.contains("jar")) {
found = true; found = true;
} }
} }

View File

@@ -26,7 +26,7 @@ import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.cpe.BaseIndexTestCase; import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
@@ -34,7 +34,7 @@ import org.owasp.dependencycheck.utils.Settings;
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public class ArchiveAnalyzerTest extends BaseIndexTestCase { public class ArchiveAnalyzerTest extends AbstractDatabaseTestCase {
public ArchiveAnalyzerTest() { public ArchiveAnalyzerTest() {
} }
@@ -147,6 +147,8 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase {
@Test @Test
public void testAnalyze() throws Exception { public void testAnalyze() throws Exception {
ArchiveAnalyzer instance = new ArchiveAnalyzer(); ArchiveAnalyzer instance = new ArchiveAnalyzer();
//trick the analyzer into thinking it is active.
instance.supportsExtension("ear");
try { try {
instance.initialize(); instance.initialize();
@@ -175,6 +177,8 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase {
@Test @Test
public void testAnalyzeTar() throws Exception { public void testAnalyzeTar() throws Exception {
ArchiveAnalyzer instance = new ArchiveAnalyzer(); ArchiveAnalyzer instance = new ArchiveAnalyzer();
//trick the analyzer into thinking it is active so that it will initialize
instance.supportsExtension("tar");
try { try {
instance.initialize(); instance.initialize();
@@ -203,6 +207,7 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase {
@Test @Test
public void testAnalyzeTarGz() throws Exception { public void testAnalyzeTarGz() throws Exception {
ArchiveAnalyzer instance = new ArchiveAnalyzer(); ArchiveAnalyzer instance = new ArchiveAnalyzer();
instance.supportsExtension("zip"); //ensure analyzer is "enabled"
try { try {
instance.initialize(); instance.initialize();
@@ -252,6 +257,7 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase {
@Test @Test
public void testAnalyzeTgz() throws Exception { public void testAnalyzeTgz() throws Exception {
ArchiveAnalyzer instance = new ArchiveAnalyzer(); ArchiveAnalyzer instance = new ArchiveAnalyzer();
instance.supportsExtension("zip"); //ensure analyzer is "enabled"
try { try {
instance.initialize(); instance.initialize();

View File

@@ -17,14 +17,17 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import java.io.File; import java.io.File;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.junit.After; import org.junit.After;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Assume; import org.junit.Assume;
import static org.junit.Assume.assumeFalse;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
@@ -54,6 +57,7 @@ public class AssemblyAnalyzerTest {
public void setUp() { public void setUp() {
try { try {
analyzer = new AssemblyAnalyzer(); analyzer = new AssemblyAnalyzer();
analyzer.supportsExtension("dll");
analyzer.initialize(); analyzer.initialize();
} catch (Exception e) { } catch (Exception e) {
LOGGER.log(Level.WARNING, "Exception setting up AssemblyAnalyzer. Tests will be incomplete", e); LOGGER.log(Level.WARNING, "Exception setting up AssemblyAnalyzer. Tests will be incomplete", e);
@@ -74,7 +78,21 @@ public class AssemblyAnalyzerTest {
File f = new File(AssemblyAnalyzerTest.class.getClassLoader().getResource("GrokAssembly.exe").getPath()); File f = new File(AssemblyAnalyzerTest.class.getClassLoader().getResource("GrokAssembly.exe").getPath());
Dependency d = new Dependency(f); Dependency d = new Dependency(f);
analyzer.analyze(d, null); analyzer.analyze(d, null);
assertTrue(d.getVersionEvidence().getEvidence().contains(new Evidence("grokassembly", "version", "1.0.5140.29700", Confidence.HIGHEST))); boolean foundVendor = false;
for (Evidence e : d.getVendorEvidence().getEvidence("grokassembly", "vendor")) {
if ("OWASP".equals(e.getValue())) {
foundVendor = true;
}
}
assertTrue(foundVendor);
boolean foundProduct = false;
for (Evidence e : d.getProductEvidence().getEvidence("grokassembly", "product")) {
if ("GrokAssembly".equals(e.getValue())) {
foundProduct = true;
}
}
assertTrue(foundProduct);
} }
@Test @Test
@@ -87,15 +105,29 @@ public class AssemblyAnalyzerTest {
assertTrue(d.getProductEvidence().getEvidence().contains(new Evidence("grokassembly", "product", "log4net", Confidence.HIGH))); assertTrue(d.getProductEvidence().getEvidence().contains(new Evidence("grokassembly", "product", "log4net", Confidence.HIGH)));
} }
@Test(expected = AnalysisException.class) @Test
public void testNonexistent() throws Exception { public void testNonexistent() {
Level oldLevel = Logger.getLogger(AssemblyAnalyzer.class.getName()).getLevel();
Level oldDependency = Logger.getLogger(Dependency.class.getName()).getLevel();
// Tweak the log level so the warning doesn't show in the console
Logger.getLogger(AssemblyAnalyzer.class.getName()).setLevel(Level.OFF);
Logger.getLogger(Dependency.class.getName()).setLevel(Level.OFF);
File f = new File(AssemblyAnalyzerTest.class.getClassLoader().getResource("log4net.dll").getPath()); File f = new File(AssemblyAnalyzerTest.class.getClassLoader().getResource("log4net.dll").getPath());
File test = new File(f.getParent(), "nonexistent.dll"); File test = new File(f.getParent(), "nonexistent.dll");
Dependency d = new Dependency(test); Dependency d = new Dependency(test);
analyzer.analyze(d, null);
try {
analyzer.analyze(d, null);
fail("Expected an AnalysisException");
} catch (AnalysisException ae) {
assertEquals("File does not exist", ae.getMessage());
} finally {
Logger.getLogger(AssemblyAnalyzer.class.getName()).setLevel(oldLevel);
Logger.getLogger(Dependency.class.getName()).setLevel(oldDependency);
}
} }
@Test(expected = AnalysisException.class) @Test
public void testWithSettingMono() throws Exception { public void testWithSettingMono() throws Exception {
//This test doesn't work on Windows. //This test doesn't work on Windows.
@@ -112,11 +144,20 @@ public class AssemblyAnalyzerTest {
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, "/yooser/bine/mono"); Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, "/yooser/bine/mono");
} }
Level oldLevel = Logger.getLogger(AssemblyAnalyzer.class.getName()).getLevel();
try { try {
// Tweak the logging to swallow the warning when testing
Logger.getLogger(AssemblyAnalyzer.class.getName()).setLevel(Level.OFF);
// Have to make a NEW analyzer because during setUp, it would have gotten the correct one // Have to make a NEW analyzer because during setUp, it would have gotten the correct one
AssemblyAnalyzer aanalyzer = new AssemblyAnalyzer(); AssemblyAnalyzer aanalyzer = new AssemblyAnalyzer();
aanalyzer.supportsExtension("dll");
aanalyzer.initialize(); aanalyzer.initialize();
fail("Expected an AnalysisException");
} catch (AnalysisException ae) {
assertEquals("An error occured with the .NET AssemblyAnalyzer", ae.getMessage());
} finally { } finally {
// Recover the logger
Logger.getLogger(AssemblyAnalyzer.class.getName()).setLevel(oldLevel);
// Now recover the way we came in. If we had to set a System property, delete it. Otherwise, // Now recover the way we came in. If we had to set a System property, delete it. Otherwise,
// reset the old value // reset the old value
if (oldValue == null) { if (oldValue == null) {

View File

@@ -30,7 +30,7 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.owasp.dependencycheck.data.cpe.BaseIndexTestCase; import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
import org.owasp.dependencycheck.data.cpe.IndexEntry; import org.owasp.dependencycheck.data.cpe.IndexEntry;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Identifier;
@@ -39,7 +39,7 @@ import org.owasp.dependencycheck.dependency.Identifier;
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public class CPEAnalyzerTest extends BaseIndexTestCase { public class CPEAnalyzerTest extends AbstractDatabaseTestCase {
@BeforeClass @BeforeClass
public static void setUpClass() throws Exception { public static void setUpClass() throws Exception {

View File

@@ -17,11 +17,9 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.util.Set;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@@ -52,16 +50,6 @@ public class DependencyBundlingAnalyzerTest {
public void tearDown() { public void tearDown() {
} }
/**
* Test of getSupportedExtensions method, of class DependencyBundlingAnalyzer.
*/
@Test
public void testGetSupportedExtensions() {
DependencyBundlingAnalyzer instance = new DependencyBundlingAnalyzer();
Set<String> result = instance.getSupportedExtensions();
assertNull(result);
}
/** /**
* Test of getName method, of class DependencyBundlingAnalyzer. * Test of getName method, of class DependencyBundlingAnalyzer.
*/ */
@@ -73,18 +61,6 @@ public class DependencyBundlingAnalyzerTest {
assertEquals(expResult, result); assertEquals(expResult, result);
} }
/**
* Test of supportsExtension method, of class DependencyBundlingAnalyzer.
*/
@Test
public void testSupportsExtension() {
String extension = "jar";
DependencyBundlingAnalyzer instance = new DependencyBundlingAnalyzer();
boolean expResult = true;
boolean result = instance.supportsExtension(extension);
assertEquals(expResult, result);
}
/** /**
* Test of getAnalysisPhase method, of class DependencyBundlingAnalyzer. * Test of getAnalysisPhase method, of class DependencyBundlingAnalyzer.
*/ */

View File

@@ -15,11 +15,9 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.util.Set;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@@ -52,17 +50,6 @@ public class FalsePositiveAnalyzerTest {
public void tearDown() { public void tearDown() {
} }
/**
* Test of getSupportedExtensions method, of class FalsePositiveAnalyzer.
*/
@Test
public void testGetSupportedExtensions() {
FalsePositiveAnalyzer instance = new FalsePositiveAnalyzer();
Set<String> result = instance.getSupportedExtensions();
assertNull(result);
}
/** /**
* Test of getName method, of class FalsePositiveAnalyzer. * Test of getName method, of class FalsePositiveAnalyzer.
*/ */
@@ -74,18 +61,6 @@ public class FalsePositiveAnalyzerTest {
assertEquals(expResult, result); assertEquals(expResult, result);
} }
/**
* Test of supportsExtension method, of class FalsePositiveAnalyzer.
*/
@Test
public void testSupportsExtension() {
String extension = "any";
FalsePositiveAnalyzer instance = new FalsePositiveAnalyzer();
boolean expResult = true;
boolean result = instance.supportsExtension(extension);
assertEquals(expResult, result);
}
/** /**
* Test of getAnalysisPhase method, of class FalsePositiveAnalyzer. * Test of getAnalysisPhase method, of class FalsePositiveAnalyzer.
*/ */

View File

@@ -18,7 +18,6 @@
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.io.File; import java.io.File;
import java.util.Set;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -53,17 +52,6 @@ public class FileNameAnalyzerTest {
public void tearDown() { public void tearDown() {
} }
/**
* Test of getSupportedExtensions method, of class FileNameAnalyzer.
*/
@Test
public void testGetSupportedExtensions() {
FileNameAnalyzer instance = new FileNameAnalyzer();
Set expResult = null;
Set result = instance.getSupportedExtensions();
assertEquals(expResult, result);
}
/** /**
* Test of getName method, of class FileNameAnalyzer. * Test of getName method, of class FileNameAnalyzer.
*/ */
@@ -75,18 +63,6 @@ public class FileNameAnalyzerTest {
assertEquals(expResult, result); assertEquals(expResult, result);
} }
/**
* Test of supportsExtension method, of class FileNameAnalyzer.
*/
@Test
public void testSupportsExtension() {
String extension = "any";
FileNameAnalyzer instance = new FileNameAnalyzer();
boolean expResult = true;
boolean result = instance.supportsExtension(extension);
assertEquals(expResult, result);
}
/** /**
* Test of getAnalysisPhase method, of class FileNameAnalyzer. * Test of getAnalysisPhase method, of class FileNameAnalyzer.
*/ */

View File

@@ -17,39 +17,43 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
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.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
public class NuspecAnalyzerTest { public class NuspecAnalyzerTest {
private NuspecAnalyzer instance;
@Before private NuspecAnalyzer instance;
public void setUp() {
instance = new NuspecAnalyzer();
}
@Test @Before
public void testGetAnalyzerName() { public void setUp() {
assertEquals("Nuspec Analyzer", instance.getName()); instance = new NuspecAnalyzer();
} instance.setEnabled(true);
}
@Test @Test
public void testGetSupportedExtensions() { public void testGetAnalyzerName() {
assertTrue(instance.getSupportedExtensions().contains("nuspec")); assertEquals("Nuspec Analyzer", instance.getName());
assertFalse(instance.getSupportedExtensions().contains("nupkg")); }
}
@Test @Test
public void testSupportsExtension() { public void testGetSupportedExtensions() {
assertTrue(instance.supportsExtension("nuspec")); assertTrue(instance.getSupportedExtensions().contains("nuspec"));
assertFalse(instance.supportsExtension("nupkg")); assertFalse(instance.getSupportedExtensions().contains("nupkg"));
} }
@Test @Test
public void testGetAnalysisPhaze() { public void testSupportsExtension() {
assertEquals(AnalysisPhase.INFORMATION_COLLECTION, instance.getAnalysisPhase()); assertTrue(instance.supportsExtension("nuspec"));
} assertFalse(instance.supportsExtension("nupkg"));
}
@Test
public void testGetAnalysisPhaze() {
assertEquals(AnalysisPhase.INFORMATION_COLLECTION, instance.getAnalysisPhase());
}
} }
// vim: cc=120:sw=4:ts=4:sts=4 // vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -0,0 +1,128 @@
/*
* 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.File;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings;
/**
* Testing the vulnerability suppression analyzer.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class VulnerabilitySuppressionAnalyzerTest extends AbstractDatabaseTestCase {
public VulnerabilitySuppressionAnalyzerTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
private boolean update = true;
private boolean nexus = false;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
update = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
nexus = Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, false);
}
@After
@Override
public void tearDown() throws Exception {
super.tearDown();
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, update);
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexus);
}
/**
* Test of getName method, of class VulnerabilitySuppressionAnalyzer.
*/
@Test
public void testGetName() {
VulnerabilitySuppressionAnalyzer instance = new VulnerabilitySuppressionAnalyzer();
String expResult = "Vulnerability Suppression Analyzer";
String result = instance.getName();
assertEquals(expResult, result);
}
/**
* Test of getAnalysisPhase method, of class VulnerabilitySuppressionAnalyzer.
*/
@Test
public void testGetAnalysisPhase() {
VulnerabilitySuppressionAnalyzer instance = new VulnerabilitySuppressionAnalyzer();
AnalysisPhase expResult = AnalysisPhase.POST_FINDING_ANALYSIS;;
AnalysisPhase result = instance.getAnalysisPhase();
assertEquals(expResult, result);
}
/**
* Test of analyze method, of class VulnerabilitySuppressionAnalyzer.
*/
@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());
Engine engine = new Engine();
engine.scan(file);
engine.analyzeDependencies();
Dependency dependency = getDependency(engine, file);
assertTrue(dependency.getVulnerabilities().size() > 0);
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppression.getAbsolutePath());
VulnerabilitySuppressionAnalyzer instance = new VulnerabilitySuppressionAnalyzer();
instance.initialize();
instance.analyze(dependency, engine);
assertTrue(dependency.getVulnerabilities().size() == 0);
engine.cleanup();
}
/**
* Retrieves a specific dependency from the engine.
*
* @param engine the engine
* @param file the dependency to retrieve
* @return the dependency
*/
private Dependency getDependency(Engine engine, File file) {
for (Dependency d : engine.getDependencies()) {
if (d.getFileName().equals(file.getName())) {
return d;
}
}
return null;
}
}

View File

@@ -25,10 +25,12 @@ import org.junit.BeforeClass;
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase; import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
/** /**
* An abstract database test case that is used to ensure the H2 DB exists prior to performing tests that utilize the
* data contained within.
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public abstract class BaseIndexTestCase extends TestCase { public abstract class AbstractDatabaseTestCase extends TestCase {
@BeforeClass @BeforeClass
public static void setUpClass() throws Exception { public static void setUpClass() throws Exception {

View File

@@ -73,7 +73,7 @@ public class FileUtilsTest {
@Test @Test
public void testDelete() throws Exception { public void testDelete() throws Exception {
File file = File.createTempFile("tmp", "deleteme"); File file = File.createTempFile("tmp", "deleteme", Settings.getTempDirectory());
if (!file.exists()) { if (!file.exists()) {
fail("Unable to create a temporary file."); fail("Unable to create a temporary file.");
} }

View File

@@ -155,6 +155,11 @@ public class SettingsTest {
boolean expResult = false; boolean expResult = false;
boolean result = Settings.getBoolean(key); boolean result = Settings.getBoolean(key);
Assert.assertEquals(expResult, result); Assert.assertEquals(expResult, result);
key = "something that does not exist";
expResult = true;
result = Settings.getBoolean(key, true);
Assert.assertEquals(expResult, result);
} }
/** /**

View File

@@ -0,0 +1,10 @@
<?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>

View File

@@ -49,7 +49,7 @@ cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled # the URL for searching Nexus for SHA-1 hashes and whether it's enabled
analyzer.nexus.enabled=true analyzer.nexus.enabled=true
analyzer.nexus.url=http://repository.sonatype.org/service/local/ 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) # If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
# are configured # are configured
analyzer.nexus.proxy=true analyzer.nexus.proxy=true

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp</groupId> <groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId> <artifactId>dependency-check-parent</artifactId>
<version>1.1.2</version> <version>1.1.4</version>
</parent> </parent>
<groupId>org.owasp</groupId> <groupId>org.owasp</groupId>

View File

@@ -23,7 +23,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<parent> <parent>
<groupId>org.owasp</groupId> <groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId> <artifactId>dependency-check-parent</artifactId>
<version>1.1.2</version> <version>1.1.4</version>
</parent> </parent>
<artifactId>dependency-check-maven</artifactId> <artifactId>dependency-check-maven</artifactId>
@@ -275,6 +275,11 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<artifactId>maven-plugin-api</artifactId> <artifactId>maven-plugin-api</artifactId>
<version>3.0</version> <version>3.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-settings</artifactId>
<version>3.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.maven</groupId> <groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId> <artifactId>maven-core</artifactId>

View File

@@ -44,6 +44,7 @@ import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.MavenMultiPageReport; import org.apache.maven.reporting.MavenMultiPageReport;
import org.apache.maven.reporting.MavenReport; import org.apache.maven.reporting.MavenReport;
import org.apache.maven.reporting.MavenReportException; import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.settings.Proxy;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
@@ -87,48 +88,45 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
@Component @Component
private MavenProject project; private MavenProject project;
/** /**
* The name of the site report destination. * The path to the verbose log.
*/
@Parameter(property = "report-name", defaultValue = "dependency-check-report")
private String reportName;
/**
* The path to the verbose log
*/ */
@Parameter(property = "logfile", defaultValue = "") @Parameter(property = "logfile", defaultValue = "")
private String logFile; private String logFile;
/** /**
* The name of the report to be displayed in the Maven Generated Reports page * The name of the report to be displayed in the Maven Generated Reports page.
*/ */
@Parameter(property = "name", defaultValue = "Dependency-Check") @Parameter(property = "name", defaultValue = "Dependency-Check")
private String name; private String name;
/** /**
* The description of the Dependency-Check report to be displayed in the Maven Generated Reports page * The description of the Dependency-Check report to be displayed in the Maven Generated Reports page.
*/ */
@Parameter(property = "description", defaultValue = "A report providing details on any published " @Parameter(property = "description", defaultValue = "A report providing details on any published "
+ "vulnerabilities within project dependencies. This report is a best effort but may contain " + "vulnerabilities within project dependencies. This report is a best effort but may contain "
+ "false positives and false negatives.") + "false positives and false negatives.")
private String description; private String description;
/** /**
* Specifies the destination directory for the generated Dependency-Check report. * 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) @Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true)
private File reportOutputDirectory; private File reportOutputDirectory;
/** /**
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 * The output directory. This generally maps to "target".
* which means since the CVSS scores are 0-10, by default the build will never fail.
*/
@Parameter(property = "failBuildOnCVSS", defaultValue = "11", required = true)
private float failBuildOnCVSS = 11;
/**
* The output directory.
*/ */
@Parameter(defaultValue = "${project.build.directory}", required = true) @Parameter(defaultValue = "${project.build.directory}", required = true)
private File outputDirectory; private File outputDirectory;
/**
* 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.
*/
@SuppressWarnings("CanBeFinal")
@Parameter(property = "failBuildOnCVSS", defaultValue = "11", required = true)
private float failBuildOnCVSS = 11;
/** /**
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to
* false. Default is true. * false. Default is true.
*/ */
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"}) @SuppressWarnings("CanBeFinal")
@Parameter(property = "autoupdate", defaultValue = "true", required = true) @Parameter(property = "autoupdate", defaultValue = "true", required = true)
private boolean autoUpdate = true; private boolean autoUpdate = true;
/** /**
@@ -146,27 +144,54 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
private boolean externalReport = false; private boolean externalReport = false;
/** /**
* The Proxy URL. * The Proxy URL.
*
* @deprecated Please use mavenSettings instead
*/ */
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"}) @SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "proxyUrl", defaultValue = "", required = false) @Parameter(property = "proxyUrl", defaultValue = "", required = false)
@Deprecated
private String proxyUrl = null; private String proxyUrl = null;
/**
* The maven settings.
*/
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "mavenSettings", defaultValue = "${settings}", required = false)
private org.apache.maven.settings.Settings mavenSettings;
/**
* The maven settings proxy id.
*/
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "mavenSettingsProxyId", required = false)
private String mavenSettingsProxyId;
/** /**
* The Proxy Port. * The Proxy Port.
*
* @deprecated Please use mavenSettings instead
*/ */
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"}) @SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "proxyPort", defaultValue = "", required = false) @Parameter(property = "proxyPort", defaultValue = "", required = false)
@Deprecated
private String proxyPort = null; private String proxyPort = null;
/** /**
* The Proxy username. * The Proxy username.
*
* @deprecated Please use mavenSettings instead
*/ */
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"}) @SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "proxyUsername", defaultValue = "", required = false) @Parameter(property = "proxyUsername", defaultValue = "", required = false)
@Deprecated
private String proxyUsername = null; private String proxyUsername = null;
/** /**
* The Proxy password. * The Proxy password.
*
* @deprecated Please use mavenSettings instead
*/ */
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"}) @SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "proxyPassword", defaultValue = "", required = false) @Parameter(property = "proxyPassword", defaultValue = "", required = false)
@Deprecated
private String proxyPassword = null; private String proxyPassword = null;
/** /**
* The Connection Timeout. * The Connection Timeout.
@@ -186,6 +211,35 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"}) @SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "showSummary", defaultValue = "true", required = false) @Parameter(property = "showSummary", defaultValue = "true", required = false)
private boolean showSummary = true; private boolean showSummary = true;
/**
* Whether or not the Jar Analyzer is enabled.
*/
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "jarAnalyzerEnabled", defaultValue = "true", required = false)
private boolean jarAnalyzerEnabled = true;
/**
* Whether or not the Archive Analyzer is enabled.
*/
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "archiveAnalyzerEnabled", defaultValue = "true", required = false)
private boolean archiveAnalyzerEnabled = true;
/**
* Whether or not the .NET Assembly Analyzer is enabled.
*/
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "assemblyAnalyzerEnabled", defaultValue = "true", required = false)
private boolean assemblyAnalyzerEnabled = true;
/**
* Whether or not the .NET Nuspec Analyzer is enabled.
*/
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal"})
@Parameter(property = "nuspecAnalyzerEnabled", defaultValue = "true", required = false)
private boolean nuspecAnalyzerEnabled = true;
/** /**
* Whether or not the Nexus Analyzer is enabled. * Whether or not the Nexus Analyzer is enabled.
*/ */
@@ -240,18 +294,21 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
@Parameter(property = "zipExtensions", required = false) @Parameter(property = "zipExtensions", required = false)
private String zipExtensions; private String zipExtensions;
/** /**
* Skip Analisys for Test Scope Dependencies * Skip Analisys for Test Scope Dependencies.
*/ */
@SuppressWarnings("CanBeFinal")
@Parameter(property = "skipTestScope", defaultValue = "true", required = false) @Parameter(property = "skipTestScope", defaultValue = "true", required = false)
private boolean skipTestScope = true; private boolean skipTestScope = true;
/** /**
* Skip Analisys for Runtime Scope Dependencies * Skip Analisys for Runtime Scope Dependencies.
*/ */
@SuppressWarnings("CanBeFinal")
@Parameter(property = "skipRuntimeScope", defaultValue = "false", required = false) @Parameter(property = "skipRuntimeScope", defaultValue = "false", required = false)
private boolean skipRuntimeScope = false; private boolean skipRuntimeScope = false;
/** /**
* Skip Analisys for Provided Scope Dependencies * Skip Analisys for Provided Scope Dependencies.
*/ */
@SuppressWarnings("CanBeFinal")
@Parameter(property = "skipProvidedScope", defaultValue = "false", required = false) @Parameter(property = "skipProvidedScope", defaultValue = "false", required = false)
private boolean skipProvidedScope = false; private boolean skipProvidedScope = false;
/** /**
@@ -260,26 +317,32 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
@Parameter(property = "dataDirectory", defaultValue = "", required = false) @Parameter(property = "dataDirectory", defaultValue = "", required = false)
private String dataDirectory; private String dataDirectory;
/** /**
* Data Mirror URL for CVE 1.2 * Data Mirror URL for CVE 1.2.
*/ */
@Parameter(property = "cveUrl12Modified", defaultValue = "", required = false) @Parameter(property = "cveUrl12Modified", defaultValue = "", required = false)
private String cveUrl12Modified; private String cveUrl12Modified;
/** /**
* Data Mirror URL for CVE 2.0 * Data Mirror URL for CVE 2.0.
*/ */
@Parameter(property = "cveUrl20Modified", defaultValue = "", required = false) @Parameter(property = "cveUrl20Modified", defaultValue = "", required = false)
private String cveUrl20Modified; private String cveUrl20Modified;
/** /**
* Base Data Mirror URL for CVE 1.2 * Base Data Mirror URL for CVE 1.2.
*/ */
@Parameter(property = "cveUrl12Base", defaultValue = "", required = false) @Parameter(property = "cveUrl12Base", defaultValue = "", required = false)
private String cveUrl12Base; private String cveUrl12Base;
/** /**
* Data Mirror URL for CVE 2.0 * Data Mirror URL for CVE 2.0.
*/ */
@Parameter(property = "cveUrl20Base", defaultValue = "", required = false) @Parameter(property = "cveUrl20Base", defaultValue = "", required = false)
private String cveUrl20Base; private String cveUrl20Base;
/**
* The path to mono for .NET Assembly analysis on non-windows systems.
*/
@Parameter(property = "pathToMono", defaultValue = "", required = false)
private String pathToMono;
// </editor-fold> // </editor-fold>
/** /**
* Executes the Dependency-Check on the dependent libraries. * Executes the Dependency-Check on the dependent libraries.
@@ -325,8 +388,9 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
* Generates the reports for a given dependency-check engine. * Generates the reports for a given dependency-check engine.
* *
* @param engine a dependency-check engine * @param engine a dependency-check engine
* @param outDirectory the directory to write the reports to
*/ */
private void generateExternalReports(Engine engine) { private void generateExternalReports(Engine engine, File outDirectory) {
DatabaseProperties prop = null; DatabaseProperties prop = null;
CveDB cve = null; CveDB cve = null;
try { try {
@@ -342,7 +406,7 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
} }
final ReportGenerator r = new ReportGenerator(project.getName(), engine.getDependencies(), engine.getAnalyzers(), prop); final ReportGenerator r = new ReportGenerator(project.getName(), engine.getDependencies(), engine.getAnalyzers(), prop);
try { try {
r.generateReports(outputDirectory.getCanonicalPath(), format); r.generateReports(outDirectory.getCanonicalPath(), format);
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.SEVERE, Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.SEVERE,
"Unexpected exception occurred during analysis; please see the verbose error log for more details."); "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
@@ -711,6 +775,41 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
} }
// </editor-fold> // </editor-fold>
/**
* Returns the maven settings proxy url.
*
* @param proxy the maven proxy
* @return the proxy url
*/
private String getMavenSettingsProxyUrl(Proxy proxy) {
return new StringBuilder(proxy.getProtocol()).append("://").append(proxy.getHost()).toString();
}
/**
* Returns the maven proxy.
*
* @return the maven proxy
*/
private Proxy getMavenProxy() {
if (mavenSettings != null) {
final List<Proxy> proxies = mavenSettings.getProxies();
if (proxies != null && proxies.size() > 0) {
if (mavenSettingsProxyId != null) {
for (Proxy proxy : proxies) {
if (mavenSettingsProxyId.equalsIgnoreCase(proxy.getId())) {
return proxy;
}
}
} else if (proxies.size() == 1) {
return proxies.get(0);
} else {
throw new IllegalStateException("Ambigous proxy definition");
}
}
}
return null;
}
/** /**
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system * 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 url, port, and connection timeout.
@@ -735,6 +834,18 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate); Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
final Proxy proxy = getMavenProxy();
if (proxy != null) {
Settings.setString(Settings.KEYS.PROXY_URL, getMavenSettingsProxyUrl(proxy));
Settings.setString(Settings.KEYS.PROXY_PORT, Integer.toString(proxy.getPort()));
final String userName = proxy.getUsername();
final String password = proxy.getPassword();
if (userName != null && password != null) {
Settings.setString(Settings.KEYS.PROXY_USERNAME, userName);
Settings.setString(Settings.KEYS.PROXY_PASSWORD, password);
}
}
if (proxyUrl != null && !proxyUrl.isEmpty()) { if (proxyUrl != null && !proxyUrl.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl); Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
} }
@@ -753,11 +864,30 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
if (suppressionFile != null && !suppressionFile.isEmpty()) { if (suppressionFile != null && !suppressionFile.isEmpty()) {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile); Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
} }
//File Type Analyzer Settings
//JAR ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
//NUSPEC ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
//NEXUS ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled); Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
if (nexusUrl != null && !nexusUrl.isEmpty()) { if (nexusUrl != null && !nexusUrl.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl); Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
} }
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy); Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
//ARCHIVE ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
if (zipExtensions != null && !zipExtensions.isEmpty()) {
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
}
//ASSEMBLY ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
if (pathToMono != null && !pathToMono.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
}
//Database configuration
if (databaseDriverName != null && !databaseDriverName.isEmpty()) { if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName); Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
} }
@@ -773,8 +903,9 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
if (databasePassword != null && !databasePassword.isEmpty()) { if (databasePassword != null && !databasePassword.isEmpty()) {
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword); Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
} }
if (zipExtensions != null && !zipExtensions.isEmpty()) { // Data Directory
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions); if (dataDirectory != null && !dataDirectory.isEmpty()) {
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
} }
// Scope Exclusion // Scope Exclusion
@@ -782,11 +913,6 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
Settings.setBoolean(Settings.KEYS.SKIP_RUNTIME_SCOPE, skipRuntimeScope); Settings.setBoolean(Settings.KEYS.SKIP_RUNTIME_SCOPE, skipRuntimeScope);
Settings.setBoolean(Settings.KEYS.SKIP_PROVIDED_SCOPE, skipProvidedScope); Settings.setBoolean(Settings.KEYS.SKIP_PROVIDED_SCOPE, skipProvidedScope);
// Data Directory
if (dataDirectory != null && !dataDirectory.isEmpty()) {
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
}
// CVE Data Mirroring // CVE Data Mirroring
if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) { if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified); Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
@@ -800,6 +926,7 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) { if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base); Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
} }
} }
/** /**
@@ -812,7 +939,7 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
Engine engine = null; Engine engine = null;
try { try {
engine = executeDependencyCheck(); engine = executeDependencyCheck();
generateExternalReports(engine); generateExternalReports(engine, outputDirectory);
if (this.showSummary) { if (this.showSummary) {
showSummary(engine.getDependencies()); showSummary(engine.getDependencies());
} }
@@ -854,7 +981,11 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
Engine engine = null; Engine engine = null;
try { try {
engine = executeDependencyCheck(); engine = executeDependencyCheck();
generateMavenSiteReport(engine, sink); if (this.externalReport) {
generateExternalReports(engine, reportOutputDirectory);
} else {
generateMavenSiteReport(engine, sink);
}
} catch (DatabaseException ex) { } catch (DatabaseException ex) {
Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.SEVERE, Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.SEVERE,
"Unable to connect to the dependency-check database; analysis has stopped"); "Unable to connect to the dependency-check database; analysis has stopped");
@@ -873,7 +1004,18 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
* @return the output name * @return the output name
*/ */
public String getOutputName() { public String getOutputName() {
return reportName; if ("HTML".equalsIgnoreCase(this.format)
|| "ALL".equalsIgnoreCase(this.format)) {
return "dependency-check-report";
} else if ("XML".equalsIgnoreCase(this.format)) {
return "dependency-check-report.xml#";
} else if ("VULN".equalsIgnoreCase(this.format)) {
return "dependency-check-vulnerability";
} else {
Logger.getLogger(DependencyCheckMojo.class
.getName()).log(Level.WARNING, "Unknown report format used during site generatation.");
return "dependency-check-report";
}
} }
/** /**
@@ -1009,7 +1151,9 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
final String msg = String.format("%n%n" final String msg = String.format("%n%n"
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s" + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString()); + "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.WARNING, msg); Logger
.getLogger(DependencyCheckMojo.class
.getName()).log(Level.WARNING, msg);
} }
} }
} }

View File

@@ -6,29 +6,66 @@ Property | Description | Default Value
---------------------|------------------------------------|------------------ ---------------------|------------------------------------|------------------
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true 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 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 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 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. | logFile | The file path to write verbose logging information. | &nbsp;
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) | suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) | &nbsp;
connectionTimeout | The Connection Timeout. | skipTestScope | Should be skip analysis for artifacts with Test Scope | true
proxyUrl | The Proxy URL. | skipProvidedScope | Should be skip analysis for artifacts with Provided Scope | false
proxyPort | The Proxy Port. | skipRuntimeScope | Should be skip analysis for artifacts with Runtime Scope | false
proxyUsername | Defines the proxy user name. |
proxyPassword | Defines the proxy password. | Analyzer Configuration
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | ====================
nexusUrl | Defines the Nexus URL. | The following properties are used to configure the various file type analyzers.
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true These properties can be used to turn off specific analyzers if it is not needed.
databaseDriverName | The name of the database driver. Example: org.h2.Driver. | Note, that specific analyzers will automatically disable themselves if no file
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. | types that they support are detected - so specifically disabling them may not
connectionString | The connection string used to connect to the database. | be needed.
databaseUser | The username used when connecting to the database. |
databasePassword | The password used when connecting to the database. | Property | Description | Default Value
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. | ------------------------|------------------------------------|------------------
skipTestScope | Should be skip analysis for artifacts with Test Scope | true archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
skipProvidedScope | Should be skip analysis for artifacts with Provided Scope | false zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. | &nbsp;
skipRuntimeScope | Should be skip analysis for artifacts with Runtime Scope | false jarAnalyzer | Sets whether Jar Analyzer will be used. | true
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. | nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
cveUrl12Modified | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
cveUrl20Modified | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
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 nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
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 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 | &nbsp;
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. | &nbsp;
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. | &nbsp;
databaseDriverName | The name of the database driver. Example: org.h2.Driver. | &nbsp;
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. | &nbsp;
connectionString | The connection string used to connect to the database. | &nbsp;
databaseUser | The username used when connecting to the database. | &nbsp;
databasePassword | The password used when connecting to the database. | &nbsp;
Deprecated Configuration
====================
The following properties have been deprecated. These can stell 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.
Property | Description | Default Value
---------------------|------------------------------------|------------------
proxyUrl | The Proxy URL. | &nbsp;
proxyPort | The Proxy Port. | &nbsp;
proxyUsername | Defines the proxy user name. | &nbsp;
proxyPassword | Defines the proxy password. | &nbsp;

View File

@@ -10,8 +10,9 @@ Vulnerability Database (NVD) hosted by NIST: https://nvd.nist.gov
After the first batch download, as long as the plugin is executed at least once every After the first batch download, as long as the plugin is executed at least once every
seven days the update will only take a few seconds. seven days the update will only take a few seconds.
Example 1: #set( $H = '#' )
---------------------
$H$H$H Example 1:
Create the DependencyCheck-report.html in the target directory Create the DependencyCheck-report.html in the target directory
```xml ```xml
@@ -39,8 +40,7 @@ Create the DependencyCheck-report.html in the target directory
</project> </project>
``` ```
Example 2: $H$H$H Example 2:
---------------------
Create the DependencyCheck-report.html and fail the build for CVSS greater then 8 Create the DependencyCheck-report.html and fail the build for CVSS greater then 8
```xml ```xml
@@ -71,8 +71,7 @@ Create the DependencyCheck-report.html and fail the build for CVSS greater then
</project> </project>
``` ```
Example 3: $H$H$H Example 3:
---------------------
Create the dependency-check report within the site Create the dependency-check report within the site
```xml ```xml
@@ -103,8 +102,8 @@ Create the dependency-check report within the site
... ...
</project> </project>
``` ```
Example 4:
--------------------- $H$H$H Example 4:
Create the DependencyCheck-report.html and skip artifacts no bundled in distribution (Provided and Runtime scope) Create the DependencyCheck-report.html and skip artifacts no bundled in distribution (Provided and Runtime scope)
```xml ```xml
@@ -135,8 +134,8 @@ Create the DependencyCheck-report.html and skip artifacts no bundled in distribu
... ...
</project> </project>
``` ```
Example 5:
--------------------- $H$H$H Example 5:
Create the DependencyCheck-report.html and use internal mirroring of CVE contents Create the DependencyCheck-report.html and use internal mirroring of CVE contents
```xml ```xml
@@ -169,4 +168,3 @@ Create the DependencyCheck-report.html and use internal mirroring of CVE content
... ...
</project> </project>
``` ```

View File

@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long
<groupId>org.owasp</groupId> <groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId> <artifactId>dependency-check-parent</artifactId>
<version>1.1.2</version> <version>1.1.4</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -50,7 +50,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
title="built with maven" title="built with maven"
alt="built with maven" alt="built with maven"
img="http://jeremylong.github.io/DependencyCheck/images/logos/maven-feather.png"/> img="http://jeremylong.github.io/DependencyCheck/images/logos/maven-feather.png"/>
<logo name="IntelliJ" href="http://maven.apache.org/" <logo name="IntelliJ" href="http://www.jetbrains.com/idea/"
title="developed using" width="170px" title="developed using" width="170px"
alt="developed using" alt="developed using"
img="http://jeremylong.github.io/DependencyCheck/images/logos/logo_intellij_idea.png"/> img="http://jeremylong.github.io/DependencyCheck/images/logos/logo_intellij_idea.png"/>