Compare commits

...

68 Commits

Author SHA1 Message Date
Jeremy Long
fc98d646a0 version 1.0.7
Former-commit-id: 3a17193efed4254ec0d4b566b01afcbda3e6af23
2013-12-03 05:38:31 -05:00
Jeremy Long
573866feee improved multi-threaded processing and renamed things for clarity
Former-commit-id: df63ca32884130892e89533f022a5df0e79c62ad
2013-12-02 21:49:55 -05:00
Jeremy Long
ebf855f2a4 checkstyle corrections
Former-commit-id: e9b583b1b1dfb73f076e91c93f2942a65193bd30
2013-12-02 21:37:22 -05:00
Jeremy Long
595452cf82 updated to throttle downloads and improve performance
Former-commit-id: b89aeeef3e8f163e9e4290eb7599104cad9b31d0
2013-12-02 20:06:50 -05:00
Jeremy Long
1439fd6104 limited the number of downloads that can happen at one time
Former-commit-id: 19b16dfd7f50faf9375b5b4efc01bfd5513d5b19
2013-12-02 09:10:12 -05:00
Jeremy Long
f8771adbe7 fixed bug allowing more then a single vulnerability to be removed
Former-commit-id: fa4fcd9917323b3a0e676dc8f16e46bc4099c725
2013-12-02 09:09:16 -05:00
Jeremy Long
4eb76e6da3 Updated to remove batch update and to remove the abstract class used to enable batch mode
Former-commit-id: bd4a2af794afaf3f04f480aa2295560427f690df
2013-12-02 05:43:54 -05:00
Jeremy Long
a84b624fa5 version 1.0.7-SNAPSHOT
Former-commit-id: 3ad98df90ba32515f23eb6d55735c645de2e94af
2013-12-01 10:01:27 -05:00
Jeremy Long
9ca198ee41 Version 1.0.6
Former-commit-id: 73c40956fe68c66d1b2b636610e7119db04b3228
2013-12-01 09:53:02 -05:00
Jeremy Long
d509523743 added ability to copy suppression data from HTML report
Former-commit-id: 60c9249f745cf6ce6649ec0e06caa351c0be31d3
2013-12-01 07:46:29 -05:00
Jeremy Long
338c70c289 fixed the loading of the suppression schema for validation during parsing
Former-commit-id: 6107226d54e3e7821140de4c04675e9713997924
2013-11-30 19:17:03 -05:00
Jeremy Long
e899ad8caa ensured resources are properely closed in finally block
Former-commit-id: f508620d90e43b35fc3d0a3c65b858ce52f731a9
2013-11-30 18:41:36 -05:00
Jeremy Long
c8c6e0350a Updated to support suppression file configuration
Former-commit-id: a84b9b51cf57e0449299d5815a5464b0f74e4a26
2013-11-30 18:17:58 -05:00
Jeremy Long
8faaf6a469 Updated to highlight the help and command line arguments
Former-commit-id: f03a036f1f8822fc3ea95d42d4007d62a5316f65
2013-11-30 18:13:11 -05:00
Jeremy Long
1a0bd89c9d updated to support suppression file configuration
Former-commit-id: 0b6737e1f764c0bdf09d989edbd1c6258b437836
2013-11-30 18:12:43 -05:00
Jeremy Long
6a9308b514 Updated to delete refused CVE entries
Former-commit-id: d17a7dc43a742a86f1f9aafa5bf379b90f40d058
2013-11-30 17:23:23 -05:00
Jeremy Long
1b1f5203f1 updated to use UTF-8
Former-commit-id: a9b40a63905122413c896c8d41b777c11549544d
2013-11-30 17:23:00 -05:00
Jeremy Long
e2c78e546d checkstyle fixes
Former-commit-id: c5488d61958f91a8f47f4df4b2206f0193eed8dd
2013-11-30 10:00:22 -05:00
Jeremy Long
dc02757bc3 added support for suppression rules, initial version
Former-commit-id: 803669d51e0b36a17c3353e40c6ebd2d8197cd76
2013-11-30 08:56:44 -05:00
Jeremy Long
19a2265792 removed
Former-commit-id: e938fad7ee4ca21107c607a056d89df4565907c5
2013-11-30 08:55:45 -05:00
Jeremy Long
7666ed070a added new services
Former-commit-id: 53f5e71bd6f16e1bddd606b72d1fdc9ca9917f06
2013-11-30 08:54:39 -05:00
Jeremy Long
d088e4574e added new suppression schema
Former-commit-id: 7e828e04ad79f41704a38b3aaa25fbb4b4c602f8
2013-11-30 08:54:08 -05:00
Jeremy Long
dd8798e52b added new package
Former-commit-id: 2a95b095f3b3a8aba014f259e54f5a9f1e218203
2013-11-30 08:53:46 -05:00
Jeremy Long
623d992e34 added new exception
Former-commit-id: b3fa50b10c1888cf88f7ed265a670d47b29038b3
2013-11-30 08:52:49 -05:00
Jeremy Long
420f9a068d added test data
Former-commit-id: 912afc4bc9990f98a226c1caf4f99f9e25b0fb1d
2013-11-30 08:52:15 -05:00
Jeremy Long
864807196c updated getFile to return null if property is not defined
Former-commit-id: b9373294be1860ecc0bbe0193fe2704f0678db69
2013-11-29 07:45:41 -05:00
Jeremy Long
a71c8cef83 renamged getFile to getDataFle (settings class)
Former-commit-id: 9a4fceaf67e3d453b13794de2a14182b877ff42a
2013-11-28 06:22:50 -05:00
Jeremy Long
f34a3e421d renamged getFile to getDataFle (settings class)
Former-commit-id: 26f07b57ffa3462c6c43ef920e7964961d24a592
2013-11-28 06:22:02 -05:00
Jeremy Long
0440a4aa7e renamged getFile to getDataFle (settings class)
Former-commit-id: 792c7dd2297616b705b4d93a3ee03ff00b3078e2
2013-11-28 06:20:52 -05:00
Jeremy Long
0faa49d0e5 renamged getFile to getDataFle (settings class)
Former-commit-id: 18ff20a2369b7ae71c6cce8bb49d258718649eaa
2013-11-28 06:20:05 -05:00
Jeremy Long
9dfc25559e renamed getFile to getDataFile and added a no frills getFile function
Former-commit-id: 26c515de47c1ec510c1249e7caab0b69ef189523
2013-11-26 05:35:40 -05:00
Jeremy Long
ee6dd0e794 added key for suppression file
Former-commit-id: 6818ec53ed3174592ebdec3e7db6841791c9b5cc
2013-11-25 19:34:49 -05:00
Jeremy Long
10824e9731 updated schema
Former-commit-id: b573be465ddcefd10fc1f14ef8e40549b31d4617
2013-11-25 19:34:07 -05:00
Jeremy Long
edcf708945 checkstyle corrections
Former-commit-id: 01bfb4aae9a49f002d9633093b6b7a2385470214
2013-11-23 22:38:55 -05:00
Jeremy Long
c96375a16c initial generated version
Former-commit-id: dac89806d53350b47a4315b92e7d26ce75c9fa4a
2013-11-23 22:07:11 -05:00
Jeremy Long
5cbf49a3dd initial version
Former-commit-id: 7a4a699b6de99d67ee5fd5bd1b10d991f9845d2d
2013-11-23 22:06:27 -05:00
Jeremy Long
eebd0491a3 initial version
Former-commit-id: 65a4d406c95101cbfc7cabb8db7cb1f5c2df768c
2013-11-23 22:00:07 -05:00
Jeremy Long
8c38a0e6cc removed call to BatchUpdateTask
Former-commit-id: 90e72fcc67d2c2773afb6b4e8a1ba2bef3636a19
2013-11-23 21:59:11 -05:00
Jeremy Long
5b9fe065d7 deprecated batch update
Former-commit-id: ff25e317e24ebe0f112e4483b9bf7b9b0bfbd187
2013-11-23 21:58:18 -05:00
Jeremy Long
8567610ddc split out core DB functions into a base class to support storing settings in the database
Former-commit-id: 88abaeb5ed81793d0f15462b5bf1d9b7ad9387dc
2013-11-19 21:05:12 -05:00
Jeremy Long
52c186868e added drop table if exists settings
Former-commit-id: 17aa304097415c585e7812d81ec3e01514cb5ad2
2013-11-19 21:04:16 -05:00
Jeremy Long
2699f8ee85 removed unused code
Former-commit-id: 3f2c0f3dab1d6a129eabdcbdaaa2277d48cdbe33
2013-11-17 22:44:33 -05:00
Jeremy Long
ebaf33a36f fixed imports
Former-commit-id: b2ecd90cd34a5c249874633f396a63f813e18505
2013-11-17 22:44:24 -05:00
Jeremy Long
b0f3c76f76 fixed logging statement
Former-commit-id: bc04e34e4c39e739acf8bac7735a9e20cebc76a4
2013-11-17 22:44:03 -05:00
Jeremy Long
acd118a58c removed references to CPE data directory as this has been moved to a RAMDisk directory
Former-commit-id: 8f4dafe9a687f254bec75703a1f392333cfbde54
2013-11-17 22:40:51 -05:00
Jeremy Long
dff0b497b0 introduced property for max thread size
Former-commit-id: 4b2175859ada2e8d375486627235ea8892f8d7ce
2013-11-17 22:37:30 -05:00
Jeremy Long
e34f51a1b0 introduced property for max thread size
Former-commit-id: b3516d41bb6aebb910a73329f2bb102d9df54903
2013-11-17 22:36:41 -05:00
Jeremy Long
e82e996fe5 updated to make downloading of the NVD CVE a multi-threaded operations
Former-commit-id: 4fea16628e8a7a3c5bfd1418129e0ec2d2d97e39
2013-11-17 22:30:31 -05:00
Jeremy Long
238abd009d initial version of Callable Download Task - used to make the downloads multi-threaded
Former-commit-id: a13d22e4197e1e9c2dc772767015871925d61901
2013-11-17 22:29:53 -05:00
Jeremy Long
25e929c10e removed un-needed test
Former-commit-id: 912d30a7a6b29b21531a525e1c53b04a922a1503
2013-11-17 20:50:07 -05:00
Jeremy Long
0e9f5978e1 updated lucene version number
Former-commit-id: cb826e6fac1b2ba1bd04b68b0929b3dc7ec0b22f
2013-11-17 15:21:38 -05:00
Jeremy Long
1024b11eeb updated functionality and incremented database schema version
Former-commit-id: fdf58314c5357a43828e6da1e95a5a88f15d1472
2013-11-17 15:20:53 -05:00
Jeremy Long
a390418f83 new exception type added
Former-commit-id: 1cae76bac4c92af9e1d98fd7a8c2a10ce3bd9edd
2013-11-17 15:20:01 -05:00
Jeremy Long
182c131ee0 initial version of cpe memory index
Former-commit-id: d4c002c275928b09d63d2ada34ed85fed0a331d3
2013-11-17 15:19:26 -05:00
Jeremy Long
1d5d104bbc updated version of lucene
Former-commit-id: 2c92ad10267847c3bee362da91151a1b449bd800
2013-11-17 15:18:55 -05:00
Jeremy Long
53cf0863d0 updated the version of lucene used
Former-commit-id: 5aec5c97c540b24246c7847344b05bd268c5988b
2013-11-17 15:18:26 -05:00
Jeremy Long
5bc64c6925 updated to use the CpeMemoryIndex
Former-commit-id: 0e309506e5503c5960e381ebebcd39fee7ab01b5
2013-11-17 15:17:56 -05:00
Jeremy Long
c2f9d3f455 updated ensureDataExists()
Former-commit-id: b0878d9d6077a199a639d6518cffffadcb848e7b
2013-11-17 15:17:21 -05:00
Jeremy Long
ddd93f518d updated lucene version
Former-commit-id: 0d315d17205781233a63e57ac5826e6b0a2ba8ee
2013-11-17 14:56:58 -05:00
Jeremy Long
6d7de79fa9 added constant Version so on the next upgrade this only needs to be updated in one location
Former-commit-id: 2131a7bae9cc75f7d7d727f0ed191f6d90d426d2
2013-11-17 08:08:59 -05:00
Jeremy Long
df0f05197a added constructor for DatabaseException(ex)
Former-commit-id: 63b28cecfd5ce5b83ac3353aec0c3c74709532ed
2013-11-17 08:08:01 -05:00
Jeremy Long
e3186e6c4c updated javadoc
Former-commit-id: 3b650e1cada9aa78c1b7995ae15286f829e25d6a
2013-11-17 08:00:32 -05:00
Jeremy Long
18bca6352d updated javadoc
Former-commit-id: eaf307a386981f0f5e6b63be92350edaea9294ed
2013-11-17 07:59:23 -05:00
Jeremy Long
fd7299c86f added the ability to retrieve the entire list of vendor/product combinations
Former-commit-id: a1e09bf566f09cb2de1ba800c56628a6e49ccd51
2013-11-16 23:19:52 -05:00
Jeremy Long
f572d32f5b no-op
Former-commit-id: 219a41ed15bd973c7f6f248ffa4bb6e74c82e2cb
2013-11-16 23:05:59 -05:00
Jeremy Long
e534d41d81 no-op
Former-commit-id: c5d0631d3692122bc1edbbc920af3a7a871520b9
2013-11-16 23:05:46 -05:00
Jeremy Long
a641c9858c removed CPE from database updates
Former-commit-id: 0243c4b17c672afd10f77db9edb8a92ea9eeb764
2013-11-16 23:05:23 -05:00
Jeremy Long
c8e339a58d version 1.0.6-SNAPSHOT
Former-commit-id: 3ee701ebd5869f9a4ba43933cba349e392310869
2013-11-16 13:48:51 -05:00
68 changed files with 4014 additions and 2140 deletions

View File

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

View File

@@ -323,7 +323,6 @@ public class DependencyCheckTask extends Task {
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
}
/**
* The Proxy username.
*/
@@ -346,7 +345,6 @@ public class DependencyCheckTask extends Task {
public void setProxyUsername(String proxyUsername) {
this.proxyUsername = proxyUsername;
}
/**
* The Proxy password.
*/
@@ -369,7 +367,6 @@ public class DependencyCheckTask extends Task {
public void setProxyPassword(String proxyPassword) {
this.proxyPassword = proxyPassword;
}
/**
* The Connection Timeout.
*/
@@ -414,6 +411,28 @@ public class DependencyCheckTask extends Task {
public void setLogFile(String logFile) {
this.logFile = logFile;
}
/**
* The path to the suppression file.
*/
private String suppressionFile;
/**
* Get the value of suppressionFile.
*
* @return the value of suppressionFile
*/
public String getSuppressionFile() {
return suppressionFile;
}
/**
* Set the value of suppressionFile.
*
* @param suppressionFile new value of suppressionFile
*/
public void setSuppressionFile(String suppressionFile) {
this.suppressionFile = suppressionFile;
}
@Override
public void execute() throws BuildException {
@@ -515,6 +534,9 @@ public class DependencyCheckTask extends Task {
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
}
if (suppressionFile != null && !suppressionFile.isEmpty()) {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
}
}
/**

View File

@@ -29,6 +29,7 @@ FailBuildOn | If set and a CVE is found that is greater then the speci
AutoUpdate | If set to false the NVD CVE data is not automatically updated. Setting this to false could result in false negatives. However, this may be required in some environments. The default value is true. | Optional
DataDirectory | The directory where dependency-check will store data used for analysis. Defaults to a folder called, called 'dependency-check-data', that is in the same directory as the dependency-check-ant jar file was installed in. *It is not recommended to change this.* | Optional
LogFile | The file path to write verbose logging information. | Optional
SuppressionFile | An XML file conforming to the suppression schema that suppresses findings; this is used to hide false positives. | Optional
ProxyUrl | Defines the proxy used to connect to the Internet. | Optional
ProxyPort | Defines the port for the proxy. | Optional
ProxyUsername | Defines the proxy user name. | Optional

View File

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

View File

@@ -99,7 +99,7 @@ public class App {
} else if (cli.isRunScan()) {
updateSettings(cli.isAutoUpdate(), cli.getConnectionTimeout(), cli.getProxyUrl(),
cli.getProxyPort(), cli.getProxyUsername(), cli.getProxyPassword(),
cli.getDataDirectory(), cli.getPropertiesFile());
cli.getDataDirectory(), cli.getPropertiesFile(), cli.getSuppressionFile());
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles());
} else {
cli.printHelp();
@@ -147,11 +147,15 @@ public class App {
* @param proxyUrl the proxy url (null or blank means no proxy will be used)
* @param proxyPort the proxy port (null or blank means no port will be
* used)
* @param proxyUser the proxy user name
* @param proxyPass the password for the proxy
* @param dataDirectory the directory to store/retrieve persistent data from
* @param propertiesFile the properties file to utilize
* @param suppressionFile the path to the suppression file
*/
private void updateSettings(boolean autoUpdate, String connectionTimeout, String proxyUrl, String proxyPort,
String proxyUser, String proxyPass, String dataDirectory, File propertiesFile) {
String proxyUser, String proxyPass, String dataDirectory, File propertiesFile,
String suppressionFile) {
if (propertiesFile != null) {
try {
@@ -194,5 +198,8 @@ public class App {
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
}
if (suppressionFile != null && !suppressionFile.isEmpty()) {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
}
}
}

View File

@@ -207,6 +207,11 @@ public final class CliParser {
.withDescription("The file path to write verbose logging information.")
.create(ArgumentName.VERBOSE_LOG_SHORT);
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.SUPPRESION_FILE)
.withDescription("The file path to the suppression XML file.")
.create(ArgumentName.SUPPRESION_FILE_SHORT);
final OptionGroup og = new OptionGroup();
og.addOption(path);
@@ -221,6 +226,7 @@ public final class CliParser {
opts.addOption(props);
opts.addOption(data);
opts.addOption(verboseLog);
opts.addOption(suppressionFile);
opts.addOption(proxyPort);
opts.addOption(proxyUrl);
opts.addOption(proxyUsername);
@@ -389,6 +395,15 @@ public final class CliParser {
return line.getOptionValue(ArgumentName.VERBOSE_LOG);
}
/**
* Returns the path to the suppression file.
*
* @return the path to the suppression file
*/
public String getSuppressionFile() {
return line.getOptionValue(ArgumentName.SUPPRESION_FILE);
}
/**
* <p>Prints the manifest information to standard output.</p>
* <ul><li>Implementation-Title: ${pom.name}</li>
@@ -549,5 +564,15 @@ public final class CliParser {
* directory.
*/
public static final String VERBOSE_LOG_SHORT = "l";
/**
* The CLI argument name for setting the location of the suppression
* file.
*/
public static final String SUPPRESION_FILE = "suppression";
/**
* The short CLI argument name for setting the location of the
* suppression file.
*/
public static final String SUPPRESION_FILE_SHORT = "sf";
}
}

View File

@@ -0,0 +1,22 @@
Command Line Arguments
====================
The following table lists the command line arguments:
Short | Argument Name | Parameter | Description | Requirement
-------|-----------------------|-------------|-------------|------------
\-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. |
\-c | \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. | Optional
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. | Optional
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. |
\-h | \-\-help | | Print the help message. | Optional
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
\-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
\-p | \-\-proxyport | \<port\> | The proxy port to use when downloading resources. | Optional
\-pp | \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. | Optional
\-pu | \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. | Optional
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. |
\-sf | \-\-suppression | \<file\> | The file path to the suppression XML file. | Optional
\-u | \-\-proxyurl | \<url\> | The proxy url to use when downloading resources. | Optional
\-v | \-\-version | | Print the version information. | Optional

View File

@@ -13,4 +13,11 @@ To scan a folder on the system you can run:
dependency-check.bat --app "My App Name" --scan "c:\java\application\lib"
### \*nix
dependency-check.sh --app "My App Name" --scan "/java/application/lib"
dependency-check.sh --app "My App Name" --scan "/java/application/lib"
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
### Windows
dependency-check.bat --help
### \*nix
dependency-check.sh --help

View File

@@ -27,6 +27,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
</breadcrumbs>
<menu name="Getting Started">
<item name="Installation" href="installation.html"/>
<item name="Configuration" href="arguments.html"/>
</menu>
<menu ref="Project Documentation" />
<menu ref="reports" />

View File

@@ -22,7 +22,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.0.5</version>
<version>1.0.7</version>
</parent>
<artifactId>dependency-check-core</artifactId>
@@ -410,17 +410,17 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.3.1</version>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>4.3.1</version>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>4.3.1</version>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>

View File

@@ -21,6 +21,7 @@ package org.owasp.dependencycheck;
import java.util.EnumMap;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
@@ -36,7 +37,10 @@ import org.owasp.dependencycheck.data.CachedWebDataSource;
import org.owasp.dependencycheck.data.NoDataException;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.data.UpdateService;
import org.owasp.dependencycheck.data.cpe.CpeIndexReader;
import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex;
import org.owasp.dependencycheck.data.cpe.IndexException;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.InvalidSettingException;
@@ -417,29 +421,28 @@ public class Engine {
* @throws NoDataException thrown if no data exists in the CPE Index
*/
private void ensureDataExists() throws NoDataException {
CpeIndexReader cpe = null;
boolean noDataExists = false;
try {
cpe = new CpeIndexReader();
cpe.open();
if (cpe.numDocs() <= 0) {
noDataExists = true;
}
} catch (IOException ex) {
noDataExists = true;
} catch (NullPointerException ex) {
noDataExists = true;
} finally {
if (cpe != null) {
cpe.close();
}
}
if (noDataExists) {
throw new NoDataException("No data exists in the data store. Please check that you are able to connect "
+ "to the Internet and re-run dependency-check. If the problem persists determine whether you need "
+ "to set a proxy url and port.\\n\\nIf you are unable to solve this problem please contact the mailing "
+ "list for help: dependency-check@googlegroups.com");
final CpeMemoryIndex cpe = CpeMemoryIndex.getInstance();
final CveDB cve = new CveDB();
try {
cve.open();
cpe.open(cve);
} catch (IndexException ex) {
throw new NoDataException(ex);
} catch (IOException ex) {
throw new NoDataException(ex);
} catch (SQLException ex) {
throw new NoDataException(ex);
} catch (DatabaseException ex) {
throw new NoDataException(ex);
} catch (ClassNotFoundException ex) {
throw new NoDataException(ex);
} finally {
cve.close();
}
if (cpe.numDocs() <= 0) {
cpe.close();
throw new NoDataException();
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.suppression.SuppressionParseException;
import org.owasp.dependencycheck.suppression.SuppressionParser;
import org.owasp.dependencycheck.suppression.SuppressionRule;
import org.owasp.dependencycheck.utils.Settings;
/**
* Abstract base suppression analyzer that contains methods for parsing the
* suppression xml file.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of 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() {
return null;
}
/**
* Returns whether or not this analyzer can process the given extension.
*
* @param extension the file extension to test for support.
* @return whether or not the specified file extension is supported by this
* analyzer.
*/
@Override
public boolean supportsExtension(String extension) {
return true;
}
//</editor-fold>
/**
* The initialize method loads the suppression XML file.
*
* @throws Exception thrown if there is an exception
*/
@Override
public void initialize() throws Exception {
super.initialize();
loadSuppressionData();
}
/**
* The list of suppression rules
*/
private List<SuppressionRule> rules;
/**
* Get the value of rules.
*
* @return the value of rules
*/
public List<SuppressionRule> getRules() {
return rules;
}
/**
* Set the value of rules.
*
* @param rules new value of rules
*/
public void setRules(List<SuppressionRule> rules) {
this.rules = rules;
}
/**
* Loads the suppression rules file.
*
* @throws SuppressionParseException thrown if the XML cannot be parsed.
*/
private void loadSuppressionData() throws SuppressionParseException {
final File file = Settings.getFile(Settings.KEYS.SUPPRESSION_FILE);
if (file != null) {
final SuppressionParser parser = new SuppressionParser();
try {
rules = parser.parseSuppressionRules(file);
} catch (SuppressionParseException ex) {
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, ex.getMessage());
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw ex;
}
}
}
}

View File

@@ -56,7 +56,7 @@ public class AnalysisException extends Exception {
}
/**
* Creates a new DownloadFailedException.
* Creates a new AnalysisException.
*
* @param msg a message for the exception.
* @param ex the cause of the failure.

View File

@@ -19,7 +19,7 @@
package org.owasp.dependencycheck.analyzer;
/**
* An exception thrown when the analysis of a dependency fails.
* An exception thrown when files in an archive cannot be extracted.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
@@ -31,14 +31,14 @@ public class ArchiveExtractionException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Creates a new AnalysisException.
* Creates a new ArchiveExtractionException.
*/
public ArchiveExtractionException() {
super();
}
/**
* Creates a new AnalysisException.
* Creates a new ArchiveExtractionException.
*
* @param msg a message for the exception.
*/
@@ -47,7 +47,7 @@ public class ArchiveExtractionException extends Exception {
}
/**
* Creates a new AnalysisException.
* Creates a new ArchiveExtractionException.
*
* @param ex the cause of the failure.
*/
@@ -56,7 +56,7 @@ public class ArchiveExtractionException extends Exception {
}
/**
* Creates a new DownloadFailedException.
* Creates a new ArchiveExtractionException.
*
* @param msg a message for the exception.
* @param ex the cause of the failure.

View File

@@ -40,9 +40,10 @@ import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.dependency.Evidence.Confidence;
import org.owasp.dependencycheck.dependency.EvidenceCollection;
import org.owasp.dependencycheck.data.cpe.CpeIndexReader;
import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex;
import org.owasp.dependencycheck.data.cpe.Fields;
import org.owasp.dependencycheck.data.cpe.IndexEntry;
import org.owasp.dependencycheck.data.cpe.IndexException;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Identifier;
@@ -83,9 +84,9 @@ public class CPEAnalyzer implements Analyzer {
*/
static final int STRING_BUILDER_BUFFER = 20;
/**
* The CPE Index Reader.
* The CPE in memory index.
*/
private CpeIndexReader cpe;
private CpeMemoryIndex cpe;
/**
* The CVE Database.
*/
@@ -100,8 +101,6 @@ public class CPEAnalyzer implements Analyzer {
* usually occurs when the database is in use by another process.
*/
public void open() throws IOException, DatabaseException {
cpe = new CpeIndexReader();
cpe.open();
cve = new CveDB();
try {
cve.open();
@@ -112,10 +111,17 @@ public class CPEAnalyzer implements Analyzer {
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to open the cve db", ex);
}
cpe = CpeMemoryIndex.getInstance();
try {
cpe.open(cve);
} catch (IndexException ex) {
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
throw new DatabaseException(ex);
}
}
/**
* Closes the data source.
* Closes the data sources.
*/
@Override
public void close() {
@@ -127,28 +133,6 @@ public class CPEAnalyzer implements Analyzer {
}
}
/**
* Returns the status of the data source - is the index open.
*
* @return true or false.
*/
public boolean isOpen() {
return (cpe != null) && cpe.isOpen();
}
/**
* Ensures that the Lucene index is closed.
*
* @throws Throwable when a throwable is thrown.
*/
@Override
protected void finalize() throws Throwable {
super.finalize();
if (isOpen()) {
close();
}
}
/**
* Searches the data store of CPE entries, trying to identify the CPE for
* the given dependency based on the evidence contained within. The

View File

@@ -0,0 +1,76 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.suppression.SuppressionRule;
/**
* The suppression analyzer processes an externally defined XML document that
* complies with the suppressions.xsd schema. Any identified CPE entries within
* the dependencies that match will be removed.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The name of the analyzer.
*/
private static final String ANALYZER_NAME = "Cpe Suppression Analyzer";
/**
* The phase that this analyzer is intended to run in.
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
/**
* Returns the name of the analyzer.
*
* @return the name of the analyzer.
*/
@Override
public String getName() {
return ANALYZER_NAME;
}
/**
* Returns the phase that the analyzer is intended to run in.
*
* @return the phase that the analyzer is intended to run in.
*/
@Override
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
//</editor-fold>
@Override
public void analyze(final Dependency dependency, final Engine engine) throws AnalysisException {
if (getRules() == null || getRules().size() <= 0) {
return;
}
for (final SuppressionRule rule : getRules()) {
rule.process(dependency);
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.suppression.SuppressionRule;
/**
* The suppression analyzer processes an externally defined XML document that
* complies with the suppressions.xsd schema. Any identified Vulnerability
* entries within the dependencies that match will be removed.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
/**
* The name of the analyzer.
*/
private static final String ANALYZER_NAME = "Vulnerability Suppression Analyzer";
/**
* The phase that this analyzer is intended to run in.
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_FINDING_ANALYSIS;
/**
* Returns the name of the analyzer.
*
* @return the name of the analyzer.
*/
@Override
public String getName() {
return ANALYZER_NAME;
}
/**
* Returns the phase that the analyzer is intended to run in.
*
* @return the phase that the analyzer is intended to run in.
*/
@Override
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
//</editor-fold>
@Override
public void analyze(final Dependency dependency, final Engine engine) throws AnalysisException {
if (getRules() == null || getRules().size() <= 0) {
return;
}
for (final SuppressionRule rule : getRules()) {
rule.process(dependency);
}
}
}

View File

@@ -0,0 +1,245 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import static org.owasp.dependencycheck.data.nvdcve.CveDB.DB_SCHEMA_VERSION;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class BaseDB {
/**
* Resource location for SQL file used to create the database schema.
*/
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
/**
* The version of the current DB Schema.
*/
public static final String DB_SCHEMA_VERSION = "2.7";
/**
* Database connection
*/
private Connection conn;
/**
* Returns the database connection.
*
* @return the database connection
*/
protected Connection getConnection() {
return conn;
}
/**
* Opens the database connection. If the database does not exist, it will
* create a new one.
*
* @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
*/
@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();
final File f = new File(fileName, "cve." + DB_SCHEMA_VERSION);
final File check = new File(f.getAbsolutePath() + ".h2.db");
final boolean createTables = !check.exists();
final String connStr = String.format("jdbc:h2:file:%s;AUTO_SERVER=TRUE", f.getAbsolutePath());
Class.forName("org.h2.Driver");
conn = DriverManager.getConnection(connStr, "sa", "");
if (createTables) {
createTables();
}
}
/**
* Closes the DB4O database. Close should be called on this object when it
* is done being used.
*/
public void close() {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
final String msg = "There was an error attempting to close the CveDB, see the log for more details.";
Logger.getLogger(BaseDB.class.getName()).log(Level.SEVERE, msg, ex);
Logger.getLogger(BaseDB.class.getName()).log(Level.FINE, null, ex);
}
conn = null;
}
}
/**
* Commits all completed transactions.
*
* @throws SQLException thrown if a SQL Exception occurs
*/
public void commit() throws SQLException {
if (conn != null) {
conn.commit();
}
}
/**
* Cleans up the object and ensures that "close" has been called.
*
* @throws Throwable thrown if there is a problem
*/
@Override
protected void finalize() throws Throwable {
close();
super.finalize(); //not necessary if extending Object.
}
/**
* Creates the database structure (tables and indexes) to store the CVE data
*
* @throws SQLException thrown if there is a sql exception
* @throws DatabaseException thrown if there is a database exception
*/
private void createTables() throws SQLException, DatabaseException {
InputStream is;
InputStreamReader reader;
BufferedReader in = null;
try {
is = this.getClass().getClassLoader().getResourceAsStream(DB_STRUCTURE_RESOURCE);
reader = new InputStreamReader(is, "UTF-8");
in = new BufferedReader(reader);
final StringBuilder sb = new StringBuilder(2110);
String tmp;
while ((tmp = in.readLine()) != null) {
sb.append(tmp);
}
Statement statement = null;
try {
statement = conn.createStatement();
statement.execute(sb.toString());
} finally {
closeStatement(statement);
}
} catch (IOException ex) {
throw new DatabaseException("Unable to create database schema", ex);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, null, ex);
}
}
}
}
/**
* Retrieves the directory that the JAR file exists in so that we can ensure
* we always use a common data directory.
*
* @return the data directory for this index.
* @throws IOException is thrown if an IOException occurs of course...
*/
public static File getDataDirectory() throws IOException {
final File path = Settings.getDataFile(Settings.KEYS.CVE_DATA_DIRECTORY);
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create NVD CVE Data directory");
}
}
return path;
}
/**
* Returns the generated integer primary key for a newly inserted row.
*
* @param statement a prepared statement that just executed an insert
* @return a primary key
* @throws DatabaseException thrown if there is an exception obtaining the
* key
*/
protected int getGeneratedKey(PreparedStatement statement) throws DatabaseException {
ResultSet rs = null;
int id = 0;
try {
rs = statement.getGeneratedKeys();
rs.next();
id = rs.getInt(1);
} catch (SQLException ex) {
throw new DatabaseException("Unable to get primary key for inserted row");
} finally {
closeResultSet(rs);
}
return id;
}
/**
* Closes the given statement object ignoring any exceptions that occur.
*
* @param statement a Statement object
*/
public void closeStatement(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, statement.toString(), ex);
}
}
}
/**
* Closes the result set capturing and ignoring any SQLExceptions that
* occur.
*
* @param rs a ResultSet to close
*/
public void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, rs.toString(), ex);
}
}
}
}

View File

@@ -1,117 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.cpe;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.owasp.dependencycheck.utils.Settings;
/**
* The Base Index class used to access the CPE Index.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public abstract class BaseIndex {
/**
* The Lucene directory containing the index.
*/
private Directory directory;
/**
* Indicates whether or not the Lucene Index is open.
*/
private boolean indexOpen = false;
/**
* Gets the directory.
*
* @return the directory
*/
public Directory getDirectory() {
return directory;
}
/**
* Opens the CPE Index.
*
* @throws IOException is thrown if an IOException occurs opening the index.
*/
public void open() throws IOException {
directory = this.openDirectory();
indexOpen = true;
}
/**
* Closes the CPE Index.
*/
public void close() {
try {
directory.close();
} catch (IOException ex) {
final String msg = "Unable to update database due to an IO error.";
Logger.getLogger(BaseIndex.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(BaseIndex.class.getName()).log(Level.FINE, null, ex);
} finally {
directory = null;
}
indexOpen = false;
}
/**
* Returns the status of the data source - is the index open.
*
* @return true or false.
*/
public boolean isOpen() {
return indexOpen;
}
/**
* Returns the Lucene directory object for the CPE Index.
*
* @return the Lucene Directory object for the CPE Index.
* @throws IOException is thrown if an IOException occurs.
*/
protected Directory openDirectory() throws IOException {
final File path = getDataDirectory();
return FSDirectory.open(path);
}
/**
* Retrieves the directory that the JAR file exists in so that we can ensure
* we always use a common data directory.
*
* @return the data directory for this index.
* @throws IOException is thrown if an IOException occurs of course...
*/
public static File getDataDirectory() throws IOException {
final File path = Settings.getFile(Settings.KEYS.CPE_DATA_DIRECTORY);
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create CPE Data directory");
}
}
return path;
}
}

View File

@@ -1,209 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.cpe;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.KeywordAnalyzer;
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.util.Version;
import org.owasp.dependencycheck.data.lucene.FieldAnalyzer;
import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class CpeIndexReader extends BaseIndex {
/**
* The Lucene IndexReader.
*/
private IndexReader indexReader;
/**
* The Lucene IndexSearcher.
*/
private IndexSearcher indexSearcher;
/**
* The Lucene Analyzer used for Searching.
*/
private Analyzer searchingAnalyzer;
/**
* The Lucene QueryParser used for Searching.
*/
private QueryParser queryParser;
/**
* The search field analyzer for the product field.
*/
private SearchFieldAnalyzer productSearchFieldAnalyzer;
/**
* The search field analyzer for the vendor field.
*/
private SearchFieldAnalyzer vendorSearchFieldAnalyzer;
/**
* Opens the CPE Index.
*
* @throws IOException is thrown if an IOException occurs opening the index.
*/
@Override
public void open() throws IOException {
//TODO add spinlock (shared)
super.open();
indexReader = DirectoryReader.open(getDirectory());
indexSearcher = new IndexSearcher(indexReader);
searchingAnalyzer = createSearchingAnalyzer();
queryParser = new QueryParser(Version.LUCENE_43, Fields.DOCUMENT_KEY, searchingAnalyzer);
}
/**
* Closes the CPE Index.
*/
@Override
public void close() {
//TODO remove spinlock (shared)
if (searchingAnalyzer != null) {
searchingAnalyzer.close();
searchingAnalyzer = null;
}
if (indexReader != null) {
try {
indexReader.close();
} catch (IOException ex) {
Logger.getLogger(CpeIndexReader.class.getName()).log(Level.FINEST, null, ex);
}
indexReader = null;
}
queryParser = null;
indexSearcher = null;
super.close();
}
/**
* Searches the index using the given search string.
*
* @param searchString the query text
* @param maxQueryResults the maximum number of documents to return
* @return the TopDocs found by the search
* @throws ParseException thrown when the searchString is invalid
* @throws IOException is thrown if there is an issue with the underlying
* Index
*/
public TopDocs search(String searchString, int maxQueryResults) throws ParseException, IOException {
if (searchString == null || searchString.trim().isEmpty()) {
throw new ParseException("Query is null or empty");
}
if (queryParser == null) {
if (isOpen()) {
final String msg = String.format("QueryParser is null for query: '%s'. Attempting to reopen index.",
searchString);
Logger.getLogger(CpeIndexReader.class.getName()).log(Level.WARNING, msg);
close();
open();
} else {
final String msg = String.format("QueryParser is null, but data source is open, for query: '%s'. Attempting to reopen index.",
searchString);
Logger.getLogger(CpeIndexReader.class.getName()).log(Level.WARNING, msg);
close();
open();
}
}
final Query query = queryParser.parse(searchString);
return indexSearcher.search(query, maxQueryResults);
}
/**
* Searches the index using the given query.
*
* @param query the query used to search the index
* @param maxQueryResults the max number of results to return
* @return the TopDocs found be the query
* @throws CorruptIndexException thrown if the Index is corrupt
* @throws IOException thrown if there is an IOException
*/
public TopDocs search(Query query, int maxQueryResults) throws CorruptIndexException, IOException {
resetSearchingAnalyzer();
return indexSearcher.search(query, maxQueryResults);
}
/**
* Retrieves a document from the Index.
*
* @param documentId the id of the document to retrieve
* @return the Document
* @throws IOException thrown if there is an IOException
*/
public Document getDocument(int documentId) throws IOException {
return indexSearcher.doc(documentId);
}
/**
* Creates an Analyzer for searching the CPE Index.
*
* @return the CPE Analyzer.
*/
@SuppressWarnings("unchecked")
private Analyzer createSearchingAnalyzer() {
final Map fieldAnalyzers = new HashMap();
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
productSearchFieldAnalyzer = new SearchFieldAnalyzer(Version.LUCENE_43);
vendorSearchFieldAnalyzer = new SearchFieldAnalyzer(Version.LUCENE_43);
fieldAnalyzers.put(Fields.PRODUCT, productSearchFieldAnalyzer);
fieldAnalyzers.put(Fields.VENDOR, vendorSearchFieldAnalyzer);
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(Version.LUCENE_43), fieldAnalyzers);
}
/**
* Resets the searching analyzers
*/
private void resetSearchingAnalyzer() {
if (productSearchFieldAnalyzer != null) {
productSearchFieldAnalyzer.clear();
}
if (vendorSearchFieldAnalyzer != null) {
vendorSearchFieldAnalyzer.clear();
}
}
/**
* Returns the number of CPE entries stored in the index.
*
* @return the number of CPE entries stored in the index
*/
public int numDocs() {
if (indexReader == null) {
return -1;
}
return indexReader.numDocs();
}
}

View File

@@ -1,149 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.cpe;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.KeywordAnalyzer;
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.util.Version;
import org.owasp.dependencycheck.data.lucene.FieldAnalyzer;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class CpeIndexWriter extends BaseIndex {
/**
* The IndexWriter for the Lucene index.
*/
private IndexWriter indexWriter;
/**
* The Lucene Analyzer used for Indexing.
*/
private Analyzer indexingAnalyzer;
/**
* Opens the CPE Index.
*
* @throws IOException is thrown if an IOException occurs opening the index.
*/
@Override
public void open() throws IOException {
//TODO add spinlock
super.open();
indexingAnalyzer = createIndexingAnalyzer();
final IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_43, indexingAnalyzer);
indexWriter = new IndexWriter(getDirectory(), conf);
}
/**
* Closes the CPE Index.
*/
@Override
public void close() {
//TODO remove spinlock
if (indexWriter != null) {
commit();
try {
indexWriter.close(true);
} catch (CorruptIndexException ex) {
final String msg = "Unable to update database, there is a corrupt index.";
Logger.getLogger(CpeIndexWriter.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(CpeIndexWriter.class.getName()).log(Level.FINE, null, ex);
} catch (IOException ex) {
final String msg = "Unable to update database due to an IO error.";
Logger.getLogger(CpeIndexWriter.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(CpeIndexWriter.class.getName()).log(Level.FINE, null, ex);
} finally {
indexWriter = null;
}
}
if (indexingAnalyzer != null) {
indexingAnalyzer.close();
indexingAnalyzer = null;
}
super.close();
}
/**
* Commits any pending changes.
*/
public void commit() {
if (indexWriter != null) {
try {
indexWriter.forceMerge(1);
indexWriter.commit();
} catch (CorruptIndexException ex) {
final String msg = "Unable to update database, there is a corrupt index.";
Logger.getLogger(CpeIndexWriter.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(CpeIndexWriter.class.getName()).log(Level.FINE, null, ex);
} catch (IOException ex) {
final String msg = "Unable to update database due to an IO error.";
Logger.getLogger(CpeIndexWriter.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(CpeIndexWriter.class.getName()).log(Level.FINE, null, ex);
}
}
}
/**
* Creates the indexing analyzer for the CPE Index.
*
* @return the CPE Analyzer.
*/
@SuppressWarnings("unchecked")
private Analyzer createIndexingAnalyzer() {
final Map fieldAnalyzers = new HashMap();
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(Version.LUCENE_43), fieldAnalyzers);
}
/**
* Saves a CPE IndexEntry into the Lucene index.
*
* @param entry a CPE entry.
* @throws CorruptIndexException is thrown if the index is corrupt.
* @throws IOException is thrown if an IOException occurs.
*/
public void saveEntry(IndexEntry entry) throws CorruptIndexException, IOException {
final Document doc = new Document();
final Field documentKey = new StringField(Fields.DOCUMENT_KEY, entry.getDocumentId(), Field.Store.NO);
final Field vendor = new TextField(Fields.VENDOR, entry.getVendor(), Field.Store.YES);
final Field product = new TextField(Fields.PRODUCT, entry.getProduct(), Field.Store.YES);
doc.add(documentKey);
doc.add(vendor);
doc.add(product);
final Term term = new Term(Fields.DOCUMENT_KEY, entry.getDocumentId());
indexWriter.updateDocument(term, doc);
}
}

View File

@@ -0,0 +1,328 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.cpe;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.KeywordAnalyzer;
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.owasp.dependencycheck.data.lucene.FieldAnalyzer;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.apache.lucene.store.RAMDirectory;
import org.owasp.dependencycheck.data.lucene.LuceneUtils;
import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer;
/**
* An in memory lucene index that contains the vendor/product combinations from
* the CPE (application) identifiers within the NVD CVE data.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public final class CpeMemoryIndex {
/**
* singleton instance.
*/
private static CpeMemoryIndex instance = new CpeMemoryIndex();
/**
* private constructor for singleton.
*/
private CpeMemoryIndex() {
}
/**
* Gets the singleton instance of the CpeMemoryIndex.
*
* @return the instance of the CpeMemoryIndex
*/
public static CpeMemoryIndex getInstance() {
return instance;
}
/**
* The in memory Lucene index.
*/
private RAMDirectory index;
/**
* The Lucene IndexReader.
*/
private IndexReader indexReader;
/**
* The Lucene IndexSearcher.
*/
private IndexSearcher indexSearcher;
/**
* The Lucene Analyzer used for Searching.
*/
private Analyzer searchingAnalyzer;
/**
* The Lucene QueryParser used for Searching.
*/
private QueryParser queryParser;
/**
* The search field analyzer for the product field.
*/
private SearchFieldAnalyzer productSearchFieldAnalyzer;
/**
* The search field analyzer for the vendor field.
*/
private SearchFieldAnalyzer vendorSearchFieldAnalyzer;
/**
* Creates and loads data into an in memory index.
*
* @param cve the data source to retrieve the cpe data
* @throws IndexException thrown if there is an error creating the index
*/
public void open(CveDB cve) throws IndexException {
if (!openState) {
index = new RAMDirectory();
buildIndex(cve);
try {
indexReader = DirectoryReader.open(index);
} catch (IOException ex) {
throw new IndexException(ex);
}
indexSearcher = new IndexSearcher(indexReader);
searchingAnalyzer = createSearchingAnalyzer();
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
openState = true;
}
}
/**
* A flag indicating whether or not the index is open.
*/
private boolean openState = false;
/**
* returns whether or not the index is open.
*
* @return whether or not the index is open
*/
public boolean isOpen() {
return openState;
}
/**
* Creates the indexing analyzer for the CPE Index.
*
* @return the CPE Analyzer.
*/
@SuppressWarnings("unchecked")
private Analyzer createIndexingAnalyzer() {
final Map fieldAnalyzers = new HashMap();
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(LuceneUtils.CURRENT_VERSION), fieldAnalyzers);
}
/**
* Creates an Analyzer for searching the CPE Index.
*
* @return the CPE Analyzer.
*/
@SuppressWarnings("unchecked")
private Analyzer createSearchingAnalyzer() {
final Map fieldAnalyzers = new HashMap();
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
productSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
vendorSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
fieldAnalyzers.put(Fields.PRODUCT, productSearchFieldAnalyzer);
fieldAnalyzers.put(Fields.VENDOR, vendorSearchFieldAnalyzer);
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(LuceneUtils.CURRENT_VERSION), fieldAnalyzers);
}
/**
* Saves a CPE IndexEntry into the Lucene index.
*
* @param vendor the vendor to index
* @param product the product to index
* @param indexWriter the index writer to write the entry into
* @throws CorruptIndexException is thrown if the index is corrupt
* @throws IOException is thrown if an IOException occurs
*/
public void saveEntry(String vendor, String product, IndexWriter indexWriter) throws CorruptIndexException, IOException {
final Document doc = new Document();
final Field v = new TextField(Fields.VENDOR, vendor, Field.Store.YES);
final Field p = new TextField(Fields.PRODUCT, product, Field.Store.YES);
doc.add(v);
doc.add(p);
indexWriter.addDocument(doc);
}
/**
* Closes the CPE Index.
*/
public void close() {
if (searchingAnalyzer != null) {
searchingAnalyzer.close();
searchingAnalyzer = null;
}
if (indexReader != null) {
try {
indexReader.close();
} catch (IOException ex) {
Logger.getLogger(CpeMemoryIndex.class.getName()).log(Level.FINEST, null, ex);
}
indexReader = null;
}
queryParser = null;
indexSearcher = null;
if (index != null) {
index.close();
index = null;
}
openState = false;
}
/**
* Builds the lucene index based off of the data within the CveDB.
*
* @param cve the data base containing the CPE data
* @throws IndexException thrown if there is an issue creating the index
*/
private void buildIndex(CveDB cve) throws IndexException {
Analyzer analyzer = null;
IndexWriter indexWriter = null;
try {
analyzer = createIndexingAnalyzer();
final IndexWriterConfig conf = new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer);
indexWriter = new IndexWriter(index, conf);
final ResultSet rs = cve.getVendorProductList();
if (rs == null) {
throw new IndexException("No data exists");
}
try {
while (rs.next()) {
saveEntry(rs.getString(1), rs.getString(2), indexWriter);
}
} catch (SQLException ex) {
Logger.getLogger(CpeMemoryIndex.class.getName()).log(Level.FINE, null, ex);
throw new IndexException("Error reading CPE data", ex);
}
} catch (CorruptIndexException ex) {
throw new IndexException("Unable to close an in-memory index", ex);
} catch (IOException ex) {
throw new IndexException("Unable to close an in-memory index", ex);
} finally {
if (indexWriter != null) {
try {
try {
indexWriter.commit();
} finally {
indexWriter.close(true);
}
} catch (CorruptIndexException ex) {
throw new IndexException("Unable to close an in-memory index", ex);
} catch (IOException ex) {
throw new IndexException("Unable to close an in-memory index", ex);
}
if (analyzer != null) {
analyzer.close();
}
}
}
}
/**
* Resets the searching analyzers
*/
private void resetSearchingAnalyzer() {
if (productSearchFieldAnalyzer != null) {
productSearchFieldAnalyzer.clear();
}
if (vendorSearchFieldAnalyzer != null) {
vendorSearchFieldAnalyzer.clear();
}
}
/**
* Searches the index using the given search string.
*
* @param searchString the query text
* @param maxQueryResults the maximum number of documents to return
* @return the TopDocs found by the search
* @throws ParseException thrown when the searchString is invalid
* @throws IOException is thrown if there is an issue with the underlying
* Index
*/
public TopDocs search(String searchString, int maxQueryResults) throws ParseException, IOException {
if (searchString == null || searchString.trim().isEmpty()) {
throw new ParseException("Query is null or empty");
}
final Query query = queryParser.parse(searchString);
return indexSearcher.search(query, maxQueryResults);
}
/**
* Searches the index using the given query.
*
* @param query the query used to search the index
* @param maxQueryResults the max number of results to return
* @return the TopDocs found be the query
* @throws CorruptIndexException thrown if the Index is corrupt
* @throws IOException thrown if there is an IOException
*/
public TopDocs search(Query query, int maxQueryResults) throws CorruptIndexException, IOException {
resetSearchingAnalyzer();
return indexSearcher.search(query, maxQueryResults);
}
/**
* Retrieves a document from the Index.
*
* @param documentId the id of the document to retrieve
* @return the Document
* @throws IOException thrown if there is an IOException
*/
public Document getDocument(int documentId) throws IOException {
return indexSearcher.doc(documentId);
}
/**
* Returns the number of CPE entries stored in the index.
*
* @return the number of CPE entries stored in the index
*/
public int numDocs() {
if (indexReader == null) {
return -1;
}
return indexReader.numDocs();
}
}

View File

@@ -16,36 +16,52 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import org.owasp.dependencycheck.data.UpdateException;
package org.owasp.dependencycheck.data.cpe;
/**
* An interface defining an update task.
* An exception thrown when the there is an issue using the in-memory CPE Index.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public interface UpdateTask {
public class IndexException extends Exception {
/**
* <p>Updates the data store to the latest version.</p>
*
* @throws UpdateException is thrown if there is an error updating the
* database
* The serial version UID for serialization.
*/
void update() throws UpdateException;
private static final long serialVersionUID = 1L;
/**
* Get the value of deleteAndRecreate.
*
* @return the value of deleteAndRecreate
* Creates a new IndexException.
*/
boolean shouldDeleteAndRecreate();
public IndexException() {
super();
}
/**
* Gets whether or not an update is needed.
* Creates a new IndexException.
*
* @return true or false depending on whether an update is needed
* @param msg a message for the exception.
*/
boolean isUpdateNeeded();
public IndexException(String msg) {
super(msg);
}
/**
* Creates a new IndexException.
*
* @param ex the cause of the failure.
*/
public IndexException(Throwable ex) {
super(ex);
}
/**
* Creates a new IndexException.
*
* @param msg a message for the exception.
* @param ex the cause of the failure.
*/
public IndexException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -18,6 +18,8 @@
*/
package org.owasp.dependencycheck.data.lucene;
import org.apache.lucene.util.Version;
/**
* <p>Lucene utils is a set of utilize written to make constructing Lucene
* queries simpler.</p>
@@ -26,6 +28,12 @@ package org.owasp.dependencycheck.data.lucene;
*/
public final class LuceneUtils {
/**
* The current version of Lucene being used. Declaring this one place so an
* upgrade doesn't require hunting through the code base.
*/
public static final Version CURRENT_VERSION = Version.LUCENE_45;
/**
* Private constructor as this is a utility class.
*/

View File

@@ -18,14 +18,7 @@
*/
package org.owasp.dependencycheck.data.nvdcve;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -36,84 +29,72 @@ import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.data.BaseDB;
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.DependencyVersion;
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
import org.owasp.dependencycheck.utils.Settings;
/**
* The database holding information about the NVD CVE data.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class CveDB {
public class CveDB extends BaseDB {
/**
* Resource location for SQL file used to create the database schema.
*/
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
/**
* The version of the current DB Schema.
*/
public static final String DB_SCHEMA_VERSION = "2.6";
/**
* Database connection
*/
private Connection conn;
//<editor-fold defaultstate="collapsed" desc="Constants to create, maintain, and retrieve data from the CVE Database">
/**
* SQL Statement to delete references by vulnerability ID.
*/
public static final String DELETE_REFERENCE = "DELETE FROM reference WHERE cveid = ?";
private static final String DELETE_REFERENCE = "DELETE FROM reference WHERE cveid = ?";
/**
* SQL Statement to delete software by vulnerability ID.
*/
public static final String DELETE_SOFTWARE = "DELETE FROM software WHERE cveid = ?";
private static final String DELETE_SOFTWARE = "DELETE FROM software WHERE cveid = ?";
/**
* SQL Statement to delete a vulnerability by CVE.
*/
public static final String DELETE_VULNERABILITY = "DELETE FROM vulnerability WHERE cve = ?";
private static final String DELETE_VULNERABILITY = "DELETE FROM vulnerability WHERE id = ?";
/**
* SQL Statement to cleanup orphan entries. Yes, the db schema could be a
* little tighter, but what we have works well to keep the data file size
* down a bit.
*/
public static final String CLEANUP_ORPHANS = "DELETE FROM CpeEntry WHERE id not in (SELECT CPEEntryId FROM Software); ";
private static final String CLEANUP_ORPHANS = "DELETE FROM CpeEntry WHERE id not in (SELECT CPEEntryId FROM Software); ";
/**
* SQL Statement to insert a new reference.
*/
public static final String INSERT_REFERENCE = "INSERT INTO reference (cveid, name, url, source) VALUES (?, ?, ?, ?)";
private static final String INSERT_REFERENCE = "INSERT INTO reference (cveid, name, url, source) VALUES (?, ?, ?, ?)";
/**
* SQL Statement to insert a new software.
*/
public static final String INSERT_SOFTWARE = "INSERT INTO software (cveid, cpeEntryId, previousVersion) VALUES (?, ?, ?)";
private static final String INSERT_SOFTWARE = "INSERT INTO software (cveid, cpeEntryId, previousVersion) VALUES (?, ?, ?)";
/**
* SQL Statement to insert a new cpe.
*/
public static final String INSERT_CPE = "INSERT INTO cpeEntry (cpe, vendor, product) VALUES (?, ?, ?)";
private static final String INSERT_CPE = "INSERT INTO cpeEntry (cpe, vendor, product) VALUES (?, ?, ?)";
/**
* SQL Statement to get a CPEProductID.
*/
public static final String SELECT_CPE_ID = "SELECT id FROM cpeEntry WHERE cpe = ?";
private static final String SELECT_CPE_ID = "SELECT id FROM cpeEntry WHERE cpe = ?";
/**
* SQL Statement to insert a new vulnerability.
*/
public static final String INSERT_VULNERABILITY = "INSERT INTO vulnerability (cve, description, cwe, cvssScore, cvssAccessVector, "
private static final String INSERT_VULNERABILITY = "INSERT INTO vulnerability (cve, description, cwe, cvssScore, cvssAccessVector, "
+ "cvssAccessComplexity, cvssAuthentication, cvssConfidentialityImpact, cvssIntegrityImpact, cvssAvailabilityImpact) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
/**
* SQL Statement to update a vulnerability.
*/
public static final String UPDATE_VULNERABILITY = "UPDATE vulnerability SET description=?, cwe=?, cvssScore=?, cvssAccessVector=?, "
private static final String UPDATE_VULNERABILITY = "UPDATE vulnerability SET description=?, cwe=?, cvssScore=?, cvssAccessVector=?, "
+ "cvssAccessComplexity=?, cvssAuthentication=?, cvssConfidentialityImpact=?, cvssIntegrityImpact=?, cvssAvailabilityImpact=? "
+ "WHERE id=?";
/**
* SQL Statement to find CVE entries based on CPE data.
*/
public static final String SELECT_CVE_FROM_SOFTWARE = "SELECT cve, cpe, previousVersion "
private static final String SELECT_CVE_FROM_SOFTWARE = "SELECT cve, cpe, previousVersion "
+ "FROM software INNER JOIN vulnerability ON vulnerability.id = software.cveId "
+ "INNER JOIN cpeEntry ON cpeEntry.id = software.cpeEntryId "
+ "WHERE vendor = ? AND product = ?";
@@ -123,15 +104,19 @@ public class CveDB {
/**
* SQL Statement to find the CPE entry based on the vendor and product.
*/
public static final String SELECT_CPE_ENTRIES = "SELECT cpe FROM cpeEntry WHERE vendor = ? AND product = ?";
private static final String SELECT_CPE_ENTRIES = "SELECT cpe FROM cpeEntry WHERE vendor = ? AND product = ?";
/**
* SQL Statement to select references by CVEID.
*/
public static final String SELECT_REFERENCE = "SELECT source, name, url FROM reference WHERE cveid = ?";
private static final String SELECT_REFERENCE = "SELECT source, name, url FROM reference WHERE cveid = ?";
/**
* SQL Statement to select vendor and product for lucene index.
*/
private static final String SELECT_VENDOR_PRODUCT_LIST = "SELECT vendor, product FROM cpeEntry GROUP BY vendor, product";
/**
* SQL Statement to select software by CVEID.
*/
public static final String SELECT_SOFTWARE = "SELECT cpe, previousVersion "
private static final String SELECT_SOFTWARE = "SELECT cpe, previousVersion "
+ "FROM software INNER JOIN cpeEntry ON software.cpeEntryId = cpeEntry.id WHERE cveid = ?";
// public static final String SELECT_SOFTWARE = "SELECT part, vendor, product, version, revision, previousVersion "
// + "FROM software INNER JOIN cpeProduct ON cpeProduct.id = software.cpeProductId LEFT JOIN cpeVersion ON "
@@ -139,80 +124,14 @@ public class CveDB {
/**
* SQL Statement to select a vulnerability by CVEID.
*/
public static final String SELECT_VULNERABILITY = "SELECT id, description, cwe, cvssScore, cvssAccessVector, cvssAccessComplexity, "
private static final String SELECT_VULNERABILITY = "SELECT id, description, cwe, cvssScore, cvssAccessVector, cvssAccessComplexity, "
+ "cvssAuthentication, cvssConfidentialityImpact, cvssIntegrityImpact, cvssAvailabilityImpact FROM vulnerability WHERE cve = ?";
/**
* SQL Statement to select a vulnerability's primary key.
*/
public static final String SELECT_VULNERABILITY_ID = "SELECT id FROM vulnerability WHERE cve = ?";
private static final String SELECT_VULNERABILITY_ID = "SELECT id FROM vulnerability WHERE cve = ?";
//</editor-fold>
/**
* Opens the database connection. If the database does not exist, it will
* create a new one.
*
* @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
*/
@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();
final File f = new File(fileName, "cve." + DB_SCHEMA_VERSION);
final File check = new File(f.getAbsolutePath() + ".h2.db");
final boolean createTables = !check.exists();
final String connStr = String.format("jdbc:h2:file:%s;AUTO_SERVER=TRUE", f.getAbsolutePath());
Class.forName("org.h2.Driver");
conn = DriverManager.getConnection(connStr, "sa", "");
if (createTables) {
createTables();
}
}
/**
* Commits all completed transactions.
*
* @throws SQLException thrown if a SQL Exception occurs
*/
public void commit() throws SQLException {
if (conn != null) {
conn.commit();
}
}
/**
* Cleans up the object and ensures that "close" has been called.
*
* @throws Throwable thrown if there is a problem
*/
@Override
protected void finalize() throws Throwable {
close();
super.finalize(); //not necessary if extending Object.
}
/**
* Closes the DB4O database. Close should be called on this object when it
* is done being used.
*/
public void close() {
if (conn != null) {
try {
conn.close();
} catch (SQLException 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;
}
}
/**
* Searches the CPE entries in the database and retrieves all entries for a
* given vendor and product combination. The returned list will include all
@@ -228,7 +147,7 @@ public class CveDB {
ResultSet rs = null;
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(SELECT_CPE_ENTRIES);
ps = getConnection().prepareStatement(SELECT_CPE_ENTRIES);
ps.setString(1, vendor);
ps.setString(2, product);
rs = ps.executeQuery();
@@ -247,6 +166,22 @@ public class CveDB {
return cpe;
}
/**
* Returns the entire list of vendor/product combinations.
*
* @return the entire list of vendor/product combinations.
*/
public ResultSet getVendorProductList() {
ResultSet rs = null;
try {
final PreparedStatement ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
rs = ps.executeQuery();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
} // can't close the statement in the PS as the resultset is returned, closing PS would close the resultset
return rs;
}
/**
* Retrieves the vulnerabilities associated with the specified CPE.
*
@@ -268,7 +203,7 @@ public class CveDB {
PreparedStatement ps;
final HashSet<String> cveEntries = new HashSet<String>();
try {
ps = conn.prepareStatement(SELECT_CVE_FROM_SOFTWARE);
ps = getConnection().prepareStatement(SELECT_CVE_FROM_SOFTWARE);
ps.setString(1, cpe.getVendor());
ps.setString(2, cpe.getProduct());
rs = ps.executeQuery();
@@ -311,7 +246,7 @@ public class CveDB {
ResultSet rsS = null;
Vulnerability vuln = null;
try {
psV = conn.prepareStatement(SELECT_VULNERABILITY);
psV = getConnection().prepareStatement(SELECT_VULNERABILITY);
psV.setString(1, cve);
rsV = psV.executeQuery();
if (rsV.next()) {
@@ -335,13 +270,13 @@ public class CveDB {
vuln.setCvssIntegrityImpact(rsV.getString(9));
vuln.setCvssAvailabilityImpact(rsV.getString(10));
psR = conn.prepareStatement(SELECT_REFERENCE);
psR = getConnection().prepareStatement(SELECT_REFERENCE);
psR.setInt(1, cveId);
rsR = psR.executeQuery();
while (rsR.next()) {
vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
}
psS = conn.prepareStatement(SELECT_SOFTWARE);
psS = getConnection().prepareStatement(SELECT_SOFTWARE);
psS.setInt(1, cveId);
rsS = psS.executeQuery();
while (rsS.next()) {
@@ -376,6 +311,7 @@ public class CveDB {
*/
public void updateVulnerability(Vulnerability vuln) throws DatabaseException {
PreparedStatement selectVulnerabilityId = null;
PreparedStatement deleteVulnerability = null;
PreparedStatement deleteReferences = null;
PreparedStatement deleteSoftware = null;
PreparedStatement updateVulnerability = null;
@@ -386,15 +322,16 @@ public class CveDB {
PreparedStatement insertSoftware = null;
try {
selectVulnerabilityId = conn.prepareStatement(SELECT_VULNERABILITY_ID);
deleteReferences = conn.prepareStatement(DELETE_REFERENCE);
deleteSoftware = conn.prepareStatement(DELETE_SOFTWARE);
updateVulnerability = conn.prepareStatement(UPDATE_VULNERABILITY);
insertVulnerability = conn.prepareStatement(INSERT_VULNERABILITY, Statement.RETURN_GENERATED_KEYS);
insertReference = conn.prepareStatement(INSERT_REFERENCE);
selectCpeId = conn.prepareStatement(SELECT_CPE_ID);
insertCpe = conn.prepareStatement(INSERT_CPE, Statement.RETURN_GENERATED_KEYS);
insertSoftware = conn.prepareStatement(INSERT_SOFTWARE);
selectVulnerabilityId = getConnection().prepareStatement(SELECT_VULNERABILITY_ID);
deleteVulnerability = getConnection().prepareStatement(DELETE_VULNERABILITY);
deleteReferences = getConnection().prepareStatement(DELETE_REFERENCE);
deleteSoftware = getConnection().prepareStatement(DELETE_SOFTWARE);
updateVulnerability = getConnection().prepareStatement(UPDATE_VULNERABILITY);
insertVulnerability = getConnection().prepareStatement(INSERT_VULNERABILITY, Statement.RETURN_GENERATED_KEYS);
insertReference = getConnection().prepareStatement(INSERT_REFERENCE);
selectCpeId = getConnection().prepareStatement(SELECT_CPE_ID);
insertCpe = getConnection().prepareStatement(INSERT_CPE, Statement.RETURN_GENERATED_KEYS);
insertSoftware = getConnection().prepareStatement(INSERT_SOFTWARE);
int vulnerabilityId = 0;
selectVulnerabilityId.setString(1, vuln.getName());
ResultSet rs = selectVulnerabilityId.executeQuery();
@@ -409,17 +346,22 @@ public class CveDB {
closeResultSet(rs);
rs = null;
if (vulnerabilityId != 0) {
updateVulnerability.setString(1, vuln.getDescription());
updateVulnerability.setString(2, vuln.getCwe());
updateVulnerability.setFloat(3, vuln.getCvssScore());
updateVulnerability.setString(4, vuln.getCvssAccessVector());
updateVulnerability.setString(5, vuln.getCvssAccessComplexity());
updateVulnerability.setString(6, vuln.getCvssAuthentication());
updateVulnerability.setString(7, vuln.getCvssConfidentialityImpact());
updateVulnerability.setString(8, vuln.getCvssIntegrityImpact());
updateVulnerability.setString(9, vuln.getCvssAvailabilityImpact());
updateVulnerability.setInt(10, vulnerabilityId);
updateVulnerability.executeUpdate();
if (vuln.getDescription().contains("** REJECT **")) {
deleteVulnerability.setInt(1, vulnerabilityId);
deleteVulnerability.executeUpdate();
} else {
updateVulnerability.setString(1, vuln.getDescription());
updateVulnerability.setString(2, vuln.getCwe());
updateVulnerability.setFloat(3, vuln.getCvssScore());
updateVulnerability.setString(4, vuln.getCvssAccessVector());
updateVulnerability.setString(5, vuln.getCvssAccessComplexity());
updateVulnerability.setString(6, vuln.getCvssAuthentication());
updateVulnerability.setString(7, vuln.getCvssConfidentialityImpact());
updateVulnerability.setString(8, vuln.getCvssIntegrityImpact());
updateVulnerability.setString(9, vuln.getCvssAvailabilityImpact());
updateVulnerability.setInt(10, vulnerabilityId);
updateVulnerability.executeUpdate();
}
} else {
insertVulnerability.setString(1, vuln.getName());
insertVulnerability.setString(2, vuln.getDescription());
@@ -496,6 +438,7 @@ public class CveDB {
closeStatement(deleteReferences);
closeStatement(deleteSoftware);
closeStatement(updateVulnerability);
closeStatement(deleteVulnerability);
closeStatement(insertVulnerability);
closeStatement(insertReference);
closeStatement(selectCpeId);
@@ -504,23 +447,6 @@ public class CveDB {
}
}
/**
* Retrieves the directory that the JAR file exists in so that we can ensure
* we always use a common data directory.
*
* @return the data directory for this index.
* @throws IOException is thrown if an IOException occurs of course...
*/
public static File getDataDirectory() throws IOException {
final File path = Settings.getFile(Settings.KEYS.CVE_DATA_DIRECTORY);
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create NVD CVE Data directory");
}
}
return path;
}
/**
* It is possible that orphaned rows may be generated during database
* updates. This should be called after all updates have been completed to
@@ -529,7 +455,7 @@ public class CveDB {
public void cleanupDatabase() {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(CLEANUP_ORPHANS);
ps = getConnection().prepareStatement(CLEANUP_ORPHANS);
if (ps != null) {
ps.executeUpdate();
}
@@ -540,102 +466,6 @@ public class CveDB {
}
}
/**
* Creates the database structure (tables and indexes) to store the CVE data
*
* @throws SQLException thrown if there is a sql exception
* @throws DatabaseException thrown if there is a database exception
*/
protected void createTables() throws SQLException, DatabaseException {
InputStream is;
InputStreamReader reader;
BufferedReader in = null;
try {
is = this.getClass().getClassLoader().getResourceAsStream(DB_STRUCTURE_RESOURCE);
reader = new InputStreamReader(is, "UTF-8");
in = new BufferedReader(reader);
final StringBuilder sb = new StringBuilder(2110);
String tmp;
while ((tmp = in.readLine()) != null) {
sb.append(tmp);
}
Statement statement = null;
try {
statement = conn.createStatement();
statement.execute(sb.toString());
} finally {
closeStatement(statement);
}
} catch (IOException ex) {
throw new DatabaseException("Unable to create database schema", ex);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, null, ex);
}
}
}
}
/**
* Closes the given statement object ignoring any exceptions that occur.
*
* @param statement a Statement object
*/
private void closeStatement(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, statement.toString(), ex);
}
}
}
/**
* Closes the result set capturing and ignoring any SQLExceptions that
* occur.
*
* @param rs a ResultSet to close
*/
private void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
Logger.getLogger(CveDB.class
.getName()).log(Level.FINEST, rs.toString(), ex);
}
}
}
/**
* Returns the generated integer primary key for a newly inserted row.
*
* @param statement a prepared statement that just executed an insert
* @return a primary key
* @throws DatabaseException thrown if there is an exception obtaining the
* key
*/
private int getGeneratedKey(PreparedStatement statement) throws DatabaseException {
ResultSet rs = null;
int id = 0;
try {
rs = statement.getGeneratedKeys();
rs.next();
id = rs.getInt(1);
} catch (SQLException ex) {
throw new DatabaseException("Unable to get primary key for inserted row");
} finally {
closeResultSet(rs);
}
return id;
}
/**
* Determines if the given identifiedVersion is affected by the given cpeId
* and previous version flag. A non-null, non-empty string passed to the

View File

@@ -39,13 +39,22 @@ public class DatabaseException extends Exception {
super(msg);
}
/**
* Creates an DatabaseException.
*
* @param ex the cause of the exception
*/
public DatabaseException(Throwable ex) {
super(ex);
}
/**
* Creates an DatabaseException.
*
* @param msg the exception message
* @param ex the cause of the exception
*/
public DatabaseException(String msg, Exception ex) {
public DatabaseException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -24,7 +24,6 @@ import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.index.CorruptIndexException;
import org.owasp.dependencycheck.data.cpe.CpeIndexWriter;
import org.owasp.dependencycheck.dependency.Reference;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
@@ -208,6 +207,9 @@ public class NvdCve20Handler extends DefaultHandler {
nodeText = null;
} else if (current.isVulnSummaryNode()) {
vulnerability.setDescription(nodeText.toString());
if (nodeText.indexOf("** REJECT **") >= 0) {
hasApplicationCpe = true; //ensure we process this to delete the vuln
}
nodeText = null;
}
}
@@ -260,26 +262,8 @@ public class NvdCve20Handler extends DefaultHandler {
vuln.updateVulnerableSoftware(vs);
}
}
for (VulnerableSoftware vs : vuln.getVulnerableSoftware()) {
if (cpeIndex != null) {
cpeIndex.saveEntry(vs);
}
}
cveDB.updateVulnerability(vuln);
}
/**
* the cpe index.
*/
private CpeIndexWriter cpeIndex;
/**
* Sets the cpe index writer.
*
* @param index the CPE Lucene Index
*/
public void setCpeIndex(CpeIndexWriter index) {
cpeIndex = index;
}
// <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
/**

View File

@@ -1,288 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.data.cpe.CpeIndexWriter;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.nvdcve.NvdCve12Handler;
import org.owasp.dependencycheck.data.nvdcve.NvdCve20Handler;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.xml.sax.SAXException;
/**
* Class responsible for updating the CPE and NVDCVE data stores.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public abstract class AbstractUpdateTask implements UpdateTask {
/**
* Initializes the AbstractUpdateTask.
*
* @param properties information about the data store
* @throws MalformedURLException thrown if the configuration contains a
* malformed url
* @throws DownloadFailedException thrown if the timestamp on a file cannot
* be checked
* @throws UpdateException thrown if the update fails
*/
public AbstractUpdateTask(DataStoreMetaInfo properties) throws MalformedURLException, DownloadFailedException, UpdateException {
this.properties = properties;
this.updateable = updatesNeeded();
}
/**
* A collection of updateable NVD CVE items.
*/
private Updateable updateable;
/**
* Utility to read and write meta-data about the data.
*/
private DataStoreMetaInfo properties = null;
/**
* Returns the data store properties.
*
* @return the data store properties
*/
protected DataStoreMetaInfo getProperties() {
return properties;
}
/**
* Reference to the Cve Database.
*/
private CveDB cveDB = null;
/**
* Returns the CveDB.
*
* @return the CveDB
*/
protected CveDB getCveDB() {
return cveDB;
}
/**
* Reference to the Cpe Index.
*/
private CpeIndexWriter cpeIndex = null;
/**
* Returns the CpeIndex.
*
* @return the CpeIndex
*/
protected CpeIndexWriter getCpeIndex() {
return cpeIndex;
}
/**
* Gets whether or not an update is needed.
*
* @return true or false depending on whether an update is needed
*/
public boolean isUpdateNeeded() {
return updateable.isUpdateNeeded();
}
/**
* Gets the updateable NVD CVE Entries.
*
* @return an Updateable object containing the NVD CVE entries
*/
protected Updateable getUpdateable() {
return updateable;
}
/**
* Determines if the index needs to be updated.
*
* @return a collection of updateable resources.
* @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
* data is incorrect.
* @throws DownloadFailedException is thrown if there is an error.
* downloading the NVD CVE download data file.
* @throws UpdateException Is thrown if there is an issue with the last
* updated properties file.
*/
protected abstract Updateable updatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException;
/**
* <p>Updates the data store to the latest version.</p>
*
* @throws UpdateException is thrown if there is an error updating the
* database
*/
public abstract void update() throws UpdateException;
/**
* A flag indicating whether or not the current data store should be
* deleted.
*/
private boolean deleteAndRecreate = false;
/**
* Get the value of deleteAndRecreate.
*
* @return the value of deleteAndRecreate
*/
public boolean shouldDeleteAndRecreate() {
return deleteAndRecreate;
}
/**
* Set the value of deleteAndRecreate.
*
* @param deleteAndRecreate new value of deleteAndRecreate
*/
protected void setDeleteAndRecreate(boolean deleteAndRecreate) {
this.deleteAndRecreate = deleteAndRecreate;
}
/**
* Deletes the existing data directories.
*
* @throws IOException thrown if the directory cannot be deleted
*/
protected void deleteExistingData() throws IOException {
File data = Settings.getFile(Settings.KEYS.CVE_DATA_DIRECTORY);
if (data.exists()) {
FileUtils.delete(data);
}
data = Settings.getFile(Settings.KEYS.CPE_DATA_DIRECTORY);
if (data.exists()) {
FileUtils.delete(data);
}
data = DataStoreMetaInfo.getPropertiesFile();
if (data.exists()) {
FileUtils.delete(data);
}
}
/**
* Closes the CVE and CPE data stores.
*/
protected void closeDataStores() {
if (cveDB != null) {
try {
cveDB.close();
} catch (Exception ignore) {
Logger.getLogger(AbstractUpdateTask.class.getName()).log(Level.FINEST, "Error closing the cveDB", ignore);
}
}
if (cpeIndex != null) {
try {
cpeIndex.close();
} catch (Exception ignore) {
Logger.getLogger(AbstractUpdateTask.class.getName()).log(Level.FINEST, "Error closing the cpeIndex", ignore);
}
}
}
/**
* Opens the CVE and CPE data stores.
*
* @throws UpdateException thrown if a data store cannot be opened
*/
protected void openDataStores() throws UpdateException {
//open the cve and cpe data stores
try {
cveDB = new CveDB();
cveDB.open();
cpeIndex = new CpeIndexWriter();
cpeIndex.open();
} catch (IOException ex) {
closeDataStores();
Logger.getLogger(AbstractUpdateTask.class.getName()).log(Level.FINE, "IO Error opening databases", ex);
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
} catch (SQLException ex) {
closeDataStores();
Logger.getLogger(AbstractUpdateTask.class.getName()).log(Level.FINE, "SQL Exception opening databases", ex);
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
} catch (DatabaseException ex) {
closeDataStores();
Logger.getLogger(AbstractUpdateTask.class.getName()).log(Level.FINE, "Database Exception opening databases", ex);
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
} catch (ClassNotFoundException ex) {
closeDataStores();
Logger.getLogger(AbstractUpdateTask.class.getName()).log(Level.FINE, "Class not found exception opening databases", ex);
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
}
}
/**
* Determines if the epoch date is within the range specified of the
* compareTo epoch time. This takes the (compareTo-date)/1000/60/60/24 to
* get the number of days. If the calculated days is less then the range the
* date is considered valid.
*
* @param date the date to be checked.
* @param compareTo the date to compare to.
* @param range the range in days to be considered valid.
* @return whether or not the date is within the range.
*/
protected boolean withinRange(long date, long compareTo, int range) {
final double differenceInDays = (compareTo - date) / 1000.0 / 60.0 / 60.0 / 24.0;
return differenceInDays < range;
}
/**
* Imports the NVD CVE XML File into the Lucene Index.
*
* @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 IOException is thrown if there is a IO Exception
* @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
*/
protected void importXML(File file, File oldVersion)
throws ParserConfigurationException, SAXException, IOException, SQLException, DatabaseException, ClassNotFoundException {
final SAXParserFactory factory = SAXParserFactory.newInstance();
final SAXParser saxParser = factory.newSAXParser();
final NvdCve12Handler cve12Handler = new NvdCve12Handler();
saxParser.parse(oldVersion, cve12Handler);
final Map<String, List<VulnerableSoftware>> prevVersionVulnMap = cve12Handler.getVulnerabilities();
final NvdCve20Handler cve20Handler = new NvdCve20Handler();
cve20Handler.setCveDB(cveDB);
cve20Handler.setPrevVersionVulnMap(prevVersionVulnMap);
cve20Handler.setCpeIndex(cpeIndex);
saxParser.parse(file, cve20Handler);
}
}

View File

@@ -1,270 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import org.owasp.dependencycheck.data.nvdcve.InvalidDataException;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import static org.owasp.dependencycheck.data.update.DataStoreMetaInfo.BATCH;
import static org.owasp.dependencycheck.data.update.DataStoreMetaInfo.MODIFIED;
/**
* Class responsible for updating the CPE and NVDCVE data stores.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class BatchUpdateTask extends AbstractUpdateTask {
/**
* Constructs a new BatchUpdateTask.
*
* @param properties information about the data store
* @throws MalformedURLException thrown if a configured URL is malformed
* @throws DownloadFailedException thrown if a timestamp cannot be checked
* on a configured URL
* @throws UpdateException thrown if there is an exception generating the
* update task
*/
public BatchUpdateTask(DataStoreMetaInfo properties) throws MalformedURLException, DownloadFailedException, UpdateException {
super(properties);
}
/**
* A flag indicating whether or not the batch update should be performed.
*/
private boolean doBatchUpdate;
/**
* Get the value of doBatchUpdate
*
* @return the value of doBatchUpdate
*/
protected boolean isDoBatchUpdate() {
return doBatchUpdate;
}
/**
* Set the value of doBatchUpdate
*
* @param doBatchUpdate new value of doBatchUpdate
*/
protected void setDoBatchUpdate(boolean doBatchUpdate) {
this.doBatchUpdate = doBatchUpdate;
}
/**
* <p>Downloads the latest NVD CVE XML file from the web and imports it into
* the current CVE Database.</p>
*
* @throws UpdateException is thrown if there is an error updating the
* database
*/
@Override
public void update() throws UpdateException {
if (getProperties().isBatchUpdateMode() && doBatchUpdate) {
final String batchSrc = Settings.getString(Settings.KEYS.BATCH_UPDATE_URL);
File tmp = null;
try {
deleteExistingData();
final File dataDirectory = CveDB.getDataDirectory().getParentFile();
final URL batchUrl = new URL(batchSrc);
if ("file".equals(batchUrl.getProtocol())) {
try {
tmp = new File(batchUrl.toURI());
} catch (URISyntaxException ex) {
final String msg = String.format("Invalid batch update URI: %s", batchSrc);
throw new UpdateException(msg, ex);
}
} else if ("http".equals(batchUrl.getProtocol())
|| "https".equals(batchUrl.getProtocol())) {
tmp = File.createTempFile("batch_", ".zip");
Downloader.fetchFile(batchUrl, tmp);
}
//TODO add FTP?
FileUtils.extractFiles(tmp, dataDirectory);
} catch (IOException ex) {
final String msg = String.format("IO Exception Occured performing batch update using: %s", batchSrc);
throw new UpdateException(msg, ex);
} finally {
if (tmp != null && !tmp.delete()) {
tmp.deleteOnExit();
}
}
}
}
/**
* Determines if the index needs to be updated. This is done by fetching the
* NVD CVE meta data and checking the last update date. If the data needs to
* be refreshed this method will return the NvdCveUrl for the files that
* need to be updated.
*
* @return the collection of files that need to be updated
* @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
* data is incorrect
* @throws DownloadFailedException is thrown if there is an error.
* downloading the NVD CVE download data file
* @throws UpdateException Is thrown if there is an issue with the last
* updated properties file
*/
@Override
public Updateable updatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
Updateable updates = null;
try {
updates = retrieveCurrentTimestampsFromWeb();
} catch (InvalidDataException ex) {
final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
Logger.getLogger(BatchUpdateTask.class.getName()).log(Level.FINE, msg, ex);
throw new DownloadFailedException(msg, ex);
} catch (InvalidSettingException ex) {
Logger.getLogger(BatchUpdateTask.class.getName()).log(Level.FINE, "Invalid setting found when retrieving timestamps", ex);
throw new DownloadFailedException("Invalid settings", ex);
}
if (updates == null) {
throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
}
final DataStoreMetaInfo properties = getProperties();
if (!properties.isEmpty()) {
try {
boolean deleteAndRecreate = false;
float version;
if (properties.getProperty("version") == null) {
deleteAndRecreate = true;
} else {
try {
version = Float.parseFloat(properties.getProperty("version"));
final float currentVersion = Float.parseFloat(CveDB.DB_SCHEMA_VERSION);
if (currentVersion > version) {
deleteAndRecreate = true;
}
} catch (NumberFormatException ex) {
deleteAndRecreate = true;
}
}
final NvdCveInfo batchInfo = updates.get(BATCH);
if (properties.isBatchUpdateMode() && batchInfo != null) {
final long lastUpdated = Long.parseLong(properties.getProperty(DataStoreMetaInfo.BATCH, "0"));
if (lastUpdated != batchInfo.getTimestamp()) {
deleteAndRecreate = true;
}
}
if (deleteAndRecreate) {
setDoBatchUpdate(properties.isBatchUpdateMode());
try {
deleteExistingData();
} catch (IOException ex) {
final String msg = "Unable to delete existing data";
Logger.getLogger(BatchUpdateTask.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(BatchUpdateTask.class.getName()).log(Level.FINE, null, ex);
}
return updates;
}
final long lastUpdated = Long.parseLong(properties.getProperty(DataStoreMetaInfo.LAST_UPDATED, "0"));
final Date now = new Date();
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR, 2002);
final int end = Calendar.getInstance().get(Calendar.YEAR);
if (lastUpdated == updates.get(MODIFIED).getTimestamp()) {
updates.clear(); //we don't need to update anything.
setDoBatchUpdate(properties.isBatchUpdateMode());
} else if (withinRange(lastUpdated, now.getTime(), days)) {
updates.get(MODIFIED).setNeedsUpdate(true);
if (properties.isBatchUpdateMode()) {
setDoBatchUpdate(false);
} else {
for (int i = start; i <= end; i++) {
updates.get(String.valueOf(i)).setNeedsUpdate(false);
}
}
} else if (properties.isBatchUpdateMode()) {
updates.get(MODIFIED).setNeedsUpdate(true);
setDoBatchUpdate(true);
} else { //we figure out which of the several XML files need to be downloaded.
updates.get(MODIFIED).setNeedsUpdate(false);
for (int i = start; i <= end; i++) {
final NvdCveInfo cve = updates.get(String.valueOf(i));
long currentTimestamp = 0;
try {
currentTimestamp = Long.parseLong(properties.getProperty(DataStoreMetaInfo.LAST_UPDATED_BASE + String.valueOf(i), "0"));
} catch (NumberFormatException ex) {
final String msg = String.format("Error parsing '%s' '%s' from nvdcve.lastupdated",
DataStoreMetaInfo.LAST_UPDATED_BASE, String.valueOf(i));
Logger.getLogger(BatchUpdateTask.class.getName()).log(Level.FINE, msg, ex);
}
if (currentTimestamp == cve.getTimestamp()) {
cve.setNeedsUpdate(false); //they default to true.
}
}
}
} catch (NumberFormatException ex) {
final String msg = "An invalid schema version or timestamp exists in the data.properties file.";
Logger.getLogger(BatchUpdateTask.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(BatchUpdateTask.class.getName()).log(Level.FINE, null, ex);
setDoBatchUpdate(properties.isBatchUpdateMode());
}
}
return updates;
}
/**
* Retrieves the timestamps from the NVD CVE meta data file.
*
* @return the timestamp from the currently published nvdcve downloads page
* @throws MalformedURLException thrown if the URL for the NVD CCE Meta data
* is incorrect.
* @throws DownloadFailedException thrown if there is an error downloading
* the nvd cve meta data file
* @throws InvalidDataException thrown if there is an exception parsing the
* timestamps
* @throws InvalidSettingException thrown if the settings are invalid
*/
private Updateable retrieveCurrentTimestampsFromWeb()
throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
final Updateable updates = new Updateable();
updates.add(BATCH, Settings.getString(Settings.KEYS.BATCH_UPDATE_URL),
null, false);
final String url = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL, "");
if (!url.isEmpty()) {
updates.add(MODIFIED, url,
Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
false);
}
return updates;
}
}

View File

@@ -0,0 +1,179 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
/**
* A callable object to download two files.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class CallableDownloadTask implements Callable<CallableDownloadTask> {
/**
* Simple constructor for the callable download task.
*
* @param nvdCveInfo the nvd cve info
* @param first the first file
* @param second the second file
*/
public CallableDownloadTask(NvdCveInfo nvdCveInfo, File first, File second) {
this.nvdCveInfo = nvdCveInfo;
this.first = first;
this.second = second;
}
/**
* The NVD CVE Meta Data.
*/
private NvdCveInfo nvdCveInfo;
/**
* Get the value of nvdCveInfo.
*
* @return the value of nvdCveInfo
*/
public NvdCveInfo getNvdCveInfo() {
return nvdCveInfo;
}
/**
* Set the value of nvdCveInfo.
*
* @param nvdCveInfo new value of nvdCveInfo
*/
public void setNvdCveInfo(NvdCveInfo nvdCveInfo) {
this.nvdCveInfo = nvdCveInfo;
}
/**
* a file.
*/
private File first;
/**
* Get the value of first.
*
* @return the value of first
*/
public File getFirst() {
return first;
}
/**
* Set the value of first.
*
* @param first new value of first
*/
public void setFirst(File first) {
this.first = first;
}
/**
* a file.
*/
private File second;
/**
* Get the value of second.
*
* @return the value of second
*/
public File getSecond() {
return second;
}
/**
* Set the value of second.
*
* @param second new value of second
*/
public void setSecond(File second) {
this.second = second;
}
/**
* A placeholder for an exception.
*/
private Exception exception = null;
/**
* Get the value of exception.
*
* @return the value of exception
*/
public Exception getException() {
return exception;
}
/**
* returns whether or not an exception occurred during download.
*
* @return whether or not an exception occurred during download
*/
public boolean hasException() {
return exception != null;
}
@Override
public CallableDownloadTask call() throws Exception {
try {
final URL url1 = new URL(nvdCveInfo.getUrl());
final URL url2 = new URL(nvdCveInfo.getOldSchemaVersionUrl());
String msg = String.format("Download Started for NVD CVE - %s", nvdCveInfo.getId());
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.INFO, msg);
Downloader.fetchFile(url1, first);
Downloader.fetchFile(url2, second);
msg = String.format("Download Complete for NVD CVE - %s", nvdCveInfo.getId());
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.INFO, msg);
} catch (DownloadFailedException ex) {
this.exception = ex;
}
return this;
}
/**
* Attempts to delete the files that were downloaded.
*/
public void cleanup() {
boolean deleted = false;
try {
if (first != null && first.exists()) {
deleted = first.delete();
}
} finally {
if (first != null && (first.exists() || !deleted)) {
first.deleteOnExit();
}
}
try {
deleted = false;
if (second != null && second.exists()) {
deleted = second.delete();
}
} finally {
if (second != null && (second.exists() || !deleted)) {
second.deleteOnExit();
}
}
}
}

View File

@@ -234,7 +234,7 @@ public class DataStoreMetaInfo {
* @return the properties file
*/
public static File getPropertiesFile() {
final File dataDirectory = Settings.getFile(Settings.KEYS.DATA_DIRECTORY);
final File dataDirectory = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
final File file = new File(dataDirectory, UPDATE_PROPERTIES_FILE);
return file;
}

View File

@@ -24,9 +24,6 @@ import org.owasp.dependencycheck.data.CachedWebDataSource;
import java.net.MalformedURLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.concurrency.DirectoryLockException;
import org.owasp.dependencycheck.concurrency.DirectorySpinLock;
import org.owasp.dependencycheck.concurrency.InvalidDirectoryException;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.FileUtils;
@@ -48,24 +45,9 @@ public class DatabaseUpdater implements CachedWebDataSource {
*/
@Override
public void update() throws UpdateException {
final File dataDir = Settings.getFile(Settings.KEYS.DATA_DIRECTORY);
DirectorySpinLock lock = null;
try {
lock = new DirectorySpinLock(dataDir);
} catch (InvalidDirectoryException ex) {
throw new UpdateException("Unable to obtain lock on the data directory", ex);
} catch (DirectoryLockException ex) {
throw new UpdateException("Unable to obtain exclusive lock on the data directory", ex);
}
try {
lock.obtainSharedLock();
final UpdateTask task = UpdateTaskFactory.getUpdateTask();
final StandardUpdate task = new StandardUpdate();
if (task.isUpdateNeeded()) {
lock.release();
lock.obtainExclusiveLock();
if (task.shouldDeleteAndRecreate()) {
try {
deleteExistingData();
@@ -76,10 +58,6 @@ public class DatabaseUpdater implements CachedWebDataSource {
}
task.update();
}
} catch (DirectoryLockException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
"Unable to obtain lock on data directory, unable to update the data to use the most current data.");
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
} catch (MalformedURLException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
"NVD CVE properties files contain an invalid URL, unable to update the data to use the most current data.");
@@ -88,10 +66,6 @@ public class DatabaseUpdater implements CachedWebDataSource {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING,
"Unable to download the NVD CVE data, unable to update the data to use the most current data.");
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
} finally {
if (lock != null) {
lock.release();
}
}
}
@@ -101,11 +75,7 @@ public class DatabaseUpdater implements CachedWebDataSource {
* @throws IOException thrown if the directory cannot be deleted
*/
protected void deleteExistingData() throws IOException {
File data = Settings.getFile(Settings.KEYS.CVE_DATA_DIRECTORY);
if (data.exists()) {
FileUtils.delete(data);
}
data = Settings.getFile(Settings.KEYS.CPE_DATA_DIRECTORY);
File data = Settings.getDataFile(Settings.KEYS.CVE_DATA_DIRECTORY);
if (data.exists()) {
FileUtils.delete(data);
}

View File

@@ -0,0 +1,148 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.nvdcve.NvdCve12Handler;
import org.owasp.dependencycheck.data.nvdcve.NvdCve20Handler;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
import org.xml.sax.SAXException;
/**
* A callable task that will process a given set of NVD CVE xml files and update
* the Cve Database accordingly.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class ProcessTask implements Callable<ProcessTask> {
/**
* A field to store any update exceptions that occur during the "call".
*/
private UpdateException exception = null;
/**
* Get the value of exception.
*
* @return the value of exception
*/
public UpdateException getException() {
return exception;
}
/**
* Set the value of exception.
*
* @param exception new value of exception
*/
public void setException(UpdateException exception) {
this.exception = exception;
}
private final CveDB cveDB;
private final CallableDownloadTask filePair;
private final DataStoreMetaInfo properties;
public ProcessTask(final CveDB cveDB, final DataStoreMetaInfo properties, final CallableDownloadTask filePair) {
this.cveDB = cveDB;
this.filePair = filePair;
this.properties = properties;
}
@Override
public ProcessTask call() throws Exception {
try {
processFiles();
} catch (UpdateException ex) {
this.exception = ex;
}
return this;
}
/**
* Imports the NVD CVE XML File into the Lucene Index.
*
* @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 IOException is thrown if there is a IO Exception
* @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
*/
protected void importXML(File file, File oldVersion) throws ParserConfigurationException,
SAXException, IOException, SQLException, DatabaseException, ClassNotFoundException {
final SAXParserFactory factory = SAXParserFactory.newInstance();
final SAXParser saxParser = factory.newSAXParser();
final NvdCve12Handler cve12Handler = new NvdCve12Handler();
saxParser.parse(oldVersion, cve12Handler);
final Map<String, List<VulnerableSoftware>> prevVersionVulnMap = cve12Handler.getVulnerabilities();
final NvdCve20Handler cve20Handler = new NvdCve20Handler();
cve20Handler.setCveDB(cveDB);
cve20Handler.setPrevVersionVulnMap(prevVersionVulnMap);
saxParser.parse(file, cve20Handler);
}
private void processFiles() throws UpdateException {
String msg = String.format("Processing Started for NVD CVE - %s", filePair.getNvdCveInfo().getId());
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO, msg);
try {
importXML(filePair.getFirst(), filePair.getSecond());
cveDB.commit();
properties.save(filePair.getNvdCveInfo());
} catch (FileNotFoundException ex) {
throw new UpdateException(ex);
} catch (ParserConfigurationException ex) {
throw new UpdateException(ex);
} catch (SAXException ex) {
throw new UpdateException(ex);
} catch (IOException ex) {
throw new UpdateException(ex);
} catch (SQLException ex) {
throw new UpdateException(ex);
} catch (DatabaseException ex) {
throw new UpdateException(ex);
} catch (ClassNotFoundException ex) {
throw new UpdateException(ex);
} finally {
filePair.cleanup();
}
msg = String.format("Processing Complete for NVD CVE - %s", filePair.getNvdCveInfo().getId());
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO, msg);
}
}

View File

@@ -0,0 +1,557 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import org.owasp.dependencycheck.data.nvdcve.InvalidDataException;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import static org.owasp.dependencycheck.data.update.DataStoreMetaInfo.MODIFIED;
import org.owasp.dependencycheck.utils.FileUtils;
/**
* Class responsible for updating the NVDCVE data store.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class StandardUpdate {
/**
* The max thread pool size to use when downloading files.
*/
public static final int MAX_THREAD_POOL_SIZE = Settings.getInt(Settings.KEYS.MAX_DOWNLOAD_THREAD_POOL_SIZE, 3);
/**
* Information about the timestamps and URLs for data that needs to be
* updated.
*/
private DataStoreMetaInfo properties;
/**
* A collection of updateable NVD CVE items.
*/
private Updateable updateable;
/**
* A flag indicating whether or not the current data store should be
* deleted.
*/
private boolean deleteAndRecreate = false;
/**
* Reference to the Cve Database.
*/
private CveDB cveDB = null;
/**
* Gets whether or not an update is needed.
*
* @return true or false depending on whether an update is needed
*/
public boolean isUpdateNeeded() {
return updateable.isUpdateNeeded();
}
/**
* Set the value of deleteAndRecreate.
*
* @param deleteAndRecreate new value of deleteAndRecreate
*/
protected void setDeleteAndRecreate(boolean deleteAndRecreate) {
this.deleteAndRecreate = deleteAndRecreate;
}
/**
* Get the value of deleteAndRecreate.
*
* @return the value of deleteAndRecreate
*/
public boolean shouldDeleteAndRecreate() {
return deleteAndRecreate;
}
/**
* Constructs a new Standard Update Task.
*
* @throws MalformedURLException thrown if a configured URL is malformed
* @throws DownloadFailedException thrown if a timestamp cannot be checked
* on a configured URL
* @throws UpdateException thrown if there is an exception generating the
* update task
*/
public StandardUpdate() throws MalformedURLException, DownloadFailedException, UpdateException {
properties = new DataStoreMetaInfo();
updateable = updatesNeeded();
}
/**
* <p>Downloads the latest NVD CVE XML file from the web and imports it into
* the current CVE Database.</p>
*
* @throws UpdateException is thrown if there is an error updating the
* database
*/
public void update() throws UpdateException {
int maxUpdates = 0;
try {
for (NvdCveInfo cve : updateable) {
if (cve.getNeedsUpdate()) {
maxUpdates += 1;
}
}
if (maxUpdates <= 0) {
return;
}
if (maxUpdates > 3) {
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO,
"NVD CVE requires several updates; this could take a couple of minutes.");
}
if (maxUpdates > 0) {
openDataStores();
}
final int poolSize = (MAX_THREAD_POOL_SIZE > maxUpdates) ? MAX_THREAD_POOL_SIZE : maxUpdates;
final ExecutorService downloadExecutor = Executors.newFixedThreadPool(poolSize);
final ExecutorService processExecutor = Executors.newSingleThreadExecutor();
final Set<Future<CallableDownloadTask>> downloadFutures = new HashSet<Future<CallableDownloadTask>>(maxUpdates);
final Set<Future<ProcessTask>> processFutures = new HashSet<Future<ProcessTask>>(maxUpdates);
int ctr = 0;
for (NvdCveInfo cve : updateable) {
if (cve.getNeedsUpdate()) {
ctr += 1;
final File file1;
final File file2;
try {
file1 = File.createTempFile("cve" + cve.getId() + "_", ".xml");
file2 = File.createTempFile("cve_1_2_" + cve.getId() + "_", ".xml");
} catch (IOException ex) {
throw new UpdateException(ex);
}
final CallableDownloadTask call = new CallableDownloadTask(cve, file1, file2);
downloadFutures.add(downloadExecutor.submit(call));
boolean waitForFuture = ctr % 2 == 0;
final Iterator<Future<CallableDownloadTask>> itr = downloadFutures.iterator();
while (itr.hasNext()) {
final Future<CallableDownloadTask> future = itr.next();
if (waitForFuture) { //only allow two NVD/CVE files to be downloaded at a time
spinWaitForFuture(future);
}
if (future.isDone()) { //if we find something complete, add it to the process queue
try {
final CallableDownloadTask filePair = future.get();
itr.remove();
final ProcessTask task = new ProcessTask(cveDB, properties, filePair);
processFutures.add(processExecutor.submit(task));
} catch (InterruptedException ex) {
downloadExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted", ex);
throw new UpdateException(ex);
} catch (ExecutionException ex) {
downloadExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException(ex);
}
}
}
}
}
try {
final Iterator<Future<CallableDownloadTask>> itr = downloadFutures.iterator();
while (itr.hasNext()) {
final Future<CallableDownloadTask> future = itr.next();
final CallableDownloadTask filePair = future.get();
final ProcessTask task = new ProcessTask(cveDB, properties, filePair);
processFutures.add(processExecutor.submit(task));
}
} catch (InterruptedException ex) {
downloadExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during download", ex);
throw new UpdateException(ex);
} catch (ExecutionException ex) {
downloadExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Execution Exception during download", ex);
throw new UpdateException(ex);
} finally {
downloadExecutor.shutdown();
}
for (Future<ProcessTask> future : processFutures) {
try {
final ProcessTask task = future.get();
if (task.getException() != null) {
throw task.getException();
}
} catch (InterruptedException ex) {
processExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during processing", ex);
throw new UpdateException(ex);
} catch (ExecutionException ex) {
processExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Execution Exception during process", ex);
throw new UpdateException(ex);
} finally {
processExecutor.shutdown();
}
}
if (maxUpdates >= 1) { //ensure the modified file date gets written
properties.save(updateable.get(MODIFIED));
cveDB.cleanupDatabase();
}
} finally {
closeDataStores();
}
}
//<editor-fold defaultstate="collapsed" desc="OLD version of update() - not multithreaded">
/*
* TODO - remove this
public void update() throws UpdateException {
try {
int maxUpdates = 0;
for (NvdCveInfo cve : getUpdateable()) {
if (cve.getNeedsUpdate()) {
maxUpdates += 1;
}
}
if (maxUpdates > 3) {
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO,
"NVD CVE requires several updates; this could take a couple of minutes.");
}
if (maxUpdates > 0) {
openDataStores();
}
int count = 0;
for (NvdCveInfo cve : getUpdateable()) {
if (cve.getNeedsUpdate()) {
count += 1;
Logger.getLogger(StandardUpdate.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(StandardUpdate.class.getName()).log(Level.INFO,
"Downloading {0}", cve.getUrl());
outputPath = File.createTempFile("cve" + cve.getId() + "_", ".xml");
Downloader.fetchFile(url, outputPath);
url = new URL(cve.getOldSchemaVersionUrl());
outputPath12 = File.createTempFile("cve_1_2_" + cve.getId() + "_", ".xml");
Downloader.fetchFile(url, outputPath12);
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO,
"Processing {0}", cve.getUrl());
importXML(outputPath, outputPath12);
getCveDB().commit();
getProperties().save(cve);
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO,
"Completed update {0} of {1}", new Object[]{count, maxUpdates});
} catch (FileNotFoundException ex) {
throw new UpdateException(ex);
} catch (ParserConfigurationException ex) {
throw new UpdateException(ex);
} catch (SAXException ex) {
throw new UpdateException(ex);
} catch (IOException ex) {
throw new UpdateException(ex);
} catch (SQLException ex) {
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()) {
deleted = outputPath.delete();
}
} finally {
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();
}
}
}
}
}
if (maxUpdates >= 1) { //ensure the modified file date gets written
getProperties().save(getUpdateable().get(MODIFIED));
getCveDB().cleanupDatabase();
}
} catch (MalformedURLException ex) {
throw new UpdateException(ex);
} finally {
closeDataStores();
}
}
*/
//</editor-fold>
/**
* Determines if the index needs to be updated. This is done by fetching the
* NVD CVE meta data and checking the last update date. If the data needs to
* be refreshed this method will return the NvdCveUrl for the files that
* need to be updated.
*
* @return the collection of files that need to be updated
* @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
* data is incorrect
* @throws DownloadFailedException is thrown if there is an error.
* downloading the NVD CVE download data file
* @throws UpdateException Is thrown if there is an issue with the last
* updated properties file
*/
protected final Updateable updatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
Updateable updates = null;
try {
updates = retrieveCurrentTimestampsFromWeb();
} catch (InvalidDataException ex) {
final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
Logger
.getLogger(StandardUpdate.class
.getName()).log(Level.FINE, msg, ex);
throw new DownloadFailedException(msg, ex);
} catch (InvalidSettingException ex) {
Logger.getLogger(StandardUpdate.class
.getName()).log(Level.FINE, "Invalid setting found when retrieving timestamps", ex);
throw new DownloadFailedException(
"Invalid settings", ex);
}
if (updates == null) {
throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
}
if (!properties.isEmpty()) {
try {
float version;
if (properties.getProperty("version") == null) {
deleteAndRecreate = true;
} else {
try {
version = Float.parseFloat(properties.getProperty("version"));
final float currentVersion = Float.parseFloat(CveDB.DB_SCHEMA_VERSION);
if (currentVersion > version) {
deleteAndRecreate = true;
}
} catch (NumberFormatException ex) {
deleteAndRecreate = true;
}
}
if (deleteAndRecreate) {
return updates;
}
final long lastUpdated = Long.parseLong(properties.getProperty(DataStoreMetaInfo.LAST_UPDATED, "0"));
final Date now = new Date();
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
if (lastUpdated == updates.getTimeStamp(MODIFIED)) {
updates.clear(); //we don't need to update anything.
} else if (withinRange(lastUpdated, now.getTime(), days)) {
for (NvdCveInfo entry : updates) {
if (MODIFIED.equals(entry.getId())) {
entry.setNeedsUpdate(true);
} else {
entry.setNeedsUpdate(false);
}
}
} else { //we figure out which of the several XML files need to be downloaded.
for (NvdCveInfo entry : updates) {
if (MODIFIED.equals(entry.getId())) {
entry.setNeedsUpdate(true);
} else {
long currentTimestamp = 0;
try {
currentTimestamp = Long.parseLong(properties.getProperty(DataStoreMetaInfo.LAST_UPDATED_BASE + entry.getId(), "0"));
} catch (NumberFormatException ex) {
final String msg = String.format("Error parsing '%s' '%s' from nvdcve.lastupdated",
DataStoreMetaInfo.LAST_UPDATED_BASE, entry.getId());
Logger
.getLogger(StandardUpdate.class
.getName()).log(Level.FINE, msg, ex);
}
if (currentTimestamp == entry.getTimestamp()) {
entry.setNeedsUpdate(false);
}
}
}
}
} catch (NumberFormatException ex) {
final String msg = "An invalid schema version or timestamp exists in the data.properties file.";
Logger
.getLogger(StandardUpdate.class
.getName()).log(Level.WARNING, msg);
Logger.getLogger(StandardUpdate.class
.getName()).log(Level.FINE, null, ex);
}
}
return updates;
}
/**
* Retrieves the timestamps from the NVD CVE meta data file.
*
* @return the timestamp from the currently published nvdcve downloads page
* @throws MalformedURLException thrown if the URL for the NVD CCE Meta data
* is incorrect.
* @throws DownloadFailedException thrown if there is an error downloading
* the nvd cve meta data file
* @throws InvalidDataException thrown if there is an exception parsing the
* timestamps
* @throws InvalidSettingException thrown if the settings are invalid
*/
private Updateable retrieveCurrentTimestampsFromWeb()
throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
final Updateable updates = new Updateable();
updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL),
Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
false);
final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
final int end = Calendar.getInstance().get(Calendar.YEAR);
final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
for (int i = start; i <= end; i++) {
updates.add(Integer.toString(i), String.format(baseUrl20, i),
String.format(baseUrl12, i),
true);
}
return updates;
}
/**
* Deletes the existing data directories.
*
* @throws IOException thrown if the directory cannot be deleted
*/
protected void deleteExistingData() throws IOException {
File data = Settings.getDataFile(Settings.KEYS.CVE_DATA_DIRECTORY);
if (data.exists()) {
FileUtils.delete(data);
}
data = DataStoreMetaInfo.getPropertiesFile();
if (data.exists()) {
FileUtils.delete(data);
}
}
/**
* Closes the CVE and CPE data stores.
*/
protected void closeDataStores() {
if (cveDB != null) {
try {
cveDB.close();
} catch (Exception ignore) {
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINEST, "Error closing the cveDB", ignore);
}
}
}
/**
* Opens the CVE and CPE data stores.
*
* @throws UpdateException thrown if a data store cannot be opened
*/
protected void openDataStores() throws UpdateException {
//open the cve and cpe data stores
try {
cveDB = new CveDB();
cveDB.open();
} catch (IOException ex) {
closeDataStores();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "IO Error opening databases", ex);
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
} catch (SQLException ex) {
closeDataStores();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "SQL Exception opening databases", ex);
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
} catch (DatabaseException ex) {
closeDataStores();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Database Exception opening databases", ex);
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
} catch (ClassNotFoundException ex) {
closeDataStores();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Class not found exception opening databases", ex);
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
}
}
/**
* Determines if the epoch date is within the range specified of the
* compareTo epoch time. This takes the (compareTo-date)/1000/60/60/24 to
* get the number of days. If the calculated days is less then the range the
* date is considered valid.
*
* @param date the date to be checked.
* @param compareTo the date to compare to.
* @param range the range in days to be considered valid.
* @return whether or not the date is within the range.
*/
protected boolean withinRange(long date, long compareTo, int range) {
final double differenceInDays = (compareTo - date) / 1000.0 / 60.0 / 60.0 / 24.0;
return differenceInDays < range;
}
private void spinWaitForFuture(final Future<CallableDownloadTask> future) {
//then wait for downloads to finish
while (!future.isDone()) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, null, ex);
}
}
}
}

View File

@@ -1,294 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import org.owasp.dependencycheck.data.nvdcve.InvalidDataException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import static org.owasp.dependencycheck.data.update.DataStoreMetaInfo.MODIFIED;
/**
* Class responsible for updating the CPE and NVDCVE data stores.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class StandardUpdateTask extends AbstractUpdateTask {
/**
* Constructs a new Standard Update Task.
*
* @param properties information about the data store
* @throws MalformedURLException thrown if a configured URL is malformed
* @throws DownloadFailedException thrown if a timestamp cannot be checked
* on a configured URL
* @throws UpdateException thrown if there is an exception generating the
* update task
*/
public StandardUpdateTask(DataStoreMetaInfo properties) throws MalformedURLException, DownloadFailedException, UpdateException {
super(properties);
}
/**
* <p>Downloads the latest NVD CVE XML file from the web and imports it into
* the current CVE Database.</p>
*
* @throws UpdateException is thrown if there is an error updating the
* database
*/
@Override
public void update() throws UpdateException {
try {
int maxUpdates = 0;
for (NvdCveInfo cve : getUpdateable()) {
if (cve.getNeedsUpdate()) {
maxUpdates += 1;
}
}
if (maxUpdates > 3) {
Logger.getLogger(StandardUpdateTask.class.getName()).log(Level.INFO,
"NVD CVE requires several updates; this could take a couple of minutes.");
}
if (maxUpdates > 0) {
openDataStores();
}
int count = 0;
for (NvdCveInfo cve : getUpdateable()) {
if (cve.getNeedsUpdate()) {
count += 1;
Logger.getLogger(StandardUpdateTask.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(StandardUpdateTask.class.getName()).log(Level.INFO,
"Downloading {0}", cve.getUrl());
outputPath = File.createTempFile("cve" + cve.getId() + "_", ".xml");
Downloader.fetchFile(url, outputPath);
url = new URL(cve.getOldSchemaVersionUrl());
outputPath12 = File.createTempFile("cve_1_2_" + cve.getId() + "_", ".xml");
Downloader.fetchFile(url, outputPath12);
Logger.getLogger(StandardUpdateTask.class.getName()).log(Level.INFO,
"Processing {0}", cve.getUrl());
importXML(outputPath, outputPath12);
getCveDB().commit();
getCpeIndex().commit();
getProperties().save(cve);
Logger.getLogger(StandardUpdateTask.class.getName()).log(Level.INFO,
"Completed update {0} of {1}", new Object[]{count, maxUpdates});
} catch (FileNotFoundException ex) {
throw new UpdateException(ex);
} catch (ParserConfigurationException ex) {
throw new UpdateException(ex);
} catch (SAXException ex) {
throw new UpdateException(ex);
} catch (IOException ex) {
throw new UpdateException(ex);
} catch (SQLException ex) {
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()) {
deleted = outputPath.delete();
}
} finally {
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();
}
}
}
}
}
if (maxUpdates >= 1) { //ensure the modified file date gets written
getProperties().save(getUpdateable().get(MODIFIED));
getCveDB().cleanupDatabase();
}
} catch (MalformedURLException ex) {
throw new UpdateException(ex);
} finally {
closeDataStores();
}
}
/**
* Determines if the index needs to be updated. This is done by fetching the
* NVD CVE meta data and checking the last update date. If the data needs to
* be refreshed this method will return the NvdCveUrl for the files that
* need to be updated.
*
* @return the collection of files that need to be updated
* @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
* data is incorrect
* @throws DownloadFailedException is thrown if there is an error.
* downloading the NVD CVE download data file
* @throws UpdateException Is thrown if there is an issue with the last
* updated properties file
*/
@Override
protected Updateable updatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
Updateable updates = null;
try {
updates = retrieveCurrentTimestampsFromWeb();
} catch (InvalidDataException ex) {
final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
Logger.getLogger(StandardUpdateTask.class.getName()).log(Level.FINE, msg, ex);
throw new DownloadFailedException(msg, ex);
} catch (InvalidSettingException ex) {
Logger.getLogger(StandardUpdateTask.class.getName()).log(Level.FINE, "Invalid setting found when retrieving timestamps", ex);
throw new DownloadFailedException("Invalid settings", ex);
}
if (updates == null) {
throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
}
final DataStoreMetaInfo properties = getProperties();
if (!properties.isEmpty()) {
try {
float version;
if (properties.getProperty("version") == null) {
setDeleteAndRecreate(true);
} else {
try {
version = Float.parseFloat(properties.getProperty("version"));
final float currentVersion = Float.parseFloat(CveDB.DB_SCHEMA_VERSION);
if (currentVersion > version) {
setDeleteAndRecreate(true);
}
} catch (NumberFormatException ex) {
setDeleteAndRecreate(true);
}
}
if (shouldDeleteAndRecreate()) {
return updates;
}
final long lastUpdated = Long.parseLong(properties.getProperty(DataStoreMetaInfo.LAST_UPDATED, "0"));
final Date now = new Date();
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
if (lastUpdated == updates.getTimeStamp(MODIFIED)) {
updates.clear(); //we don't need to update anything.
} else if (withinRange(lastUpdated, now.getTime(), days)) {
for (NvdCveInfo entry : updates) {
if (MODIFIED.equals(entry.getId())) {
entry.setNeedsUpdate(true);
} else {
entry.setNeedsUpdate(false);
}
}
} else { //we figure out which of the several XML files need to be downloaded.
for (NvdCveInfo entry : updates) {
if (MODIFIED.equals(entry.getId())) {
entry.setNeedsUpdate(true);
} else {
long currentTimestamp = 0;
try {
currentTimestamp = Long.parseLong(properties.getProperty(DataStoreMetaInfo.LAST_UPDATED_BASE + entry.getId(), "0"));
} catch (NumberFormatException ex) {
final String msg = String.format("Error parsing '%s' '%s' from nvdcve.lastupdated",
DataStoreMetaInfo.LAST_UPDATED_BASE, entry.getId());
Logger.getLogger(StandardUpdateTask.class.getName()).log(Level.FINE, msg, ex);
}
if (currentTimestamp == entry.getTimestamp()) {
entry.setNeedsUpdate(false);
}
}
}
}
} catch (NumberFormatException ex) {
final String msg = "An invalid schema version or timestamp exists in the data.properties file.";
Logger.getLogger(StandardUpdateTask.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(StandardUpdateTask.class.getName()).log(Level.FINE, null, ex);
}
}
return updates;
}
/**
* Retrieves the timestamps from the NVD CVE meta data file.
*
* @return the timestamp from the currently published nvdcve downloads page
* @throws MalformedURLException thrown if the URL for the NVD CCE Meta data
* is incorrect.
* @throws DownloadFailedException thrown if there is an error downloading
* the nvd cve meta data file
* @throws InvalidDataException thrown if there is an exception parsing the
* timestamps
* @throws InvalidSettingException thrown if the settings are invalid
*/
private Updateable retrieveCurrentTimestampsFromWeb()
throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
final Updateable updates = new Updateable();
updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL),
Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
false);
final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
final int end = Calendar.getInstance().get(Calendar.YEAR);
final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
for (int i = start; i <= end; i++) {
updates.add(Integer.toString(i), String.format(baseUrl20, i),
String.format(baseUrl12, i),
true);
}
return updates;
}
}

View File

@@ -1,60 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import java.net.MalformedURLException;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
/**
* An UpdateTask Factory that instantiates the correct UpdateTask based on the
* given configuration.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public final class UpdateTaskFactory {
/**
* private constructor for a utility class.
*/
private UpdateTaskFactory() {
//empty contrusctor for utility class
}
/**
* Constructs the appropriate update task based on configuration.
*
* @return an UpdateTask
* @throws MalformedURLException thrown if a configured URL is malformed
* @throws DownloadFailedException thrown if a timestamp cannot be checked
* on a configured URL
* @throws UpdateException thrown if there is an exception generating the
* update task
*/
public static UpdateTask getUpdateTask() throws MalformedURLException, DownloadFailedException, UpdateException {
final UpdateTask task;
final DataStoreMetaInfo properties = new DataStoreMetaInfo();
if (properties.isBatchUpdateMode()) {
task = new BatchUpdateTask(properties);
} else {
task = new StandardUpdateTask(properties);
}
return task;
}
}

View File

@@ -0,0 +1,186 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import java.util.regex.Pattern;
/**
* A simple PropertyType used to represent a string value that could be used as
* a regular expression or could be case insensitive. The equals method has been
* over-ridden so that the object will correctly compare to strings.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class PropertyType {
//<editor-fold defaultstate="collapsed" desc="properties">
/**
* The value.
*/
private String value;
/**
* Gets the value of the value property.
*
* @return the value of the value property
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value the value of the value property
*/
public void setValue(String value) {
this.value = value;
}
/**
* Whether or not the expression is a regex.
*/
private boolean regex = false;
/**
* Returns whether or not the value is a regex.
*
* @return true if the value is a regex, otherwise false
*
*/
public boolean isRegex() {
return regex;
}
/**
* Sets whether the value property is a regex.
*
* @param value true if the value is a regex, otherwise false
*
*/
public void setRegex(boolean value) {
this.regex = value;
}
/**
* Indicates case sensitivity.
*/
private boolean caseSensitive = false;
/**
* Gets the value of the caseSensitive property.
*
* @return true if the value is case sensitive
*
*/
public boolean isCaseSensitive() {
return caseSensitive;
}
/**
* Sets the value of the caseSensitive property.
*
* @param value whether the value is case sensitive
*
*/
public void setCaseSensitive(boolean value) {
this.caseSensitive = value;
}
//</editor-fold>
/**
* Uses the object's properties to determine if the supplied string matches
* the value of this property.
*
* @param text the String to validate
* @return whether the text supplied is matched by the value of the property
*/
public boolean matches(String text) {
if (text == null) {
return false;
}
if (this.regex) {
Pattern rx;
if (this.caseSensitive) {
rx = Pattern.compile(this.value);
} else {
rx = Pattern.compile(this.value, Pattern.CASE_INSENSITIVE);
}
return rx.matcher(text).matches();
} else {
if (this.caseSensitive) {
return value.equals(text);
} else {
return value.equalsIgnoreCase(text);
}
}
}
//<editor-fold defaultstate="collapsed" desc="standard implmentations of hashCode, equals, and toString">
/**
* Default implementation of hashCode.
*
* @return the hash code
*/
@Override
public int hashCode() {
int hash = 3;
hash = 59 * hash + (this.value != null ? this.value.hashCode() : 0);
hash = 59 * hash + (this.regex ? 1 : 0);
hash = 59 * hash + (this.caseSensitive ? 1 : 0);
return hash;
}
/**
* Default implementation of equals.
*
* @param obj the object to compare
* @return whether the objects are equivalent
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PropertyType other = (PropertyType) obj;
if ((this.value == null) ? (other.value != null) : !this.value.equals(other.value)) {
return false;
}
if (this.regex != other.regex) {
return false;
}
if (this.caseSensitive != other.caseSensitive) {
return false;
}
return true;
}
/**
* Default implementation of toString().
*
* @return the string representation of the object
*/
@Override
public String toString() {
return "PropertyType{" + "value=" + value + ", regex=" + regex + ", caseSensitive=" + caseSensitive + '}';
}
//</editor-fold>
}

View File

@@ -0,0 +1,93 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* An XML parsing error handler.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class SuppressionErrorHandler implements ErrorHandler {
/**
* Builds a prettier exception message.
*
* @param ex the SAXParseException
* @return an easier to read exception message
*/
private String getPrettyParseExceptionInfo(SAXParseException ex) {
final StringBuffer sb = new StringBuffer();
if (ex.getSystemId() != null) {
sb.append("systemId=").append(ex.getSystemId()).append(", ");
}
if (ex.getPublicId() != null) {
sb.append("publicId=").append(ex.getPublicId()).append(", ");
}
if (ex.getLineNumber() > 0) {
sb.append("Line=").append(ex.getLineNumber());
}
if (ex.getColumnNumber() > 0) {
sb.append(", Column=").append(ex.getColumnNumber());
}
sb.append(": ").append(ex.getMessage());
return sb.toString();
}
/**
* Logs warnings.
*
* @param ex the warning to log
* @throws SAXException is never thrown
*/
@Override
public void warning(SAXParseException ex) throws SAXException {
Logger.getLogger(SuppressionErrorHandler.class.getName()).log(Level.FINE, null, ex);
}
/**
* Handles errors.
*
* @param ex the error to handle
* @throws SAXException is always thrown
*/
@Override
public void error(SAXParseException ex) throws SAXException {
throw new SAXException(getPrettyParseExceptionInfo(ex));
}
/**
* Handles fatal exceptions.
*
* @param ex a fatal exception
* @throws SAXException is always
*/
@Override
public void fatalError(SAXParseException ex) throws SAXException {
throw new SAXException(getPrettyParseExceptionInfo(ex));
}
}

View File

@@ -0,0 +1,174 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* A handler to load suppression rules.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class SuppressionHandler extends DefaultHandler {
/**
* The suppress node, indicates the start of a new rule.
*/
public static final String SUPPRESS = "suppress";
/**
* The file path element name.
*/
public static final String FILE_PATH = "filePath";
/**
* The sha1 hash element name.
*/
public static final String SHA1 = "sha1";
/**
* The CVE element name.
*/
public static final String CVE = "cve";
/**
* The CPE element name.
*/
public static final String CPE = "cpe";
/**
* The CWE element name.
*/
public static final String CWE = "cwe";
/**
* The cvssBelow element name.
*/
public static final String CVSS_BELOW = "cvssBelow";
/**
* A list of suppression rules.
*/
private List<SuppressionRule> supressionRules = new ArrayList<SuppressionRule>();
/**
* Get the value of supressionRules.
*
* @return the value of supressionRules
*/
public List<SuppressionRule> getSupressionRules() {
return supressionRules;
}
/**
* The current rule being read.
*/
private SuppressionRule rule;
/**
* The attributes of the node being read.
*/
private Attributes currentAttributes;
/**
* The current node text being extracted from the element.
*/
private StringBuffer currentText;
/**
* Handles the start element event.
*
* @param uri the uri of the element being processed
* @param localName the local name of the element being processed
* @param qName the qName of the element being processed
* @param attributes the attributes of the element being processed
* @throws SAXException thrown if there is an exception processing
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currentAttributes = null;
currentText = new StringBuffer();
if (SUPPRESS.equals(qName)) {
rule = new SuppressionRule();
} else if (FILE_PATH.equals(qName)) {
currentAttributes = attributes;
}
}
/**
* Handles the end element event.
*
* @param uri the uri of the element
* @param localName the local name of the element
* @param qName the qName of the element
* @throws SAXException thrown if there is an exception processing
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (SUPPRESS.equals(qName)) {
supressionRules.add(rule);
rule = null;
} else if (FILE_PATH.equals(qName)) {
final PropertyType pt = processPropertyType();
rule.setFilePath(pt);
} else if (SHA1.equals(qName)) {
rule.setSha1(currentText.toString());
} else if (CPE.equals(qName)) {
final PropertyType pt = processPropertyType();
rule.addCpe(pt);
} else if (CWE.equals(qName)) {
rule.addCwe(currentText.toString());
} else if (CVE.equals(qName)) {
rule.addCve(currentText.toString());
} else if (CVSS_BELOW.equals(qName)) {
final float cvss = Float.parseFloat(currentText.toString());
rule.addCvssBelow(cvss);
}
}
/**
* Collects the body text of the node being processed.
*
* @param ch the char array of text
* @param start the start position to copy text from in the char array
* @param length the number of characters to copy from the char array
* @throws SAXException thrown if there is a parsing exception
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
currentText.append(ch, start, length);
}
/**
* Processes field members that have been collected during the characters
* and startElement method to construct a PropertyType object.
*
* @return a PropertyType object
*/
private PropertyType processPropertyType() {
final PropertyType pt = new PropertyType();
pt.setValue(currentText.toString());
if (currentAttributes != null && currentAttributes.getLength() > 0) {
final String regex = currentAttributes.getValue("regex");
if (regex != null) {
pt.setRegex(Boolean.parseBoolean(regex));
}
final String caseSensitive = currentAttributes.getValue("caseSensitive");
if (regex != null) {
pt.setCaseSensitive(Boolean.parseBoolean(caseSensitive));
}
}
return pt;
}
}

View File

@@ -0,0 +1,69 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import java.io.IOException;
/**
* An exception used when parsing a suppression rule file fails.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class SuppressionParseException extends IOException {
/**
* The serial version UID.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new SuppressionParseException.
*/
public SuppressionParseException() {
super();
}
/**
* Creates a new SuppressionParseException.
*
* @param msg a message for the exception.
*/
public SuppressionParseException(String msg) {
super(msg);
}
/**
* Creates a new SuppressionParseException.
*
* @param ex the cause of the download failure.
*/
public SuppressionParseException(Throwable ex) {
super(ex);
}
/**
* Creates a new SuppressionParseException.
*
* @param msg a message for the exception.
* @param ex the cause of the download failure.
*/
public SuppressionParseException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,107 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
/**
* A simple validating parser for XML Suppression Rules.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class SuppressionParser {
/**
* JAXP Schema Language. Source:
* http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
*/
public static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
/**
* W3C XML Schema. Source:
* http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
*/
public static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
/**
* JAXP Schema Source. Source:
* http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
*/
public static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
/**
* Parses the given xml file and returns a list of the suppression rules
* contained.
*
* @param file an xml file containing suppression rules
* @return a list of suppression rules
* @throws SuppressionParseException thrown if the xml file cannot be parsed
*/
public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
try {
final InputStream schemaStream = this.getClass().getClassLoader().getResourceAsStream("schema/suppression.xsd");
final SuppressionHandler handler = new SuppressionHandler();
final SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
final SAXParser saxParser = factory.newSAXParser();
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
final XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setErrorHandler(new SuppressionErrorHandler());
xmlReader.setContentHandler(handler);
final InputStream inputStream = new FileInputStream(file);
final Reader reader = new InputStreamReader(inputStream, "UTF-8");
final InputSource in = new InputSource(reader);
//in.setEncoding("UTF-8");
xmlReader.parse(in);
return handler.getSupressionRules();
} catch (ParserConfigurationException ex) {
Logger.getLogger(SuppressionParser.class.getName()).log(Level.FINE, null, ex);
throw new SuppressionParseException(ex);
} catch (SAXException ex) {
Logger.getLogger(SuppressionParser.class.getName()).log(Level.FINE, null, ex);
throw new SuppressionParseException(ex);
} catch (FileNotFoundException ex) {
Logger.getLogger(SuppressionParser.class.getName()).log(Level.FINE, null, ex);
throw new SuppressionParseException(ex);
} catch (IOException ex) {
Logger.getLogger(SuppressionParser.class.getName()).log(Level.FINE, null, ex);
throw new SuppressionParseException(ex);
}
}
}

View File

@@ -0,0 +1,365 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class SuppressionRule {
/**
* The file path for the suppression.
*/
private PropertyType filePath;
/**
* Get the value of filePath.
*
* @return the value of filePath
*/
public PropertyType getFilePath() {
return filePath;
}
/**
* Set the value of filePath.
*
* @param filePath new value of filePath
*/
public void setFilePath(PropertyType filePath) {
this.filePath = filePath;
}
/**
* The sha1 hash.
*/
private String sha1;
/**
* Get the value of sha1.
*
* @return the value of sha1
*/
public String getSha1() {
return sha1;
}
/**
* Set the value of sha1.
*
* @param sha1 new value of sha1
*/
public void setSha1(String sha1) {
this.sha1 = sha1;
}
/**
* A list of CPEs to suppression
*/
private List<PropertyType> cpe = new ArrayList<PropertyType>();
/**
* Get the value of cpe.
*
* @return the value of cpe
*/
public List<PropertyType> getCpe() {
return cpe;
}
/**
* Set the value of cpe.
*
* @param cpe new value of cpe
*/
public void setCpe(List<PropertyType> cpe) {
this.cpe = cpe;
}
/**
* Adds the cpe to the cpe list.
*
* @param cpe the cpe to add
*/
public void addCpe(PropertyType cpe) {
this.cpe.add(cpe);
}
/**
* Returns whether or not this suppression rule as CPE entries.
*
* @return whether or not this suppression rule as CPE entries
*/
public boolean hasCpe() {
return cpe.size() > 0;
}
/**
* The list of cvssBelow scores.
*/
private List<Float> cvssBelow = new ArrayList<Float>();
/**
* Get the value of cvssBelow.
*
* @return the value of cvssBelow
*/
public List<Float> getCvssBelow() {
return cvssBelow;
}
/**
* Set the value of cvssBelow.
*
* @param cvssBelow new value of cvssBelow
*/
public void setCvssBelow(List<Float> cvssBelow) {
this.cvssBelow = cvssBelow;
}
/**
* Adds the cvss to the cvssBelow list.
*
* @param cvss the cvss to add
*/
public void addCvssBelow(Float cvss) {
this.cvssBelow.add(cvss);
}
/**
* Returns whether or not this suppression rule has cvss suppressions.
*
* @return whether or not this suppression rule has cvss suppressions
*/
public boolean hasCvssBelow() {
return cvssBelow.size() > 0;
}
/**
* The list of cwe entries to suppress.
*/
private List<String> cwe = new ArrayList<String>();
/**
* Get the value of cwe.
*
* @return the value of cwe
*/
public List<String> getCwe() {
return cwe;
}
/**
* Set the value of cwe.
*
* @param cwe new value of cwe
*/
public void setCwe(List<String> cwe) {
this.cwe = cwe;
}
/**
* Adds the cwe to the cwe list.
*
* @param cwe the cwe to add
*/
public void addCwe(String cwe) {
this.cwe.add(cwe);
}
/**
* Returns whether this suppression rule has CWE entries.
*
* @return whether this suppression rule has CWE entries
*/
public boolean hasCwe() {
return cwe.size() > 0;
}
/**
* The list of cve entries to suppress.
*/
private List<String> cve = new ArrayList<String>();
/**
* Get the value of cve.
*
* @return the value of cve
*/
public List<String> getCve() {
return cve;
}
/**
* Set the value of cve.
*
* @param cve new value of cve
*/
public void setCve(List<String> cve) {
this.cve = cve;
}
/**
* Adds the cve to the cve list.
*
* @param cve the cve to add
*/
public void addCve(String cve) {
this.cve.add(cve);
}
/**
* Returns whether this suppression rule has CVE entries.
*
* @return whether this suppression rule has CVE entries
*/
public boolean hasCve() {
return cve.size() > 0;
}
/**
* Processes a given dependency to determine if any CPE, CVE, CWE, or CVSS
* scores should be suppressed. If any should be, they are removed from the
* dependency.
*
* @param dependency a project dependency to analyze
*/
public void process(Dependency dependency) {
if (filePath != null && !filePath.matches(dependency.getFilePath())) {
return;
}
if (sha1 != null && !sha1.equalsIgnoreCase(dependency.getSha1sum())) {
return;
}
if (this.hasCpe()) {
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
while (itr.hasNext()) {
final Identifier i = itr.next();
for (PropertyType c : this.cpe) {
if (cpeMatches(c, i)) {
itr.remove();
break;
}
}
}
}
if (hasCve() || hasCwe() || hasCvssBelow()) {
final Iterator<Vulnerability> itr = dependency.getVulnerabilities().iterator();
while (itr.hasNext()) {
boolean remove = false;
final Vulnerability v = itr.next();
for (String entry : this.cve) {
if (entry.equalsIgnoreCase(v.getName())) {
remove = true;
break;
}
}
if (!remove) {
for (String entry : this.cwe) {
if (v.getCwe() != null) {
final String toMatch = String.format("CWE-%s ", entry);
final String toTest = v.getCwe().substring(0, toMatch.length()).toUpperCase();
if (toTest.equals(toMatch)) {
remove = true;
break;
}
}
}
}
if (!remove) {
for (float cvss : this.cvssBelow) {
if (v.getCvssScore() < cvss) {
remove = true;
break;
}
}
}
if (remove) {
itr.remove();
}
}
}
}
/**
* Identifies if the cpe specified by the cpe suppression rule does not
* specify a version.
*
* @param c a suppression rule identifier
* @return true if the property type does not specify a version; otherwise
* false
*/
boolean cpeHasNoVersion(PropertyType c) {
if (c.isRegex()) {
return false;
} // cpe:/a:jboss:jboss:1.0.0:
if (countCharacter(c.getValue(), ':') == 3) {
return true;
}
return false;
}
/**
* Counts the number of occurrences of the character found within the
* string.
*
* @param str the string to check
* @param c the character to count
* @return the number of times the character is found in the string
*/
int countCharacter(String str, char c) {
int count = 0;
int pos = str.indexOf(c) + 1;
while (pos > 0) {
count += 1;
pos = str.indexOf(c, pos) + 1;
}
return count;
}
/**
* Determines if the cpeEntry specified as a PropertyType matches the given
* Identifier.
*
* @param cpeEntry a suppression rule entry
* @param identifier a CPE identifier to check
* @return true if the entry matches; otherwise false
*/
boolean cpeMatches(PropertyType cpeEntry, Identifier identifier) {
if (cpeEntry.matches(identifier.getValue())) {
return true;
} else if (cpeHasNoVersion(cpeEntry)) {
if (cpeEntry.isCaseSensitive()) {
if (identifier.getValue().startsWith(cpeEntry.getValue())) {
return true;
}
} else {
final String id = identifier.getValue().toLowerCase();
final String check = cpeEntry.getValue().toLowerCase();
if (id.startsWith(check)) {
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,11 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.suppression</title>
* </head>
* <body>
* Contains classes used to suppress findings.
* </body>
* </html>
*/
package org.owasp.dependencycheck.suppression;

View File

@@ -72,11 +72,6 @@ public final class Settings {
* contains the contents of the data directory.
*/
public static final String BATCH_UPDATE_URL = "batch.update.url";
/**
* The properties key for the path where the CPE Lucene Index will be
* stored.
*/
public static final String CPE_DATA_DIRECTORY = "data.cpe";
/**
* The properties key for the path where the CVE H2 database will be
* stored.
@@ -141,6 +136,14 @@ public final class Settings {
* The location of the temporary directory.
*/
public static final String TEMP_DIRECTORY = "temp.directory";
/**
* The maximum number of threads to allocate when downloading files.
*/
public static final String MAX_DOWNLOAD_THREAD_POOL_SIZE = "max.download.threads";
/**
* The key for a list of suppression files.
*/
public static final String SUPPRESSION_FILE = "suppression.file";
}
/**
* The properties file location.
@@ -257,13 +260,32 @@ public final class Settings {
* argument - this method will return the value from the system properties
* before the values in the contained configuration file.
*
* This method will also replace a leading "[JAR]\" sequence with the path
* to the folder containing the JAR file containing this class.
*
* @param key the key to lookup within the properties file
* @return the property from the properties file converted to a File object
*/
public static File getFile(String key) {
final String file = getString(key);
if (file == null) {
return null;
}
return new File(file);
}
/**
* Returns a value from the properties file as a File object. 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.
*
* This method will check the configured base directory and will use this as
* the base of the file path. Additionally, if the base directory begins
* with a leading "[JAR]\" sequence with the path to the folder containing
* the JAR file containing this class.
*
* @param key the key to lookup within the properties file
* @return the property from the properties file converted to a File object
*/
public static File getDataFile(String key) {
final String file = getString(key);
final String baseDir = getString(Settings.KEYS.DATA_DIRECTORY);
if (baseDir != null) {

View File

@@ -1,8 +1,10 @@
org.owasp.dependencycheck.analyzer.ArchiveAnalyzer
org.owasp.dependencycheck.analyzer.JarAnalyzer
org.owasp.dependencycheck.analyzer.FileNameAnalyzer
org.owasp.dependencycheck.analyzer.JarAnalyzer
org.owasp.dependencycheck.analyzer.HintAnalyzer
org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer
org.owasp.dependencycheck.analyzer.FalsePositiveAnalyzer
org.owasp.dependencycheck.analyzer.CPEAnalyzer
org.owasp.dependencycheck.analyzer.NvdCveAnalyzer
org.owasp.dependencycheck.analyzer.FalsePositiveAnalyzer
org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer
org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer
org.owasp.dependencycheck.analyzer.NvdCveAnalyzer
org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer

View File

@@ -8,6 +8,7 @@ DROP TABLE IF EXISTS vulnerability;
DROP TABLE IF EXISTS reference;
DROP TABLE IF EXISTS cpeEntry;
DROP TABLE IF EXISTS software;
DROP TABLE IF EXISTS settings;
CREATE TABLE settings (id varchar(50) PRIMARY KEY, value varchar(200));

View File

@@ -1,14 +1,13 @@
application.name=${pom.name}
application.version=${pom.version}
autoupdate=true
max.download.threads=3
#temp.directory defaults to System.getProperty("java.io.tmpdir")
#temp.directory=[path to temp directory]
# the path to the data directory; if tis
data.directory=[JAR]/data
# the path to the lucene index to store the cpe data
data.cpe=cpe
# the path to the h2 database to store the nvd cve data
data.cve=cve

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema id="suppressions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression"
xmlns:dc="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
<xs:complexType name="regexStringType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="regex" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="caseSensitive" use="optional" type="xs:boolean" default="false"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="cvssScoreType">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="10"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="cveType">
<xs:restriction base="xs:string">
<xs:pattern value="CVE\-\d\d\d\d\-\d+"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="sha1Type">
<xs:restriction base="xs:string">
<xs:pattern value="[a-fA-F0-9]{40}"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="suppressions">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="suppress">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element name="notes" type="xs:string"/>
</xs:sequence>
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element name="filePath" type="dc:regexStringType"/>
<xs:element name="sha1" type="dc:sha1Type"/>
</xs:choice>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="cpe" type="dc:regexStringType"/>
<xs:element name="cve" type="dc:cveType"/>
<xs:element name="cwe" type="xs:positiveInteger"/>
<xs:element name="cvssBelow" type="dc:cvssScoreType"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -51,14 +51,132 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
});
});
</script>
<script type="text/javascript">
$(function(){
$("#modal-background, #modal-close").click(function () {
$("#modal-content,#modal-background").toggleClass("active");
});
$("#modal-text").bind('copy cut', function() {
setTimeout('$("#modal-content,#modal-background").toggleClass("active");',100);
});
$("#modal-add-header").click(function () {
xml = '<?xml version="1.0" encoding="UTF-8"?>\n<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">\n ';
xml += $("#modal-text").text().replace(/\n/g,'\n ');
xml += '\n</suppressions>';
$("#modal-text").text(xml).focus().select();
});
});
function copyText(name, sha1, type, val) {
xml = '<suppress>\n';
xml += ' <notes><!'+'[CDATA[\n file name: ' + name + '\n ]]'+'></notes>\n';
xml += ' <sha1>' + sha1 + '</sha1>\n';
xml += ' <'+type+'>' + val + '</'+type+'>\n';
xml += '</suppress>';
$("#modal-text").text(xml);
$("#modal-content,#modal-background").toggleClass("active");
$("#modal-text").focus();
$("#modal-text").select();
}
function toggleVuln() {
$(".notvulnerable").toggle();
}
</script>
<style type="text/css">
#modal-background {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: white;
opacity: .50;
-webkit-opacity: .5;
-moz-opacity: .5;
filter: alpha(opacity=50);
z-index: 1000;
}
#modal-content {
background-color: white;
border-radius: 10px;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
box-shadow: 0 0 20px 0 #222;
-webkit-box-shadow: 0 0 20px 0 #222;
-moz-box-shadow: 0 0 20px 0 #222;
display: none;
height: 240px;
left: 50%;
margin: -120px 0 0 -160px;
padding: 10px;
position: absolute;
top: 50%;
z-index: 1000;
}
#modal-background.active, #modal-content.active {
display: block;
}
#modal-text {
border: 0;
overflow: hidden
}
#modal-text:focus {
outline: none;
}
.copybutton {
padding:1px;
background-color: #eeeeee;
border: 1px solid #555555;
color:#555555;
text-decoration:none;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-khtml-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
}
.copybutton:hover {
padding:1px;
background-color: #dddddd;
border: 1px solid #444444;
color:#444444;
text-decoration:none;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-khtml-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
}
.modal-button {
padding:1px;
float:right;
background-color: #eeeeee;
border: 1px solid #555555;
color:#555555;
text-decoration:none;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-khtml-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
}
.modal-button:hover {
padding:1px;
float:right;
background-color: #dddddd;
border: 1px solid #333333;
color:#333333;
text-decoration:none;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-khtml-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
}
.rounded-corners {
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
@@ -292,6 +410,12 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
</style>
</head>
<body>
<div id="modal-background"></div>
<div id="modal-content">
<div>Press CTR-C to copy XML<button id="modal-add-header" class="modal-button">Complete XML Doc</button></div>
<textarea id="modal-text" cols="50" rows="10"></textarea><br/>
<button id="modal-close" class="modal-button">Close</button>
</div>
<div class="wrapper">
<h1>Dependency Report</h1>
]]#
@@ -424,6 +548,8 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
#else
<li><b>$esc.html($id.type):</b>&nbsp;$esc.html($id.value)
#end
##yes, we are HTML Encoding into JavaScript... the escape utils don't have a JS Encode and I haven't written one yet
&nbsp;&nbsp;<button class="copybutton" onclick="copyText('$esc.html($dependency.FileName)', '$esc.html($dependency.Sha1sum)', 'cpe', '$esc.html($id.value)')">suppress</button>
#if( $id.description )
<br/>$esc.html($id.description)
#end
@@ -437,7 +563,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<h4 id="header$cnt" class="subsectionheader expandable collaspablesubsection white">Published Vulnerabilities</h4>
<div id="content$cnt" class="subsectioncontent standardsubsection">
#foreach($vuln in $dependency.getVulnerabilities())
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$esc.url($vuln.name)">$esc.html($vuln.name)</a></b></p>
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$esc.url($vuln.name)">$esc.html($vuln.name)</a></b>&nbsp;&nbsp;<button class="copybutton" onclick="copyText('$esc.html($dependency.FileName)', '$esc.html($dependency.Sha1sum)', 'cve', '$esc.html($vuln.name)')">suppress</button></p>
<p>Severity:
#if ($vuln.cvssScore<4.0)
Low

View File

@@ -101,21 +101,6 @@ public class CPEAnalyzerTest extends BaseIndexTestCase {
Assert.assertTrue(expResult.equals(queryText));
}
/**
* Test of open method, of class CPEAnalyzer.
*
* @throws Exception is thrown when an exception occurs
*/
@Test
public void testOpen() throws Exception {
CPEAnalyzer instance = new CPEAnalyzer();
Assert.assertFalse(instance.isOpen());
instance.open();
Assert.assertTrue(instance.isOpen());
instance.close();
Assert.assertFalse(instance.isOpen());
}
/**
* Test of determineCPE method, of class CPEAnalyzer.
*

View File

@@ -1,75 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.cpe;
import java.io.File;
import java.io.IOException;
import org.apache.lucene.store.Directory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class IndexIntegrationTest {
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of update method, of class Index.
*/
@Test
public void testUpdate() throws Exception {
//deprecated
//Index instance = new Index();
//instance.update();
}
/**
* Test of updateNeeded method, of class Index.
*/
@Test
public void testUpdateNeeded() throws Exception {
//deprecated
//Index instance = new Index();
//instance.updateNeeded();
//if an exception is thrown this test fails. However, because it depends on the
// order of the tests what this will return I am just testing for the exception.
//assertTrue(expResult < result);
}
}

View File

@@ -72,7 +72,7 @@ public class FieldAnalyzerTest {
@Test
public void testAnalyzers() throws Exception {
Analyzer analyzer = new FieldAnalyzer(Version.LUCENE_43);
Analyzer analyzer = new FieldAnalyzer(LuceneUtils.CURRENT_VERSION);
Directory index = new RAMDirectory();
String field1 = "product";
@@ -83,16 +83,16 @@ public class FieldAnalyzerTest {
createIndex(analyzer, index, field1, text1, field2, text2);
//Analyzer searchingAnalyzer = new SearchFieldAnalyzer(Version.LUCENE_43);
//Analyzer searchingAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
String querystr = "product:\"(Spring Framework Core)\" vendor:(SpringSource)";
SearchFieldAnalyzer searchAnalyzerProduct = new SearchFieldAnalyzer(Version.LUCENE_43);
SearchFieldAnalyzer searchAnalyzerVendor = new SearchFieldAnalyzer(Version.LUCENE_43);
SearchFieldAnalyzer searchAnalyzerProduct = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
SearchFieldAnalyzer searchAnalyzerVendor = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
HashMap<String, Analyzer> map = new HashMap<String, Analyzer>();
map.put(field1, searchAnalyzerProduct);
map.put(field2, searchAnalyzerVendor);
PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(new StandardAnalyzer(Version.LUCENE_43), map);
QueryParser parser = new QueryParser(Version.LUCENE_43, field1, wrapper);
PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(new StandardAnalyzer(LuceneUtils.CURRENT_VERSION), map);
QueryParser parser = new QueryParser(LuceneUtils.CURRENT_VERSION, field1, wrapper);
Query q = parser.parse(querystr);
//System.out.println(q.toString());
@@ -116,7 +116,7 @@ public class FieldAnalyzerTest {
}
private void createIndex(Analyzer analyzer, Directory index, String field1, String text1, String field2, String text2) throws IOException {
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_43, analyzer);
IndexWriterConfig config = new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer);
IndexWriter w = new IndexWriter(index, config);
addDoc(w, field1, text1, field2, text2);
w.close();

View File

@@ -53,7 +53,7 @@ public class TokenPairConcatenatingFilterTest extends BaseTokenStreamTestCase {
* test some examples
*/
public void testExamples() throws IOException {
Tokenizer wsTokenizer = new WhitespaceTokenizer(Version.LUCENE_43, new StringReader("one two three"));
Tokenizer wsTokenizer = new WhitespaceTokenizer(LuceneUtils.CURRENT_VERSION, new StringReader("one two three"));
TokenStream filter = new TokenPairConcatenatingFilter(wsTokenizer);
assertTokenStreamContents(filter,
new String[]{"one", "onetwo", "two", "twothree", "three"});
@@ -65,7 +65,7 @@ public class TokenPairConcatenatingFilterTest extends BaseTokenStreamTestCase {
@Test
public void testClear() throws IOException {
TokenStream ts = new WhitespaceTokenizer(Version.LUCENE_43, new StringReader("one two three"));
TokenStream ts = new WhitespaceTokenizer(LuceneUtils.CURRENT_VERSION, new StringReader("one two three"));
TokenPairConcatenatingFilter filter = new TokenPairConcatenatingFilter(ts);
assertTokenStreamContents(filter, new String[]{"one", "onetwo", "two", "twothree", "three"});

View File

@@ -49,7 +49,7 @@ public abstract class BaseDBTestCase extends TestCase {
public static void ensureDBExists() throws Exception {
java.io.File dataPath = Settings.getFile(Settings.KEYS.DATA_DIRECTORY);
java.io.File dataPath = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
if (!dataPath.exists() || (dataPath.isDirectory() && dataPath.listFiles().length < 3)) {
dataPath.mkdirs();
FileInputStream fis = null;

View File

@@ -1,121 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.net.MalformedURLException;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class BatchUpdateTaskTest {
public BatchUpdateTaskTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
private String old12;
private String old20;
@Before
public void setUp() throws Exception {
old12 = Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL);
old20 = Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL);
File tmp = Settings.getTempDirectory();
if (!tmp.exists()) {
tmp.mkdirs();
}
File dest = new File(tmp, "data.zip");
File file = new File(this.getClass().getClassLoader().getResource("data.zip").toURI());
FileUtils.copyFile(file, dest);
String path = "file:///" + dest.getCanonicalPath();
Settings.setString(Settings.KEYS.BATCH_UPDATE_URL, path);
dest = new File(tmp, "nvdcve-2012.xml");
file = new File(this.getClass().getClassLoader().getResource("nvdcve-2012.xml").toURI());
FileUtils.copyFile(file, dest);
path = "file:///" + dest.getCanonicalPath();
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, path);
dest = new File(tmp, "nvdcve-2.0-2012.xml");
file = new File(this.getClass().getClassLoader().getResource("nvdcve-2.0-2012.xml").toURI());
FileUtils.copyFile(file, dest);
path = "file:///" + dest.getCanonicalPath();
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, path);
}
@After
public void tearDown() {
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, old12);
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, old20);
Settings.setString(Settings.KEYS.BATCH_UPDATE_URL, "");
}
public BatchUpdateTask getBatchUpdateTask() throws MalformedURLException, DownloadFailedException, UpdateException {
DataStoreMetaInfo props = new DataStoreMetaInfo();
BatchUpdateTask instance = new BatchUpdateTask(props);
return instance;
}
/**
* Test of setDoBatchUpdate method, of class BatchUpdateTask.
*/
@Test
public void testSetDoBatchUpdate() throws DownloadFailedException, MalformedURLException, UpdateException {
boolean expected = false;
BatchUpdateTask instance = getBatchUpdateTask();
instance.setDoBatchUpdate(expected);
boolean results = instance.isDoBatchUpdate();
assertEquals(results, expected);
}
/**
* Test of update method, of class BatchUpdateTask.
*/
@Test
public void testUpdate() throws Exception {
BatchUpdateTask instance = getBatchUpdateTask();
//do some setup
instance.setDoBatchUpdate(true);
instance.deleteExistingData();
instance.update(); //no exceptions it worked?
//todo add some actual asserts to check things.
}
}

View File

@@ -18,13 +18,9 @@
*/
package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -38,9 +34,9 @@ import org.owasp.dependencycheck.utils.DownloadFailedException;
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class AbstractUpdateTaskTest {
public class StandardUpdateIntegrationTest {
public AbstractUpdateTaskTest() {
public StandardUpdateIntegrationTest() {
}
@BeforeClass
@@ -59,31 +55,30 @@ public class AbstractUpdateTaskTest {
public void tearDown() {
}
public AbstractUpdateTask getAbstractUpdateImpl() throws Exception {
DataStoreMetaInfo props = new DataStoreMetaInfo();
AbstractUpdateTask instance = new AbstractUpdateImpl(props);
public StandardUpdate getStandardUpdateTask() throws MalformedURLException, DownloadFailedException, UpdateException {
StandardUpdate instance = new StandardUpdate();
return instance;
}
/**
* Test of setDeleteAndRecreate method, of class AbstractUpdateTask.
* Test of setDeleteAndRecreate method, of class StandardUpdate.
*/
@Test
public void testSetDeleteAndRecreate() throws Exception {
boolean deleteAndRecreate = false;
boolean expResult = false;
AbstractUpdateTask instance = getAbstractUpdateImpl();
StandardUpdate instance = getStandardUpdateTask();
instance.setDeleteAndRecreate(deleteAndRecreate);
boolean result = instance.shouldDeleteAndRecreate();
assertEquals(expResult, result);
}
/**
* Test of deleteExistingData method, of class AbstractUpdateTask.
* Test of deleteExistingData method, of class StandardUpdate.
*/
@Test
public void testDeleteExistingData() throws Exception {
AbstractUpdateTask instance = getAbstractUpdateImpl();
StandardUpdate instance = getStandardUpdateTask();
Exception result = null;
try {
instance.deleteExistingData();
@@ -94,17 +89,17 @@ public class AbstractUpdateTaskTest {
}
/**
* Test of openDataStores method, of class AbstractUpdateTask.
* Test of openDataStores method, of class StandardUpdate.
*/
@Test
public void testOpenDataStores() throws Exception {
AbstractUpdateTask instance = getAbstractUpdateImpl();
StandardUpdate instance = getStandardUpdateTask();
instance.openDataStores();
instance.closeDataStores();
}
/**
* Test of withinRange method, of class AbstractUpdateTask.
* Test of withinRange method, of class StandardUpdate.
*/
@Test
public void testWithinRange() throws Exception {
@@ -113,7 +108,7 @@ public class AbstractUpdateTaskTest {
long current = c.getTimeInMillis();
long lastRun = c.getTimeInMillis() - (3 * (1000 * 60 * 60 * 24));
int range = 7; // 7 days
AbstractUpdateTask instance = getAbstractUpdateImpl();
StandardUpdate instance = getStandardUpdateTask();
boolean expResult = true;
boolean result = instance.withinRange(lastRun, current, range);
assertEquals(expResult, result);
@@ -124,17 +119,23 @@ public class AbstractUpdateTaskTest {
assertEquals(expResult, result);
}
public class AbstractUpdateImpl extends AbstractUpdateTask {
/**
* Test of update method, of class StandardUpdate.
*/
@Test
public void testUpdate() throws Exception {
StandardUpdate instance = getStandardUpdateTask();
instance.update();
//TODO make this an actual test
}
public AbstractUpdateImpl(DataStoreMetaInfo props) throws Exception {
super(props);
}
public Updateable updatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
return null;
}
public void update() throws UpdateException {
}
/**
* Test of updatesNeeded method, of class StandardUpdate.
*/
@Test
public void testUpdatesNeeded() throws Exception {
StandardUpdate instance = getStandardUpdateTask();
Updateable result = instance.updatesNeeded();
assertNotNull(result);
}
}

View File

@@ -1,81 +0,0 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import java.net.MalformedURLException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class StandardUpdateTaskIntegrationTest {
public StandardUpdateTaskIntegrationTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
public StandardUpdateTask getStandardUpdateTask() throws MalformedURLException, DownloadFailedException, UpdateException {
DataStoreMetaInfo props = new DataStoreMetaInfo();
StandardUpdateTask instance = new StandardUpdateTask(props);
return instance;
}
/**
* Test of update method, of class StandardUpdateTask.
*/
@Test
public void testUpdate() throws Exception {
StandardUpdateTask instance = getStandardUpdateTask();
instance.update();
//TODO make this an actual test
}
/**
* Test of updatesNeeded method, of class StandardUpdateTask.
*/
@Test
public void testUpdatesNeeded() throws Exception {
StandardUpdateTask instance = getStandardUpdateTask();
Updateable result = instance.updatesNeeded();
assertNotNull(result);
}
}

View File

@@ -0,0 +1,108 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class PropertyTypeTest {
public PropertyTypeTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of set and getValue method, of class PropertyType.
*/
@Test
public void testSetGetValue() {
PropertyType instance = new PropertyType();
String expResult = "test";
instance.setValue(expResult);
String result = instance.getValue();
assertEquals(expResult, result);
}
/**
* Test of isRegex method, of class PropertyType.
*/
@Test
public void testIsRegex() {
PropertyType instance = new PropertyType();
boolean result = instance.isRegex();
assertFalse(instance.isRegex());
instance.setRegex(true);
assertTrue(instance.isRegex());
}
/**
* Test of isCaseSensitive method, of class PropertyType.
*/
@Test
public void testIsCaseSensitive() {
PropertyType instance = new PropertyType();
assertFalse(instance.isCaseSensitive());
instance.setCaseSensitive(true);
assertTrue(instance.isCaseSensitive());
}
/**
* Test of matches method, of class PropertyType.
*/
@Test
public void testMatches() {
String text = "Simple";
PropertyType instance = new PropertyType();
instance.setValue("simple");
assertTrue(instance.matches(text));
instance.setCaseSensitive(true);
assertFalse(instance.matches(text));
instance.setValue("s.*le");
instance.setRegex(true);
assertFalse(instance.matches(text));
instance.setCaseSensitive(false);
assertTrue(instance.matches(text));
}
}

View File

@@ -0,0 +1,95 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class SuppressionHandlerTest {
public SuppressionHandlerTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of getSupressionRules method, of class SuppressionHandler.
*
* @throws Exception thrown if there is an exception....
*/
@Test
public void testHandler() throws Exception {
File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath());
File schema = new File(this.getClass().getClassLoader().getResource("schema/suppression.xsd").getPath());
SuppressionHandler handler = new SuppressionHandler();
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
SAXParser saxParser = factory.newSAXParser();
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, schema);
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setErrorHandler(new SuppressionErrorHandler());
xmlReader.setContentHandler(handler);
InputStream inputStream = new FileInputStream(file);
Reader reader = new InputStreamReader(inputStream, "UTF-8");
InputSource in = new InputSource(reader);
//in.setEncoding("UTF-8");
xmlReader.parse(in);
List result = handler.getSupressionRules();
assertTrue(result.size() > 3);
}
}

View File

@@ -14,12 +14,12 @@
* You should have received a copy of the GNU General Public License along with
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.cpe;
package org.owasp.dependencycheck.suppression;
import org.owasp.dependencycheck.data.cpe.BaseIndex;
import java.io.File;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -28,17 +28,21 @@ import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test of the suppression parser.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class BaseIndexTest {
public class SuppressionParserTest {
public SuppressionParserTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() throws Exception {
public static void tearDownClass() {
}
@Before
@@ -50,14 +54,13 @@ public class BaseIndexTest {
}
/**
* Test of getDataDirectory method, of class BaseIndex.
*
* @throws Exception
* Test of parseSuppressionRules method, of class SuppressionParser.
*/
@Test
public void testGetDataDirectory() throws Exception {
String file = BaseIndex.getDataDirectory().getPath();
String exp = File.separatorChar + "target" + File.separatorChar + "data" + File.separatorChar + "cpe";
assertTrue(file.contains(exp));
public void testParseSuppressionRules() throws Exception {
File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath());
SuppressionParser instance = new SuppressionParser();
List result = instance.parseSuppressionRules(file);
assertTrue(result.size() > 3);
}
}

View File

@@ -0,0 +1,471 @@
/*
* This file is part of dependency-check-core.
*
* Dependency-check-core 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-core 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-core. If not, see http://www.gnu.org/licenses/.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.suppression;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
/**
* Test of the suppression rule.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class SuppressionRuleTest {
public SuppressionRuleTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
//<editor-fold defaultstate="collapsed" desc="Stupid tests of properties">
/**
* Test of FilePath property, of class SuppressionRule.
*/
@Test
public void testFilePath() {
SuppressionRule instance = new SuppressionRule();
PropertyType expResult = new PropertyType();
expResult.setValue("test");
instance.setFilePath(expResult);
PropertyType result = instance.getFilePath();
assertEquals(expResult, result);
}
/**
* Test of Sha1 property, of class SuppressionRule.
*/
@Test
public void testSha1() {
SuppressionRule instance = new SuppressionRule();
String expResult = "384FAA82E193D4E4B0546059CA09572654BC3970";
instance.setSha1(expResult);
String result = instance.getSha1();
assertEquals(expResult, result);
}
/**
* Test of Cpe property, of class SuppressionRule.
*/
@Test
public void testCpe() {
SuppressionRule instance = new SuppressionRule();
ArrayList<PropertyType> cpe = new ArrayList<PropertyType>();
instance.setCpe(cpe);
assertFalse(instance.hasCpe());
PropertyType pt = new PropertyType();
pt.setValue("one");
instance.addCpe(pt);
assertTrue(instance.hasCpe());
List<PropertyType> result = instance.getCpe();
assertEquals(cpe, result);
}
/**
* Test of CvssBelow property, of class SuppressionRule.
*/
@Test
public void testGetCvssBelow() {
SuppressionRule instance = new SuppressionRule();
ArrayList<Float> cvss = new ArrayList<Float>();
instance.setCvssBelow(cvss);
assertFalse(instance.hasCvssBelow());
instance.addCvssBelow(0.7f);
assertTrue(instance.hasCvssBelow());
List<Float> result = instance.getCvssBelow();
assertEquals(cvss, result);
}
/**
* Test of Cwe property, of class SuppressionRule.
*/
@Test
public void testCwe() {
SuppressionRule instance = new SuppressionRule();
ArrayList<String> cwe = new ArrayList<String>();
instance.setCwe(cwe);
assertFalse(instance.hasCwe());
instance.addCwe("2");
assertTrue(instance.hasCwe());
List<String> result = instance.getCwe();
assertEquals(cwe, result);
}
/**
* Test of Cve property, of class SuppressionRule.
*/
@Test
public void testCve() {
SuppressionRule instance = new SuppressionRule();
ArrayList<String> cve = new ArrayList<String>();
instance.setCve(cve);
assertFalse(instance.hasCve());
instance.addCve("CVE-2013-1337");
assertTrue(instance.hasCve());
List<String> result = instance.getCve();
assertEquals(cve, result);
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Ignored duplicate tests, left in, as empty tests, so IDE doesn't re-generate them">
/**
* Test of getFilePath method, of class SuppressionRule.
*/
@Test
public void testGetFilePath() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of setFilePath method, of class SuppressionRule.
*/
@Test
public void testSetFilePath() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of getSha1 method, of class SuppressionRule.
*/
@Test
public void testGetSha1() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of setSha1 method, of class SuppressionRule.
*/
@Test
public void testSetSha1() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of getCpe method, of class SuppressionRule.
*/
@Test
public void testGetCpe() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of setCpe method, of class SuppressionRule.
*/
@Test
public void testSetCpe() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of addCpe method, of class SuppressionRule.
*/
@Test
public void testAddCpe() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of hasCpe method, of class SuppressionRule.
*/
@Test
public void testHasCpe() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of setCvssBelow method, of class SuppressionRule.
*/
@Test
public void testSetCvssBelow() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of addCvssBelow method, of class SuppressionRule.
*/
@Test
public void testAddCvssBelow() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of hasCvssBelow method, of class SuppressionRule.
*/
@Test
public void testHasCvssBelow() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of getCwe method, of class SuppressionRule.
*/
@Test
public void testGetCwe() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of setCwe method, of class SuppressionRule.
*/
@Test
public void testSetCwe() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of addCwe method, of class SuppressionRule.
*/
@Test
public void testAddCwe() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of hasCwe method, of class SuppressionRule.
*/
@Test
public void testHasCwe() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of getCve method, of class SuppressionRule.
*/
@Test
public void testGetCve() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of setCve method, of class SuppressionRule.
*/
@Test
public void testSetCve() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of addCve method, of class SuppressionRule.
*/
@Test
public void testAddCve() {
//already tested, this is just left so the IDE doesn't recreate it.
}
/**
* Test of hasCve method, of class SuppressionRule.
*/
@Test
public void testHasCve() {
//already tested, this is just left so the IDE doesn't recreate it.
}
//</editor-fold>
/**
* Test of cpeHasNoVersion method, of class SuppressionRule.
*/
@Test
public void testCpeHasNoVersion() {
PropertyType c = new PropertyType();
c.setValue("cpe:/a:microsoft:.net_framework:4.5");
SuppressionRule instance = new SuppressionRule();
assertFalse(instance.cpeHasNoVersion(c));
c.setValue("cpe:/a:microsoft:.net_framework:");
assertFalse(instance.cpeHasNoVersion(c));
c.setValue("cpe:/a:microsoft:.net_framework");
assertTrue(instance.cpeHasNoVersion(c));
}
/**
* Test of countCharacter method, of class SuppressionRule.
*/
@Test
public void testCountCharacter() {
String str = "cpe:/a:microsoft:.net_framework:4.5";
char c = ':';
SuppressionRule instance = new SuppressionRule();
int expResult = 4;
int result = instance.countCharacter(str, c);
assertEquals(expResult, result);
str = "::";
expResult = 2;
result = instance.countCharacter(str, c);
assertEquals(expResult, result);
str = "these are not the characters you are looking for";
expResult = 0;
result = instance.countCharacter(str, c);
assertEquals(expResult, result);
}
/**
* Test of cpeMatches method, of class SuppressionRule.
*/
@Test
public void testCpeMatches() {
Identifier identifier = new Identifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
PropertyType cpe = new PropertyType();
cpe.setValue("cpe:/a:microsoft:.net_framework:4.5");
SuppressionRule instance = new SuppressionRule();
boolean expResult = true;
boolean result = instance.cpeMatches(cpe, identifier);
assertEquals(expResult, result);
cpe.setValue("cpe:/a:microsoft:.net_framework:4.0");
expResult = false;
result = instance.cpeMatches(cpe, identifier);
assertEquals(expResult, result);
cpe.setValue("CPE:/a:microsoft:.net_framework:4.5");
cpe.setCaseSensitive(true);
expResult = false;
result = instance.cpeMatches(cpe, identifier);
assertEquals(expResult, result);
cpe.setValue("cpe:/a:microsoft:.net_framework");
cpe.setCaseSensitive(false);
expResult = true;
result = instance.cpeMatches(cpe, identifier);
assertEquals(expResult, result);
cpe.setValue("cpe:/a:microsoft:.*");
cpe.setRegex(true);
expResult = true;
result = instance.cpeMatches(cpe, identifier);
assertEquals(expResult, result);
cpe.setValue("CPE:/a:microsoft:.*");
cpe.setRegex(true);
cpe.setCaseSensitive(true);
expResult = false;
result = instance.cpeMatches(cpe, identifier);
assertEquals(expResult, result);
cpe.setValue("cpe:/a:apache:.*");
cpe.setRegex(true);
cpe.setCaseSensitive(false);
expResult = false;
result = instance.cpeMatches(cpe, identifier);
assertEquals(expResult, result);
}
/**
* Test of process method, of class SuppressionRule.
*/
@Test
public void testProcess() {
File struts = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
Dependency dependency = new Dependency(struts);
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
String sha1 = dependency.getSha1sum();
dependency.setSha1sum("384FAA82E193D4E4B0546059CA09572654BC3970");
Vulnerability v = createVulnerability();
dependency.addVulnerability(v);
//cwe
SuppressionRule instance = new SuppressionRule();
instance.setSha1(sha1);
instance.addCwe("287");
instance.process(dependency);
assertTrue(dependency.getVulnerabilities().size() == 1);
dependency.setSha1sum(sha1);
instance.process(dependency);
assertTrue(dependency.getVulnerabilities().isEmpty());
//cvss
dependency.addVulnerability(v);
instance = new SuppressionRule();
instance.addCvssBelow(5f);
instance.process(dependency);
assertTrue(dependency.getVulnerabilities().size() == 1);
instance.addCvssBelow(8f);
instance.process(dependency);
assertTrue(dependency.getVulnerabilities().isEmpty());
//cve
dependency.addVulnerability(v);
instance = new SuppressionRule();
instance.addCve("CVE-2012-1337");
instance.process(dependency);
assertTrue(dependency.getVulnerabilities().size() == 1);
instance.addCve("CVE-2013-1337");
instance.process(dependency);
assertTrue(dependency.getVulnerabilities().isEmpty());
//cpe
instance = new SuppressionRule();
PropertyType pt = new PropertyType();
pt.setValue("cpe:/a:microsoft:.net_framework:4.0");
instance.addCpe(pt);
instance.process(dependency);
assertTrue(dependency.getIdentifiers().size() == 1);
pt = new PropertyType();
pt.setValue("cpe:/a:microsoft:.net_framework:4.5");
instance.addCpe(pt);
pt = new PropertyType();
pt.setValue(".*");
pt.setRegex(true);
instance.setFilePath(pt);
instance.process(dependency);
assertTrue(dependency.getIdentifiers().isEmpty());
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
pt = new PropertyType();
pt.setValue("cpe:/a:microsoft:.net_framework");
instance.addCpe(pt);
assertTrue(dependency.getIdentifiers().size() == 3);
instance.process(dependency);
assertTrue(dependency.getIdentifiers().isEmpty());
}
private Vulnerability createVulnerability() {
Vulnerability v = new Vulnerability();
v.setCwe("CWE-287 Improper Authentication");
v.setName("CVE-2013-1337");
v.setCvssScore(7.5f);
return v;
}
}

View File

@@ -57,23 +57,23 @@ public class SettingsTest {
*/
@Test
public void testGetString() {
String key = Settings.KEYS.CPE_DATA_DIRECTORY;
String expResult = "cpe";
String key = Settings.KEYS.CVE_DATA_DIRECTORY;
String expResult = "cve";
String result = Settings.getString(key);
Assert.assertTrue(result.endsWith(expResult));
}
/**
* Test of getFile method, of class Settings.
* Test of getDataFile method, of class Settings.
*/
@Test
public void testGetFile() throws IOException {
String key = Settings.KEYS.CPE_DATA_DIRECTORY;
String expResult = "data" + File.separator + "cpe";
File result = Settings.getFile(key);
public void testGetDataFile() throws IOException {
String key = Settings.KEYS.CVE_DATA_DIRECTORY;
String expResult = "data" + File.separator + "cve";
File result = Settings.getDataFile(key);
Assert.assertTrue(result.getAbsolutePath().endsWith(expResult));
result = Settings.getFile(Settings.KEYS.DATA_DIRECTORY);
result = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
String path = result.getPath();
Assert.assertTrue(path.endsWith("data") || path.endsWith("data" + File.separator));
}

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<suppressions
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression'
xsi:schemaLocation='https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression suppression.xsd'>
<suppress>
<notes><![CDATA[
This suppresses cpe:/a:csv:csv:1.0 for some.jar in the "c:\path\to" directory.
]]></notes>
<filePath>c:\path\to\some.jar</filePath>
<cpe>cpe:/a:csv:csv:1.0</cpe>
</suppress>
<suppress>
<notes><![CDATA[
This suppresses any jboss:jboss cpe for any test.jar in any directory.
]]></notes>
<filePath regex="true">.*\btest\.jar</filePath>
<cpe>cpe:/a:jboss:jboss</cpe>
</suppress>
<suppress>
<notes><![CDATA[
This suppresses a specific cve for any test.jar in any directory.
]]></notes>
<filePath regex="true">.*\btest\.jar</filePath>
<cve>CVE-2013-1337</cve>
</suppress>
<suppress>
<notes><![CDATA[
This suppresses a specific cve for any dependency in any directory that has the specified sha1 checksum.
]]></notes>
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
<cve>CVE-2013-1337</cve>
</suppress>
<suppress>
<notes><![CDATA[
This suppresses all CVE entries that have a score below CVSS 7.
]]></notes>
<cvssBelow>7</cvssBelow>
</suppress>
</suppressions>

View File

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

View File

@@ -24,7 +24,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.0.5</version>
<version>1.0.7</version>
</parent>
<artifactId>dependency-check-maven</artifactId>

View File

@@ -178,8 +178,14 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
@SuppressWarnings("CanBeFinal")
@Parameter(property = "connectionTimeout", defaultValue = "", required = false)
private String connectionTimeout = null;
/**
* The Connection Timeout.
*/
@SuppressWarnings("CanBeFinal")
@Parameter(property = "suppressionFile", defaultValue = "", required = false)
private String suppressionFile = null;
// </editor-fold>
/**
* Executes the Dependency-Check on the dependent libraries.
*
@@ -646,6 +652,9 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
}
if (suppressionFile != null && !suppressionFile.isEmpty()) {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
}
}
/**

View File

@@ -9,6 +9,7 @@ externalReport | When using as a Site plugin this parameter sets whether or
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
logFile | The file path to write verbose logging information. |
suppressionFile | The file path to the XML suppression file \- used to support suppressing false positives |
connectionTimeout | The Connection Timeout. |
proxyUrl | The Proxy URL. |
proxyPort | The Proxy Port. |

View File

@@ -22,7 +22,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.0.5</version>
<version>1.0.7</version>
<packaging>pom</packaging>
<parent>