Compare commits

...

80 Commits

Author SHA1 Message Date
Jeremy Long
cc6f4803b9 updated to version 0.3.2.4
Former-commit-id: 9d6644482abcfb4f69f360fa60cf08370579250c
2013-06-17 20:42:07 -04:00
Jeremy Long
080ccbe7a0 updated logging
Former-commit-id: a7b76150de7f5c2fe68ad648dcb3271380887c1d
2013-06-17 20:40:29 -04:00
Jeremy Long
657891055b added message about BH Arsenal
Former-commit-id: 01821d375cccd0cd9995e16a07cb11687a965dd8
2013-06-17 20:25:40 -04:00
Jeremy Long
ce1c097136 checkstyle correction
Former-commit-id: b04b910c546a0ff7f58ca8cfe1f8a3afd06a4d62
2013-06-16 07:43:54 -04:00
Jeremy Long
f18827614d updated logging
Former-commit-id: 149530418c3807d59c93615e9c5283e4a151576f
2013-06-16 07:24:34 -04:00
Jeremy Long
a49a4ea059 updated logging
Former-commit-id: 457f15cabd21e7fc4bea0b6baaa37234fdeb1176
2013-06-16 06:36:14 -04:00
Jeremy Long
cb50651764 updated logging
Former-commit-id: d1f027c888ef83e8b2b223f3864eedbd730aa8ce
2013-06-15 23:42:45 -04:00
Jeremy Long
5a6a3dc17f fixed null pointer exception
Former-commit-id: be278e1ce8479bb28912bee00eae1f1c1c0bbdf4
2013-06-15 22:40:11 -04:00
Jeremy Long
d179b7bf3f minor updates - still no implementation though
Former-commit-id: 53b5a5ad98e02cf9b18b167205079c489c75a336
2013-06-11 06:23:05 -04:00
Jeremy Long
31e6d1e0c1 updated javadoc
Former-commit-id: d8526a7b902438a83138a677a37c709684c76ed8
2013-06-11 06:20:00 -04:00
Jeremy Long
13c239c9d4 fixed compilation issue due to changes in other classes
Former-commit-id: 171336be7223c6ebf4a416dc55b98407aeb73f19
2013-06-11 06:05:07 -04:00
Jeremy Long
e985ebff3f added a temp directory property
Former-commit-id: 97cdce3ca6be8d599c3805d3316c09512ae38694
2013-06-11 06:03:52 -04:00
Jeremy Long
3d00927033 added a getInt with a default value
Former-commit-id: 61d31f994354bfb5047432424f8d34492023a73b
2013-06-11 06:03:13 -04:00
Jeremy Long
8bdb7e239d minor update to support new analyzer
Former-commit-id: 24224a255ebe67f31041716b3e2ab8b22a9273c0
2013-06-11 06:00:09 -04:00
Jeremy Long
a5b0136897 added netbeans configuration files too
Former-commit-id: 5c0704462790b8b1394532a73f12843d7796742a
2013-06-11 05:58:06 -04:00
Jeremy Long
41ea697483 added throws clause to initialize and close as specified by the interface
Former-commit-id: dca013ac170a09297bc5bbf96ee8fecc9d2baaef
2013-06-07 22:24:01 -04:00
Jeremy Long
fb0f4dd2cf re-arranged code and improved documentation (some)
Former-commit-id: 24b983d81673b2055bef970e04a040c334a716bb
2013-06-07 22:04:35 -04:00
Jeremy Long
8eb373a612 made snapshot
Former-commit-id: 5dd3bf273a5b76342ef03d90affd11d638cc73c7
2013-06-07 22:00:36 -04:00
Jeremy Long
2933526aee v0.3.2.3
Former-commit-id: f1a80ca108a9089e26c716bab8389844faa3e3a4
2013-06-07 15:53:03 -04:00
Jeremy Long
ef2a22b216 v0.3.2.3
Former-commit-id: dc8b892541970156a95a14d11c5eb3c5d610e676
2013-06-07 15:52:24 -04:00
Jeremy Long
d4ab1a56e2 to revert
Former-commit-id: 30a068f5e6a0ef6d5a2cd8c37f4b8b3d616d16b3
2013-06-07 15:51:20 -04:00
Jeremy Long
0e351568f9 next snapshot
Former-commit-id: b1e338bf6ff18bbc55e27ef26aa31d0913cd4d50
2013-06-07 15:47:33 -04:00
Jeremy Long
4eab9d77ae removed deprecated code
Former-commit-id: 07a96fff9c7ba0d0c5a56367937e9653c1717253
2013-06-07 15:46:30 -04:00
Jeremy Long
afeecf9fa9 v0.3.2.3
Former-commit-id: 0b33ececc336e9f060168b8bece28741cf3ea75d
2013-06-07 15:46:17 -04:00
Jeremy Long
27affe8568 checkstyle fix
Former-commit-id: 193f06ad6458fe0aead3703f6019e6dc6ac37aec
2013-06-07 15:46:02 -04:00
Jeremy Long
5015686a8f checkstyle fix
Former-commit-id: 3c9c00f8c03726603f708dd94f135001f29d5f41
2013-06-07 15:45:32 -04:00
Jeremy Long
e72b97289d added vulnerable library count
Former-commit-id: f01ff6a85098e91d9cfb6f83905e939e3cf84815
2013-06-07 15:44:15 -04:00
Jeremy Long
dd497e5ffc added a new vulnerability report
Former-commit-id: f36e328929921e4d278ee8fa5a7370d228bac299
2013-06-07 15:20:38 -04:00
Jeremy Long
f100161f67 added Stupid Table Plugin
Former-commit-id: 96c30d1cc8a175b6662cebbbf8e454ce07bd08df
2013-06-07 15:20:23 -04:00
Jeremy Long
488305def1 version 0.3.2.3-SNAPSHOT
Former-commit-id: 8b26510ff5255afb97bd66a780053e1f1cdf9b33
2013-06-05 00:07:59 -04:00
Jeremy Long
dea5a6937e version 0.3.2.2
Former-commit-id: e90cf514695052e64d4f26e108c3d2e0298b03d6
2013-06-05 00:06:09 -04:00
Jeremy Long
545c324e56 checkstyle fix
Former-commit-id: deb86ab62846aa9f2d63221dca5cfe52bbf244e4
2013-06-05 00:05:46 -04:00
Jeremy Long
535d1e4aff checkstle fixes
Former-commit-id: d7f55af71bca0347b03db5fb9660c3b391619100
2013-06-04 23:47:22 -04:00
Jeremy Long
8debea384f checkstyle fixes
Former-commit-id: c903dc9e96171a07c2d1473d59f53df4a1838128
2013-06-04 23:40:37 -04:00
Jeremy Long
a0b6b66a5f updated javadoc
Former-commit-id: d98e6f3a7be907ea4e15b4e2555f7566fc5c476b
2013-06-04 23:40:11 -04:00
Jeremy Long
37d165d6cb updated javadoc
Former-commit-id: 89eab3c72a4de3c95e5debc38e937166a93ad47d
2013-06-04 23:40:02 -04:00
Jeremy Long
5b6eb13cf6 fixed bug where dependencies would get bundled even if they were different versions
Former-commit-id: 910e26ad24be705750c71738d8518abc5b83e0f3
2013-06-04 23:27:14 -04:00
Jeremy Long
5d68c9f1e1 added equals and hashCode
Former-commit-id: 42b91e996715657069c58a6edbb52588a089c0db
2013-06-04 23:06:02 -04:00
Jeremy Long
faff34a8c6 added filter to add the correct Maven namespace to the POM if it is missing
Former-commit-id: c8e02d730b9c0195fa390b3cced77a4fd4410197
2013-06-04 22:54:28 -04:00
Jeremy Long
c31be72c8a added filter to add the correct Maven namespace to the POM if it is missing
Former-commit-id: 79efc8a8a876831739874914a97ba2d764dd6a7a
2013-06-04 22:54:09 -04:00
Jeremy Long
1f0c13b7cb minor bug fix
Former-commit-id: ec12f812c5170c72f20548b0e00cb5947aacb54d
2013-06-04 05:09:04 -04:00
Jeremy Long
f06f1d1c42 checkstyle fixes (javadoc, final variables, etc)
Former-commit-id: 1f8649c19d845cf3eb80730fb91b33c089e86aae
2013-06-03 20:23:23 -04:00
Jeremy Long
2eca1f9702 added attribute to ignore a findbugs style error
Former-commit-id: 0c34765ce1e4e9825083ed8afb6cbb76e0cc73ec
2013-06-03 20:17:07 -04:00
Jeremy Long
ca6cb8811e findbugs fixes
Former-commit-id: 124207a2cf9022c8e663313da847a76f639cd355
2013-06-03 20:07:39 -04:00
Jeremy Long
ff14d8344f add jsoup to help convert the HTML, specified within nodes in the POM, into text.
Former-commit-id: c6fd21572a01d2cdf457302c9739b54d20e27b05
2013-06-02 21:45:49 -04:00
Jeremy Long
bfb6373742 added code to remove additional false positives
Former-commit-id: 1a15cccd4790fee2044de40843305762cfbefe96
2013-06-02 21:44:20 -04:00
Jeremy Long
e3f401debb added initial version filter - only supporting struts1/2 right now
Former-commit-id: 353a6fec78140b50622b4d267ddf6de34461027c
2013-05-31 22:57:04 -04:00
Jeremy Long
c515afd8eb added another manifest entry to ignore
Former-commit-id: 63a6f3bd3f2d95ac6b101520b3974fc79286ec7b
2013-05-31 22:32:56 -04:00
Jeremy Long
e028641861 added another manifest entry to ignore
Former-commit-id: 7d647e2e298fe142e5230c479b7bd6b51cab5417
2013-05-31 21:52:36 -04:00
Jeremy Long
72f9cb2ab2 fixed javadoc typo
Former-commit-id: 625b8d9958d2cf6123fb583864720d4f5c0c9e01
2013-05-31 21:24:33 -04:00
Jeremy Long
e8694de6fa fixed javadoc typo
Former-commit-id: 5d2f64e0e13f595f08b8e984b422531f8b484321
2013-05-31 21:24:06 -04:00
Jeremy Long
18d38592d4 reduced complexity around determining if the jar contains classes
Former-commit-id: cc42a0c674bc0027c9bd53b250afa9e985b59da0
2013-05-31 20:48:33 -04:00
Jeremy Long
b9767acd02 removed a reported exception for javadoc or sources jar files for not having a manifest
Former-commit-id: 8dbe960af8c2391343d779708672d97a0c530a09
2013-05-31 20:41:23 -04:00
Jeremy Long
c9060da46e minor update to text
Former-commit-id: d413abef8fd16742abb47ef046807233dafc5d16
2013-05-27 22:22:44 -04:00
Jeremy Long
ddbcea7abe v0.3.2.1-SNAPSHOT
Former-commit-id: 9c7996f097e3fad59d99624cddf64b10be4c4524
2013-05-27 22:18:20 -04:00
Jeremy Long
e488767cea 0.3.2.0
Former-commit-id: 8431f1312204c78a829f269954161d7187245493
2013-05-27 22:14:27 -04:00
Jeremy Long
85cacaf91e testing
Former-commit-id: 7fd42dc4c273eff98a8fbc3e3a14f0ce1fd26abe
2013-05-27 22:12:25 -04:00
Jeremy Long
a038bef7fe reset username and blank password
Former-commit-id: 398c0723854c8c43d674d03a6433611c8572cec5
2013-05-27 21:32:05 -04:00
Jeremy Long
539d3cbaba updated H2 version
Former-commit-id: b7193bc7c2e256ebdcabc039d573994daab47415
2013-05-27 20:47:13 -04:00
Jeremy Long
80784a44c5 added compile time support for findbugs suppress warning annotation
Former-commit-id: 83d178ebafafe8ffc1f10b91d7336490c046990b
2013-05-27 20:02:54 -04:00
Jeremy Long
b1a55e2df3 updated javadoc
Former-commit-id: 2818f04997c8fa1c81c8e9bddaea0e9370b76350
2013-05-27 20:01:47 -04:00
Jeremy Long
870d345de8 updated javadoc
Former-commit-id: 3e05f7622618e2dc27fe40cfbdb488303d5c0ec9
2013-05-27 20:01:16 -04:00
Jeremy Long
2b830dccfa added findbugs suppression for a non-issue and made a few checkstyle corrections
Former-commit-id: a4a3c3503eee772c13d567d473f7ed5126941301
2013-05-27 20:00:46 -04:00
Jeremy Long
9f08cf553b added findbugs suppress warning for a false positive
Former-commit-id: c493f8178c129cb73f023b605599dc3dfa558f58
2013-05-27 19:59:16 -04:00
Jeremy Long
7c14017db3 collapsed nested if statements
Former-commit-id: e4d466f50e76659bece83b46f8a111a3d8225353
2013-05-27 19:58:26 -04:00
Jeremy Long
e0e85c468a added supresswarnings for findbugs false positive
Former-commit-id: 7423c03adb41f92e447aba5e58bc415d27c6c957
2013-05-27 19:56:19 -04:00
Jeremy Long
6628fc3c33 updated javadoc
Former-commit-id: 591bec1e2d5a2945a9cca5bf02cd1cea1bd8a38c
2013-05-27 19:55:13 -04:00
Jeremy Long
61a1531e7b checkstyle fixes
Former-commit-id: 5281b8ecb5163ce4a0a6464fea4f6d2a4baffafd
2013-05-27 19:54:41 -04:00
Jeremy Long
933a8f8ec6 reduced size to make tests fasters
Former-commit-id: d8a3b0c2382ae28a519c2cb44fb93205015e82b0
2013-05-27 19:53:14 -04:00
Jeremy Long
f660afc6cb updated javadoc and copyright
Former-commit-id: d48d9e1deed118e9b60d37185cdbfda47898ef6f
2013-05-27 09:14:56 -04:00
Jeremy Long
a5dc79dffe Merge branch 'master' of https://github.com/jeremylong/DependencyCheck
Former-commit-id: 9189529fca392ee1ef0b810528288e243dcdb6e4
2013-05-27 09:07:18 -04:00
Steve Springett
dbc862ad39 Adding more control over data directory path
Former-commit-id: 263475fc5b3aae04f2530ea78a0456deb18686fe
2013-05-27 00:10:08 -07:00
Jeremy Long
e6efe6e610 Applied patch from Steve to change the loading of the H2 db
Former-commit-id: cfce611fadbd2a39880f01d61054dbb8f72f81dc
2013-05-25 10:56:41 -04:00
Steve Springett
9a7fbe44eb Adding more control over data directory path
Former-commit-id: 966544bd738646ba57be087f413f686ecdfcee9c
2013-05-24 23:53:24 -07:00
Steve Springett
adfc913a0e Fixed Velocity logging issues in server environment.
Former-commit-id: 429105274ee0c2e78c3398e3c019feaaa056866d
2013-05-24 16:00:10 -07:00
Steve Springett
8813652f0d Forcing the class loading of the H2 JDBC driver.
Former-commit-id: d6c11d56afc04d115bbf1d0962072c70cb205dd8
2013-05-22 01:11:02 -07:00
Jeremy Long
250444dd25 made outDir final
Former-commit-id: 7987673433e91d54efa138bfafd7fbe1a22ee089
2013-05-20 22:54:35 -04:00
Jeremy Long
a939d0c844 various updates recommended by intelliJ
Former-commit-id: 2909f6b33224c74a2984f94651f6418bf60d88fc
2013-05-20 22:50:21 -04:00
Jeremy Long
577b5ad704 various updates recommended by intelliJ
Former-commit-id: 5ec42c1470384e9acd203819daa7d688ed10e965
2013-05-20 22:17:19 -04:00
Jeremy Long
7476550356 version 0.3.1.1-snapshot
Former-commit-id: 172a258ed0804641d1c6f73cb745330213014ceb
2013-05-20 17:04:03 -04:00
62 changed files with 5502 additions and 681 deletions

4
.gitignore vendored
View File

@@ -6,4 +6,6 @@
.idea/
# Eclipse project files
.classpath
.project
.project
# Netbeans configuration
nb-configuration.xml

View File

@@ -3,11 +3,11 @@ Copyright (c) 2012-2013 Jeremy Long. All Rights Reserved.
The licenses for the software listed below can be found in the META-INF/licenses/[dependency name].
This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).
This product includes software developed by The Apache Software Foundation (http://www.apache.org/).
This product includes software developed by
Jquery.com (http://jquery.com/).
This product includes software developed by Jquery.com (http://jquery.com/).
This product includs software developed by Jonathan Hedley (jsoup.org)
This software contains unmodified binary redistributions for H2 database engine (http://www.h2database.com/), which is dual licensed and available under a modified version of the MPL 1.1 (Mozilla Public License) or under the (unmodified) EPL 1.0 (Eclipse Public License).
An original copy of the license agreement can be found at: http://www.h2database.com/html/license.html

View File

@@ -1,10 +1,15 @@
DependencyCheck
Dependency-Check
=========
DependencyCheck is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries..
Dependency-Check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.
More information can be found on the [wiki].
Notice
-
A very big release of new functionality and plugins will be made available during the BlackHat Arsenal on July 31st, 2013. If you are at BlackHat stop by and see the demos!
Usage
-

39
pom.xml
View File

@@ -22,7 +22,7 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
<groupId>org.owasp</groupId>
<artifactId>dependency-check</artifactId>
<version>0.3.1.1</version>
<version>0.3.2.4</version>
<packaging>jar</packaging>
<name>DependencyCheck</name>
@@ -37,13 +37,22 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
<developer>
<name>Jeremy Long</name>
<email>jeremy.long@owasp.org</email>
<organization>owasp</organization>
<organization>OWASP</organization>
<organizationUrl>https://www.owasp.org/index.php/OWASP_Dependency_Check</organizationUrl>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
</developer>
<developer>
<name>Steve Springett</name>
<email>Steve.Springett@owasp.org</email>
<organization>OWASP</organization>
<organizationUrl>https://www.owasp.org/index.php/OWASP_Dependency_Check</organizationUrl>
<roles>
<role>contributor</role>
</roles>
</developer>
</developers>
<scm>
<connection>scm:git:git@github.com:jeremylong/DependencyCheck.git</connection>
@@ -147,7 +156,6 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
@@ -397,8 +405,13 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>2.0.1</version>
<scope>provided</scope><!-- don't include this in the libs-->
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
@@ -410,10 +423,9 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
<version>2.4</version>
</dependency>
<dependency>
<!-- Using the same as Lucene-->
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
<version>2.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -425,18 +437,17 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.0.0</version>
<!--<version>3.5.0</version>-->
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>4.0.0</version>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>4.0.0</version>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
@@ -490,7 +501,13 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.171</version>
<version>1.3.172</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.7.2</version>
<type>jar</type>
</dependency>
<!-- The following dependencies are only scanned during integration testing -->

View File

@@ -14,6 +14,6 @@
^ \* You should have received a copy of the GNU General Public License along with\s*$
^ \* Dependency-Check\. If not, see http://www.gnu.org/licenses/\.\s*$
^ \*\s*$
^ \* Copyright \(c\) 201[23] Jeremy Long\. All Rights Reserved\.\s*$
^ \* Copyright \(c\) 201[23] (Jeremy Long|Steve Springett)\. All Rights Reserved\.\s*$
^ \*/\s*$
^package

View File

@@ -81,16 +81,16 @@ public class App {
LogManager.getLogManager().reset();
LogManager.getLogManager().readConfiguration(in);
} catch (IOException ex) {
System.err.println(ex.toString());
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(App.class.getName()).log(Level.FINE, "IO Error preparing the logger", ex);
} catch (SecurityException ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(App.class.getName()).log(Level.FINE, "Error preparing the logger", ex);
} finally {
try {
in.close();
} catch (Exception ex) {
//ignore
in = null;
if (in != null) {
try {
in.close();
} catch (Exception ex) {
Logger.getLogger(App.class.getName()).log(Level.FINEST, "Error closing resource stream", ex);
}
}
}
}
@@ -108,12 +108,10 @@ public class App {
} catch (FileNotFoundException ex) {
System.err.println(ex.getMessage());
cli.printHelp();
Logger.getLogger(App.class.getName()).log(Level.WARNING, null, ex);
return;
} catch (ParseException ex) {
System.err.println(ex.getMessage());
cli.printHelp();
Logger.getLogger(App.class.getName()).log(Level.INFO, null, ex);
return;
}
@@ -151,9 +149,11 @@ public class App {
try {
report.generateReports(reportDirectory, outputFormat);
} catch (IOException ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(App.class.getName()).log(Level.SEVERE, "There was an IO error while attempting to generate the report.");
Logger.getLogger(App.class.getName()).log(Level.INFO, null, ex);
} catch (Exception ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(App.class.getName()).log(Level.SEVERE, "There was an error while attempting to generate the report.");
Logger.getLogger(App.class.getName()).log(Level.INFO, null, ex);
}
}

View File

@@ -52,28 +52,28 @@ public class Engine {
/**
* The list of dependencies.
*/
private List<Dependency> dependencies = new ArrayList<Dependency>();
private final List<Dependency> dependencies = new ArrayList<Dependency>();
/**
* A Map of analyzers grouped by Analysis phase.
*/
private EnumMap<AnalysisPhase, List<Analyzer>> analyzers =
private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers =
new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
/**
* A set of extensions supported by the analyzers.
*/
private Set<String> extensions = new HashSet<String>();
private final Set<String> extensions = new HashSet<String>();
/**
* Creates a new Engine.
*/
public Engine() {
boolean autoupdate = true;
boolean autoUpdate = true;
try {
autoupdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
} catch (InvalidSettingException ex) {
Logger.getLogger(Engine.class.getName()).log(Level.WARNING, "Invalid setting for auto-update.");
Logger.getLogger(Engine.class.getName()).log(Level.FINE, "Invalid setting for auto-update; using true.");
}
if (autoupdate) {
if (autoUpdate) {
doUpdates();
}
loadAnalyzers();
@@ -83,8 +83,9 @@ public class Engine {
* Creates a new Engine.
*
* @param autoUpdate indicates whether or not data should be updated from
* the Internet.
* @deprecated this function should no longer be used; the autoupdate flag should be set using
* the Internet
* @deprecated This function should no longer be used;
* the autoupdate flag should be set using:
* <code>Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, value);</code>
*/
@Deprecated
@@ -144,6 +145,18 @@ public class Engine {
*/
public void scan(String path) {
final File file = new File(path);
scan(file);
}
/**
* Scans a given file or directory. If a directory is specified, it will be
* scanned recursively. Any dependencies identified are added to the
* dependency collection.
*
* @since v0.3.2.4
*
* @param file the path to a file or directory to be analyzed.
*/
public void scan(File file) {
if (file.exists()) {
if (file.isDirectory()) {
scanDirectory(file);
@@ -152,7 +165,6 @@ public class Engine {
}
}
}
/**
* Recursively scans files and directories. Any dependencies identified are
* added to the dependency collection.
@@ -161,11 +173,13 @@ public class Engine {
*/
protected void scanDirectory(File dir) {
final File[] files = dir.listFiles();
for (File f : files) {
if (f.isDirectory()) {
scanDirectory(f);
} else {
scanFile(f);
if (files != null) {
for (File f : files) {
if (f.isDirectory()) {
scanDirectory(f);
} else {
scanFile(f);
}
}
}
}
@@ -178,8 +192,9 @@ public class Engine {
*/
protected void scanFile(File file) {
if (!file.isFile()) {
final String msg = String.format("Path passed to scanFile(File) is not a file: %s.", file.toString());
Logger.getLogger(Engine.class.getName()).log(Level.WARNING, msg);
final String msg = String.format("Path passed to scanFile(File) is not a file: %s. Skipping the file.", file.toString());
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
return;
}
final String fileName = file.getName();
final String extension = FileUtils.getFileExtension(fileName);
@@ -206,12 +221,13 @@ public class Engine {
try {
a.initialize();
} catch (Exception ex) {
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE,
"Exception occurred initializing " + a.getName() + ".", 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.INFO, msg, ex);
try {
a.close();
} catch (Exception ex1) {
Logger.getLogger(Engine.class.getName()).log(Level.FINER, null, ex1);
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, null, ex1);
}
}
}
@@ -222,8 +238,10 @@ public class Engine {
final List<Analyzer> analyzerList = analyzers.get(phase);
for (Analyzer a : analyzerList) {
//need to create a copy of the collection because some of the
// analyzers may modify it. This prevents ConcurrentModificationExceptions.
/* need to create a copy of the collection because some of the
* analyzers may modify it. This prevents ConcurrentModificationExceptions.
* This is okay for adds/deletes because it happens per analyzer.
*/
final Set<Dependency> dependencySet = new HashSet<Dependency>();
dependencySet.addAll(dependencies);
for (Dependency d : dependencySet) {
@@ -245,7 +263,7 @@ public class Engine {
try {
a.close();
} catch (Exception ex) {
Logger.getLogger(Engine.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, null, ex);
}
}
}
@@ -264,9 +282,8 @@ public class Engine {
} catch (UpdateException ex) {
Logger.getLogger(Engine.class.getName()).log(Level.WARNING,
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
Logger.getLogger(Engine.class.getName()).log(Level.INFO,
String.format("Unable to update details for %s",
source.getClass().getName()), ex);
Logger.getLogger(Engine.class.getName()).log(Level.FINE,
String.format("Unable to update details for %s", source.getClass().getName()), ex);
}
}
}

View File

@@ -47,15 +47,17 @@ public abstract class AbstractAnalyzer implements Analyzer {
/**
* The initialize method does nothing for this Analyzer.
* @throws Exception thrown if there is an exception
*/
public void initialize() {
public void initialize() throws Exception {
//do nothing
}
/**
* The close method does nothing for this Analyzer.
* @throws Exception thrown if there is an exception
*/
public void close() {
public void close() throws Exception {
//do nothing
}
}

View File

@@ -23,8 +23,12 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.DependencyVersion;
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
/**
* <p>This analyzer ensures dependencies that should be grouped together, to
@@ -39,6 +43,18 @@ import org.owasp.dependencycheck.dependency.Dependency;
*/
public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Analyzer {
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
/**
* A pattern for obtaining the first part of a filename.
*/
private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z]*");
/**
* a flag indicating if this analyzer has run. This analyzer only runs once.
*/
private boolean analyzed = false;
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The set of file extensions supported by this analyzer.
*/
@@ -51,10 +67,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
* The phase that this analyzer is intended to run in.
*/
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() {
@@ -63,7 +77,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
/**
* Returns the name of the analyzer.
*
* @return the name of the analyzer.
*/
public String getName() {
@@ -72,7 +85,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
/**
* 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.
@@ -83,16 +95,12 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
/**
* Returns the phase that the analyzer is intended to run in.
*
* @return the phase that the analyzer is intended to run in.
*/
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
/**
* a flag indicating if this analyzer has run. This analyzer only runs once.
*/
private boolean analyzed = false;
//</editor-fold>
/**
* Analyzes a set of dependencies. If they have been found to have the same
@@ -118,7 +126,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
final Dependency nextDependency = subIterator.next();
if (identifiersMatch(dependency, nextDependency)
&& hasSameBasePath(dependency, nextDependency)) {
&& hasSameBasePath(dependency, nextDependency)
&& fileNameMatch(dependency, nextDependency)) {
if (isCore(dependency, nextDependency)) {
dependency.addRelatedDependency(nextDependency);
@@ -155,7 +164,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
/**
* Attempts to trim a maven repo to a common base path. This is typically
* [drive]\[repolocation\repository\[path1]\[path2].
* [drive]\[repo_location]\repository\[path1]\[path2].
*
* @param path the path to trim
* @return a string representing the base path.
@@ -179,6 +188,38 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
return path.substring(0, pos);
}
/**
* Returns true if the file names (and version if it exists) of the two
* dependencies are sufficiently similiar.
* @param dependency1 a dependency2 to compare
* @param dependency2 a dependency2 to compare
* @return true if the identifiers in the two supplied dependencies are equal
*/
private boolean fileNameMatch(Dependency dependency1, Dependency dependency2) {
if (dependency1 == null || dependency1.getFileName() == null
|| dependency2 == null || dependency2.getFileName() == null) {
return false;
}
final String fileName1 = dependency1.getFileName();
final String fileName2 = dependency2.getFileName();
//version check
final DependencyVersion version1 = DependencyVersionUtil.parseVersionFromFileName(fileName1);
final DependencyVersion version2 = DependencyVersionUtil.parseVersionFromFileName(fileName2);
if (version1 != null && version2 != null) {
if (!version1.equals(version2)) {
return false;
}
}
//filename check
final Matcher match1 = STARTING_TEXT_PATTERN.matcher(fileName1);
final Matcher match2 = STARTING_TEXT_PATTERN.matcher(fileName2);
if (match1.find() && match2.find()) {
return match1.group().equals(match2.group());
}
return false;
}
/**
* Returns true if the identifiers in the two supplied dependencies are equal.
* @param dependency1 a dependency2 to compare

View File

@@ -41,6 +41,7 @@ import org.owasp.dependencycheck.utils.Settings;
*/
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The set of file extensions supported by this analyzer.
*/
@@ -56,7 +57,6 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
/**
* Returns a list of file EXTENSIONS supported by this analyzer.
*
* @return a list of file EXTENSIONS supported by this analyzer.
*/
public Set<String> getSupportedExtensions() {
@@ -65,7 +65,6 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
/**
* Returns the name of the analyzer.
*
* @return the name of the analyzer.
*/
public String getName() {
@@ -74,27 +73,26 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
/**
* 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; //EXTENSIONS.contains(extension);
return true;
}
/**
* Returns the phase that the analyzer is intended to run in.
*
* @return the phase that the analyzer is intended to run in.
*/
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
//</editor-fold>
/**
*
*
* Analyzes the dependencies and removes bad/incorrect CPE associations
* based on various heuristics.
* @param dependency the dependency to analyze.
* @param engine the engine that is scanning the dependencies
* @throws AnalysisException is thrown if there is an error reading the JAR
@@ -102,11 +100,12 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
*/
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
removeJreEntries(dependency);
removeBadMatches(dependency);
boolean deepScan = false;
try {
deepScan = Settings.getBoolean(Settings.KEYS.PERFORM_DEEP_SCAN);
} catch (InvalidSettingException ex) {
Logger.getLogger(FalsePositiveAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(FalsePositiveAnalyzer.class.getName()).log(Level.INFO, "deepscan setting is incorrect; expected a boolean.", ex);
}
if (!deepScan) {
removeSpuriousCPE(dependency);
@@ -182,7 +181,10 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
final Iterator<Identifier> itr = identifiers.iterator();
while (itr.hasNext()) {
final Identifier i = itr.next();
if ((i.getValue().startsWith("cpe:/a:sun:java:")
|| i.getValue().startsWith("cpe:/a:sun:java_se")
|| i.getValue().startsWith("cpe:/a:oracle:java_se")
|| i.getValue().startsWith("cpe:/a:oracle:jre")
|| i.getValue().startsWith("cpe:/a:oracle:jdk"))
&& !dependency.getFileName().toLowerCase().endsWith("rt.jar")) {
@@ -210,4 +212,23 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
}
return cpe;
}
/**
* Removes bad CPE matches for a dependency. Unfortunately, right now
* these are hard-coded patches for specific problems identified when
* testing this ona LARGE volume of jar files.
* @param dependency the dependency to analyze
*/
private void removeBadMatches(Dependency dependency) {
final Set<Identifier> identifiers = dependency.getIdentifiers();
final Iterator<Identifier> itr = identifiers.iterator();
while (itr.hasNext()) {
final Identifier i = itr.next();
//TODO move this startswith expression to a configuration file?
if (i.getValue().startsWith("cpe:/a:apache:xerces-c++:")
&& dependency.getFileName().toLowerCase().endsWith(".jar")) {
itr.remove();
}
}
}
}

View File

@@ -31,6 +31,7 @@ import org.owasp.dependencycheck.Engine;
*/
public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The name of the analyzer.
*/
@@ -46,7 +47,6 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* Returns a list of file EXTENSIONS supported by this analyzer.
*
* @return a list of file EXTENSIONS supported by this analyzer.
*/
public Set<String> getSupportedExtensions() {
@@ -55,7 +55,6 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* Returns the name of the analyzer.
*
* @return the name of the analyzer.
*/
public String getName() {
@@ -64,7 +63,6 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements 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.
@@ -75,12 +73,12 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* Returns the phase that the analyzer is intended to run in.
*
* @return the phase that the analyzer is intended to run in.
*/
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
//</editor-fold>
/**
* Collects information about the file name.

View File

@@ -29,6 +29,7 @@ import org.owasp.dependencycheck.dependency.Evidence;
*/
public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The name of the analyzer.
*/
@@ -41,10 +42,8 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
* 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() {
@@ -53,7 +52,6 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* Returns the name of the analyzer.
*
* @return the name of the analyzer.
*/
public String getName() {
@@ -62,7 +60,6 @@ public class HintAnalyzer extends AbstractAnalyzer implements 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.
@@ -73,12 +70,12 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* Returns the phase that the analyzer is intended to run in.
*
* @return the phase that the analyzer is intended to run in.
*/
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
//</editor-fold>
/**
* The HintAnalyzer uses knowledge about a dependency to add additional information

View File

@@ -19,11 +19,11 @@
package org.owasp.dependencycheck.analyzer;
import java.io.File;
import java.io.FileInputStream;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.ParserConfigurationException;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
@@ -39,19 +39,28 @@ import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import org.jsoup.Jsoup;
import org.owasp.dependencycheck.analyzer.pom.MavenNamespaceFilter;
import org.owasp.dependencycheck.analyzer.pom.generated.License;
import org.owasp.dependencycheck.analyzer.pom.generated.Model;
import org.owasp.dependencycheck.analyzer.pom.generated.Organization;
import org.owasp.dependencycheck.utils.NonClosingStream;
import org.owasp.dependencycheck.utils.Settings;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;
/**
*
@@ -62,18 +71,11 @@ import org.owasp.dependencycheck.utils.Settings;
*/
public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
/**
* The system independent newline character.
*/
private static final String NEWLINE = System.getProperty("line.separator");
/**
* The name of the analyzer.
*/
private static final String ANALYZER_NAME = "Jar Analyzer";
/**
* The phase that this analyzer is intended to run in.
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
/**
* A list of elements in the manifest to ignore.
*/
@@ -99,11 +101,9 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
"class-path",
"tool",
"bundle-manifestversion",
"bundlemanifestversion");
/**
* The set of file extensions supported by this analyzer.
*/
private static final Set<String> EXTENSIONS = newHashSet("jar");
"bundlemanifestversion",
"include-resource");
/**
* item in some manifest, should be considered medium confidence.
*/
@@ -120,10 +120,15 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
* item in some manifest, should be considered medium confidence.
*/
private static final String BUNDLE_VENDOR = "Bundle-Vendor"; //: Apache Software Foundation
/**
* A pattern to detect HTML within text.
*/
private static final Pattern HTML_DETECTION_PATTERN = Pattern.compile("\\<[a-z]+.*/?\\>", Pattern.CASE_INSENSITIVE);
/**
* The unmarshaller used to parse the pom.xml from a JAR file.
*/
private Unmarshaller pomUnmarshaller;
//</editor-fold>
/**
* Constructs a new JarAnalyzer.
@@ -133,31 +138,40 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.analyzer.pom.generated");
pomUnmarshaller = jaxbContext.createUnmarshaller();
} catch (JAXBException ex) { //guess we will just have a null pointer exception later...
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE, "Unable to load parser. See the log for more details.");
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex);
}
}
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The name of the analyzer.
*/
private static final String ANALYZER_NAME = "Jar Analyzer";
/**
* The phase that this analyzer is intended to run in.
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
/**
* The set of file extensions supported by this analyzer.
*/
private static final Set<String> EXTENSIONS = newHashSet("jar");
/**
* 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.
*
* @return the name of the analyzer.
*/
public String getName() {
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.
@@ -165,7 +179,6 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
public boolean supportsExtension(String extension) {
return EXTENSIONS.contains(extension);
}
/**
* Returns the phase that the analyzer is intended to run in.
*
@@ -174,6 +187,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
//</editor-fold>
/**
* Loads a specified JAR file and collects information from the manifest and
@@ -214,154 +228,229 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
* the strings contained within the pom.properties if one exists.
*
* @param dependency the dependency being analyzed.
* @throws IOException is thrown if there is an error reading the zip file.
* @throws AnalysisException is thrown if there is an exception parsing the
* pom.
* @throws AnalysisException is thrown if there is an exception parsing the pom.
* @return whether or not evidence was added to the dependency
*/
protected boolean analyzePOM(Dependency dependency) throws IOException, AnalysisException {
protected boolean analyzePOM(Dependency dependency) throws AnalysisException {
boolean foundSomething = false;
Properties pomProperties = null;
final List<Model> poms = new ArrayList<Model>();
FileInputStream fs = null;
final JarFile jar;
try {
fs = new FileInputStream(dependency.getActualFilePath());
final ZipInputStream zin = new ZipInputStream(fs);
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
final String entryName = (new File(entry.getName())).getName().toLowerCase();
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
final NonClosingStream stream = new NonClosingStream(zin);
Model p = null;
try {
final JAXBElement obj = (JAXBElement) pomUnmarshaller.unmarshal(stream);
p = (Model) obj.getValue();
} catch (JAXBException ex) {
final String msg = String.format("Unable to parse POM '%s' in '%s'",
entry.getName(), dependency.getFilePath());
final AnalysisException ax = new AnalysisException(msg, ex);
dependency.getAnalysisExceptions().add(ax);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.INFO, msg);
}
if (p != null) {
poms.add(p);
}
zin.closeEntry();
} else if (!entry.isDirectory() && "pom.properties".equals(entryName)) {
//TODO what if there is more then one pom.properties?
// need to find the POM, then look to see if there is a sibling
// pom.properties and use those together.
if (pomProperties == null) {
Reader reader;
try {
reader = new InputStreamReader(zin, "UTF-8");
pomProperties = new Properties();
pomProperties.load(reader);
} finally {
//zin.closeEntry closes the reader
//reader.close();
zin.closeEntry();
}
} else {
final String msg = "JAR file contains multiple pom.properties files - unable to process POM";
final AnalysisException ax = new AnalysisException(msg);
dependency.getAnalysisExceptions().add(ax);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.INFO, msg);
}
}
entry = zin.getNextEntry();
}
jar = new JarFile(dependency.getActualFilePath());
} catch (IOException ex) {
throw new AnalysisException("Error reading JAR file as zip.", ex);
} finally {
if (fs != null) {
fs.close();
}
final String msg = String.format("Unable to read JarFile '%s'.", dependency.getActualFilePath());
final AnalysisException ax = new AnalysisException(msg, ex);
dependency.getAnalysisExceptions().add(ax);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex);
return foundSomething;
}
List<String> pomEntries;
try {
pomEntries = retrievePomListing(jar);
} catch (IOException ex) {
final String msg = String.format("Unable to read Jar file entries in '%s'.", dependency.getActualFilePath());
final AnalysisException ax = new AnalysisException(msg, ex);
dependency.getAnalysisExceptions().add(ax);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.INFO, msg, ex);
return foundSomething;
}
for (Model pom : poms) {
//group id
final String groupid = interpolateString(pom.getGroupId(), pomProperties);
if (groupid != null) {
foundSomething = true;
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Evidence.Confidence.HIGH);
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Evidence.Confidence.LOW);
for (String path : pomEntries) {
Properties pomProperties = null;
try {
pomProperties = retrievePomProperties(path, jar);
} catch (IOException ex) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINEST, "ignore this, failed reading a non-existent pom.properties", ex);
}
//artifact id
final String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
if (artifactid != null) {
foundSomething = true;
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Evidence.Confidence.HIGH);
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Evidence.Confidence.LOW);
Model pom = null;
try {
pom = retrievePom(path, jar);
} catch (JAXBException ex) {
final String msg = String.format("Unable to parse POM '%s' in '%s'",
path, dependency.getFilePath());
final AnalysisException ax = new AnalysisException(msg, ex);
dependency.getAnalysisExceptions().add(ax);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ax);
} catch (IOException ex) {
final String msg = String.format("Unable to retrieve POM '%s' in '%s'",
path, dependency.getFilePath());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ex);
}
//version
final String version = interpolateString(pom.getVersion(), pomProperties);
if (version != null) {
foundSomething = true;
dependency.getVersionEvidence().addEvidence("pom", "version", version, Evidence.Confidence.HIGH);
foundSomething = setPomEvidence(dependency, pom, pomProperties) || foundSomething;
}
return foundSomething;
}
/**
* Given a path to a pom.xml within a JarFile, this method attempts to load
* a sibling pom.properties if one exists.
* @param path the path to the pom.xml within the JarFile
* @param jar the JarFile to load the pom.properties from
* @return a Properties object or null if no pom.properties was found
* @throws IOException thrown if there is an exception reading the pom.properties
*/
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "OS_OPEN_STREAM",
justification = "The reader is closed by closing the zipEntry")
private Properties retrievePomProperties(String path, final JarFile jar) throws IOException {
Properties pomProperties = null;
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
final ZipEntry propEntry = jar.getEntry(propPath);
if (propEntry != null) {
final Reader reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
pomProperties = new Properties();
pomProperties.load(reader);
}
return pomProperties;
}
/**
* Searches a JarFile for pom.xml entries and returns a listing of these entries.
* @param jar the JarFile to search
* @return a list of pom.xml entries
* @throws IOException thrown if there is an exception reading a JarEntry
*/
private List<String> retrievePomListing(final JarFile jar) throws IOException {
final List<String> pomEntries = new ArrayList<String>();
final Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
final JarEntry entry = entries.nextElement();
final String entryName = (new File(entry.getName())).getName().toLowerCase();
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
pomEntries.add(entry.getName());
}
}
return pomEntries;
}
/**
* Retrieves the specified POM from a jar file and converts it to a Model.
* @param path the path to the pom.xml file within the jar file
* @param jar the jar file to extract the pom from
* @return returns a {@link org.owasp.dependencycheck.analyzer.pom.generated.Model} object
* @throws JAXBException is thrown if there is an exception parsing the pom
* @throws IOException is thrown if there is an exception reading the jar
*/
private Model retrievePom(String path, JarFile jar) throws JAXBException, IOException {
final ZipEntry entry = jar.getEntry(path);
if (entry != null) { //should never be null
Model m = null;
try {
final XMLFilter filter = new MavenNamespaceFilter();
final SAXParserFactory spf = SAXParserFactory.newInstance();
final SAXParser sp = spf.newSAXParser();
final XMLReader xr = sp.getXMLReader();
filter.setParent(xr);
final NonClosingStream stream = new NonClosingStream(jar.getInputStream(entry));
final InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
final InputSource xml = new InputSource(reader);
final SAXSource source = new SAXSource(filter, xml);
final JAXBElement<Model> el = pomUnmarshaller.unmarshal(source, Model.class);
m = el.getValue();
} catch (ParserConfigurationException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s'", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ex);
} catch (SAXException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s'", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ex);
}
// org name
final Organization org = pom.getOrganization();
if (org != null && org.getName() != null) {
foundSomething = true;
final String orgName = interpolateString(org.getName(), pomProperties);
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Evidence.Confidence.HIGH);
}
//pom name
final String pomName = interpolateString(pom.getName(), pomProperties);
if (pomName != null) {
foundSomething = true;
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Evidence.Confidence.HIGH);
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Evidence.Confidence.HIGH);
return m;
}
return null;
}
/**
* Sets evidence from the pom on the supplied dependency.
* @param dependency the dependency to set data on
* @param pom the information from the pom
* @param pomProperties the pom properties file (null if none exists)
* @return true if there was evidence within the pom that we could use; otherwise false
*/
private boolean setPomEvidence(Dependency dependency, Model pom, Properties pomProperties) {
boolean foundSomething = false;
if (pom == null) {
return foundSomething;
}
//group id
final String groupid = interpolateString(pom.getGroupId(), pomProperties);
if (groupid != null) {
foundSomething = true;
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Evidence.Confidence.HIGH);
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Evidence.Confidence.LOW);
}
//artifact id
final String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
if (artifactid != null) {
foundSomething = true;
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Evidence.Confidence.HIGH);
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Evidence.Confidence.LOW);
}
//version
final String version = interpolateString(pom.getVersion(), pomProperties);
if (version != null) {
foundSomething = true;
dependency.getVersionEvidence().addEvidence("pom", "version", version, Evidence.Confidence.HIGH);
}
// org name
final Organization org = pom.getOrganization();
if (org != null && org.getName() != null) {
foundSomething = true;
final String orgName = interpolateString(org.getName(), pomProperties);
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Evidence.Confidence.HIGH);
}
//pom name
final String pomName = interpolateString(pom.getName(), pomProperties);
if (pomName != null) {
foundSomething = true;
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Evidence.Confidence.HIGH);
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Evidence.Confidence.HIGH);
}
//Description
if (pom.getDescription() != null) {
foundSomething = true;
String description = interpolateString(pom.getDescription(), pomProperties);
if (HTML_DETECTION_PATTERN.matcher(description).find()) {
description = Jsoup.parse(description).text();
}
//Description
if (pom.getDescription() != null) {
foundSomething = true;
final String description = interpolateString(pom.getDescription(), pomProperties);
dependency.setDescription(description);
dependency.getProductEvidence().addEvidence("pom", "description", description, Evidence.Confidence.MEDIUM);
dependency.getVendorEvidence().addEvidence("pom", "description", description, Evidence.Confidence.MEDIUM);
}
dependency.setDescription(description);
dependency.getProductEvidence().addEvidence("pom", "description", description, Evidence.Confidence.MEDIUM);
dependency.getVendorEvidence().addEvidence("pom", "description", description, Evidence.Confidence.MEDIUM);
}
//license
if (pom.getLicenses() != null) {
String license = null;
for (License lic : pom.getLicenses().getLicense()) {
String tmp = null;
if (lic.getName() != null) {
tmp = interpolateString(lic.getName(), pomProperties);
}
if (lic.getUrl() != null) {
if (tmp == null) {
tmp = interpolateString(lic.getUrl(), pomProperties);
} else {
tmp += ": " + interpolateString(lic.getUrl(), pomProperties);
}
}
//license
if (pom.getLicenses() != null) {
String license = null;
for (License lic : pom.getLicenses().getLicense()) {
String tmp = null;
if (lic.getName() != null) {
tmp = interpolateString(lic.getName(), pomProperties);
}
if (lic.getUrl() != null) {
if (tmp == null) {
continue;
}
if (license == null) {
license = tmp;
tmp = interpolateString(lic.getUrl(), pomProperties);
} else {
license += "\n" + tmp;
tmp += ": " + interpolateString(lic.getUrl(), pomProperties);
}
}
if (license != null) {
dependency.setLicense(license);
if (tmp == null) {
continue;
}
if (HTML_DETECTION_PATTERN.matcher(tmp).find()) {
tmp = Jsoup.parse(tmp).text();
}
if (license == null) {
license = tmp;
} else {
license += "\n" + tmp;
}
}
if (license != null) {
dependency.setLicense(license);
}
}
return foundSomething;
}
/**
* Tracks whether the jar being analyzed contains classes.
*/
private boolean hasClasses = false;
/**
* Analyzes the path information of the classes contained within the
@@ -377,7 +466,6 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
*/
protected boolean analyzePackageNames(Dependency dependency, boolean addPackagesAsEvidence)
throws IOException {
hasClasses = false;
JarFile jar = null;
try {
jar = new JarFile(dependency.getActualFilePath());
@@ -389,7 +477,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
final int count = collectPackageNameInformation(en, level0, level1, level2, level3);
if (count == 0) {
return hasClasses;
return false;
}
final EvidenceCollection vendor = dependency.getVendorEvidence();
final EvidenceCollection product = dependency.getProductEvidence();
@@ -488,7 +576,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
jar.close();
}
}
return hasClasses;
return true;
}
/**
@@ -511,9 +599,15 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
final Manifest manifest = jar.getManifest();
if (manifest == null) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE,
String.format("Jar file '%s' does not contain a manifest.",
dependency.getFileName()));
//don't log this for javadoc or sources jar files
if (!dependency.getFileName().toLowerCase().endsWith("-sources.jar")
&& !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
&& !dependency.getFileName().toLowerCase().endsWith("-src.jar")
&& !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.INFO,
String.format("Jar file '%s' does not contain a manifest.",
dependency.getFileName()));
}
return false;
}
final Attributes atts = manifest.getMainAttributes();
@@ -526,7 +620,10 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
for (Entry<Object, Object> entry : atts.entrySet()) {
String key = entry.getKey().toString();
final String value = atts.getValue(key);
String value = atts.getValue(key);
if (HTML_DETECTION_PATTERN.matcher(value).find()) {
value = Jsoup.parse(value).text();
}
if (key.equals(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
foundSomething = true;
productEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH);
@@ -563,6 +660,8 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
&& !key.endsWith("jdk")
&& !key.contains("lastmodified")
&& !key.endsWith("package")
&& !key.endsWith("classpath")
&& !key.endsWith("class-path")
&& !isImportPackage(key, value)) {
foundSomething = true;
@@ -715,10 +814,9 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
HashMap<String, Integer> level1, HashMap<String, Integer> level2, HashMap<String, Integer> level3) {
int count = 0;
while (en.hasMoreElements()) {
final java.util.jar.JarEntry entry = (java.util.jar.JarEntry) en.nextElement();
final JarEntry entry = (JarEntry) en.nextElement();
if (entry.getName().endsWith(".class")) {
hasClasses = true;
String[] path = null;
String[] path;
if (entry.getName().contains("/")) {
path = entry.getName().toLowerCase().split("/");
if ("java".equals(path[0])

View File

@@ -32,10 +32,7 @@ import java.util.regex.Pattern;
*/
public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* The system independent newline character.
*/
private static final String NEWLINE = System.getProperty("line.separator");
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The name of the analyzer.
*/
@@ -86,6 +83,7 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
//</editor-fold>
/**
* Loads a specified JAR file and collects information from the manifest and
@@ -101,32 +99,23 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
}
/**
* Adds license information to the given dependency.
*
* @param d the dependency
* @param license the license
*/
private void addLicense(Dependency d, String license) {
if (d.getLicense() == null) {
d.setLicense(license);
} else if (!d.getLicense().contains(license)) {
d.setLicense(d.getLicense() + NEWLINE + license);
}
}
/**
* The initialize method does nothing for this Analyzer.
*
* @throws Exception thrown if there is an exception
*/
public void initialize() {
@Override
public void initialize() throws Exception {
//do nothing
}
/**
* The close method does nothing for this Analyzer.
*
* @throws Exception thrown if there is an exception
*/
public void close() {
@Override
public void close() throws Exception {
//do nothing
}
}

View File

@@ -1,165 +0,0 @@
/*
* This file is part of Dependency-Check.
*
* Dependency-Check is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Dependency-Check is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* Dependency-Check. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
/**
* This analyzer ensures that the Spring Framework Core CPE identifiers are only associated
* with the "core" jar files. If there are other Spring JARs, such as spring-beans, and
* spring-core is in the scanned dependencies then only the spring-core will have a reference
* to the CPE values (if there are any for the version of spring being used).
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @deprecated This class has been deprecated as it has been replaced by the BundlingAnalyzer
*/
@Deprecated
public class SpringCleaningAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* The set of file extensions supported by this analyzer.
*/
private static final Set<String> EXTENSIONS = newHashSet("jar");
/**
* The name of the analyzer.
*/
private static final String ANALYZER_NAME = "Jar Analyzer";
/**
* The phase that this analyzer is intended to run in.
*/
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.
*
* @return the name of the analyzer.
*/
public String getName() {
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.
*
* @return the phase that the analyzer is intended to run in.
*/
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
/**
* a list of spring versions.
*/
private List<Identifier> springVersions;
/**
* Determines if several "spring" libraries were scanned and trims the
* cpe:/a:springsource:spring_framework:[version] from the none "core" framework
* if the core framework was part of the scan.
*
* @param dependency the dependency to analyze.
* @param engine the engine that is scanning the dependencies
* @throws AnalysisException is thrown if there is an error reading the JAR
* file.
*/
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
collectSpringFrameworkIdentifiers(engine);
final List<Identifier> identifiersToRemove = new ArrayList<Identifier>();
for (Identifier identifier : dependency.getIdentifiers()) {
if (springVersions.contains(identifier) && !isCoreFramework(dependency.getFileName())) {
identifiersToRemove.add(identifier);
}
}
for (Identifier i : identifiersToRemove) {
dependency.getIdentifiers().remove(i);
}
}
/**
* Cycles through the dependencies and creates a collection of the spring identifiers.
*
* @param engine the core engine.
*/
private void collectSpringFrameworkIdentifiers(Engine engine) {
//check to see if any of the libs are the core framework
if (springVersions == null) {
springVersions = new ArrayList<Identifier>();
for (Dependency d : engine.getDependencies()) {
if (supportsExtension(d.getFileExtension())) {
for (Identifier i : d.getIdentifiers()) {
if (isSpringFrameworkCpe(i)) {
if (isCoreFramework(d.getFileName())) {
springVersions.add(i);
}
}
}
}
}
}
}
/**
* Attempts to determine if the identifier is for the spring framework.
*
* @param identifier an identifier
* @return whether or not it is believed to be a spring identifier
*/
private boolean isSpringFrameworkCpe(Identifier identifier) {
return "cpe".equals(identifier.getType())
&& (identifier.getValue().startsWith("cpe:/a:springsource:spring_framework:")
|| identifier.getValue().startsWith("cpe:/a:vmware:springsource_spring_framework"));
}
/**
* Attempts to determine if the file name passed in is for the core spring-framework.
*
* @param filename a file name
* @return whether or not it is believed the file name is for the core spring framework
*/
private boolean isCoreFramework(String filename) {
return filename.toLowerCase().matches("^spring([ _-]?core)?[ _-]?\\d.*");
}
}

View File

@@ -1,13 +1,11 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.scanner</title>
* <title>org.owasp.dependencycheck.analyzer</title>
* </head>
* <body>
* The scanner package contains the utilities to scan files and directories for
* dependencies. Analyzers are used to inspect the identified dependencies and
* collect Evidence. This evidence is then used to determine if the dependency
* has a known CPE.
* Analyzers are used to inspect the identified dependencies, collect Evidence,
* and process the dependencies.
* </body>
* </html>
*/

View File

@@ -0,0 +1,93 @@
/*
* This file is part of Dependency-Check.
*
* Dependency-Check is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Dependency-Check is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* Dependency-Check. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer.pom;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
/**
* This filter is used when parsing POM documents. Some POM documents
* do not specify the xmlns="http://maven.apache.org/POM/4.0.0". This
* filter ensures that the correct namespace is added so that both
* types of POMs can be read.
* @author Jeremy Long (jeremy.long@gmail.com)
*/
public class MavenNamespaceFilter extends XMLFilterImpl {
/**
* The namespace to add for Maven POMs.
*/
private static final String NAMESPACE = "http://maven.apache.org/POM/4.0.0";
/**
* A flag indicating whether or not the namespace (prefix) has been added.
*/
private boolean namespaceAdded = false;
/**
* Called at the start of the document parsing.
* @throws SAXException thrown if there is a SAXException
*/
@Override
public void startDocument() throws SAXException {
super.startDocument();
startPrefixMapping("", NAMESPACE);
}
/**
* Called when an element is started.
* @param uri the uri
* @param localName the localName
* @param qName the qualified name
* @param atts the attributes
* @throws SAXException thrown if there is a SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
super.startElement(NAMESPACE, localName, qName, atts);
}
/**
* Indicatees the start of the document.
* @param uri the uri
* @param localName the localName
* @param qName the qualified name
* @throws SAXException thrown if there is a SAXException
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(NAMESPACE, localName, qName);
}
/**
* Called when prefix mapping is started.
* @param prefix the prefix
* @param url the url
* @throws SAXException thrown if there is a SAXException
*/
@Override
public void startPrefixMapping(String prefix, String url) throws SAXException {
if (!this.namespaceAdded) {
namespaceAdded = true;
super.startPrefixMapping("", NAMESPACE);
}
}
}

View File

@@ -0,0 +1,12 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.analyzer.pom</title>
* </head>
* <body>
* This package contains utility classes used to parse pom.xml files.
* </body>
* </html>
*/
package org.owasp.dependencycheck.analyzer.pom;

View File

@@ -49,7 +49,7 @@ public class Entry implements Serializable {
try {
entry.parseName(doc.get(Fields.NAME));
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(Entry.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(Entry.class.getName()).log(Level.FINE, null, ex);
entry.name = doc.get(Fields.NAME);
}
return entry;
@@ -228,10 +228,7 @@ public class Entry implements Serializable {
return false;
}
final Entry other = (Entry) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
return true;
return !((this.name == null) ? (other.name != null) : !this.name.equals(other.name));
}
@Override

View File

@@ -20,7 +20,6 @@ package org.owasp.dependencycheck.data.cpe;
import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
@@ -37,6 +36,7 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.owasp.dependencycheck.data.lucene.AbstractIndex;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.data.lucene.FieldAnalyzer;
import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer;
@@ -58,8 +58,7 @@ public class Index extends AbstractIndex {
*/
public Directory getDirectory() throws IOException {
final File path = getDataDirectory();
final Directory dir = FSDirectory.open(path);
return dir;
return FSDirectory.open(path);
}
/**
@@ -71,20 +70,9 @@ public class Index extends AbstractIndex {
*/
public File getDataDirectory() throws IOException {
final String fileName = Settings.getString(Settings.KEYS.CPE_INDEX);
final String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath();
final String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File(".");
}
File path = new File(exePath.getCanonicalFile() + File.separator + fileName);
path = new File(path.getCanonicalPath());
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create CPE Data directory");
}
final File path = FileUtils.getDataDirectory(fileName, Index.class);
if (!path.exists() && !path.mkdirs()) {
throw new IOException("Unable to create CPE Data directory");
}
return path;
}
@@ -102,10 +90,7 @@ public class Index extends AbstractIndex {
fieldAnalyzers.put(Fields.VERSION, new VersionAnalyzer(Version.LUCENE_40));
fieldAnalyzers.put(Fields.NAME, new KeywordAnalyzer());
final PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(
new FieldAnalyzer(Version.LUCENE_40), fieldAnalyzers);
return wrapper;
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(Version.LUCENE_40), fieldAnalyzers);
}
/**
* The search field analyzer for the product field.
@@ -133,10 +118,7 @@ public class Index extends AbstractIndex {
fieldAnalyzers.put(Fields.PRODUCT, productSearchFieldAnalyzer);
fieldAnalyzers.put(Fields.VENDOR, vendorSearchFieldAnalyzer);
final PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(
new FieldAnalyzer(Version.LUCENE_40), fieldAnalyzers);
return wrapper;
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(Version.LUCENE_40), fieldAnalyzers);
}
/**
@@ -169,7 +151,6 @@ public class Index extends AbstractIndex {
*/
public void saveEntry(Entry entry) throws CorruptIndexException, IOException {
final Document doc = convertEntryToDoc(entry);
//Term term = new Term(Fields.NVDID, LuceneUtils.escapeLuceneQuery(entry.getNvdId()));
final Term term = new Term(Fields.NAME, entry.getName());
getIndexWriter().updateDocument(term, doc);
}
@@ -196,7 +177,7 @@ public class Index extends AbstractIndex {
//TODO revision should likely be its own field
if (entry.getVersion() != null) {
Field version = null;
Field version;
if (entry.getRevision() != null) {
version = new TextField(Fields.VERSION, entry.getVersion() + " "
+ entry.getRevision(), Field.Store.NO);

View File

@@ -53,19 +53,19 @@ public final class CweDB {
final String filePath = "data/cwe.hashmap.serialized";
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
oin = new ObjectInputStream(input);
@SuppressWarnings("unchecked")
final HashMap<String, String> data = (HashMap<String, String>) oin.readObject();
return data;
return (HashMap<String, String>) oin.readObject();
} catch (ClassNotFoundException ex) {
Logger.getLogger(CweDB.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(CweDB.class.getName()).log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
Logger.getLogger(CweDB.class.getName()).log(Level.FINE, null, ex);
} catch (IOException ex) {
Logger.getLogger(CweDB.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(CweDB.class.getName()).log(Level.WARNING, "Unable to load CWE data due to an IO Error. This should not be an issue.");
Logger.getLogger(CweDB.class.getName()).log(Level.FINE, null, ex);
} finally {
if (oin != null) {
try {
oin.close();
} catch (IOException ex) {
Logger.getLogger(CweDB.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(CweDB.class.getName()).log(Level.FINEST, null, ex);
}
}
}

View File

@@ -33,7 +33,7 @@ public class CweHandler extends DefaultHandler {
/**
* a HashMap containing the CWE data.
*/
private HashMap<String, String> cwe = new HashMap<String, String>();
private final HashMap<String, String> cwe = new HashMap<String, String>();
/**
* Returns the HashMap of CWE entries (CWE-ID, Full CWE Name).

View File

@@ -98,16 +98,24 @@ public abstract class AbstractIndex {
try {
indexWriter.commit();
} catch (CorruptIndexException ex) {
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "Unable to update database, there is a corrupt index.";
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(AbstractIndex.class.getName()).log(Level.FINE, null, ex);
} catch (IOException ex) {
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "Unable to update database due to an IO error.";
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(AbstractIndex.class.getName()).log(Level.FINE, null, ex);
}
try {
indexWriter.close(true);
} catch (CorruptIndexException ex) {
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "Unable to update database, there is a corrupt index.";
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(AbstractIndex.class.getName()).log(Level.FINE, null, ex);
} catch (IOException ex) {
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "Unable to update database due to an IO error.";
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(AbstractIndex.class.getName()).log(Level.FINE, null, ex);
} finally {
indexWriter = null;
}
@@ -129,7 +137,9 @@ public abstract class AbstractIndex {
try {
directory.close();
} catch (IOException ex) {
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "Unable to update database due to an IO error.";
Logger.getLogger(AbstractIndex.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(AbstractIndex.class.getName()).log(Level.FINE, null, ex);
} finally {
directory = null;
}
@@ -250,14 +260,11 @@ public abstract class AbstractIndex {
* @throws IOException is thrown if there is an issue with the underlying Index
*/
public TopDocs search(String searchString, int maxQueryResults) throws ParseException, IOException {
final QueryParser parser = getQueryParser();
final Query query = parser.parse(searchString);
resetSearchingAnalyzer();
final IndexSearcher is = getIndexSearcher();
final TopDocs docs = is.search(query, maxQueryResults);
return docs;
return is.search(query, maxQueryResults);
}
/**

View File

@@ -41,7 +41,7 @@ public class FieldAnalyzer extends Analyzer {
/**
* The Lucene Version used.
*/
private Version version;
private final Version version;
/**
* Creates a new FieldAnalyzer.

View File

@@ -40,6 +40,9 @@ public final class LuceneUtils {
* @param text the data to be escaped
*/
@SuppressWarnings("fallthrough")
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
value = "SF_SWITCH_NO_DEFAULT",
justification = "The switch below does have a default.")
public static void appendEscapedLuceneQuery(StringBuilder buf,
final CharSequence text) {

View File

@@ -39,7 +39,7 @@ public class SearchFieldAnalyzer extends Analyzer {
/**
* The Lucene Version used.
*/
private Version version;
private final Version version;
/**
* A local reference to the TokenPairConcatenatingFilter so that we
* can clear any left over state if this analyzer is re-used.

View File

@@ -42,7 +42,7 @@ public class SearchVersionAnalyzer extends Analyzer {
/**
* The Lucene Version used.
*/
private Version version;
private final Version version;
/**
* Creates a new SearchVersionAnalyzer.

View File

@@ -50,7 +50,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
/**
* A list of words parsed.
*/
private LinkedList<String> words;
private final LinkedList<String> words;
/**
* Constructs a new TokenPairConcatenatingFilter.

View File

@@ -42,7 +42,7 @@ public class VersionAnalyzer extends Analyzer {
/**
* The Lucene Version used.
*/
private Version version;
private final Version version;
/**
* Creates a new VersionAnalyzer.

View File

@@ -41,7 +41,7 @@ public final class VersionTokenizingFilter extends TokenFilter {
/**
* A collection of tokens to add to the stream.
*/
private LinkedList<String> tokens;
private final LinkedList<String> tokens;
/**
* Constructs a new VersionTokenizingFilter.

View File

@@ -21,7 +21,6 @@ package org.owasp.dependencycheck.data.nvdcve;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -37,6 +36,7 @@ import org.owasp.dependencycheck.data.cwe.CweDB;
import org.owasp.dependencycheck.dependency.Reference;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
/**
@@ -181,14 +181,19 @@ public class CveDB {
* @throws IOException thrown if there is an IO Exception
* @throws SQLException thrown if there is a SQL Exception
* @throws DatabaseException thrown if there is an error initializing a new database
* @throws ClassNotFoundException thrown if the h2 database driver cannot be loaded
*/
public void open() throws IOException, SQLException, DatabaseException {
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
value = "DMI_EMPTY_DB_PASSWORD",
justification = "Yes, I know... Blank password.")
public void open() throws IOException, SQLException, DatabaseException, ClassNotFoundException {
final String fileName = CveDB.getDataDirectory().getCanonicalPath()
+ File.separator
+ "cve";
final File f = new File(fileName);
final boolean createTables = !f.exists();
final String connStr = "jdbc:h2:file:" + fileName;
Class.forName("org.h2.Driver");
conn = DriverManager.getConnection(connStr, "sa", "");
if (createTables) {
createTables();
@@ -215,16 +220,18 @@ public class CveDB {
try {
conn.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "There was an error attempting to close the CveDB, see the log for more details.";
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg, ex);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
}
conn = null;
}
}
/**
* Retrieves the vulnerabilities associated with the specified CPE cpe.
* Retrieves the vulnerabilities associated with the specified CPE.
*
* @param cpeStr the CPE cpe name
* @param cpeStr the CPE name
* @return a list of Vulnerabilities
* @throws DatabaseException thrown if there is an exception retrieving data
*/
@@ -234,7 +241,9 @@ public class CveDB {
try {
cpe.parseName(cpeStr);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "There was an encoding error parsing a vulerability, see the log for more details.";
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, String.format("Error parsing '%s'", cpeStr), ex);
}
final List<Vulnerability> vulnerabilities = new ArrayList<Vulnerability>();
@@ -254,7 +263,7 @@ public class CveDB {
try {
rs.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Error closing RecordSet", ex);
}
}
}
@@ -305,11 +314,11 @@ public class CveDB {
rsS = selectSoftware.executeQuery();
while (rsS.next()) {
final String cpe = rsS.getString(1);
final String prevVers = rsS.getString(2);
if (prevVers == null) {
final String prevVersion = rsS.getString(2);
if (prevVersion == null) {
vuln.addVulnerableSoftware(cpe);
} else {
vuln.addVulnerableSoftware(cpe, prevVers);
vuln.addVulnerableSoftware(cpe, prevVersion);
}
}
}
@@ -320,21 +329,21 @@ public class CveDB {
try {
rsV.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Error closing RecordSet", ex);
}
}
if (rsR != null) {
try {
rsR.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Error closing RecordSet", ex);
}
}
if (rsS != null) {
try {
rsS.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Error closing RecordSet", ex);
}
}
}
@@ -393,8 +402,9 @@ public class CveDB {
}
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
throw new DatabaseException("Error updating '" + vuln.getName() + "'", ex);
final String msg = String.format("Error updating '%s'", vuln.getName());
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException(msg, ex);
}
}
@@ -407,18 +417,7 @@ public class CveDB {
*/
public static File getDataDirectory() throws IOException {
final String fileName = Settings.getString(Settings.KEYS.CVE_INDEX);
final String filePath = CveDB.class.getProtectionDomain().getCodeSource().getLocation().getPath();
final String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File(".");
}
File path = new File(exePath.getCanonicalFile() + File.separator + fileName);
path = new File(path.getCanonicalPath());
final File path = FileUtils.getDataDirectory(fileName, CveDB.class);
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create NVD CVE Data directory");
@@ -449,7 +448,7 @@ public class CveDB {
try {
statement.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Error closing Statement", ex);
}
}
}

View File

@@ -29,6 +29,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
/**
* NvdCveAnalyzer is a utility class that takes a project dependency and
* attempts to discern if there is an associated CVEs. It uses the the
@@ -53,8 +54,9 @@ public class NvdCveAnalyzer implements Analyzer {
* @throws SQLException thrown when there is a SQL Exception
* @throws IOException thrown when there is an IO Exception
* @throws DatabaseException thrown when there is a database exceptions
* @throws ClassNotFoundException thrown if the h2 database driver cannot be loaded
*/
public void open() throws SQLException, IOException, DatabaseException {
public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
cveDB = new CveDB();
cveDB.open();
}
@@ -105,7 +107,9 @@ public class NvdCveAnalyzer implements Analyzer {
final String value = id.getValue();
final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
for (Vulnerability v : vulns) {
dependency.addVulnerability(v);
if (isValidMatch(dependency, v)) {
dependency.addVulnerability(v);
}
}
} catch (DatabaseException ex) {
throw new AnalysisException(ex);
@@ -159,4 +163,52 @@ public class NvdCveAnalyzer implements Analyzer {
public void initialize() throws Exception {
this.open();
}
/**
* <p>Determines if this is a valid vulnerability match for the given dependency.
* Specifically, this is concerned with ensuring the version numbers are correct.</p>
* <p>Currently, this is focused on the issues with the versions for Struts 1 and Struts 2.
* In the future this will due better matching on more version numbers.</p>
* @param dependency the dependency
* @param v the vulnerability
* @return returns true if the vulnerability is for the given dependency
*/
private boolean isValidMatch(final Dependency dependency, final Vulnerability v) {
//right now I only know of the issue with Struts1/2
// start with fixing this problem.
//TODO extend this solution to do better version matching for the vulnerable software.
boolean struts1 = false;
boolean struts2 = false;
for (Identifier i : dependency.getIdentifiers()) {
if (i.getValue().startsWith("cpe:/a:apache:struts:")) {
final char version = i.getValue().charAt(21);
if (version == '1') {
struts1 = true;
}
if (version == '2') {
struts2 = true;
}
}
}
if (!struts1 && !struts2) {
return true; //we are not looking at struts, so return true.
}
if (struts1 && struts2) {
return true; //there is a mismatch here, but we can't solve it here so we return valid.
}
if (struts1) {
boolean hasStruts1Vuln = false;
boolean hasStruts2PreviousVersion = false;
for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
hasStruts2PreviousVersion |= vs.hasPreviousVersion() && vs.getName().charAt(21) == '2';
hasStruts1Vuln |= vs.getName().charAt(21) == '1';
}
if (!hasStruts1Vuln && hasStruts2PreviousVersion) {
return false;
}
}
return true;
}
}

View File

@@ -96,20 +96,20 @@ public class DatabaseUpdater implements CachedWebDataSource {
}
}
if (maxUpdates > 3) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
"NVD CVE requires several updates; this could take a couple of minutes.");
}
int count = 0;
for (NvdCveUrl cve : update.values()) {
if (cve.getNeedsUpdate()) {
count += 1;
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
"Updating NVD CVE ({0} of {1})", new Object[]{count, maxUpdates});
URL url = new URL(cve.getUrl());
File outputPath = null;
File outputPath12 = null;
try {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
"Downloading {0}", cve.getUrl());
outputPath = File.createTempFile("cve" + cve.getId() + "_", ".xml");
@@ -119,11 +119,11 @@ public class DatabaseUpdater implements CachedWebDataSource {
outputPath12 = File.createTempFile("cve_1_2_" + cve.getId() + "_", ".xml");
Downloader.fetchFile(url, outputPath12, false);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
"Processing {0}", cve.getUrl());
importXML(outputPath, outputPath12);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO,
"Completed updated {0} of {1}", new Object[]{count, maxUpdates});
} catch (FileNotFoundException ex) {
throw new UpdateException(ex);
@@ -137,16 +137,29 @@ public class DatabaseUpdater implements CachedWebDataSource {
throw new UpdateException(ex);
} catch (DatabaseException ex) {
throw new UpdateException(ex);
} catch (ClassNotFoundException ex) {
throw new UpdateException(ex);
} finally {
boolean deleted = false;
try {
if (outputPath != null && outputPath.exists()) {
outputPath.delete();
deleted = outputPath.delete();
}
} finally {
if (outputPath != null && outputPath.exists()) {
if (outputPath != null && (outputPath.exists() || !deleted)) {
outputPath.deleteOnExit();
}
}
try {
deleted = false;
if (outputPath12 != null && outputPath12.exists()) {
deleted = outputPath12.delete();
}
} finally {
if (outputPath12 != null && (outputPath12.exists() || !deleted)) {
outputPath12.deleteOnExit();
}
}
}
}
}
@@ -166,13 +179,14 @@ public class DatabaseUpdater implements CachedWebDataSource {
* @param file the file containing the NVD CVE XML
* @param oldVersion contains the file containing the NVD CVE XML 1.2
* @throws ParserConfigurationException is thrown if there is a parser configuration exception
* @throws SAXException is thrown if there is a saxexception
* @throws SAXException is thrown if there is a SAXException
* @throws IOException is thrown if there is a ioexception
* @throws SQLException is thrown if there is a sql exception
* @throws DatabaseException is thrown if there is a database exception
* @throws ClassNotFoundException thrown if the h2 database driver cannot be loaded
*/
private void importXML(File file, File oldVersion)
throws ParserConfigurationException, SAXException, IOException, SQLException, DatabaseException {
throws ParserConfigurationException, SAXException, IOException, SQLException, DatabaseException, ClassNotFoundException {
CveDB cveDB = null;
Index cpeIndex = null;
@@ -196,12 +210,6 @@ public class DatabaseUpdater implements CachedWebDataSource {
cve20Handler.setPrevVersionVulnMap(prevVersionVulnMap);
cve20Handler.setCpeIndex(cpeIndex);
saxParser.parse(file, cve20Handler);
// Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
// String.format("%d out of %d entries processed were application specific CVEs.",
// cve20Handler.getTotalNumberOfApplicationEntries(),
// cve20Handler.getTotalNumberOfEntries()));
cve20Handler = null;
} finally {
if (cpeIndex != null) {
@@ -228,7 +236,7 @@ public class DatabaseUpdater implements CachedWebDataSource {
try {
dir = CveDB.getDataDirectory().getCanonicalPath();
} catch (IOException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "Error updating the databases propterty file.", ex);
throw new UpdateException("Unable to locate last updated properties file.", ex);
}
final File cveProp = new File(dir + File.separatorChar + UPDATE_PROPERTIES_FILE);
@@ -245,17 +253,24 @@ public class DatabaseUpdater implements CachedWebDataSource {
out = new OutputStreamWriter(os, "UTF-8");
prop.store(out, dir);
} catch (FileNotFoundException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
throw new UpdateException("Unable to find last updated properties file.", ex);
} catch (IOException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
throw new UpdateException("Unable to update last updated properties file.", ex);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
}
}
if (os != null) {
try {
os.close();
} catch (IOException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
}
}
}
@@ -281,11 +296,12 @@ public class DatabaseUpdater implements CachedWebDataSource {
try {
currentlyPublished = retrieveCurrentTimestampsFromWeb();
} catch (InvalidDataException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.SEVERE, null, ex);
throw new DownloadFailedException("Unable to retrieve valid timestamp from nvd cve downloads page", ex);
final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, msg, ex);
throw new DownloadFailedException(msg, ex);
} catch (InvalidSettingException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "Invalid setting found when retrieving timestamps", ex);
throw new DownloadFailedException("Invalid settings", ex);
}
@@ -296,7 +312,7 @@ public class DatabaseUpdater implements CachedWebDataSource {
try {
dir = CveDB.getDataDirectory().getCanonicalPath();
} catch (IOException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, "CveDB data directory doesn't exist?", ex);
throw new UpdateException("Unable to locate last updated properties file.", ex);
}
@@ -311,7 +327,7 @@ public class DatabaseUpdater implements CachedWebDataSource {
prop.load(is);
boolean deleteAndRecreate = false;
float version = 0;
float version;
if (prop.getProperty("version") == null) {
deleteAndRecreate = true;
@@ -327,14 +343,14 @@ public class DatabaseUpdater implements CachedWebDataSource {
}
}
if (deleteAndRecreate) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING, "Index version is old. Rebuilding the index.");
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.INFO, "The database version is old. Rebuilding the database.");
is.close();
//this is an old version of the lucene index - just delete it
FileUtils.delete(f);
//this importer also updates the CPE index and it is also using an old version
final Index cpeid = new Index();
final File cpeDir = cpeid.getDataDirectory();
final Index cpeId = new Index();
final File cpeDir = cpeId.getDataDirectory();
FileUtils.delete(cpeDir);
return currentlyPublished;
}
@@ -358,8 +374,8 @@ public class DatabaseUpdater implements CachedWebDataSource {
try {
currentTimestamp = Long.parseLong(prop.getProperty(LAST_UPDATED_BASE + String.valueOf(i), "0"));
} catch (NumberFormatException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, "Error parsing " + LAST_UPDATED_BASE
+ String.valueOf(i) + " from nvdcve.lastupdated", ex);
final String msg = String.format("Error parsing '%s' '%s' from nvdcve.lastupdated", LAST_UPDATED_BASE, String.valueOf(i));
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, msg, ex);
}
if (currentTimestamp == cve.getTimestamp()) {
cve.setNeedsUpdate(false); //they default to true.
@@ -377,7 +393,7 @@ public class DatabaseUpdater implements CachedWebDataSource {
try {
is.close();
} catch (IOException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINEST, null, ex);
}
}
}

View File

@@ -69,7 +69,7 @@ public class NvdCve12Handler extends DefaultHandler {
/**
* The current element.
*/
private Element current = new Element();
private final Element current = new Element();
/**
* a map of vulnerabilities.
*/

View File

@@ -49,7 +49,7 @@ public class NvdCve20Handler extends DefaultHandler {
/**
* the current element.
*/
private Element current = new Element();
private final Element current = new Element();
/**
* the text of the node.
*/
@@ -172,7 +172,8 @@ public class NvdCve20Handler extends DefaultHandler {
final float score = Float.parseFloat(nodeText.toString());
vulnerability.setCvssScore(score);
} catch (NumberFormatException ex) {
Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.SEVERE, "Error parsing CVSS Score.");
Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.FINE, null, ex);
}
nodeText = null;
} else if (current.isCVSSAccessVectorNode()) {

View File

@@ -72,15 +72,15 @@ public class Dependency implements Comparable<Dependency> {
/**
* A collection of vendor evidence.
*/
private EvidenceCollection vendorEvidence;
private final EvidenceCollection vendorEvidence;
/**
* A collection of product evidence.
*/
private EvidenceCollection productEvidence;
private final EvidenceCollection productEvidence;
/**
* A collection of version evidence.
*/
private EvidenceCollection versionEvidence;
private final EvidenceCollection versionEvidence;
/**
* Constructs a new Dependency object.
@@ -379,8 +379,8 @@ public class Dependency implements Comparable<Dependency> {
if (str == null) {
return false;
}
if (vendorEvidence.containsUsedString(str)) {
return versionEvidence.containsUsedString(str) || productEvidence.containsUsedString(str) || vendorEvidence.containsUsedString(str);
/*if (vendorEvidence.containsUsedString(str)) {
return true;
}
if (productEvidence.containsUsedString(str)) {
@@ -390,6 +390,7 @@ public class Dependency implements Comparable<Dependency> {
return true;
}
return false;
*/
}
/**
* A list of vulnerabilities for this dependency.
@@ -426,9 +427,13 @@ public class Dependency implements Comparable<Dependency> {
md5 = Checksum.getMD5Checksum(file);
sha1 = Checksum.getSHA1Checksum(file);
} catch (IOException ex) {
Logger.getLogger(Dependency.class.getName()).log(Level.SEVERE, null, ex);
final String msg = String.format("Unable to read '%s' to determine hashes.", file.getName());
Logger.getLogger(Dependency.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(Dependency.class.getName()).log(Level.FINE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(Dependency.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "Unable to use MD5 of SHA1 checksums.";
Logger.getLogger(Dependency.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(Dependency.class.getName()).log(Level.FINE, null, ex);
}
this.setMd5sum(md5);
this.setSha1sum(sha1);

View File

@@ -80,7 +80,7 @@ public class EvidenceCollection implements Iterable<Evidence> {
*
* @param confidence the confidence level for the evidence to be iterated
* over.
* @return Iterable<Evidence>.
* @return Iterable<Evidence> an iterable collectoin of evidence
*/
public final Iterable<Evidence> iterator(Evidence.Confidence confidence) {
if (confidence == Evidence.Confidence.HIGH) {
@@ -94,11 +94,11 @@ public class EvidenceCollection implements Iterable<Evidence> {
/**
* A collection of evidence.
*/
private Set<Evidence> list;
private final Set<Evidence> list;
/**
* A collection of strings used to adjust Lucene's term weighting.
*/
private Set<String> weightedStrings;
private final Set<String> weightedStrings;
/**
* Creates a new EvidenceCollection.

View File

@@ -46,7 +46,9 @@ public class VulnerableSoftware extends Entry implements Serializable, Comparabl
try {
parseName(cpe);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(VulnerableSoftware.class.getName()).log(Level.SEVERE, null, ex);
final String msg = String.format("Character encoding is unsupported for CPE '%s'.", cpe);
Logger.getLogger(VulnerableSoftware.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(VulnerableSoftware.class.getName()).log(Level.FINE, null, ex);
setName(cpe);
}
}

View File

@@ -64,16 +64,20 @@ public class ReportGenerator {
/**
* Generate HTML report.
*/
HTML
HTML,
/**
* Generate HTML Vulnerability report.
*/
VULN
}
/**
* The Velocity Engine.
*/
private VelocityEngine engine;
private final VelocityEngine engine;
/**
* The Velocity Engine Context.
*/
private Context context;
private final Context context;
/**
* Constructs a new ReportGenerator.
@@ -100,6 +104,7 @@ public class ReportGenerator {
*/
private VelocityEngine createVelocityEngine() {
final VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
return ve;
@@ -110,6 +115,8 @@ public class ReportGenerator {
*
* @return a Velocity Context.
*/
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_RETURN_VALUE_IGNORED_INFERRED",
justification = "No plan to fix this style issue")
private Context createContext() {
final ToolManager manager = new ToolManager();
final Context c = manager.createContext();
@@ -136,6 +143,9 @@ public class ReportGenerator {
if (format == Format.HTML || format == Format.ALL) {
generateReport("HtmlReport", outputDir + File.separator + "DependencyCheck-Report.html");
}
if (format == Format.VULN || format == Format.ALL) {
generateReport("VulnerabilityReport", outputDir + File.separator + "DependencyCheck-Vulnerability.html");
}
}
/**
@@ -148,14 +158,20 @@ public class ReportGenerator {
* reports.
*/
public void generateReports(String outputDir, String outputFormat) throws IOException, Exception {
if ("XML".equalsIgnoreCase(outputFormat)) {
generateReports(outputDir, Format.XML);
}
if ("HTML".equalsIgnoreCase(outputFormat)) {
generateReports(outputDir, Format.HTML);
}
if ("ALL".equalsIgnoreCase(outputFormat)) {
generateReports(outputDir, Format.ALL);
final String format = outputFormat.toUpperCase();
if (format.matches("^(XML|HTML|VULN|ALL)$")) {
if ("XML".equalsIgnoreCase(format)) {
generateReports(outputDir, Format.XML);
}
if ("HTML".equalsIgnoreCase(format)) {
generateReports(outputDir, Format.HTML);
}
if ("VULN".equalsIgnoreCase(format)) {
generateReports(outputDir, Format.VULN);
}
if ("ALL".equalsIgnoreCase(format)) {
generateReports(outputDir, Format.ALL);
}
}
}
@@ -178,7 +194,9 @@ public class ReportGenerator {
templatePath = templateName;
input = new FileInputStream(f);
} catch (FileNotFoundException ex) {
Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "Unable to generate the report, the report template file could not be found.";
Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINE, null, ex);
}
} else {
templatePath = "templates/" + templateName + ".vsl";
@@ -193,14 +211,16 @@ public class ReportGenerator {
OutputStream outputStream = null;
try {
File foutDir = new File(outFileName).getParentFile();
if (!foutDir.exists()) {
foutDir.mkdirs();
final File outDir = new File(outFileName).getParentFile();
if (!outDir.exists()) {
final boolean created = outDir.mkdirs();
if (!created) {
throw new Exception("Unable to create directory '" + outDir.getAbsolutePath() + "'.");
}
}
outputStream = new FileOutputStream(outFileName);
writer = new OutputStreamWriter(outputStream, "UTF-8");
//writer = new BufferedWriter(oswriter);
if (!engine.evaluate(context, writer, templatePath, reader)) {
throw new Exception("Failed to convert the template into html.");

View File

@@ -0,0 +1,103 @@
/*
* This file is part of Dependency-Check.
*
* Dependency-Check is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Dependency-Check is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* Dependency-Check. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Steve Springett. All Rights Reserved.
*/
package org.owasp.dependencycheck.reporting;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.log.LogChute;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <p>DependencyCheck uses {@link java.util.logging.Logger} as a logging framework,
* and Apache Velocity uses a custom logging implementation that outputs to a
* file named velocity.log by default. This class is an implementation of a
* custom Velocity logger that redirects all velocity logging to the Java Logger
* class.
* </p><p>
* This class was written to address permission issues when using Dependency-Check
* in a server environment (such as the Jenkins plugin). In some circumstances,
* Velocity would attempt to create velocity.log in an un-writable directory.</p>
*
* @author Steve Springett (steve.springett@owasp.org)
*/
public class VelocityLoggerRedirect implements LogChute {
/**
* This will be invoked once by the LogManager.
* @param rsvc the RuntimeServices
*/
public void init(RuntimeServices rsvc) {
// do nothing
}
/**
* Given a Velocity log level and message, this method will
* call the appropriate Logger level and log the specified values.
* @param level the logging level
* @param message the message to be logged
*/
public void log(int level, String message) {
Logger.getLogger(Velocity.class.getName()).log(getLevel(level), message);
}
/**
* Given a Velocity log level, message and Throwable, this method will
* call the appropriate Logger level and log the specified values.
* @param level the logging level
* @param message the message to be logged
* @param t a throwable to log
*/
public void log(int level, String message, Throwable t) {
Logger.getLogger(Velocity.class.getName()).log(getLevel(level), message, t);
}
/**
* Will always return true. The property file will decide what level to log.
* @param level the logging level
* @return true
*/
public boolean isLevelEnabled(int level) {
return true;
}
/**
* Maps Velocity log levels to {@link Logger} values.
* @param velocityLevel the logging level
* @return the logging level
*/
private Level getLevel(int velocityLevel) {
switch (velocityLevel) {
case TRACE_ID:
return Level.ALL;
case DEBUG_ID:
return Level.FINE;
case INFO_ID:
return Level.INFO;
case WARN_ID:
return Level.WARNING;
case ERROR_ID:
return Level.SEVERE;
default:
return Level.INFO;
}
}
}

View File

@@ -51,7 +51,7 @@ public class Checksum {
try {
fis.close();
} catch (IOException ex) {
Logger.getLogger(Checksum.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(Checksum.class.getName()).log(Level.FINEST, "Error closing file '" + file.getName() + "'.", ex);
}
}
}

View File

@@ -44,7 +44,7 @@ public final class CliParser {
/**
* The options for the command line parser.
*/
private Options options = createCommandLineOptions();
private final Options options = createCommandLineOptions();
/**
* Indicates whether the arguments are valid.
*/
@@ -75,8 +75,7 @@ public final class CliParser {
*/
private CommandLine parseArgs(String[] args) throws ParseException {
final CommandLineParser parser = new PosixParser();
final CommandLine ln = parser.parse(options, args);
return ln;
return parser.parse(options, args);
}
/**
@@ -102,7 +101,7 @@ public final class CliParser {
+ "the 'out' argument.");
}
}
if (!line.hasOption(ArgumentName.APPNAME)) {
if (!line.hasOption(ArgumentName.APP_NAME)) {
throw new ParseException("Scan cannot be run without specifying an application "
+ "name via the 'app' argument.");
}
@@ -110,8 +109,9 @@ public final class CliParser {
final String format = line.getOptionValue(ArgumentName.OUTPUT_FORMAT);
if (!("ALL".equalsIgnoreCase(format)
|| "XML".equalsIgnoreCase(format)
|| "HTML".equalsIgnoreCase(format))) {
throw new ParseException("Supported output formats are XML, HTML, or ALL");
|| "HTML".equalsIgnoreCase(format)
|| "VULN".equalsIgnoreCase(format))) {
throw new ParseException("Supported output formats are XML, HTML, VULN, or ALL");
}
}
}
@@ -158,47 +158,47 @@ public final class CliParser {
@SuppressWarnings("static-access")
private Options createCommandLineOptions() {
final Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false,
"print this message.");
"Print this message.");
final Option deepScan = new Option(ArgumentName.PERFORM_DEEP_SCAN_SHORT, ArgumentName.PERFORM_DEEP_SCAN, false,
"extracts extra information from dependencies that may increase false positives, but also decrease false negatives.");
"Extracts extra information from dependencies that may increase false positives, but also decrease false negatives.");
final Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION,
false, "print the version information.");
false, "Print the version information.");
final Option noupdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
false, "disables the automatic updating of the CPE data.");
final Option noUpdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
false, "Disables the automatic updating of the CPE data.");
final Option appname = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APPNAME)
.withDescription("the name of the application being scanned.")
.create(ArgumentName.APPNAME_SHORT);
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APP_NAME)
.withDescription("The name of the application being scanned.")
.create(ArgumentName.APP_NAME_SHORT);
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ArgumentName.CONNECTION_TIMEOUT)
.withDescription("the connection timeout (in milliseconds) to use when downloading resources.")
.withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
.create(ArgumentName.CONNECTION_TIMEOUT_SHORT);
final Option proxyUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.PROXY_URL)
.withDescription("the proxy url to use when downloading resources.")
.withDescription("The proxy url to use when downloading resources.")
.create(ArgumentName.PROXY_URL_SHORT);
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ArgumentName.PROXY_PORT)
.withDescription("the proxy port to use when downloading resources.")
.withDescription("The proxy port to use when downloading resources.")
.create(ArgumentName.PROXY_PORT_SHORT);
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.")
.create(ArgumentName.SCAN_SHORT);
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
.withDescription("a property file to load.")
.withDescription("A property file to load.")
.create(ArgumentName.PROP_SHORT);
final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
.withDescription("the folder to write reports to.")
.withDescription("The folder to write reports to.")
.create(ArgumentName.OUT_SHORT);
final Option outputformat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ArgumentName.OUTPUT_FORMAT)
.withDescription("the output format to write to (XML, HTML, ALL).")
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ArgumentName.OUTPUT_FORMAT)
.withDescription("The output format to write to (XML, HTML, VULN, ALL).")
.create(ArgumentName.OUTPUT_FORMAT_SHORT);
final OptionGroup og = new OptionGroup();
@@ -207,11 +207,11 @@ public final class CliParser {
final Options opts = new Options();
opts.addOptionGroup(og);
opts.addOption(out);
opts.addOption(outputformat);
opts.addOption(appname);
opts.addOption(outputFormat);
opts.addOption(appName);
opts.addOption(version);
opts.addOption(help);
opts.addOption(noupdate);
opts.addOption(noUpdate);
opts.addOption(deepScan);
opts.addOption(props);
opts.addOption(proxyPort);
@@ -301,7 +301,7 @@ public final class CliParser {
* @return the application name.
*/
public String getApplicationName() {
return line.getOptionValue(ArgumentName.APPNAME);
return line.getOptionValue(ArgumentName.APP_NAME);
}
/**
@@ -405,12 +405,12 @@ public final class CliParser {
* The long CLI argument name specifying the name of the application to
* be scanned.
*/
public static final String APPNAME = "app";
public static final String APP_NAME = "app";
/**
* The short CLI argument name specifying the name of the application to
* be scanned.
*/
public static final String APPNAME_SHORT = "a";
public static final String APP_NAME_SHORT = "a";
/**
* The long CLI argument name asking for help.
*/

View File

@@ -33,7 +33,7 @@ import org.apache.commons.lang.StringUtils;
* versionParts[2] = 3;
* </code></p>
* <p>Note, the parser contained in this class expects the version numbers to be
* separated by periods. If a different seperator is used the parser will likely
* separated by periods. If a different separator is used the parser will likely
* fail.</p>
* @author Jeremy Long (jeremy.long@owasp.org)
*/
@@ -111,4 +111,35 @@ public class DependencyVersion implements Iterable {
public String toString() {
return StringUtils.join(versionParts.toArray(), ".");
}
/**
* Compares the equality of this object to the one passed in as a parameter.
* @param obj the object to compare equality
* @return returns true only if the two objects are equal, otherwise false
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DependencyVersion other = (DependencyVersion) obj;
if (this.versionParts != other.versionParts && (this.versionParts == null || !this.versionParts.equals(other.versionParts))) {
return false;
}
return true;
}
/**
* Calculates the hashCode for this object.
* @return the hashCode
*/
@Override
public int hashCode() {
int hash = 5;
hash = 71 * hash + (this.versionParts != null ? this.versionParts.hashCode() : 0);
return hash;
}
}

View File

@@ -126,7 +126,7 @@ public final class Downloader {
writer = new BufferedOutputStream(new FileOutputStream(outputPath));
final byte[] buffer = new byte[4096];
int bytesRead = 0;
int bytesRead;
while ((bytesRead = reader.read(buffer)) > 0) {
writer.write(buffer, 0, bytesRead);
}

View File

@@ -21,6 +21,7 @@ package org.owasp.dependencycheck.utils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLDecoder;
/**
* A collection of utilities for processing information about files.
@@ -67,4 +68,34 @@ public final class FileUtils {
throw new FileNotFoundException("Failed to delete file: " + file);
}
}
/**
* 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 File object will be created
* based on the file location of the JAR containing the specified class.
*
* @param configuredFilePath the configured relative or absolute path
* @param clazz the class whos path will be resolved
* @return a File object
* @throws IOException is thrown if the path could not be decoded
*/
public static File getDataDirectory(String configuredFilePath, Class clazz) throws IOException {
final File file = new File(configuredFilePath);
if (file.exists() && file.isDirectory() && file.canWrite()) {
return new File(file.getCanonicalPath());
} else {
final String filePath = clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
final String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File(".");
}
final File path = new File(exePath.getCanonicalFile() + File.separator + configuredFilePath);
return new File(path.getCanonicalPath());
}
}
}

View File

@@ -31,7 +31,7 @@ public abstract class Filter<T> {
private class FilterIterator implements Iterator<T> {
private Iterator<T> iterator;
private final Iterator<T> iterator;
private T next;
private FilterIterator(Iterator<T> iterator) {

View File

@@ -37,19 +37,19 @@ public final class Settings {
* The collection of keys used within the properties file.
*/
public static final class KEYS {
/**
* private constructor because this is a "utility" class containing constants
* private constructor because this is a "utility" class containing
* constants
*/
private KEYS() {
//do nothing
}
/**
* The properties key indicating whether or not the cached data sources
* should be updated.
*/
public static final String AUTO_UPDATE = "autoupdate";
/**
* The properties key for the path where the CPE Lucene Index will be
* stored.
@@ -107,8 +107,6 @@ public final class Settings {
* The properties key for the CVE schema version 2.0.
*/
public static final String CVE_SCHEMA_2_0 = "2.0.";
/**
* The properties key for the proxy url.
*/
@@ -126,6 +124,10 @@ public final class Settings {
* The properties key indicating a deep scan should be performed.
*/
public static final String PERFORM_DEEP_SCAN = "perform.deepscan";
/**
* The location of the temporary directory.
*/
public static final String TEMP_DIRECTORY = "temp.directory";
}
/**
* The properties file location.
@@ -150,24 +152,26 @@ public final class Settings {
try {
props.load(in);
} catch (IOException ex) {
Logger.getLogger(Settings.class.getName()).log(Level.SEVERE, "Unable to load default settings.", ex);
Logger.getLogger(Settings.class.getName()).log(Level.SEVERE, "Unable to load default settings.");
Logger.getLogger(Settings.class.getName()).log(Level.FINE, null, ex);
}
}
/**
* Sets a property value.
*
* @param key the key for the property.
* @param value the value for the property.
* @param key the key for the property
* @param value the value for the property
*/
public static void setString(String key, String value) {
INSTANCE.props.setProperty(key, value);
}
/**
* Sets a property value.
*
* @param key the key for the property.
* @param value the value for the property.
* @param key the key for the property
* @param value the value for the property
*/
public static void setBoolean(String key, boolean value) {
if (value) {
@@ -185,9 +189,9 @@ public final class Settings {
*
* @param filePath the path to the properties file to merge.
* @throws FileNotFoundException is thrown when the filePath points to a
* non-existent file.
* non-existent file
* @throws IOException is thrown when there is an exception loading/merging
* the properties.
* the properties
*/
public static void mergeProperties(String filePath) throws FileNotFoundException, IOException {
final FileInputStream fis = new FileInputStream(filePath);
@@ -200,7 +204,7 @@ public final class Settings {
* Note: even if using this method - system properties will be loaded before
* properties loaded from files.
*
* @param stream an Input Stream pointing at a properties file to merge.
* @param stream an Input Stream pointing at a properties file to merge
* @throws IOException is thrown when there is an exception loading/merging
* the properties
*/
@@ -214,9 +218,9 @@ public final class Settings {
* 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 for the requested property.
* @return the property from the properties file.
* @param key the key to lookup within the properties file
* @param defaultValue the default value for the requested property
* @return the property from the properties file
*/
public static String getString(String key, String defaultValue) {
String str = System.getProperty(key, INSTANCE.props.getProperty(key));
@@ -232,8 +236,8 @@ public final class Settings {
* 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.
* @return the property from the properties file.
* @param key the key to lookup within the properties file
* @return the property from the properties file
*/
public static String getString(String key) {
return System.getProperty(key, INSTANCE.props.getProperty(key));
@@ -245,10 +249,10 @@ public final class Settings {
* 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.
* @return the property from the properties file.
* @param key the key to lookup within the properties file
* @return the property from the properties file
* @throws InvalidSettingException is thrown if there is an error retrieving
* the setting.
* the setting
*/
public static int getInt(String key) throws InvalidSettingException {
int value;
@@ -260,16 +264,39 @@ public final class Settings {
return value;
}
/**
* Returns an int value from the properties file. If the value was specified
* as a system property or passed in via the -Dprop=value 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
* @return the property from the properties file or the defaultValue if the
* property does not exist or cannot be converted to an integer
*/
public static int getInt(String key, int defaultValue) {
int value;
try {
value = Integer.parseInt(Settings.getString(key));
} catch (NumberFormatException ex) {
final String msg = String.format("Could not convert property '%s' to an int.", key);
Logger.getLogger(Settings.class.getName()).log(Level.FINEST, msg, ex);
value = defaultValue;
}
return value;
}
/**
* Returns a long value from the properties file. If the value was specified
* as a system property or passed in via the -Dprop=value 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.
* @return the property from the properties file.
* @param key the key to lookup within the properties file
* @return the property from the properties file
* @throws InvalidSettingException is thrown if there is an error retrieving
* the setting.
* the setting
*/
public static long getLong(String key) throws InvalidSettingException {
long value;
@@ -283,14 +310,15 @@ public final class Settings {
/**
* Returns a boolean value from the properties file. If the value was
* specified as a system property or passed in via the -Dprop=value argument
* - this method will return the value from the system properties before the
* values in the contained configuration file.
* 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.
* @return the property from the properties file.
* @param key the key to lookup within the properties file
* @return the property from the properties file
* @throws InvalidSettingException is thrown if there is an error retrieving
* the setting.
* the setting
*/
public static boolean getBoolean(String key) throws InvalidSettingException {
boolean value;

View File

@@ -0,0 +1,19 @@
Copyright (c) 2012 Joseph McCullough
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2009, 2010, 2011, 2012, 2013 Jonathan Hedley <jonathan@hedley.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -2,6 +2,9 @@ application.name=${pom.name}
application.version=${pom.version}
autoupdate=true
#temp.directory defaults to System.getProperty("java.io.tmpdir")
#temp.directory=[path to temp directory]
# the path to the lucene index to store the cpe data
cpe=data/cpe
# the path to the cpe xml file

View File

@@ -5,13 +5,13 @@ handlers=java.util.logging.ConsoleHandler
# FINEST, FINER, FINE, CONFIG, INFO, WARNING and SEVERE.
# Configure the ConsoleHandler.
java.util.logging.ConsoleHandler.level=WARNING
java.util.logging.ConsoleHandler.level=INFO
org.owasp.dependencycheck.data.nvdcve.xml
# Configure the FileHandler.
#java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
#java.util.logging.FileHandler.level=FINEST
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level=FINE
# The following special tokens can be used in the pattern property
# which specifies the location and name of the log file.
@@ -21,4 +21,4 @@ org.owasp.dependencycheck.data.nvdcve.xml
# %g - generation number for rotating logs
# %u - unique number to avoid conflicts
# FileHandler writes to %h/demo0.log by default.
#java.util.logging.FileHandler.pattern=./logs/DependencyCheck%u.log
java.util.logging.FileHandler.pattern=./logs/DependencyCheck.log

View File

@@ -284,10 +284,16 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<h2 class="sectionheader white">Project:&nbsp;$esc.html($applicationName)</h2>
<div class="sectioncontent">Report Generated On: $date<br/><br/>
#set($depCount=$dependencies.size())
#set($vulnCount=0)
#foreach($dependency in $dependencies)
#set($depCount=$depCount+$dependency.getRelatedDependencies().size())
#if($dependency.getVulnerabilities().size()>0)
#set($vulnCount=$vulnCount+1)
#end
#end
Dependencies Scanned:&nbsp;$depCount<br/><br/>
Dependencies Scanned:&nbsp;$depCount<br/>
Vulnerable Dependencies:&nbsp;$vulnCount<br/><br/>
<div class="indent">
#set($lnkcnt=0)
#foreach($dependency in $dependencies)

File diff suppressed because one or more lines are too long

View File

@@ -116,7 +116,7 @@ public class FileNameAnalyzerTest {
* Test of initialize method, of class FileNameAnalyzer.
*/
@Test
public void testInitialize() {
public void testInitialize() throws Exception {
FileNameAnalyzer instance = new FileNameAnalyzer();
instance.initialize();
assertTrue(true); //initialize does nothing.
@@ -126,7 +126,7 @@ public class FileNameAnalyzerTest {
* Test of close method, of class FileNameAnalyzer.
*/
@Test
public void testClose() {
public void testClose() throws Exception {
FileNameAnalyzer instance = new FileNameAnalyzer();
instance.close();
assertTrue(true); //close does nothing.

View File

@@ -18,20 +18,19 @@
*/
package org.owasp.dependencycheck.data.cpe;
import org.owasp.dependencycheck.data.cpe.Index;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
/**
@@ -59,17 +58,7 @@ public abstract class BaseIndexTestCase {
protected static File getDataDirectory() throws IOException {
String fileName = Settings.getString(Settings.KEYS.CPE_INDEX);
String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File(".");
}
File path = new File(exePath.getCanonicalFile() + File.separator + fileName);
path = new File(path.getCanonicalPath());
return path;
return FileUtils.getDataDirectory(fileName, Index.class);
}
public static void ensureIndexExists() throws Exception {

View File

@@ -28,6 +28,7 @@ import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
@@ -61,7 +62,8 @@ public class IndexTest {
try {
instance.open();
} catch (IOException ex) {
Assert.fail(ex.getMessage());
assertNull(ex.getMessage(), ex);
//Assert.fail(ex.getMessage());
}
instance.close();
}
@@ -76,6 +78,6 @@ public class IndexTest {
Directory result = index.getDirectory();
String exp = File.separatorChar + "target" + File.separatorChar + "data" + File.separatorChar + "cpe";
Assert.assertTrue(result.toString().contains(exp));
assertTrue(result.toString().contains(exp));
}
}

View File

@@ -25,10 +25,10 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import junit.framework.TestCase;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
/**
@@ -49,17 +49,7 @@ public abstract class BaseDBTestCase extends TestCase {
protected static File getDataDirectory() throws IOException {
String fileName = Settings.getString(Settings.KEYS.CVE_INDEX);
String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(filePath, "UTF-8");
File exePath = new File(decodedPath);
if (exePath.getName().toLowerCase().endsWith(".jar")) {
exePath = exePath.getParentFile();
} else {
exePath = new File(".");
}
File path = new File(exePath.getCanonicalFile() + File.separator + fileName);
path = new File(path.getCanonicalPath());
return path;
return FileUtils.getDataDirectory(fileName, Index.class);
}
public static void ensureDBExists() throws Exception {

View File

@@ -72,9 +72,9 @@ public class DependencyVersionUtilTest {
String[] failingNames = { "no-version-identified.jar", "somelib-04aug2000r7-dev.jar", "no.version15.jar",
"lib_1.0_spec-1.1.jar", "lib-api_1.0_spec-1.0.1.jar" };
for (int i = 0; i < failingNames.length; i++) {
final DependencyVersion version = DependencyVersionUtil.parseVersionFromFileName(failingNames[i]);
assertNull("Found version in name that should have failed \"" + failingNames[i] + "\".", version);
for (String failingName : failingNames) {
final DependencyVersion version = DependencyVersionUtil.parseVersionFromFileName(failingName);
assertNull("Found version in name that should have failed \"" + failingName + "\".", version);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
9b5390434d0c6bbf79b5b64c94bff06f497f780c

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
f2ff6066ee3da30900f068dae7819e3bbf5a0618