Compare commits

...

202 Commits

Author SHA1 Message Date
Jeremy Long
3002c9e430 release 1.0.8
Former-commit-id: d84fcbf655179b64f75898bb5892c6bb5cf2f84a
2014-01-16 08:00:54 -05:00
Jeremy Long
749d70ca94 added additional logging statements
Former-commit-id: 20343aaed618b6b32d2a03b806a913f68c545bb9
2014-01-15 20:45:55 -05:00
Jeremy Long
70b4adeda0 added information on suppressing false positives to the site
Former-commit-id: 39176151fc0bbf304e1d7754f8f1f61d8d776c32
2014-01-15 20:43:09 -05:00
Jeremy Long
7eb86d0a58 added tests for MySQL External DB
Former-commit-id: 54ad0176f42da0932e06aa01ba56424f3ae856e7
2014-01-15 16:13:08 -05:00
Jeremy Long
5545d43417 added autocommit=on to H2 connection string
Former-commit-id: 7c62f36c5636415c80ddabb0ba3896de753ccd95
2014-01-15 13:18:32 -05:00
Jeremy Long
2e3f68bd2c added autocommit=on to H2 connection string
Former-commit-id: 26903f3a375ff6223fb6c5db7117f8bfb84e3a92
2014-01-15 13:16:05 -05:00
Jeremy Long
539babed18 added autocommit=on to H2 connection string
Former-commit-id: b2f8958707ae211970640b124906bc3a67f04fc3
2014-01-15 13:15:50 -05:00
Jeremy Long
300752ab47 removed calls to commit as autocommit is on
Former-commit-id: 8f8473946dcd0133db91017e1a2a7764d0bb9e6f
2014-01-15 13:15:08 -05:00
Jeremy Long
2c34c10c7e Updated plugin versions
Former-commit-id: fb6be27500d24f29f814d9a3c237bb49bddedb56
2014-01-14 06:11:42 -05:00
Jeremy Long
e2fb261e5b javadoc correction
Former-commit-id: abe3b139d3025d05de2b32db84d4020ffc795541
2014-01-14 05:59:52 -05:00
Will Stranathan
6399978168 Actually added the analyzer
Former-commit-id: 2fc4f2b3ec3d353c389ba70e71cd047cd35f28ad
2014-01-13 14:18:49 -05:00
Will Stranathan
4f94765156 Added files I missed during the last change
Former-commit-id: 43785f55a00e7683aa0083296efc923b306f6d6b
2014-01-13 14:16:41 -05:00
Will Stranathan
d58e2aa701 Checkin of the NexusAnalyzer and its tests
Former-commit-id: d9c29602efeaf923feb941ec38c8fc704eb99c11
2014-01-13 10:22:40 -05:00
Will Stranathan
000f382143 Added vim swap files to .gitignore
Former-commit-id: bb02b22571904e3561583612102c0da90dec6120
2014-01-13 10:11:51 -05:00
Jeremy Long
cede2e8843 added DriverShim to resolve class loader issues with the DriverManager
Former-commit-id: 730f626e6a5ec5c6dd9726abdf33d05975ea6d5f
2014-01-13 06:55:47 -05:00
Jeremy Long
66c3450d46 improved test case so that the driver is retrieved to ensure the DriverManager registered the driver correctly
Former-commit-id: d66e20fd2c0a74f6a589702ccbf0d136c413921c
2014-01-13 06:55:27 -05:00
Jeremy Long
9e6e6701be implemented one test to connect to a MySQL DB Server
Former-commit-id: ff8217ef7634412df10974e1e2648b3ab4171d83
2014-01-13 06:54:22 -05:00
Jeremy Long
e60ec5df3c Added DriverShim to get around issue with loading drivers via URLClassLoader
Former-commit-id: 9aac9909503c01e2b41261556252e550a3253005
2014-01-13 06:53:39 -05:00
Jeremy Long
3eae185ae2 noop
Former-commit-id: a78b29d3cf6f23a02c1372d293cbf4027c037ee6
2014-01-13 06:52:55 -05:00
Jeremy Long
053057fdd2 externalized properties for testing mysql db connections
Former-commit-id: e58feddb22961d3a72a6996c4f04d3577ad1605c
2014-01-13 06:51:40 -05:00
Jeremy Long
0af856d566 updated build plugin versions
Former-commit-id: 01675b4348914f7f8d844461462bb00f3275984c
2014-01-12 08:31:37 -05:00
Jeremy Long
76f2b39ce6 updated author tag
Former-commit-id: c216a3b3cfc12b874ac9c39fcc5613980372bf9e
2014-01-12 08:27:52 -05:00
Jeremy Long
7b646c04d5 initial [empty] version
Former-commit-id: 1642f701eea410c3cf2c0b5f9e6a12a6f8ac018e
2014-01-12 08:19:53 -05:00
Jeremy Long
45ae3209b6 updated to support MySQL test cases
Former-commit-id: 6030de95a37397559470bb0f0bb801ed1ff058c6
2014-01-12 08:18:18 -05:00
Jeremy Long
9b04ceedf1 fixed typos
Former-commit-id: 490de2990dab978493b27a8faf8ec6c40b97c6dc
2014-01-12 07:35:03 -05:00
Jeremy Long
41a31cdf4c fixed spelling errors
Former-commit-id: 6c7d9240d7091204f09d37e405675dace1a2159e
2014-01-11 19:55:21 -05:00
Jeremy Long
fe072cd2e3 various IntelliJ analysis recommendations
Former-commit-id: 7b5f0b5c5e0fc37b58e7cecbcf190c0df56ffe0f
2014-01-11 16:04:43 -05:00
Jeremy Long
525933be99 added database connection properties
Former-commit-id: 7abf08834cf366e7c998d33a9a05387192a1f24a
2014-01-11 13:19:33 -05:00
Jeremy Long
98792fde85 removed file
Former-commit-id: 31618dcec4acb3a5c5dda4ba9762519d8c22bf49
2014-01-11 12:45:29 -05:00
Jeremy Long
81733d9f81 removed sonatype parent
Former-commit-id: d31569e6bfd8f8674ea06304bf2d0ee22a2e6679
2014-01-11 12:44:33 -05:00
Jeremy Long
03a753b82c removed one test as method was removed
Former-commit-id: 1910abb63319e5afd451dc241a1b3f7f76bd9704
2014-01-11 12:43:44 -05:00
Jeremy Long
6938b0f4ae removed unused imports
Former-commit-id: 71b42ce0e203e5897492ade452683fc15b0f99a6
2014-01-11 12:43:11 -05:00
Jeremy Long
a50c61e5c5 added new properties for database connections
Former-commit-id: 184db1b04818703598faafe4eccf951febebb52a
2014-01-11 12:42:50 -05:00
Jeremy Long
5450bdbc55 added new property keys for database connection properties
Former-commit-id: 9205017c862fcfc0e30354964bfebe750163b74b
2014-01-11 12:41:58 -05:00
Jeremy Long
11a634b9be updated package info
Former-commit-id: 61a2ac8c1d1888e508118805752d67e23e63bce3
2014-01-11 12:41:30 -05:00
Jeremy Long
801102d379 removed un-needed import after moving classes around
Former-commit-id: 4e196144166ff57e898b1fd1009c7c3cb410c514
2014-01-11 12:41:03 -05:00
Jeremy Long
8eaba18e91 removed unused properties field
Former-commit-id: 08a2b2a405b7f3176cbf44251cf99a8a22286e48
2014-01-11 12:40:37 -05:00
Jeremy Long
d1cb88b5c5 removed un-needed import after moving classes around
Former-commit-id: bf1d7742c91a7a4b22f5f8850e9e7ca45b4fee8a
2014-01-11 12:40:11 -05:00
Jeremy Long
940889f96f removed the ability to delete and recreate the schema
Former-commit-id: ea65f6f2ba5740c930cb8d4ab724cb029e7f6a04
2014-01-11 12:39:34 -05:00
Jeremy Long
3d5b934f54 removed the ability to delete and recreate the schema
Former-commit-id: 0bcec9bb3d09038b03b5307c92104880c1393189
2014-01-11 12:39:01 -05:00
Jeremy Long
155f62fd22 initial implementation
Former-commit-id: 76116c9ababd6a1b5a1c77756826f875cffa6325
2014-01-11 12:38:26 -05:00
Jeremy Long
6c3025c487 initial version of exception
Former-commit-id: 4e728dce235f4cf86534db2c1992916c0b889328
2014-01-11 12:37:56 -05:00
Jeremy Long
4e62a2ee4f removed un-neede property value update
Former-commit-id: 313e74b97e818fda1421785c4c462f6c330122a3
2014-01-11 12:37:28 -05:00
Jeremy Long
712a076be8 updated to utilize the ConnectionFactory
Former-commit-id: 0fc86441610efd54905864a6e64b57d35e86b86b
2014-01-11 12:36:58 -05:00
Jeremy Long
97f1ff02a0 initial implementation
Former-commit-id: c69a772ec7d0d39dd880c8ffa7f75d0d4c254ec3
2014-01-11 12:36:17 -05:00
Jeremy Long
2b36eb42a8 added additional verbose logging
Former-commit-id: 49f9467ab33a3d260b295a938bac702358a522c6
2014-01-11 12:35:44 -05:00
Jeremy Long
ada2972669 updated to conform with new api (less exceptions caught)
Former-commit-id: aa52a7c9429b292061a3dd7afdaf7fb887cdbea9
2014-01-11 12:35:07 -05:00
Jeremy Long
5822dcccec initial version of tests
Former-commit-id: 38a225894315cef478ad713609a1beebe925a8d2
2014-01-11 12:34:24 -05:00
Jeremy Long
843fd4abec added MySQL Initialization script
Former-commit-id: 86a513207d3ae6fde7082e4fa8be38ece041384c
2014-01-11 12:33:57 -05:00
Jeremy Long
8d840bfe0e added mysql connector
Former-commit-id: 4a968876865087db300180712031dd8c78d24392
2014-01-11 12:33:29 -05:00
Jeremy Long
a2d0c335d0 updated year regex
Former-commit-id: 5f3225071b1c5a45bb280ec3e5b6455da465283e
2014-01-11 12:31:41 -05:00
Jeremy Long
645735a048 updated to make SQL statements more cross platform
Former-commit-id: 7ddd41ed025effcf1f3cf0562105ab8208f46202
2014-01-10 06:16:32 -05:00
Jeremy Long
c58d27fe2d fixed bug 40 - version evidence is not showing up in the final reports
Former-commit-id: 8801f3d14c5d1e866bb3c81c73d807c4dd51bfbd
2014-01-08 05:23:18 -05:00
Jeremy Long
b9a2bcb0bf Fixed typo in logging
Former-commit-id: 4699a65d895dd2268973c7ef4a7fcde5045da119
2014-01-05 07:14:59 -05:00
Jeremy Long
8eb2f738ef Initial version
Former-commit-id: e7be5c63fd8ffb67d4813a7804082d282a80e134
2014-01-05 07:13:50 -05:00
Jeremy Long
af77ab01c2 updated logging
Former-commit-id: cf72503083e68cc1f58a20d8a0e86f3fca00295d
2014-01-05 07:12:55 -05:00
Jeremy Long
6022b13285 updated package-info
Former-commit-id: fdc542ccc2d06f352b2bb949e5107b7cbaf6561b
2014-01-04 09:17:02 -05:00
Jeremy Long
735660c830 moved several classes
Former-commit-id: ea163c7ee1ffeb968a78bed953abdad55083b87f
2014-01-04 09:08:22 -05:00
Jeremy Long
27daccfc35 moved several classes
Former-commit-id: 16322c61d505a25eb1037a90e2ca941147fad6cf
2014-01-04 09:01:04 -05:00
Jeremy Long
2a54077ab1 moved several classes
Former-commit-id: 3bd04e0484cd888b18b929249bed82ca1130a5f2
2014-01-04 08:56:09 -05:00
Jeremy Long
8e2e258518 updated JavaDoc
Former-commit-id: 38777540e58ce5821fbb86f183e824c143635825
2014-01-04 08:54:36 -05:00
Jeremy Long
a4771090ed renamed and moved classes
Former-commit-id: b0e9d931be4d61eb25178182e8602a0c0be4b6b9
2014-01-04 08:47:25 -05:00
Jeremy Long
133a18b70c Moved DBUtils to the utils package
Former-commit-id: 50c78e572be6ac878b29430adeed4c084f50e417
2014-01-04 08:40:23 -05:00
Jeremy Long
4286c79173 removed code that had been previously commented out
Former-commit-id: be89d4ed5ed3f54d0b179a9614ce8e0f0de745e3
2014-01-03 15:15:52 -05:00
Jeremy Long
97238b764f findbugs/checkstyle patches
Former-commit-id: b796c6631e20064fe2098721995a271b6cb44f66
2014-01-03 14:56:18 -05:00
Jeremy Long
b9f3c41a9d checkstyle patches
Former-commit-id: 2c8f71524fb0eb600b41a06c9bdad8d65519551f
2014-01-03 14:39:09 -05:00
Jeremy Long
e8e951e7ff checkstyle patches
Former-commit-id: 0220c6278809ce9f50fa33f9376b90e54c61b612
2014-01-03 14:30:12 -05:00
Jeremy Long
f4928dd0b4 moved files to a new package
Former-commit-id: 129b8d0c256104fe2ae28bb45c0418114ed28e35
2014-01-03 14:29:35 -05:00
Jeremy Long
8e14a54815 minor changes to make this a utility class (final, private constructor)
Former-commit-id: 0571f0eddc640925d5f5f2ffbdb873d082191ba9
2014-01-03 14:29:12 -05:00
Jeremy Long
52b2bfcd41 updated to use DBUtils rather then the, now removed, parent class
Former-commit-id: 9bccc5e3eb5f9c0846eec99a95395a69101715ee
2014-01-03 14:28:30 -05:00
Jeremy Long
a383fe09f6 converted to BaseDB to DBUtils
Former-commit-id: f5366fef82cb43c52e1cdfc49388090fa05fb13a
2014-01-03 14:27:43 -05:00
Jeremy Long
00446f7093 removed unused import
Former-commit-id: 585d9bc2c68d32551b4f1a7cae30fc5bda1d059a
2014-01-03 14:21:21 -05:00
Jeremy Long
7b0d04ef72 removed unused imports
Former-commit-id: e4528fee0acd15217db45b8531ffa498e9c4f36d
2014-01-03 14:20:54 -05:00
Jeremy Long
66996ec1d3 moved to new package
Former-commit-id: df0c16afe8fac4250e83fbbf66e48eee0ff2df5c
2014-01-03 14:20:12 -05:00
Jeremy Long
71f40856dc renamed files
Former-commit-id: b8d315c127b078e1d09280c36d08a74b851ceff6
2014-01-03 14:06:49 -05:00
Jeremy Long
2c19cc3dff removed unused properties
Former-commit-id: 4662d7c84968e036a3bacbc377337b9b63bf68e4
2014-01-03 14:06:14 -05:00
Jeremy Long
40a1b6fde0 fixed tests based on changes to APIs and available settings
Former-commit-id: 120cbabb800de8c3d385a52f3ae8bd25d9492830
2014-01-03 14:05:47 -05:00
Jeremy Long
ca5ce25dee removed test for deleteExistingData (which was also removed from the class being tested)
Former-commit-id: 001b6c1870b7a91e11042ee7f7b46e67b6e0e36e
2014-01-03 14:05:01 -05:00
Jeremy Long
ca08887dca fixed tests to work with the new method for accessing the DB properties
Former-commit-id: 1cbd6305d8aa758618f80a4c46d6bb20d03fc57f
2014-01-03 14:04:11 -05:00
Jeremy Long
b7804a4c83 removed unused import
Former-commit-id: 3323ba22888f13af6d1620e0175221e385ada254
2014-01-03 14:03:25 -05:00
Jeremy Long
5460645d4a removed unused property
Former-commit-id: 87027e6ba903fa3719cded64525949b453912c6b
2014-01-03 14:03:05 -05:00
Jeremy Long
0fbfbfb8f7 updated getDataFile() so that it no longer checks for a base data directory as the subdirectories have been removed
Former-commit-id: ea5f520dbc71243d15e89e6b318c9bd7cbbe22ab
2014-01-03 14:02:36 -05:00
Jeremy Long
998f916cdc removed unused function deleteExistingData
Former-commit-id: 824275af643b7b47cb7b029bd4d6ecd8b69a7d01
2014-01-03 14:01:26 -05:00
Jeremy Long
1895af9f39 Moved meta data about the NVD CVE into a database table rather then an external properties file
Former-commit-id: 72e131d34110856bc2a20371f2b7661928311efe
2014-01-03 14:00:39 -05:00
Jeremy Long
720870675c Moved properties to the table in the DB rather then an external file and moved several methods from the parent class into this class
Former-commit-id: 9a8ca2484cd866eb2825f3c80b9a35b9558fcc33
2014-01-03 13:59:39 -05:00
Jeremy Long
a58eba37a9 Moved most functions to CveDB.java; slowly converting the class to a pure DB utility rather then a base class
Former-commit-id: 48cae3cfeee70312f04605cc1772d735ddb0d969
2014-01-03 13:40:25 -05:00
Jeremy Long
9a2ec6b110 moved properties to DB, minor change to API to support this
Former-commit-id: e4a6c6c1eca6806a0d3228ded911fed3ab0f0b19
2014-01-03 09:02:08 -05:00
Jeremy Long
389852c979 fixed logging issue
Former-commit-id: 99fdbe6b0388b68537d6741ad29714b40bada033
2014-01-03 09:00:35 -05:00
Jeremy Long
bbee8e7d81 corrected logging problem
Former-commit-id: bbde8ab5d76970d7a9bf99e299802119e03c9ed3
2014-01-03 09:00:11 -05:00
Jeremy Long
161cd1ee13 moved properties to database along with lots of other minor changes
Former-commit-id: 46c5cac920eead5b1367657b64466b72b8dab5fc
2014-01-03 08:59:40 -05:00
Jeremy Long
3adc6a646f Changed from deleting existing physical files to recreating the table structure when data was too old
Former-commit-id: a51d372188b371a0b3ebfe23fd21bae1b8284088
2014-01-03 08:58:39 -05:00
Jeremy Long
13ba54183a Updated as properties moved to the DB
Former-commit-id: 6904cc3f79cb60379addecdb0f63f8da64a32255
2014-01-03 08:57:27 -05:00
Jeremy Long
8be331ddcb fixed logging issue
Former-commit-id: 30d6eb459098c31f085c35ef8af787bc4fdb3993
2014-01-03 08:56:11 -05:00
Jeremy Long
a896566a14 improved error handling and logging
Former-commit-id: d6b755d0ade7ec3cb5ad7f4ff9edb1ccf4969d60
2014-01-03 08:55:29 -05:00
Jeremy Long
58ebcbce3d Fixed logging issue
Former-commit-id: 68ee302cbd37302345b8d83c8e588ade2383436d
2014-01-03 08:54:40 -05:00
Jeremy Long
06cff0b2a6 renamed settings to properties in the schema
Former-commit-id: 37c8965f64f52b1ae261c18b6d4fce9b5df8b737
2013-12-21 08:15:20 -05:00
Jeremy Long
74c0e3a659 updated schema version to 2.8
Former-commit-id: e8f640e632ab2778327bf57a0ba5b3539bc2a822
2013-12-21 08:14:29 -05:00
Jeremy Long
076ad8ef7e made error handling more robust so analysis should stop when something goes wrong with a signle jar
Former-commit-id: 1e8fb3a5e6e904751c98a3621630f7953400e802
2013-12-21 07:46:47 -05:00
Jeremy Long
64ebc35dbd improved error handling/reporting
Former-commit-id: e94f29085e11a331d028ee38d24d69017de679c6
2013-12-20 05:36:04 -05:00
Jeremy Long
ee5146273e updated documentation to demonstrate a very basic configuration
Former-commit-id: 19425cd973799d866dd92bf1748b0484a3eac180
2013-12-14 13:19:57 -05:00
Jeremy Long
2c82711476 removed batch mode property test cases
Former-commit-id: e64ad0e00a94c4b24585e42c41712fdeba44ba3d
2013-12-07 13:34:30 -05:00
Jeremy Long
897650cf27 removed unused imports
Former-commit-id: a8848b211e0e602ba20cc196e87dd6336596a3b5
2013-12-07 13:32:57 -05:00
Jeremy Long
8e4a3c705a removed batch update properties
Former-commit-id: 255c6e71949efe83516c9eec47b7fcf12f5aef29
2013-12-07 13:30:55 -05:00
Jeremy Long
01bf6a7eee added some JavaDoc comments
Former-commit-id: b1c8567fc7d29aa2e3285838fabba9f4e5a63fc3
2013-12-07 13:29:28 -05:00
Jeremy Long
4ea9445a8f added some JavaDoc comments
Former-commit-id: f4c296a2bbc5b56f8bcd944974e651bf1e19c431
2013-12-07 13:29:05 -05:00
Jeremy Long
b3980acbf5 Changed order to prevent blocking, CallableDownloadTasks automatically submit the results to the process executor queue now
Former-commit-id: 536fd58f195fd46de16d56064453409d0e39536b
2013-12-07 13:25:34 -05:00
Jeremy Long
d3a1f73d3e Changed order to prevent blocking, CallableDownloadTasks automatically submit the results to the process executor queue now
Former-commit-id: 7b3e75b8b0903041624edb5aba260ac58f6a8099
2013-12-07 12:04:08 -05:00
Jeremy Long
7faa9adf79 added a warning to the build output if CVEs are identified
Former-commit-id: bf7b1297a62ec37207fc6409ae62208c117bdb7b
2013-12-07 10:09:07 -05:00
Jeremy Long
1a5ce8f2e9 1.0.8 snapshot
Former-commit-id: f753b911d8f69537c4645d6b0de779d40e2d415e
2013-12-03 05:53:39 -05:00
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
Jeremy Long
5cfb83a912 version 1.0.5
Former-commit-id: 3315c121f8adeeb5e4dc9fff9d2753bc5faf78fc
2013-11-16 13:42:19 -05:00
Jeremy Long
85540e6fe3 updated import list to remove .* imports
Former-commit-id: 9e4cfec62260d663af9836984367ea2bb0985fe0
2013-11-16 13:18:11 -05:00
Jeremy Long
eda770570c added javadoc comments
Former-commit-id: 0c3f625e56e09965a34b3707dcea4598408eaea9
2013-11-16 13:17:34 -05:00
Jeremy Long
41476943ef minor checkstyle fix
Former-commit-id: 3081c6252d389f3ec051982e07f5fc680475d506
2013-11-16 13:12:05 -05:00
Jeremy Long
68857fea24 suppressed null warnings
Former-commit-id: 50dbea3c9b9a101b1e4bcb9714845d9cf182fea9
2013-11-16 13:09:33 -05:00
Jeremy Long
98911eca05 fixed bug in verbose logging
Former-commit-id: fd4a9b85c3b54ce9f96eaba12b2305614407729d
2013-11-16 13:04:05 -05:00
Jeremy Long
d71e61df8b fixed string format newline character
Former-commit-id: 490c6b3666f03c6796ddd9b47ce83fe8bc070645
2013-11-16 13:03:46 -05:00
Jeremy Long
3188b0f6cb added information about configuring the verbose log file
Former-commit-id: 1d6927fbe8b880894b1e49ed5df2151501961270
2013-11-16 09:26:22 -05:00
Jeremy Long
9885b8d117 added the ability to retrieve the number of documents in the index
Former-commit-id: a88ba4ac5e919f0cac03e08c04d8f4554a22903b
2013-11-16 09:18:02 -05:00
Jeremy Long
f868c3d172 Updated error reporting if data does not exist
Former-commit-id: 99047450cd010ba92e14d2dd70701b3fa38f60f1
2013-11-16 09:17:13 -05:00
Jeremy Long
a169183783 Updated error reporting if data does not exist
Former-commit-id: 299c9815cc5c65d7d16c267a185388367529ee90
2013-11-16 09:16:35 -05:00
Jeremy Long
415edd2265 updated configuration settings
Former-commit-id: d7156d493cae5ab5ee8b0d1e75bd0260f065da50
2013-11-08 19:15:44 -05:00
Jeremy Long
255c80953d Merge branch 'master' of https://github.com/jeremylong/DependencyCheck
Former-commit-id: 3793397b9e14acedaff1425461b907b05e69fa16
2013-11-02 07:19:49 -04:00
Jeremy Long
bf08aeeaad updated base class of test case to ensure data exists for analysis
Former-commit-id: 19ced06bad2174e5877790d35d86d3e1c0028496
2013-11-02 07:18:26 -04:00
Jeremy Long
45143ba8d4 added support for tar and gz files
Former-commit-id: 4ab0e862a52b22ad20c7c1d1de2121c29aa2ebb1
2013-11-02 07:02:02 -04:00
Jeremy Long
ffeac233c2 added new exception type
Former-commit-id: 5b5154cba53bbaa5a57ae9ee1aa4e35fb8243dc1
2013-11-02 06:49:17 -04:00
Jeremy Long
6903ecbeb4 added license file for commons-compress
Former-commit-id: f72b7a92442da254125c8cca9d1459316b00b17d
2013-10-27 14:29:18 -04:00
Jeremy Long
64f0c37251 updated test cases
Former-commit-id: c5b3e27cd038a8f73dadac8f95f589809e90f1c6
2013-10-27 14:28:47 -04:00
Jeremy Long
2331c569df added additional test files
Former-commit-id: 4cffba9e158421721a02a21514abed58451d2750
2013-10-27 14:28:26 -04:00
Steve Springett
34ae6fd089 Merge remote-tracking branch 'origin/master'
Former-commit-id: 8af006894ebed7450ea1253e277674f7f5abae86
2013-10-27 12:42:41 -05:00
Steve Springett
5b58894b02 Adding support for proxy authentication to core, cli, ant and maven.
Former-commit-id: 80048b95bcef525d34f517ddf4dbfffc67b9d410
2013-10-27 12:42:27 -05:00
Jeremy Long
ed5e8e2666 added additional verbose logging capabilities
Former-commit-id: 2a14a2c3ee30f85d3400858be24e5f87d8aa1d9b
2013-10-27 09:13:21 -04:00
Jeremy Long
f903d91dca added false positive checks for axis vs axis2
Former-commit-id: 4548c6d0e8ba036756721460d0d439ff90279dd4
2013-10-26 17:21:14 -04:00
Jeremy Long
58cfdd6d05 attempted to fix minor bug of files not being extracted due to a failure when calling mkdirs()
Former-commit-id: 9136102643bb654b28c39571bbe8ac568a592ea5
2013-10-26 17:19:55 -04:00
Jeremy Long
28523c356c incremented version to 1.0.5-SNAPSHOT
Former-commit-id: 778b13f3c67aa760c1f577037b5e76554be6e067
2013-10-21 21:28:04 -04:00
197 changed files with 7260 additions and 3213 deletions

4
.gitignore vendored
View File

@@ -11,4 +11,6 @@
nb-configuration.xml
/target/
#maven-shade-plugin generated pom
dependency-reduced-pom.xml
dependency-reduced-pom.xml
# vim files
*.swp

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.4</version>
<version>1.0.8</version>
</parent>
<artifactId>dependency-check-ant</artifactId>
@@ -268,7 +268,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14</version>
<version>2.16</version>
<configuration>
<systemProperties>
<property>
@@ -286,9 +286,11 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<version>3.1</version>
<configuration>
<showDeprecation>false</showDeprecation>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
@@ -300,7 +302,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.4</version>
<version>1.5</version>
</dependency>
</dependencies>
<configuration>
@@ -309,7 +311,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.6</version>
<version>2.7</version>
<reportSets>
<reportSet>
<reports>
@@ -324,7 +326,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<version>2.9.1</version>
<reportSets>
<reportSet>
<id>default</id>
@@ -337,7 +339,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.0</version>
<version>2.1</version>
<reportSets>
<reportSet>
<reports>
@@ -350,7 +352,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.3</version>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
@@ -360,7 +362,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.14</version>
<version>2.16</version>
<reportSets>
<reportSet>
<reports>
@@ -396,7 +398,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.10</version>
<version>2.11</version>
<configuration>
<enableRulesSummary>false</enableRulesSummary>
<configLocation>${basedir}/config/checkstyle-checks.xml</configLocation>
@@ -418,7 +420,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.5.2</version>
<version>2.5.3</version>
</plugin>
</reportPlugins>
</configuration>

View File

@@ -34,6 +34,7 @@ import org.apache.tools.ant.types.resources.FileProvider;
import org.apache.tools.ant.types.resources.Resources;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
@@ -43,7 +44,7 @@ import org.owasp.dependencycheck.utils.Settings;
/**
* An Ant task definition to execute dependency-check during an Ant build.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DependencyCheckTask extends Task {
@@ -55,6 +56,10 @@ public class DependencyCheckTask extends Task {
* Name of the logging properties file.
*/
private static final String LOG_PROPERTIES_FILE = "log.properties";
/**
* System specific new line character.
*/
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
/**
* Construct a new DependencyCheckTask.
@@ -323,6 +328,50 @@ public class DependencyCheckTask extends Task {
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
}
/**
* The Proxy username.
*/
private String proxyUsername;
/**
* Get the value of proxyUsername.
*
* @return the value of proxyUsername
*/
public String getProxyUsername() {
return proxyUsername;
}
/**
* Set the value of proxyUsername.
*
* @param proxyUsername new value of proxyUsername
*/
public void setProxyUsername(String proxyUsername) {
this.proxyUsername = proxyUsername;
}
/**
* The Proxy password.
*/
private String proxyPassword;
/**
* Get the value of proxyPassword.
*
* @return the value of proxyPassword
*/
public String getProxyPassword() {
return proxyPassword;
}
/**
* Set the value of proxyPassword.
*
* @param proxyPassword new value of proxyPassword
*/
public void setProxyPassword(String proxyPassword) {
this.proxyPassword = proxyPassword;
}
/**
* The Connection Timeout.
*/
@@ -367,6 +416,50 @@ 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;
}
/**
* flag indicating whether or not to show a summary of findings.
*/
private boolean showSummary = true;
/**
* Get the value of showSummary.
*
* @return the value of showSummary
*/
public boolean isShowSummary() {
return showSummary;
}
/**
* Set the value of showSummary.
*
* @param showSummary new value of showSummary
*/
public void setShowSummary(boolean showSummary) {
this.showSummary = showSummary;
}
@Override
public void execute() throws BuildException {
@@ -395,12 +488,15 @@ public class DependencyCheckTask extends Task {
if (this.failBuildOnCVSS <= 10) {
checkForFailure(engine.getDependencies());
}
if (this.showSummary) {
showSummary(engine.getDependencies());
}
} catch (IOException ex) {
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, null, ex);
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "Unable to generate dependency-check report", ex);
throw new BuildException("Unable to generate dependency-check report", ex);
} catch (Exception ex) {
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.SEVERE, null, ex);
throw new BuildException("An exception occured; unable to continue task", ex);
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "An exception occurred; unable to continue task", ex);
throw new BuildException("An exception occurred; unable to continue task", ex);
}
}
@@ -459,9 +555,18 @@ public class DependencyCheckTask extends Task {
if (proxyPort != null && !proxyPort.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
}
if (proxyUsername != null && !proxyUsername.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername);
}
if (proxyPassword != null && !proxyPassword.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
}
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
}
if (suppressionFile != null && !suppressionFile.isEmpty()) {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
}
}
/**
@@ -493,6 +598,47 @@ public class DependencyCheckTask extends Task {
}
}
/**
* Generates a warning message listing a summary of dependencies and their
* associated CPE and CVE entries.
*
* @param dependencies a list of dependency objects
*/
private void showSummary(List<Dependency> dependencies) {
final StringBuilder summary = new StringBuilder();
for (Dependency d : dependencies) {
boolean firstEntry = true;
final StringBuilder ids = new StringBuilder();
for (Vulnerability v : d.getVulnerabilities()) {
if (firstEntry) {
firstEntry = false;
} else {
ids.append(", ");
}
ids.append(v.getName());
}
if (ids.length() > 0) {
summary.append(d.getFileName()).append(" (");
firstEntry = true;
for (Identifier id : d.getIdentifiers()) {
if (firstEntry) {
firstEntry = false;
} else {
summary.append(", ");
}
summary.append(id.getValue());
}
summary.append(") : ").append(ids).append(NEW_LINE);
}
}
if (summary.length() > 0) {
final String msg = String.format("%n%n"
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.WARNING, msg);
}
}
/**
* An enumeration of supported report formats: "ALL", "HTML", "XML", "VULN",
* etc..

View File

@@ -28,8 +28,12 @@ ReportOutputDirectory | The directory where dependency-check will store data use
FailBuildOn | If set and a CVE is found that is greater then the specified value the build will fail. The default value is 11 which means that the build will not fail. Valid values are 0-11. | Optional
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](../suppression.html). | 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
ProxyPassword | Defines the proxy password. | Optional
ConnectionTimeout | The connection timeout used when downloading data files from the Internet. | Optional

View File

@@ -30,7 +30,7 @@ import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DependencyCheckTaskTest extends BuildFileTest {

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.4</version>
<version>1.0.8</version>
</parent>
<artifactId>dependency-check-cli</artifactId>
@@ -113,7 +113,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14</version>
<version>2.16</version>
<configuration>
<systemProperties>
<property>
@@ -137,9 +137,11 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<version>3.1</version>
<configuration>
<showDeprecation>false</showDeprecation>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
@@ -150,7 +152,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.4</version>
<version>1.5</version>
</dependency>
</dependencies>
<configuration>
@@ -159,7 +161,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.6</version>
<version>2.7</version>
<reportSets>
<reportSet>
<reports>
@@ -174,7 +176,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<version>2.9.1</version>
<reportSets>
<reportSet>
<id>default</id>
@@ -187,7 +189,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.0</version>
<version>2.1</version>
<reportSets>
<reportSet>
<reports>
@@ -200,7 +202,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.3</version>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
@@ -210,7 +212,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.14</version>
<version>2.16</version>
<reportSets>
<reportSet>
<reports>
@@ -246,7 +248,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.10</version>
<version>2.11</version>
<configuration>
<enableRulesSummary>false</enableRulesSummary>
<configLocation>${basedir}/config/checkstyle-checks.xml</configLocation>
@@ -271,7 +273,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.5.2</version>
<version>2.5.3</version>
</plugin>
</reportPlugins>
</configuration>
@@ -279,7 +281,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.4</version>
<version>1.7</version>
<configuration>
<programs>
<program>

View File

@@ -52,7 +52,7 @@ import org.owasp.dependencycheck.utils.Settings;
/**
* The command line interface for the DependencyCheck application.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class App {
@@ -98,7 +98,8 @@ public class App {
cli.printVersionInfo();
} else if (cli.isRunScan()) {
updateSettings(cli.isAutoUpdate(), cli.getConnectionTimeout(), cli.getProxyUrl(),
cli.getProxyPort(), cli.getDataDirectory(), cli.getPropertiesFile());
cli.getProxyPort(), cli.getProxyUsername(), cli.getProxyPassword(),
cli.getDataDirectory(), cli.getPropertiesFile(), cli.getSuppressionFile());
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles());
} else {
cli.printHelp();
@@ -146,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 dataDirectory, File propertiesFile) {
private void updateSettings(boolean autoUpdate, String connectionTimeout, String proxyUrl, String proxyPort,
String proxyUser, String proxyPass, String dataDirectory, File propertiesFile,
String suppressionFile) {
if (propertiesFile != null) {
try {
@@ -184,8 +189,17 @@ public class App {
if (proxyPort != null && !proxyPort.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
}
if (proxyUser != null && !proxyUser.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUser);
}
if (proxyPass != null && !proxyPass.isEmpty()) {
Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPass);
}
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

@@ -35,7 +35,7 @@ import org.owasp.dependencycheck.utils.Settings;
/**
* A utility to parse command line arguments for the DependencyCheck.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public final class CliParser {
@@ -175,6 +175,14 @@ public final class CliParser {
.withDescription("The proxy port to use when downloading resources.")
.create(ArgumentName.PROXY_PORT_SHORT);
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.PROXY_USERNAME)
.withDescription("The proxy username to use when downloading resources.")
.create(ArgumentName.PROXY_USERNAME_SHORT);
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ArgumentName.PROXY_PASSWORD)
.withDescription("The proxy password to use when downloading resources.")
.create(ArgumentName.PROXY_PASSWORD_SHORT);
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
.withDescription("The path to scan - this option can be specified multiple times.")
.create(ArgumentName.SCAN_SHORT);
@@ -199,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);
@@ -213,8 +226,11 @@ 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);
opts.addOption(proxyPassword);
opts.addOption(connectionTimeout);
return opts;
@@ -330,6 +346,24 @@ public final class CliParser {
return line.getOptionValue(ArgumentName.PROXY_PORT);
}
/**
* Returns the proxy username.
*
* @return the proxy username
*/
public String getProxyUsername() {
return line.getOptionValue(ArgumentName.PROXY_USERNAME);
}
/**
* Returns the proxy password.
*
* @return the proxy password
*/
public String getProxyPassword() {
return line.getOptionValue(ArgumentName.PROXY_PASSWORD);
}
/**
* Get the value of dataDirectory.
*
@@ -361,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>
@@ -470,11 +513,27 @@ public final class CliParser {
*/
public static final String PROXY_URL = "proxyurl";
/**
* The short CLI argument name indicating the proxy url.
* The short CLI argument name indicating the proxy username.
*/
public static final String PROXY_USERNAME_SHORT = "pu";
/**
* The CLI argument name indicating the proxy username.
*/
public static final String PROXY_USERNAME = "proxyuser";
/**
* The short CLI argument name indicating the proxy password.
*/
public static final String PROXY_PASSWORD_SHORT = "pp";
/**
* The CLI argument name indicating the proxy password.
*/
public static final String PROXY_PASSWORD = "proxypass";
/**
* The short CLI argument name indicating the connection timeout.
*/
public static final String CONNECTION_TIMEOUT_SHORT = "c";
/**
* The CLI argument name indicating the proxy url.
* The CLI argument name indicating the connection timeout.
*/
public static final String CONNECTION_TIMEOUT = "connectiontimeout";
/**
@@ -505,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; used to suppress [false positives](../suppression.html). | 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

@@ -34,7 +34,7 @@ import org.junit.Test;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class CliParserTest {

View File

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

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.4</version>
<version>1.0.8</version>
</parent>
<artifactId>dependency-check-core</artifactId>
@@ -77,6 +77,9 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
</testResource>
<testResource>
<directory>${basedir}/src/test/resources</directory>
<excludes>
<exclude>**/mysql-connector-java-5.1.27-bin.jar</exclude>
</excludes>
<filtering>false</filtering>
</testResource>
</testResources>
@@ -132,7 +135,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.5.2</version>
<version>2.6</version>
<configuration>
<instrumentation>
<ignores>
@@ -182,14 +185,9 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14</version>
<version>2.16</version>
<configuration>
<systemProperties>
<property>
<name>net.sourceforge.cobertura.datafile</name>
<value>${project.build.directory}/cobertura/cobertura.ser</value>
<workingDirectory>target</workingDirectory>
</property>
<property>
<name>data.directory</name>
<value>${project.build.directory}/data</value>
@@ -201,13 +199,14 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
</systemProperties>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*MySQLTest.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.14</version>
<version>2.16</version>
<configuration>
<systemProperties>
<property>
@@ -236,7 +235,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.4</version>
<version>1.5</version>
</dependency>
</dependencies>
<configuration>
@@ -245,7 +244,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.6</version>
<version>2.7</version>
<reportSets>
<reportSet>
<reports>
@@ -260,7 +259,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<version>2.9.1</version>
<reportSets>
<reportSet>
<id>default</id>
@@ -273,7 +272,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.0</version>
<version>2.1</version>
<reportSets>
<reportSet>
<reports>
@@ -286,17 +285,17 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.3</version>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.5.2</version>
<version>2.6</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.14</version>
<version>2.16</version>
<reportSets>
<reportSet>
<reports>
@@ -339,7 +338,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.10</version>
<version>2.11</version>
<configuration>
<enableRulesSummary>false</enableRulesSummary>
<configLocation>${basedir}/config/checkstyle-checks.xml</configLocation>
@@ -364,7 +363,7 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.5.2</version>
<version>2.5.3</version>
</plugin>
</reportPlugins>
</configuration>
@@ -372,9 +371,11 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<version>3.1</version>
<configuration>
<showDeprecation>false</showDeprecation>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
@@ -410,17 +411,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>
@@ -569,4 +570,59 @@ along with Dependency-Check. If not, see <http://www.gnu.org/licenses />.
<optional>true</optional>
</dependency>
</dependencies>
<profiles>
<profile>
<id>MySQL-IntegrationTest</id>
<activation>
<property>
<name>mysql</name>
<!--value>test</value-->
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.16</version>
<configuration>
<systemProperties>
<property>
<name>data.driver_path</name>
<value>${basedir}/${driver_path}</value>
</property>
<property>
<name>data.driver_name</name>
<value>${driver_name}</value>
</property>
<property>
<name>data.connection_string</name>
<value>${connection_string}</value>
</property>
</systemProperties>
<includes>
<include>**/*MySQLTest.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -18,9 +18,9 @@
*/
package org.owasp.dependencycheck;
import java.util.EnumMap;
import java.io.File;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -31,21 +31,25 @@ import org.owasp.dependencycheck.analyzer.AnalysisException;
import org.owasp.dependencycheck.analyzer.AnalysisPhase;
import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.analyzer.AnalyzerService;
import org.owasp.dependencycheck.data.CachedWebDataSource;
import org.owasp.dependencycheck.data.UpdateException;
import org.owasp.dependencycheck.data.UpdateService;
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.data.update.CachedWebDataSource;
import org.owasp.dependencycheck.data.update.UpdateService;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.NoDataException;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
/**
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and
* used to process the files found by the scan, if a file is encountered and an
* Analyzer is associated with the file type then the file is turned into a
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and used to process the files found by the
* scan, if a file is encountered and an Analyzer is associated with the file type then the file is turned into a
* dependency.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class Engine {
@@ -56,8 +60,8 @@ public class Engine {
/**
* A Map of analyzers grouped by Analysis phase.
*/
private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers =
new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers
= new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
/**
* A set of extensions supported by the analyzers.
*/
@@ -82,10 +86,8 @@ public class Engine {
/**
* Creates a new Engine.
*
* @param autoUpdate indicates whether or not data should be updated from
* the Internet
* @deprecated This function should no longer be used; the autoupdate flag
* should be set using:
* @param autoUpdate indicates whether or not data should be updated from the Internet
* @deprecated This function should no longer be used; the autoupdate flag should be set using:
* <code>Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, value);</code>
*/
@Deprecated
@@ -97,8 +99,7 @@ public class Engine {
}
/**
* Loads the analyzers specified in the configuration file (or system
* properties).
* Loads the analyzers specified in the configuration file (or system properties).
*/
private void loadAnalyzers() {
@@ -137,9 +138,8 @@ public class Engine {
}
/**
* Scans an array of files or directories. If a directory is specified, it
* will be scanned recursively. Any dependencies identified are added to the
* dependency collection.
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
* dependencies identified are added to the dependency collection.
*
* @since v0.3.2.5
*
@@ -153,9 +153,8 @@ public class Engine {
}
/**
* Scans a given file or directory. If a directory is specified, it will be
* scanned recursively. Any dependencies identified are added to the
* dependency collection.
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
* identified are added to the dependency collection.
*
* @param path the path to a file or directory to be analyzed.
*/
@@ -165,9 +164,8 @@ public class Engine {
}
/**
* Scans an array of files or directories. If a directory is specified, it
* will be scanned recursively. Any dependencies identified are added to the
* dependency collection.
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
* dependencies identified are added to the dependency collection.
*
* @since v0.3.2.5
*
@@ -180,9 +178,8 @@ public class Engine {
}
/**
* Scans a list of files or directories. If a directory is specified, it
* will be scanned recursively. Any dependencies identified are added to the
* dependency collection.
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
* dependencies identified are added to the dependency collection.
*
* @since v0.3.2.5
*
@@ -195,9 +192,8 @@ public class Engine {
}
/**
* Scans a list of files or directories. If a directory is specified, it
* will be scanned recursively. Any dependencies identified are added to the
* dependency collection.
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
* dependencies identified are added to the dependency collection.
*
* @since v0.3.2.5
*
@@ -210,9 +206,8 @@ public class Engine {
}
/**
* Scans a given file or directory. If a directory is specified, it will be
* scanned recursively. Any dependencies identified are added to the
* dependency collection.
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
* identified are added to the dependency collection.
*
* @since v0.3.2.4
*
@@ -229,8 +224,7 @@ public class Engine {
}
/**
* Recursively scans files and directories. Any dependencies identified are
* added to the dependency collection.
* Recursively scans files and directories. Any dependencies identified are added to the dependency collection.
*
* @param dir the directory to scan.
*/
@@ -248,8 +242,7 @@ public class Engine {
}
/**
* Scans a specified file. If a dependency is identified it is added to the
* dependency collection.
* Scans a specified file. If a dependency is identified it is added to the dependency collection.
*
* @param file The file to scan.
*/
@@ -277,6 +270,29 @@ public class Engine {
* Runs the analyzers against all of the dependencies.
*/
public void analyzeDependencies() {
//need to ensure that data exists
try {
ensureDataExists();
} catch (NoDataException ex) {
final String msg = String.format("%s%n%nUnable to continue dependency-check analysis.", ex.getMessage());
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(Engine.class.getName()).log(Level.FINE, null, ex);
return;
} catch (DatabaseException ex) {
final String msg = String.format("%s%n%nUnable to continue dependency-check analysis.", ex.getMessage());
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(Engine.class.getName()).log(Level.FINE, null, ex);
return;
}
final String logHeader = String.format("%n"
+ "----------------------------------------------------%n"
+ "BEGIN ANALYSIS%n"
+ "----------------------------------------------------");
Logger.getLogger(Engine.class.getName()).log(Level.FINE, logHeader);
Logger.getLogger(Engine.class.getName()).log(Level.INFO, "Analysis Starting");
//phase one initialize
for (AnalysisPhase phase : AnalysisPhase.values()) {
final List<Analyzer> analyzerList = analyzers.get(phase);
@@ -312,13 +328,19 @@ public class Engine {
final Set<Dependency> dependencySet = new HashSet<Dependency>();
dependencySet.addAll(dependencies);
for (Dependency d : dependencySet) {
final String msgFile = String.format("Begin Analysis of '%s'", d.getActualFilePath());
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msgFile);
if (a.supportsExtension(d.getFileExtension())) {
final String msgFile = String.format("Begin Analysis of '%s'", d.getActualFilePath());
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msgFile);
try {
a.analyze(d, this);
} catch (AnalysisException ex) {
d.addAnalysisException(ex);
} catch (Throwable ex) {
final String axMsg = String.format("An unexpected error occurred during analysis of '%s'", d.getActualFilePath());
final AnalysisException ax = new AnalysisException(axMsg, ex);
d.addAnalysisException(ax);
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, axMsg);
Logger.getLogger(Engine.class.getName()).log(Level.FINE, axMsg, ex);
}
}
}
@@ -338,11 +360,16 @@ public class Engine {
}
}
}
final String logFooter = String.format("%n"
+ "----------------------------------------------------%n"
+ "END ANALYSIS%n"
+ "----------------------------------------------------");
Logger.getLogger(Engine.class.getName()).log(Level.FINE, logFooter);
}
/**
* Cycles through the cached web data sources and calls update on all of
* them.
* Cycles through the cached web data sources and calls update on all of them.
*/
private void doUpdates() {
final UpdateService service = UpdateService.getInstance();
@@ -361,8 +388,7 @@ public class Engine {
}
/**
* Returns a full list of all of the analyzers. This is useful for reporting
* which analyzers where used.
* Returns a full list of all of the analyzers. This is useful for reporting which analyzers where used.
*
* @return a list of Analyzers
*/
@@ -379,8 +405,7 @@ public class Engine {
* Checks all analyzers to see if an extension is supported.
*
* @param ext a file extension
* @return true or false depending on whether or not the file extension is
* supported
* @return true or false depending on whether or not the file extension is supported
*/
public boolean supportsExtension(String ext) {
if (ext == null) {
@@ -396,4 +421,30 @@ public class Engine {
}
return false;
}
/**
* Checks the CPE Index to ensure documents exists. If none exist a NoDataException is thrown.
*
* @throws NoDataException thrown if no data exists in the CPE Index
* @throws DatabaseException thrown if there is an exception opening the database
*/
private void ensureDataExists() throws NoDataException, DatabaseException {
final CpeMemoryIndex cpe = CpeMemoryIndex.getInstance();
final CveDB cve = new CveDB();
try {
cve.open();
cpe.open(cve);
} catch (IndexException ex) {
throw new NoDataException(ex.getMessage(), ex);
} catch (DatabaseException ex) {
throw new NoDataException(ex.getMessage(), ex);
} finally {
cve.close();
}
if (cpe.numDocs() <= 0) {
cpe.close();
throw new NoDataException("No documents exist");
}
}
}

View File

@@ -24,7 +24,7 @@ import java.util.Set;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public abstract class AbstractAnalyzer implements Analyzer {

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 implementation 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

@@ -21,7 +21,7 @@ package org.owasp.dependencycheck.analyzer;
/**
* An exception thrown when the analysis of a dependency fails.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class AnalysisException extends Exception {
@@ -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

@@ -21,7 +21,7 @@ package org.owasp.dependencycheck.analyzer;
/**
* An enumeration defining the phases of analysis.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public enum AnalysisPhase {

View File

@@ -27,7 +27,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
* An analyzer will collect information about the dependency in the form of
* Evidence.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public interface Analyzer {

View File

@@ -23,7 +23,7 @@ import java.util.ServiceLoader;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public final class AnalyzerService {

View File

@@ -32,31 +32,23 @@ import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
//import java.util.zip.ZipEntry;
//import java.util.zip.ZipException;
//import java.util.zip.ZipInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.compressors.CompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipUtils;
import org.h2.store.fs.FileUtils;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings;
/**
* <p>An analyzer that works on archive files:
* <ul>
* <li><b>ZIP</b> - if it is determined to be a JAR, WAR or EAR a copy is made
* and the copy is given the correct extension so that it will be correctly
* analyzed.</li>
* <li><b>WAR</b> - the WAR contents are extracted and added as dependencies to
* the scan. The displayed path is relative to the WAR.</li>
* <li><b>EAR</b> - the WAR contents are extracted and added as dependencies to
* the scan. Any WAR files are also processed so that the contained JAR files
* are added to the list of dependencies. The displayed path is relative to the
* EAR.</li>
* </ul></p>
* <p>An analyzer that extracts files from archives and ensures any supported
* files contained within the archive are added to the dependency list.</p>
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
@@ -82,7 +74,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
* Tracks the current scan/extraction depth for nested archives.
*/
private int scanDepth = 0;
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/**
* The name of the analyzer.
*/
@@ -94,7 +86,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
/**
* The set of file extensions supported by this analyzer.
*/
private static final Set<String> EXTENSIONS = newHashSet("zip", "ear", "war");
private static final Set<String> EXTENSIONS = newHashSet("zip", "ear", "war", "tar", "gz", "tgz");
/**
* Returns a list of file EXTENSIONS supported by this analyzer.
@@ -152,10 +144,12 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
}
tempFileLocation = File.createTempFile("check", "tmp", baseDir);
if (!tempFileLocation.delete()) {
throw new AnalysisException("Unable to delete temporary file '" + tempFileLocation.getAbsolutePath() + "'.");
final String msg = String.format("Unable to delete temporary file '%s'.", tempFileLocation.getAbsolutePath());
throw new AnalysisException(msg);
}
if (!tempFileLocation.mkdirs()) {
throw new AnalysisException("Unable to create directory '" + tempFileLocation.getAbsolutePath() + "'.");
final String msg = String.format("Unable to create directory '%s'.", tempFileLocation.getAbsolutePath());
throw new AnalysisException(msg);
}
}
@@ -231,8 +225,13 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
private File getNextTempDirectory() throws AnalysisException {
dirCount += 1;
final File directory = new File(tempFileLocation, String.valueOf(dirCount));
//getting an exception for some directories not being able to be created; might be because the directory already exists?
if (directory.exists()) {
return getNextTempDirectory();
}
if (!directory.mkdirs()) {
throw new AnalysisException("Unable to create temp directory '" + directory.getAbsolutePath() + "'.");
final String msg = String.format("Unable to create temp directory '%s'.", directory.getAbsolutePath());
throw new AnalysisException(msg);
}
return directory;
}
@@ -241,37 +240,75 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
* Extracts the contents of an archive into the specified directory.
*
* @param archive an archive file such as a WAR or EAR
* @param extractTo a directory to extract the contents to
* @param destination a directory to extract the contents to
* @param engine the scanning engine
* @throws AnalysisException thrown if the archive is not found
*/
private void extractFiles(File archive, File extractTo, Engine engine) throws AnalysisException {
if (archive == null || extractTo == null) {
private void extractFiles(File archive, File destination, Engine engine) throws AnalysisException {
if (archive == null || destination == null) {
return;
}
FileInputStream fis = null;
//ZipInputStream zis = null;
ZipArchiveInputStream zis = null;
try {
fis = new FileInputStream(archive);
} catch (FileNotFoundException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.INFO, null, ex);
throw new AnalysisException("Archive file was not found.", ex);
}
zis = new ZipArchiveInputStream(new BufferedInputStream(fis));
ZipArchiveEntry entry;
final String archiveExt = org.owasp.dependencycheck.utils.FileUtils.getFileExtension(archive.getName()).toLowerCase();
try {
while ((entry = zis.getNextZipEntry()) != null) {
if ("zip".equals(archiveExt) || "war".equals(archiveExt) || "ear".equals(archiveExt)) {
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
} else if ("tar".equals(archiveExt)) {
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
final String uncompressedExt = org.owasp.dependencycheck.utils.FileUtils.getFileExtension(uncompressedName).toLowerCase();
if (engine.supportsExtension(uncompressedExt)) {
decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), new File(destination, uncompressedName));
}
}
} catch (ArchiveExtractionException ex) {
final String msg = String.format("Exception extracting archive '%s'.", archive.getName());
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
} catch (IOException ex) {
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
} finally {
try {
fis.close();
} catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
}
}
}
/**
* Extracts files from an archive.
*
* @param input the archive to extract files from
* @param destination the location to write the files too
* @param engine the dependency-check engine
* @throws ArchiveExtractionException thrown if there is an exception
* extracting files from the archive
*/
private void extractArchive(ArchiveInputStream input, File destination, Engine engine) throws ArchiveExtractionException {
ArchiveEntry entry;
try {
while ((entry = input.getNextEntry()) != null) {
if (entry.isDirectory()) {
final File d = new File(extractTo, entry.getName());
if (!d.mkdirs()) {
throw new AnalysisException("Unable to create '" + d.getAbsolutePath() + "'.");
final File d = new File(destination, entry.getName());
if (!d.exists()) {
if (!d.mkdirs()) {
final String msg = String.format("Unable to create '%s'.", d.getAbsolutePath());
throw new AnalysisException(msg);
}
}
} else {
final File file = new File(extractTo, entry.getName());
final File file = new File(destination, entry.getName());
final String ext = org.owasp.dependencycheck.utils.FileUtils.getFileExtension(file.getName());
if (engine.supportsExtension(ext)) {
BufferedOutputStream bos = null;
@@ -281,22 +318,27 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
int count;
final byte data[] = new byte[BUFFER_SIZE];
while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
bos.write(data, 0, count);
}
bos.flush();
} catch (FileNotFoundException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException("Unable to find file '" + file.getName() + "'.", ex);
Logger.getLogger(ArchiveAnalyzer.class
.getName()).log(Level.FINE, null, ex);
final String msg = String.format("Unable to find file '%s'.", file.getName());
throw new AnalysisException(msg, ex);
} catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException("IO Exception while parsing file '" + file.getName() + "'.", ex);
Logger.getLogger(ArchiveAnalyzer.class
.getName()).log(Level.FINE, null, ex);
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
throw new AnalysisException(msg, ex);
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
Logger.getLogger(ArchiveAnalyzer.class
.getName()).log(Level.FINEST, null, ex);
}
}
}
@@ -304,20 +346,50 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
}
}
} catch (IOException ex) {
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException(msg, ex);
throw new ArchiveExtractionException(ex);
} catch (Throwable ex) {
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, null, ex);
throw new AnalysisException(msg, ex);
throw new ArchiveExtractionException(ex);
} finally {
try {
zis.close();
} catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
if (input != null) {
try {
input.close();
} catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
}
}
}
}
/**
* Decompresses a file.
*
* @param inputStream the compressed file
* @param outputFile the location to write the decompressed file
* @throws ArchiveExtractionException thrown if there is an exception
* decompressing the file
*/
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
FileOutputStream out = null;
try {
out = new FileOutputStream(outputFile);
final byte[] buffer = new byte[BUFFER_SIZE];
int n = 0;
while (-1 != (n = inputStream.read(buffer))) {
out.write(buffer, 0, n);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new ArchiveExtractionException(ex);
} catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new ArchiveExtractionException(ex);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ex) {
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
}
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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;
/**
* An exception thrown when files in an archive cannot be extracted.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class ArchiveExtractionException extends Exception {
/**
* The serial version UID for serialization.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new ArchiveExtractionException.
*/
public ArchiveExtractionException() {
super();
}
/**
* Creates a new ArchiveExtractionException.
*
* @param msg a message for the exception.
*/
public ArchiveExtractionException(String msg) {
super(msg);
}
/**
* Creates a new ArchiveExtractionException.
*
* @param ex the cause of the failure.
*/
public ArchiveExtractionException(Throwable ex) {
super(ex);
}
/**
* Creates a new ArchiveExtractionException.
*
* @param msg a message for the exception.
* @param ex the cause of the failure.
*/
public ArchiveExtractionException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -21,7 +21,6 @@ package org.owasp.dependencycheck.analyzer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -40,9 +39,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;
@@ -55,7 +55,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
* to discern if there is an associated CPE. It uses the evidence contained
* within the dependency to search the Lucene index.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class CPEAnalyzer implements Analyzer {
@@ -83,9 +83,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,22 +100,21 @@ 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();
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, "Opening the CVE Database");
cve = new CveDB();
cve.open();
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, "Creating the Lucene CPE Index");
cpe = CpeMemoryIndex.getInstance();
try {
cve.open();
} catch (SQLException ex) {
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to open the cve db", ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to open the cve db", ex);
cpe.open(cve);
} catch (IndexException ex) {
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, "IndexException", ex);
throw new DatabaseException(ex);
}
}
/**
* Closes the data source.
* Closes the data sources.
*/
@Override
public void close() {
@@ -127,28 +126,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
@@ -160,11 +137,13 @@ public class CPEAnalyzer implements Analyzer {
* @throws ParseException is thrown when the Lucene query cannot be parsed.
*/
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
Confidence vendorConf = Confidence.HIGHEST;
Confidence productConf = Confidence.HIGHEST;
Confidence confidence = Confidence.HIGHEST;
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), vendorConf);
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), productConf);
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), confidence);
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), confidence);
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
int ctr = 0;
do {
@@ -180,13 +159,17 @@ public class CPEAnalyzer implements Analyzer {
}
}
}
vendorConf = reduceConfidence(vendorConf);
if (dependency.getVendorEvidence().contains(vendorConf)) {
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), vendorConf);
confidence = reduceConfidence(confidence);
if (dependency.getVendorEvidence().contains(confidence)) {
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
}
productConf = reduceConfidence(productConf);
if (dependency.getProductEvidence().contains(productConf)) {
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), productConf);
if (dependency.getProductEvidence().contains(confidence)) {
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
}
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
if (dependency.getVersionEvidence().contains(confidence)) {
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
}
} while ((++ctr) < 4);
}
@@ -451,8 +434,10 @@ public class CPEAnalyzer implements Analyzer {
final List<String> list = new ArrayList<String>();
String tempWord = null;
for (String word : words) {
//single letter words should be concatonated with the next word.
// so { "m", "core", "sample" } -> { "mcore", "sample" }
/*
single letter words should be concatenated with the next word.
so { "m", "core", "sample" } -> { "mcore", "sample" }
*/
if (tempWord != null) {
list.add(tempWord + word);
tempWord = null;
@@ -577,7 +562,7 @@ public class CPEAnalyzer implements Analyzer {
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
}
if (dbVer == null //special case, no version specified - everything is vulnerable
|| evVer.equals(dbVer)) { //woot exect match
|| evVer.equals(dbVer)) { //yeah! exact match
final String url = String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(vs.getName(), "UTF-8"));
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
collected.add(match);
@@ -643,7 +628,7 @@ public class CPEAnalyzer implements Analyzer {
private static class IdentifierMatch implements Comparable<IdentifierMatch> {
/**
* Constructs an IdentiferMatch.
* Constructs an IdentifierMatch.
*
* @param type the type of identifier (such as CPE)
* @param value the value of the identifier

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

@@ -23,12 +23,15 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.DependencyVersion;
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
import org.owasp.dependencycheck.utils.LogUtils;
/**
* <p>This analyzer ensures dependencies that should be grouped together, to
@@ -39,7 +42,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
* <p>Note, this grouping only works on dependencies with identified CVE
* entries</p>
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Analyzer {
@@ -53,7 +56,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
*/
private boolean analyzed = false;
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/**
* The set of file extensions supported by this analyzer.
*/
@@ -144,16 +147,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
}
dependenciesToRemove.add(nextDependency);
} else {
if (isCore(nextDependency, dependency)) {
nextDependency.addRelatedDependency(dependency);
//move any "related dependencies" to the new "parent" dependency
final Iterator<Dependency> i = dependency.getRelatedDependencies().iterator();
while (i.hasNext()) {
nextDependency.addRelatedDependency(i.next());
i.remove();
}
dependenciesToRemove.add(dependency);
nextDependency.addRelatedDependency(dependency);
//move any "related dependencies" to the new "parent" dependency
final Iterator<Dependency> i = dependency.getRelatedDependencies().iterator();
while (i.hasNext()) {
nextDependency.addRelatedDependency(i.next());
i.remove();
}
dependenciesToRemove.add(dependency);
}
}
}
@@ -195,7 +196,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
/**
* Returns true if the file names (and version if it exists) of the two
* dependencies are sufficiently similiar.
* dependencies are sufficiently similar.
*
* @param dependency1 a dependency2 to compare
* @param dependency2 a dependency2 to compare
@@ -217,7 +218,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
final String oneParent = one.getParent();
final String twoParent = two.getParent();
if (oneParent != null) {
if (twoParent != null && oneParent.equals(twoParent)) {
if (oneParent.equals(twoParent)) {
fileName1 = one.getName();
fileName2 = two.getName();
} else {
@@ -260,8 +261,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|| dependency2 == null || dependency2.getIdentifiers() == null) {
return false;
}
return dependency1.getIdentifiers().size() > 0
final boolean matches = dependency1.getIdentifiers().size() > 0
&& dependency2.getIdentifiers().equals(dependency1.getIdentifiers());
if (LogUtils.isVerboseLoggingEnabled()) {
final String msg = String.format("IdentifiersMatch=%s (%s, %s)", matches, dependency1.getFileName(), dependency2.getFileName());
Logger.getLogger(DependencyBundlingAnalyzer.class.getName()).log(Level.FINE, msg);
}
return matches;
}
/**
@@ -280,10 +286,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
final File rFile = new File(dependency2.getFilePath());
String right = rFile.getParent();
if (left == null) {
if (right == null) {
return true;
}
return false;
return right == null;
}
if (left.equalsIgnoreCase(right)) {
return true;
@@ -299,10 +302,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
* This is likely a very broken attempt at determining if the 'left'
* dependency is the 'core' library in comparison to the 'right' library.
*
* TODO - consider splitting on /\._-\s/ and checking if all of one side is
* fully contained in the other With the exception of the word "core". This
* might work even on groups when we don't have a CVE.
*
* @param left the dependency to test
* @param right the dependency to test against
* @return a boolean indicating whether or not the left dependency should be
@@ -311,18 +310,27 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
private boolean isCore(Dependency left, Dependency right) {
final String leftName = left.getFileName().toLowerCase();
final String rightName = right.getFileName().toLowerCase();
final boolean returnVal;
if (rightName.contains("core") && !leftName.contains("core")) {
return false;
returnVal = false;
} else if (!rightName.contains("core") && leftName.contains("core")) {
return true;
returnVal = true;
} else {
//TODO should we be splitting the name on [-_(.\d)+] and seeing if the
// parts are contained in the other side?
if (leftName.length() > rightName.length()) {
return false;
}
return true;
/*
* considered splitting the names up and comparing the components,
* but decided that the file name length should be sufficient as the
* "core" component, if this follows a normal naming protocol should
* be shorter:
* axis2-saaj-1.4.1.jar
* axis2-1.4.1.jar <-----
* axis2-kernal-1.4.1.jar
*/
returnVal = leftName.length() <= rightName.length();
}
if (LogUtils.isVerboseLoggingEnabled()) {
final String msg = String.format("IsCore=%s (%s, %s)", returnVal, left.getFileName(), right.getFileName());
Logger.getLogger(DependencyBundlingAnalyzer.class.getName()).log(Level.FINE, msg);
}
return returnVal;
}
}

View File

@@ -39,7 +39,7 @@ import org.owasp.dependencycheck.dependency.VulnerableSoftware;
* This analyzer attempts to remove some well known false positives -
* specifically regarding the java runtime.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
@@ -109,6 +109,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
removeJreEntries(dependency);
removeBadMatches(dependency);
removeWrongVersionMatches(dependency);
removeSpuriousCPE(dependency);
addFalseNegativeCPEs(dependency);
}
@@ -129,6 +130,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
*
* @param dependency the dependency being analyzed
*/
@SuppressWarnings("null")
private void removeSpuriousCPE(Dependency dependency) {
final List<Identifier> ids = new ArrayList<Identifier>();
ids.addAll(dependency.getIdentifiers());
@@ -291,6 +293,40 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
}
}
/**
* Removes CPE matches for the wrong version of a dependency. Currently,
* this only covers Axis 1 & 2.
*
* @param dependency the dependency to analyze
*/
private void removeWrongVersionMatches(Dependency dependency) {
final Set<Identifier> identifiers = dependency.getIdentifiers();
final Iterator<Identifier> itr = identifiers.iterator();
final String fileName = dependency.getFileName();
if (fileName != null && fileName.contains("axis2")) {
while (itr.hasNext()) {
final Identifier i = itr.next();
if ("cpe".equals(i.getType())) {
final String cpe = i.getValue();
if (cpe != null && (cpe.startsWith("cpe:/a:apache:axis:") || "cpe:/a:apache:axis".equals(cpe))) {
itr.remove();
}
}
}
} else if (fileName != null && fileName.contains("axis")) {
while (itr.hasNext()) {
final Identifier i = itr.next();
if ("cpe".equals(i.getType())) {
final String cpe = i.getValue();
if (cpe != null && (cpe.startsWith("cpe:/a:apache:axis2:") || "cpe:/a:apache:axis2".equals(cpe))) {
itr.remove();
}
}
}
}
}
/**
* There are some known CPE entries, specifically regarding sun and oracle
* products due to the acquisition and changes in product names, that based

View File

@@ -30,7 +30,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
*
* Takes a dependency and analyzes the filename and determines the hashes.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {

View File

@@ -27,7 +27,7 @@ import org.owasp.dependencycheck.dependency.Evidence;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {

View File

@@ -67,7 +67,7 @@ import org.xml.sax.XMLReader;
* Used to load a JAR file and collect information that can be used to determine
* the associated CPE.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
@@ -281,18 +281,10 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
Model pom = null;
try {
pom = retrievePom(path, jar);
} catch (JAXBException ex) {
final String msg = String.format("Unable to parse POM '%s' in '%s'",
path, dependency.getFilePath());
final AnalysisException ax = new AnalysisException(msg, ex);
dependency.getAnalysisExceptions().add(ax);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ax);
} catch (IOException ex) {
final String msg = String.format("Unable to retrieve POM '%s' in '%s'",
path, dependency.getFilePath());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ex);
foundSomething = setPomEvidence(dependency, pom, pomProperties, classes) || foundSomething;
} catch (AnalysisException ex) {
dependency.addAnalysisException(ex);
}
foundSomething = setPomEvidence(dependency, pom, pomProperties, classes) || foundSomething;
}
return foundSomething;
}
@@ -348,14 +340,14 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
* @param path the path to the pom.xml file within the jar file
* @param jar the jar file to extract the pom from
* @return returns a
* {@link org.owasp.dependencycheck.analyzer.pom.generated.Model} object
* @throws JAXBException is thrown if there is an exception parsing the pom
* @throws IOException is thrown if there is an exception reading the jar
* @throws AnalysisException is thrown if there is an exception extracting
* or parsing the POM
* {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
*/
private Model retrievePom(String path, JarFile jar) throws JAXBException, IOException {
private Model retrievePom(String path, JarFile jar) throws AnalysisException {
final ZipEntry entry = jar.getEntry(path);
Model model = null;
if (entry != null) { //should never be null
Model m = null;
try {
final XMLFilter filter = new MavenNamespaceFilter();
final SAXParserFactory spf = SAXParserFactory.newInstance();
@@ -367,17 +359,40 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
final InputSource xml = new InputSource(reader);
final SAXSource source = new SAXSource(filter, xml);
final JAXBElement<Model> el = pomUnmarshaller.unmarshal(source, Model.class);
m = el.getValue();
model = el.getValue();
} catch (SecurityException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s'; invalid signature", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException(ex);
} catch (ParserConfigurationException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s'", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ex);
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (Parser Configuration Error)", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException(ex);
} catch (SAXException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s'", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, msg, ex);
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (SAX Error)", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException(ex);
} catch (JAXBException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (JAXB Exception)", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException(ex);
} catch (IOException ex) {
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (IO Exception)", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException(ex);
} catch (Throwable ex) {
final String msg = String.format("Unexpected error during parsing of the pom '%s' in jar '%s'", path, jar.getName());
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINE, null, ex);
throw new AnalysisException(ex);
}
return m;
}
return null;
return model;
}
/**

View File

@@ -28,7 +28,7 @@ import java.util.regex.Pattern;
* Used to load a JAR file and collect information that can be used to determine
* the associated CPE.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {

View File

@@ -0,0 +1,182 @@
/*
* 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.analyzer;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import java.util.logging.Logger;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
import org.owasp.dependencycheck.data.nexus.NexusSearch;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.utils.Settings;
/**
* Analyzer which will attempt to locate a dependency on a Nexus service
* by SHA-1 digest of the dependency.
*
* There are two settings which govern this behavior:
*
* <ul>
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_ENABLED}
* determines whether this analyzer is even enabled. This can be overridden by
* setting the system property.</li>
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_URL}
* the URL to a Nexus service to search by SHA-1. There is an expected <code>%s</code>
* in this where the SHA-1 will get entered.</li>
* </ul>
*
* @author colezlaw
*/
public class NexusAnalyzer extends AbstractAnalyzer {
/**
* The logger
*/
private static final Logger LOGGER = Logger.getLogger(NexusAnalyzer.class.getName());
/**
* The name of the analyzer
*/
private static final String ANALYZER_NAME = "Nexus Analyzer";
/**
* The phase in which the analyzer runs
*/
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
/**
* The types of files on which this will work.
*/
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
/**
* Whether this is actually enabled. Will get set during initialization
*/
private boolean enabled = false;
/**
* The Nexus Search to be set up for this analyzer.
*/
private NexusSearch searcher;
/**
* Initializes the analyzer once before any analysis is performed.
*
* @throws Exception if there's an error during initialization.
*/
public void initialize() throws Exception {
enabled = Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED);
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
if (enabled) {
try {
searcher = new NexusSearch(new URL(searchUrl));
} catch (MalformedURLException mue) {
// I know that initialize can throw an exception, but we'll
// just disable the analyzer if the URL isn't valid
LOGGER.warning(String.format("Property %s not a valid URL. Nexus searching disabled",
searchUrl));
}
}
}
/**
* Returns the analyzer's name.
*
* @return the name of the analyzer
*/
public String getName() {
return ANALYZER_NAME;
}
/**
* Returns the analysis phase under which the analyzer runs.
*
* @return the phase under which this analyzer runs
*/
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
/**
* Returns the extensions for which this Analyzer runs.
*
* @return the extensions for which this Analyzer runs
*/
public Set<String> getSupportedExtensions() {
return SUPPORTED_EXTENSIONS;
}
/**
* Determines whether the incoming extension is supported.
*
* @param extension the extension to check for support
* @return whether the extension is supported
*/
public boolean supportsExtension(String extension) {
return SUPPORTED_EXTENSIONS.contains(extension);
}
/**
* Performs the analysis.
*
* @param dependency the dependency to analyze
* @param engine the engine
* @throws AnalysisException when there's an exception during analysis
*/
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
// Make a quick exit if this analyzer is disabled
if (!enabled) {
return;
}
try {
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) {
dependency.getVendorEvidence().addEvidence("nexus", "groupid", ma.getGroupId(),
Evidence.Confidence.HIGH);
}
if (ma.getArtifactId() != null && !"".equals(ma.getArtifactId())) {
dependency.getProductEvidence().addEvidence("nexus", "artifactid", ma.getArtifactId(),
Evidence.Confidence.HIGH);
}
if (ma.getVersion() != null && !"".equals(ma.getVersion())) {
dependency.getVersionEvidence().addEvidence("nexus", "version", ma.getVersion(),
Evidence.Confidence.HIGH);
}
if (ma.getArtifactUrl() != null && !"".equals(ma.getArtifactUrl())) {
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl());
}
} catch (IllegalArgumentException iae) {
dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
} catch (FileNotFoundException fnfe) {
dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
} catch (IOException ioe) {
dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
}
}
}
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -34,7 +34,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
* attempts to discern if there is an associated CVEs. It uses the the
* identifiers found by other analyzers to lookup the CVE data.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class NvdCveAnalyzer implements Analyzer {
@@ -107,13 +107,6 @@ public class NvdCveAnalyzer implements Analyzer {
final String value = id.getValue();
final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
dependency.getVulnerabilities().addAll(vulns);
//TODO - remove this comment block after additional testing is completed
//note - valid match functionality has been moved into the CveDB class.
//// for (Vulnerability v : vulns) {
//// if (isValidMatch(dependency, v)) {
//// dependency.addVulnerability(v);
//// }
//// }
} catch (DatabaseException ex) {
throw new AnalysisException(ex);
}
@@ -166,57 +159,4 @@ public class NvdCveAnalyzer implements Analyzer {
public void initialize() throws Exception {
this.open();
}
//TODO - remove this comment block after additional testing is completed
// The following check has been moved into the CveDB class.
//// /**
//// * <p>Determines if this is a valid vulnerability match for the given
//// * dependency. Specifically, this is concerned with ensuring the version
//// * numbers are correct.</p>
//// * <p>Currently, this is focused on the issues with the versions for Struts
//// * 1 and Struts 2. In the future this will due better matching on more
//// * version numbers.</p>
//// *
//// * @param dependency the dependency
//// * @param v the vulnerability
//// * @return returns true if the vulnerability is for the given dependency
//// */
//// private boolean isValidMatch(final Dependency dependency, final Vulnerability v) {
//// //right now I only know of the issue with Struts1/2
//// // start with fixing this problem.
////
//// //TODO extend this solution to do better version matching for the vulnerable software.
//// boolean struts1 = false;
//// boolean struts2 = false;
//// for (Identifier i : dependency.getIdentifiers()) {
//// if (i.getValue().startsWith("cpe:/a:apache:struts:")) {
//// final char version = i.getValue().charAt(21);
//// if (version == '1') {
//// struts1 = true;
//// }
//// if (version == '2') {
//// struts2 = true;
//// }
//// }
//// }
//// if (!struts1 && !struts2) {
//// return true; //we are not looking at struts, so return true.
//// }
//// if (struts1 && struts2) {
//// return true; //there is a mismatch here, but we can't solve it here so we return valid.
//// }
//// if (struts1) {
//// boolean hasStruts1Vuln = false;
//// boolean hasStruts2PreviousVersion = false;
//// for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
//// //TODO FIX THIS
//// //hasStruts2PreviousVersion |= vs.hasPreviousVersion() && vs.getName().charAt(21) == '2';
//// //hasStruts1Vuln |= vs.getName().charAt(21) == '1';
//// }
//// if (!hasStruts1Vuln && hasStruts2PreviousVersion) {
//// return false;
//// }
//// }
////
//// return true;
//// }
}

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 implementation 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

@@ -21,7 +21,7 @@ package org.owasp.dependencycheck.concurrency;
/**
* If thrown, indicates that a problem occurred when locking a directory.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DirectoryLockException extends Exception {

View File

@@ -38,7 +38,7 @@ import java.util.logging.Logger;
* the process will "spin" waiting for an opportunity to obtain the lock
* requested.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DirectorySpinLock implements Closeable /*, AutoCloseable*/ {
@@ -258,7 +258,7 @@ public class DirectorySpinLock implements Closeable /*, AutoCloseable*/ {
try {
lock.release();
} catch (ClosedChannelException ex) {
Logger.getLogger(DirectorySpinLock.class.getName()).log(Level.FINEST, "Uable to release file lock", ex);
Logger.getLogger(DirectorySpinLock.class.getName()).log(Level.FINEST, "Unable to release file lock", ex);
} catch (IOException ex) {
Logger.getLogger(DirectorySpinLock.class.getName()).log(Level.FINEST, "Unable to release file lock due to IO Exception", ex);
}

View File

@@ -21,7 +21,7 @@ package org.owasp.dependencycheck.concurrency;
/**
* If thrown, indicates that there is a problem with a directory.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class InvalidDirectoryException extends Exception {

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,197 +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();
}
}
}

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

@@ -22,7 +22,7 @@ package org.owasp.dependencycheck.data.cpe;
* Fields is a collection of field names used within the Lucene index for CPE
* entries.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public abstract class Fields {

View File

@@ -25,7 +25,7 @@ import java.net.URLDecoder;
/**
* A CPE entry containing the name, vendor, product, and version.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class IndexEntry implements Serializable {

View File

@@ -0,0 +1,67 @@
/*
* 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;
/**
* An exception thrown when the there is an issue using the in-memory CPE Index.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class IndexException extends Exception {
/**
* The serial version UID for serialization.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new IndexException.
*/
public IndexException() {
super();
}
/**
* Creates a new IndexException.
*
* @param msg a message for the exception.
*/
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

@@ -27,7 +27,7 @@ import java.util.logging.Logger;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public final class CweDB {

View File

@@ -26,7 +26,7 @@ import org.xml.sax.helpers.DefaultHandler;
/**
* A SAX Handler that will parse the CWE XML.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class CweHandler extends DefaultHandler {

View File

@@ -27,7 +27,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
* An abstract tokenizing filter that can be used as the base for a tokenizing
* filter.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public abstract class AbstractTokenizingFilter extends TokenFilter {

View File

@@ -26,7 +26,7 @@ import org.apache.lucene.util.Version;
* Tokenizes the input breaking it into tokens when non-alpha/numeric characters
* are found.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class AlphaNumericTokenizer extends CharTokenizer {

View File

@@ -22,7 +22,7 @@ import org.apache.lucene.search.similarities.DefaultSimilarity;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DependencySimilarity extends DefaultSimilarity {

View File

@@ -33,7 +33,7 @@ import org.apache.lucene.util.Version;
* WordDelimiterFilter, LowerCaseFilter, and StopFilter. The intended purpose of
* this Analyzer is to index the CPE fields vendor and product.</p>
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class FieldAnalyzer extends Analyzer {

View File

@@ -18,14 +18,22 @@
*/
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>
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
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

@@ -31,7 +31,7 @@ import org.apache.lucene.util.Version;
/**
* A Lucene field analyzer used to analyzer queries against the CPE data.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class SearchFieldAnalyzer extends Analyzer {

View File

@@ -30,7 +30,7 @@ import org.apache.lucene.util.Version;
* SearchVersionAnalyzer is a Lucene Analyzer used to analyze version
* information.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
* @deprecated version information is no longer stored in lucene
*/
@Deprecated

View File

@@ -30,7 +30,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
* <p><b>Example:</b> "Spring Framework Core" -> "Spring SpringFramework
* Framework FrameworkCore Core".</p>
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public final class TokenPairConcatenatingFilter extends TokenFilter {

View File

@@ -34,7 +34,7 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
* <p><b>Example:</b> "3.0.0.RELEASE" -> "3 3.0 3.0.0 RELEASE
* 3.0.0.RELEASE".</p>
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public final class UrlTokenizingFilter extends AbstractTokenizingFilter {

View File

@@ -29,7 +29,7 @@ import org.apache.lucene.util.Version;
/**
* VersionAnalyzer is a Lucene Analyzer used to analyze version information.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
* @deprecated version information is no longer stored in lucene
*/
@Deprecated

View File

@@ -29,7 +29,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
* <p><b>Example:</b> "3.0.0.RELEASE" -> "3 3.0 3.0.0 RELEASE
* 3.0.0.RELEASE".</p>
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
* @deprecated version information is no longer stored in lucene
*/
@Deprecated

View File

@@ -0,0 +1,154 @@
/*
* 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.nexus;
/**
* Simple bean representing a Maven Artifact.
*
* @author colezlaw
*/
public class MavenArtifact {
/**
* The groupId
*/
private String groupId;
/**
* The artifactId
*/
private String artifactId;
/**
* The version
*/
private String version;
/**
* The artifact url. This may change depending on which Nexus
* server the search took place.
*/
private String artifactUrl;
/**
* Creates an empty MavenArtifact.
*/
public MavenArtifact() {
}
/**
* Creates a MavenArtifact with the given attributes.
*
* @param groupId the groupId
* @param artifactId the artifactId
* @param version the version
*/
public MavenArtifact(String groupId, String artifactId, String version) {
setGroupId(groupId);
setArtifactId(artifactId);
setVersion(version);
}
/**
* Creates a MavenArtifact with the given attributes.
*
* @param groupId the groupId
* @param artifactId the artifactId
* @param version the version
* @param url the artifactLink url
*/
public MavenArtifact(String groupId, String artifactId, String version, String url) {
setGroupId(groupId);
setArtifactId(artifactId);
setVersion(version);
setArtifactUrl(url);
}
/**
* Returns the Artifact coordinates as a String.
*
* @return the String representation of the artifact coordinates
*/
@Override
public String toString() {
return String.format("%s:%s:%s", groupId, artifactId, version);
}
/**
* Sets the groupId.
*
* @param groupId the groupId
*/
public void setGroupId(String groupId) { this.groupId = groupId; }
/**
* Gets the groupId.
*
* @return the groupId
*/
public String getGroupId() { return groupId; }
/**
* Sets the artifactId.
*
* @param artifactId the artifactId
*/
public void setArtifactId(String artifactId) { this.artifactId = artifactId; }
/**
* Gets the artifactId.
*
* @return the artifactId
*/
public String getArtifactId() { return artifactId; }
/**
* Sets the version.
*
* @param version the version
*/
public void setVersion(String version) { this.version = version; }
/**
* Gets the version.
*
* @return the version
*/
public String getVersion() { return version; }
/**
* Sets the artifactUrl.
*
* @param artifactUrl the artifactUrl
*/
public void setArtifactUrl(String artifactUrl) {
this.artifactUrl = artifactUrl;
}
/**
* Gets the artifactUrl.
*
* @return the artifactUrl
*/
public String getArtifactUrl() {
return artifactUrl;
}
}
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -0,0 +1,105 @@
/*
* 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.nexus;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
/**
* Class of methods to search Nexus repositories.
*
* @author colezlaw
*/
public class NexusSearch {
/**
* The root URL for the Nexus repository service
*/
private final URL rootURL;
/**
* Used for logging.
*/
private static final Logger LOGGER = Logger.getLogger(NexusSearch.class.getName());
/**
* Creates a NexusSearch for the given repository URL.
*
* @param rootURL the root URL of the repository on which searches should execute.
* full URL's are calculated relative to this URL, so it should end with a /
*/
public NexusSearch(URL rootURL) {
this.rootURL = rootURL;
}
/**
* Searches the configured Nexus repository for the given sha1
* hash. If the artifact is found, a <code>MavenArtifact</code> is populated
* with the coordinate information.
*
* @param sha1 The SHA-1 hash string for which to search
* @return the populated Maven coordinates
* @throws IOException if it's unable to connect to the specified repositor or
* if the specified artifact is not found.
*/
public MavenArtifact searchSha1(String sha1) throws IOException {
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
throw new IllegalArgumentException("Invalid SHA1 format");
}
final URL url = new URL(rootURL, String.format("identify/sha1/%s", sha1.toLowerCase()));
LOGGER.fine(String.format("Searching Nexus url %s", url.toString()));
final URLConnection conn = url.openConnection();
conn.setDoOutput(true);
// JSON would be more elegant, but there's not currently a dependency
// on JSON, so don't want to add one just for this
conn.addRequestProperty("Accept", "application/xml");
conn.connect();
try {
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final Document doc = builder.parse(conn.getInputStream());
final XPath xpath = XPathFactory.newInstance().newXPath();
final String groupId = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/groupId", doc);
final String artifactId = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/artifactId", doc);
final String version = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/version", doc);
final String link = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink", doc);
return new MavenArtifact(groupId, artifactId, version, link);
} catch (FileNotFoundException fnfe) {
// This is what we get when the SHA1 they sent doesn't exist in Nexus. This
// is useful upstream for recovery, so we just re-throw it
throw fnfe;
} catch (Exception e) {
// Anything else is jacked-up XML stuff that we really can't recover from well
throw new IOException(e.getMessage(), e);
}
}
}
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -0,0 +1,12 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.data.nexus</title>
* </head>
* <body>
* <p>Contains classes related to searching a Nexus repository.</p>
* <p>These are used to abstract Nexus searching away from
* OWASP Dependency Check so they can be reused elsewhere.</p>
* </body>
* </html>
*/

View File

@@ -0,0 +1,238 @@
/*
* 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) 2014 Jeremy Long. All Rights Reserved.
*/
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.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
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.utils.DBUtils;
import org.owasp.dependencycheck.utils.Settings;
/**
* Loads the configured database driver and returns the database connection. If the embedded H2 database is used
* obtaining a connection will ensure the database file exists and that the appropriate table structure has been
* created.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public final class ConnectionFactory {
/**
* The version of the current DB Schema.
*/
public static final String DB_SCHEMA_VERSION = "2.8";
/**
* Resource location for SQL file used to create the database schema.
*/
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
/**
* Private constructor for this factory class; no instance is ever needed.
*/
private ConnectionFactory() {
}
/**
* Constructs a new database connection object per the database configuration. This will load the appropriate
* database driver, via the DriverManager, if configured.
*
* @return a database connection object
* @throws DatabaseException thrown if there is an exception loading the database connection
*/
public static Connection getConnection() throws DatabaseException {
Connection conn = null;
try {
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading database connection");
final String connStr = getConnectionString();
final String user = Settings.getString(Settings.KEYS.DB_USER, "dcuser");
//yes, yes - hard-coded password - only if there isn't one in the properties file.
final String pass = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Connection String: {0}", connStr);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Database User: {0}", user);
boolean createTables = false;
if (connStr.startsWith("jdbc:h2:file:")) { //H2
createTables = needToCreateDatabaseStructure();
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Need to create DB Structure: {0}", createTables);
}
final String driverName = Settings.getString(Settings.KEYS.DB_DRIVER_NAME, "");
if (!driverName.isEmpty()) { //likely need to load the correct driver
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading driver: {0}", driverName);
final String driverPath = Settings.getString(Settings.KEYS.DB_DRIVER_PATH, "");
if (!driverPath.isEmpty()) { //ugh, driver is not on classpath?
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading driver from: {0}", driverPath);
DriverLoader.load(driverName, driverPath);
} else {
DriverLoader.load(driverName);
}
}
//JDBC4 drivers don't need this call.
//Class.forName("org.h2.Driver");
conn = DriverManager.getConnection(connStr, user, pass);
if (createTables) {
createTables(conn);
} else {
ensureSchemaVersion(conn);
}
} catch (IOException ex) {
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to load database");
} catch (DriverLoadException ex) {
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to load database driver");
} catch (SQLException ex) {
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to connect to the database");
} catch (DatabaseException ex) {
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to create the database structure");
}
return conn;
}
/**
* Returns the configured connection string. If using the embedded H2 database this function will also ensure the
* data directory exists and if not create it.
*
* @return the connection string
* @throws IOException thrown the data directory cannot be created
*/
private static String getConnectionString() throws IOException {
final String connStr = Settings.getString(Settings.KEYS.DB_CONNECTION_STRING, "jdbc:h2:file:%s;AUTO_SERVER=TRUE");
if (connStr.contains("%s")) {
final String fileName = getDataDirectory().getCanonicalPath();
final File file = new File(fileName, "cve." + DB_SCHEMA_VERSION);
return String.format(connStr, file.getAbsolutePath());
}
return connStr;
}
/**
* Retrieves the directory that the JAR file exists in so that we can ensure we always use a common data directory
* for the embedded H2 database. This is public solely for some unit tests; otherwise this should be private.
*
* @return the data directory to store data files
* @throws IOException is thrown if an IOException occurs of course...
*/
public static File getDataDirectory() throws IOException {
final File path = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
if (!path.exists()) {
if (!path.mkdirs()) {
throw new IOException("Unable to create NVD CVE Data directory");
}
}
return path;
}
/**
* Determines if the H2 database file exists. If it does not exist then the data structure will need to be created.
*
* @return true if the H2 database file does not exist; otherwise false
* @throws IOException thrown if the data directory does not exist and cannot be created
*/
private static boolean needToCreateDatabaseStructure() throws IOException {
final File dir = getDataDirectory();
final String name = String.format("cve.%s.h2.db", DB_SCHEMA_VERSION);
final File file = new File(dir, name);
return !file.exists();
}
/**
* Creates the database structure (tables and indexes) to store the CVE data.
*
* @param conn the database connection
* @throws DatabaseException thrown if there is a Database Exception
*/
private static void createTables(Connection conn) throws DatabaseException {
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "Creating database structure");
InputStream is;
InputStreamReader reader;
BufferedReader in = null;
try {
is = ConnectionFactory.class.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());
} catch (SQLException ex) {
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to create database statement", ex);
} finally {
DBUtils.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(ConnectionFactory.class.getName()).log(Level.FINEST, null, ex);
}
}
}
}
/**
* Uses the provided connection to check the specified schema version within the database.
*
* @param conn the database connection object
* @throws DatabaseException thrown if the schema version is not compatible with this version of dependency-check
*/
private static void ensureSchemaVersion(Connection conn) throws DatabaseException {
ResultSet rs = null;
CallableStatement cs = null;
try {
cs = conn.prepareCall("SELECT value FROM properties WHERE id = 'version'");
rs = cs.executeQuery();
if (rs.next()) {
final boolean isWrongSchema = !DB_SCHEMA_VERSION.equals(rs.getString(1));
if (isWrongSchema) {
throw new DatabaseException("Incorrect database schema; unable to continue");
}
} else {
throw new DatabaseException("Database schema is missing");
}
} catch (SQLException ex) {
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException("Unable to check the database schema version");
} finally {
DBUtils.closeResultSet(rs);
DBUtils.closeStatement(cs);
}
}
}

View File

@@ -22,7 +22,7 @@ package org.owasp.dependencycheck.data.nvdcve;
* An exception used to indicate the db4o database is corrupt. This could be due
* to invalid data or a complete failure of the db.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
class CorruptDatabaseException extends DatabaseException {

View File

@@ -18,14 +18,8 @@
*/
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;
@@ -33,6 +27,8 @@ import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -40,140 +36,81 @@ 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.DBUtils;
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)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class CveDB {
/**
* 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 = ?";
/**
* SQL Statement to delete software by vulnerability ID.
*/
public 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 = ?";
/**
* 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); ";
/**
* SQL Statement to insert a new reference.
*/
public 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 (?, ?, ?)";
/**
* SQL Statement to insert a new cpe.
*/
public 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 = ?";
/**
* SQL Statement to insert a new vulnerability.
*/
public 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=?, "
+ "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 "
+ "FROM software INNER JOIN vulnerability ON vulnerability.id = software.cveId "
+ "INNER JOIN cpeEntry ON cpeEntry.id = software.cpeEntryId "
+ "WHERE vendor = ? AND product = ?";
//unfortunately, the version info is too complicated to do in a select. Need to filter this afterwards
// + " AND (version = '-' OR previousVersion IS NOT NULL OR version=?)";
//
/**
* 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 = ?";
/**
* SQL Statement to select references by CVEID.
*/
public static final String SELECT_REFERENCE = "SELECT source, name, url FROM reference WHERE cveid = ?";
/**
* SQL Statement to select software by CVEID.
*/
public 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 "
// + "software.cpeVersionId = cpeVersion.id LEFT JOIN Version ON cpeVersion.versionId = version.id WHERE cveid = ?";
/**
* SQL Statement to select a vulnerability by CVEID.
*/
public 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 = ?";
//</editor-fold>
/**
* Opens the database connection. If the database does not exist, it will
* create a new one.
* Creates a new CveDB object and opens the database connection. Note, the connection must be closed by the caller
* by calling the close method.
*
* @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
* @throws DatabaseException thrown if there is an exception opening the database.
*/
@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();
public CveDB() throws DatabaseException {
super();
try {
open();
databaseProperties = new DatabaseProperties(this);
} catch (DatabaseException ex) {
throw ex;
}
}
/**
* 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 DatabaseException thrown if there is an error opening the database connection
*/
public final void open() throws DatabaseException {
conn = ConnectionFactory.getConnection();
}
/**
* 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(DBUtils.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(DBUtils.class.getName()).log(Level.FINE, null, ex);
}
conn = null;
}
}
/**
* Returns whether the database connection is open or closed.
*
* @return whether the database connection is open or closed
*/
public boolean isOpen() {
return conn != null;
}
/**
* Commits all completed transactions.
*
@@ -181,7 +118,8 @@ public class CveDB {
*/
public void commit() throws SQLException {
if (conn != null) {
conn.commit();
//temporary remove this as autocommit is on.
//conn.commit();
}
}
@@ -193,34 +131,134 @@ public class CveDB {
@Override
protected void finalize() throws Throwable {
close();
super.finalize(); //not necessary if extending Object.
super.finalize();
}
/**
* Closes the DB4O database. Close should be called on this object when it
* is done being used.
* Database properties object containing the 'properties' from the database table.
*/
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;
}
}
private DatabaseProperties databaseProperties;
/**
* Searches the CPE entries in the database and retrieves all entries for a
* given vendor and product combination. The returned list will include all
* versions of the product that are registered in the NVD CVE data.
* Get the value of databaseProperties.
*
* @return the value of databaseProperties
*/
public DatabaseProperties getDatabaseProperties() {
return databaseProperties;
}
//<editor-fold defaultstate="collapsed" desc="Constants to create, maintain, and retrieve data from the CVE Database">
/**
* SQL Statement to delete references by vulnerability ID.
*/
private static final String DELETE_REFERENCE = "DELETE FROM reference WHERE cveid = ?";
/**
* SQL Statement to delete software by vulnerability ID.
*/
private static final String DELETE_SOFTWARE = "DELETE FROM software WHERE cveid = ?";
/**
* SQL Statement to delete a vulnerability by 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.
*/
private static final String CLEANUP_ORPHANS = "DELETE FROM CpeEntry WHERE id not in (SELECT CPEEntryId FROM Software); ";
/**
* SQL Statement to insert a new reference.
*/
private static final String INSERT_REFERENCE = "INSERT INTO reference (cveid, name, url, source) VALUES (?, ?, ?, ?)";
/**
* SQL Statement to insert a new software.
*/
private static final String INSERT_SOFTWARE = "INSERT INTO software (cveid, cpeEntryId, previousVersion) VALUES (?, ?, ?)";
/**
* SQL Statement to insert a new cpe.
*/
private static final String INSERT_CPE = "INSERT INTO cpeEntry (cpe, vendor, product) VALUES (?, ?, ?)";
/**
* SQL Statement to get a CPEProductID.
*/
private static final String SELECT_CPE_ID = "SELECT id FROM cpeEntry WHERE cpe = ?";
/**
* SQL Statement to insert a new vulnerability.
*/
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.
*/
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.
*/
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 = ?";
//unfortunately, the version info is too complicated to do in a select. Need to filter this afterwards
// + " AND (version = '-' OR previousVersion IS NOT NULL OR version=?)";
//
/**
* SQL Statement to find the CPE entry based on the 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.
*/
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.
*/
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 "
// + "software.cpeVersionId = cpeVersion.id LEFT JOIN Version ON cpeVersion.versionId = version.id WHERE cveid = ?";
/**
* SQL Statement to select a vulnerability by CVEID.
*/
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.
*/
private static final String SELECT_VULNERABILITY_ID = "SELECT id FROM vulnerability WHERE cve = ?";
/**
* SQL Statement to retrieve the properties from the database.
*/
private static final String SELECT_PROPERTIES = "SELECT id, value FROM properties";
/**
* SQL Statement to retrieve a property from the database.
*/
private static final String SELECT_PROPERTY = "SELECT id, value FROM properties WHERE id = ?";
/**
* SQL Statement to insert a new property.
*/
private static final String INSERT_PROPERTY = "INSERT INTO properties (id, value) VALUES (?, ?)";
/**
* SQL Statement to update a property.
*/
private static final String UPDATE_PROPERTY = "UPDATE properties SET value = ? WHERE id = ?";
/**
* SQL Statement to delete a property.
*/
private static final String DELETE_PROPERTY = "DELETE FROM properties WHERE id = ?";
//</editor-fold>
/**
* Searches the CPE entries in the database and retrieves all entries for a given vendor and product combination.
* The returned list will include all versions of the product that are registered in the NVD CVE data.
*
* @param vendor the identified vendor name of the dependency being analyzed
* @param product the identified name of the product of the dependency being
* analyzed
* @param product the identified name of the product of the dependency being analyzed
* @return a set of vulnerable software
*/
public Set<VulnerableSoftware> getCPEs(String vendor, String product) {
@@ -228,7 +266,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();
@@ -239,14 +277,142 @@ public class CveDB {
cpe.add(vs);
}
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
} finally {
closeResultSet(rs);
closeStatement(ps);
DBUtils.closeResultSet(rs);
DBUtils.closeStatement(ps);
}
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) {
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
} // can't close the statement in the PS as the resultset is returned, closing PS would close the resultset
return rs;
}
/**
* Returns a set of properties.
*
* @return the properties from the database
*/
Properties getProperties() {
final Properties prop = new Properties();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = getConnection().prepareStatement(SELECT_PROPERTIES);
rs = ps.executeQuery();
while (rs.next()) {
prop.setProperty(rs.getString(1), rs.getString(2));
}
} catch (SQLException ex) {
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
} finally {
DBUtils.closeStatement(ps);
DBUtils.closeResultSet(rs);
}
return prop;
}
/**
* Saves a set of properties to the database.
*
* @param props a collection of properties
*/
void saveProperties(Properties props) {
PreparedStatement updateProperty = null;
PreparedStatement insertProperty = null;
try {
try {
updateProperty = getConnection().prepareStatement(UPDATE_PROPERTY);
insertProperty = getConnection().prepareStatement(INSERT_PROPERTY);
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, "Unable to save properties to the database");
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Unable to save properties to the database", ex);
return;
}
for (Entry<Object, Object> entry : props.entrySet()) {
final String key = entry.getKey().toString();
final String value = entry.getValue().toString();
try {
updateProperty.setString(1, value);
updateProperty.setString(2, key);
if (updateProperty.executeUpdate() == 0) {
insertProperty.setString(1, key);
insertProperty.setString(2, value);
}
} catch (SQLException ex) {
final String msg = String.format("Unable to save property '%s' with a value of '%s' to the database", key, value);
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
}
}
} finally {
DBUtils.closeStatement(updateProperty);
DBUtils.closeStatement(insertProperty);
}
}
/**
* Saves a property to the database.
*
* @param key the property key
* @param value the property value
*/
void saveProperty(String key, String value) {
PreparedStatement updateProperty = null;
PreparedStatement insertProperty = null;
try {
try {
updateProperty = getConnection().prepareStatement(UPDATE_PROPERTY);
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, "Unable to save properties to the database");
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Unable to save properties to the database", ex);
return;
}
try {
updateProperty.setString(1, value);
updateProperty.setString(2, key);
if (updateProperty.executeUpdate() == 0) {
try {
insertProperty = getConnection().prepareStatement(INSERT_PROPERTY);
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, "Unable to save properties to the database");
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Unable to save properties to the database", ex);
return;
}
insertProperty.setString(1, key);
insertProperty.setString(2, value);
insertProperty.execute();
}
} catch (SQLException ex) {
final String msg = String.format("Unable to save property '%s' with a value of '%s' to the database", key, value);
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
}
} finally {
DBUtils.closeStatement(updateProperty);
DBUtils.closeStatement(insertProperty);
}
}
/**
* Retrieves the vulnerabilities associated with the specified CPE.
*
@@ -268,7 +434,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();
@@ -280,8 +446,8 @@ public class CveDB {
cveEntries.add(cveId);
}
}
closeResultSet(rs);
closeStatement(ps);
DBUtils.closeResultSet(rs);
DBUtils.closeStatement(ps);
for (String cve : cveEntries) {
final Vulnerability v = getVulnerability(cve);
vulnerabilities.add(v);
@@ -290,7 +456,7 @@ public class CveDB {
} catch (SQLException ex) {
throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
} finally {
closeResultSet(rs);
DBUtils.closeResultSet(rs);
}
return vulnerabilities;
}
@@ -311,7 +477,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 +501,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()) {
@@ -357,25 +523,25 @@ public class CveDB {
} catch (SQLException ex) {
throw new DatabaseException("Error retrieving " + cve, ex);
} finally {
closeResultSet(rsV);
closeResultSet(rsR);
closeResultSet(rsS);
closeStatement(psV);
closeStatement(psR);
closeStatement(psS);
DBUtils.closeResultSet(rsV);
DBUtils.closeResultSet(rsR);
DBUtils.closeResultSet(rsS);
DBUtils.closeStatement(psV);
DBUtils.closeStatement(psR);
DBUtils.closeStatement(psS);
}
return vuln;
}
/**
* Updates the vulnerability within the database. If the vulnerability does
* not exist it will be added.
* Updates the vulnerability within the database. If the vulnerability does not exist it will be added.
*
* @param vuln the vulnerability to add to the database
* @throws DatabaseException is thrown if the database
*/
public void updateVulnerability(Vulnerability vuln) throws DatabaseException {
PreparedStatement selectVulnerabilityId = null;
PreparedStatement deleteVulnerability = null;
PreparedStatement deleteReferences = null;
PreparedStatement deleteSoftware = null;
PreparedStatement updateVulnerability = null;
@@ -386,15 +552,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();
@@ -406,20 +573,25 @@ public class CveDB {
deleteSoftware.setInt(1, vulnerabilityId);
deleteSoftware.execute();
}
closeResultSet(rs);
DBUtils.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());
@@ -440,7 +612,7 @@ public class CveDB {
final String msg = String.format("Unable to retrieve id for new vulnerability for '%s'", vuln.getName());
throw new DatabaseException(msg, ex);
} finally {
closeResultSet(rs);
DBUtils.closeResultSet(rs);
rs = null;
}
}
@@ -462,7 +634,7 @@ public class CveDB {
} catch (SQLException ex) {
throw new DatabaseException("Unable to get primary key for new cpe: " + s.getName(), ex);
} finally {
closeResultSet(rs);
DBUtils.closeResultSet(rs);
rs = null;
}
@@ -471,7 +643,7 @@ public class CveDB {
insertCpe.setString(2, s.getVendor());
insertCpe.setString(3, s.getProduct());
insertCpe.executeUpdate();
cpeProductId = getGeneratedKey(insertCpe);
cpeProductId = DBUtils.getGeneratedKey(insertCpe);
}
if (cpeProductId == 0) {
throw new DatabaseException("Unable to retrieve cpeProductId - no data returned");
@@ -492,171 +664,55 @@ public class CveDB {
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
throw new DatabaseException(msg, ex);
} finally {
closeStatement(selectVulnerabilityId);
closeStatement(deleteReferences);
closeStatement(deleteSoftware);
closeStatement(updateVulnerability);
closeStatement(insertVulnerability);
closeStatement(insertReference);
closeStatement(selectCpeId);
closeStatement(insertCpe);
closeStatement(insertSoftware);
DBUtils.closeStatement(selectVulnerabilityId);
DBUtils.closeStatement(deleteReferences);
DBUtils.closeStatement(deleteSoftware);
DBUtils.closeStatement(updateVulnerability);
DBUtils.closeStatement(deleteVulnerability);
DBUtils.closeStatement(insertVulnerability);
DBUtils.closeStatement(insertReference);
DBUtils.closeStatement(selectCpeId);
DBUtils.closeStatement(insertCpe);
DBUtils.closeStatement(insertSoftware);
}
}
/**
* 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
* ensure orphan entries are removed.
* It is possible that orphaned rows may be generated during database updates. This should be called after all
* updates have been completed to ensure orphan entries are removed.
*/
public void cleanupDatabase() {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(CLEANUP_ORPHANS);
ps = getConnection().prepareStatement(CLEANUP_ORPHANS);
if (ps != null) {
ps.executeUpdate();
}
} catch (SQLException ex) {
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg);
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
} finally {
closeStatement(ps);
DBUtils.closeStatement(ps);
}
}
/**
* 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
* previous version argument indicates that all previous versions are
* affected.
* Determines if the given identifiedVersion is affected by the given cpeId and previous version flag. A non-null,
* non-empty string passed to the previous version argument indicates that all previous versions are affected.
*
* @param vendor the vendor of the dependency being analyzed
* @param product the product name of the dependency being analyzed
* @param identifiedVersion the identified version of the dependency being
* analyzed
* @param cpeId the cpe identifier of software that has a known
* vulnerability
* @param previous a flag indicating if previous versions of the product are
* vulnerable
* @param identifiedVersion the identified version of the dependency being analyzed
* @param cpeId the cpe identifier of software that has a known vulnerability
* @param previous a flag indicating if previous versions of the product are vulnerable
* @return true if the identified version is affected, otherwise false
*/
private boolean isAffected(String vendor, String product, DependencyVersion identifiedVersion, String cpeId, String previous) {
boolean affected = false;
final boolean isStruts = "apache".equals(vendor) && "struts".equals(product);
final DependencyVersion v = parseDependencyVersion(cpeId);
final boolean prevAffected = previous == null ? false : !previous.isEmpty();
final boolean prevAffected = previous != null && !previous.isEmpty();
if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
if (v == null || "-".equals(v.toString())) {
affected = true;
@@ -678,8 +734,8 @@ public class CveDB {
}
/**
* Parses the version (including revision) from a CPE identifier. If no
* version is identified then a '-' is returned.
* Parses the version (including revision) from a CPE identifier. If no version is identified then a '-' is
* returned.
*
* @param cpeStr a cpe identifier
* @return a dependency version
@@ -696,8 +752,7 @@ public class CveDB {
}
/**
* Takes a CPE and parses out the version number. If no version is
* identified then a '-' is returned.
* Takes a CPE and parses out the version number. If no version is identified then a '-' is returned.
*
* @param cpe a cpe object
* @return a dependency version

View File

@@ -21,7 +21,7 @@ package org.owasp.dependencycheck.data.nvdcve;
/**
* An exception thrown if an operation against the database fails.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DatabaseException extends Exception {
@@ -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

@@ -0,0 +1,120 @@
/*
* 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.nvdcve;
import java.util.Properties;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.data.update.NvdCveInfo;
/**
* This is a wrapper around a set of properties that are stored in the database.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DatabaseProperties {
/**
* Modified key word, used as a key to store information about the modified
* file (i.e. the containing the last 8 days of updates)..
*/
public static final String MODIFIED = "modified";
/**
* The properties file key for the last updated field - used to store the
* last updated time of the Modified NVD CVE xml file.
*/
public static final String LAST_UPDATED = "lastupdated.modified";
/**
* Stores the last updated time for each of the NVD CVE files. These
* timestamps should be updated if we process the modified file within 7
* days of the last update.
*/
public static final String LAST_UPDATED_BASE = "lastupdated.";
/**
* A collection of properties about the data.
*/
private Properties properties;
/**
* A reference to the database.
*/
private CveDB cveDB;
/**
* Constructs a new data properties object.
*
* @param cveDB the database object holding the properties
*/
DatabaseProperties(CveDB cveDB) {
this.cveDB = cveDB;
loadProperties();
}
/**
* Loads the properties from the database.
*/
private void loadProperties() {
this.properties = cveDB.getProperties();
}
/**
* Returns whether or not any properties are set.
*
* @return whether or not any properties are set
*/
public boolean isEmpty() {
return properties == null || properties.isEmpty();
}
/**
* Writes a properties file containing the last updated date to the
* VULNERABLE_CPE directory.
*
* @param updatedValue the updated NVD CVE entry
* @throws UpdateException is thrown if there is an update exception
*/
public void save(NvdCveInfo updatedValue) throws UpdateException {
if (updatedValue == null) {
return;
}
properties.put(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
cveDB.saveProperty(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
}
/**
* Returns the property value for the given key. If the key is not contained
* in the underlying properties null is returned.
*
* @param key the property key
* @return the value of the property
*/
public String getProperty(String key) {
return properties.getProperty(key);
}
/**
* Returns the property value for the given key. If the key is not contained
* in the underlying properties the default value is returned.
*
* @param key the property key
* @param defaultValue the default value
* @return the value of the property
*/
public String getProperty(String key, String defaultValue) {
return properties.getProperty(key, defaultValue);
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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) 2014 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.nvdcve;
/**
* An exception thrown the database driver is unable to be loaded.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DriverLoadException extends Exception {
/**
* the serial version uid.
*/
private static final long serialVersionUID = 1L;
/**
* Creates an DriverLoadException.
*
* @param msg the exception message
*/
public DriverLoadException(String msg) {
super(msg);
}
/**
* Creates an DriverLoadException.
*
* @param ex the cause of the exception
*/
public DriverLoadException(Throwable ex) {
super(ex);
}
/**
* Creates an DriverLoadException.
*
* @param msg the exception message
* @param ex the cause of the exception
*/
public DriverLoadException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,141 @@
/*
* 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) 2014 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.nvdcve;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* DriverLoader is a utility class that is used to load database drivers.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public final class DriverLoader {
/**
* Private constructor for a utility class.
*/
private DriverLoader() {
}
/**
* Loads the specified class using the system class loader and registers the driver with the driver manager.
*
* @param className the fully qualified name of the desired class
* @throws DriverLoadException thrown if the driver cannot be loaded
*/
public static void load(String className) throws DriverLoadException {
final ClassLoader loader = ClassLoader.getSystemClassLoader();
load(className, loader);
}
/**
* Loads the specified class by registering the supplied paths to the class loader and then registers the driver
* with the driver manager. The pathToDriver argument is added to the class loader so that an external driver can be
* loaded. Note, the pathTodriver can contain a semi-colon separated list of paths so any dependencies can be added
* as needed. If a path in the pathToDriver argument is a directory all files in the directory are added to the
* class path.
*
* @param className the fully qualified name of the desired class
* @param pathToDriver the path to the JAR file containing the driver; note, this can be a semi-colon separated list
* of paths
* @throws DriverLoadException thrown if the driver cannot be loaded
*/
public static void load(String className, String pathToDriver) throws DriverLoadException {
final URLClassLoader parent = (URLClassLoader) ClassLoader.getSystemClassLoader();
final ArrayList<URL> urls = new ArrayList<URL>();
final String[] paths = pathToDriver.split(File.pathSeparator);
for (String path : paths) {
final File file = new File(path);
if (file.isDirectory()) {
final File[] files = file.listFiles();
for (File f : files) {
try {
urls.add(f.toURI().toURL());
} catch (MalformedURLException ex) {
final String msg = String.format("Unable to load database driver '%s'; invalid path provided '%s'",
className, f.getAbsoluteFile());
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
throw new DriverLoadException(msg, ex);
}
}
} else if (file.exists()) {
try {
urls.add(file.toURI().toURL());
} catch (MalformedURLException ex) {
final String msg = String.format("Unable to load database driver '%s'; invalid path provided '%s'",
className, file.getAbsoluteFile());
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
throw new DriverLoadException(msg, ex);
}
}
}
final URLClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<URLClassLoader>() {
@Override
public URLClassLoader run() {
return new URLClassLoader(urls.toArray(new URL[urls.size()]), parent);
}
});
load(className, loader);
}
/**
* Loads the specified class using the supplied class loader and registers the driver with the driver manager.
*
* @param className the fully qualified name of the desired class
* @param loader the class loader to use when loading the driver
* @throws DriverLoadException thrown if the driver cannot be loaded
*/
private static void load(String className, ClassLoader loader) throws DriverLoadException {
try {
final Class c = loader.loadClass(className);
final Driver driver = (Driver) c.newInstance();
//using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path
DriverManager.registerDriver(new DriverShim(driver));
} catch (ClassNotFoundException ex) {
final String msg = String.format("Unable to load database driver '%s'", className);
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
throw new DriverLoadException(msg, ex);
} catch (InstantiationException ex) {
final String msg = String.format("Unable to load database driver '%s'", className);
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
throw new DriverLoadException(msg, ex);
} catch (IllegalAccessException ex) {
final String msg = String.format("Unable to load database driver '%s'", className);
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
throw new DriverLoadException(msg, ex);
} catch (SQLException ex) {
final String msg = String.format("Unable to load database driver '%s'", className);
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
throw new DriverLoadException(msg, ex);
}
}
}

View File

@@ -0,0 +1,180 @@
/*
* 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) 2014 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.nvdcve;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.logging.Logger;
/**
* <p>
* Driver shim to get around the class loader issue with the DriverManager. The following code is a nearly identical
* copy (with more comments and a few more methods implemented) of the DriverShim from:</p>
* <blockquote>http://www.kfu.com/~nsayer/Java/dyn-jdbc.html</blockquote>
*
* @author Jeremy Long <jeremy.long@owasp.org>
* @see java.sql.Driver
*/
class DriverShim implements Driver {
/**
* The database driver being wrapped.
*/
private final Driver driver;
/**
* Constructs a new wrapper around a Driver.
*
* @param driver the database driver to wrap
*/
DriverShim(Driver driver) {
this.driver = driver;
}
/**
* Wraps the underlying driver's call to acceptsURL. Returns whether or not the driver can open a connection to the
* given URL.
*
* @param url the URL of the database
* @return true if the wrapped driver can connect to the specified URL
* @throws SQLException thrown if there is an error connecting to the database
* @see java.sql.Driver#acceptsURL(java.lang.String)
*/
@Override
public boolean acceptsURL(String url) throws SQLException {
return this.driver.acceptsURL(url);
}
/**
* Returns the wrapped driver's major version number.
*
* @return the wrapped driver's major version number
* @see java.sql.Driver#getMajorVersion()
*/
@Override
public int getMajorVersion() {
return this.driver.getMajorVersion();
}
/**
* Returns the wrapped driver's minor version number.
*
* @return the wrapped driver's minor version number
* @see java.sql.Driver#getMinorVersion()
*/
@Override
public int getMinorVersion() {
return this.driver.getMinorVersion();
}
/**
* Returns whether or not the wrapped driver is jdbcCompliant.
*
* @return true if the wrapped driver is JDBC compliant; otherwise false
* @see java.sql.Driver#jdbcCompliant()
*/
@Override
public boolean jdbcCompliant() {
return this.driver.jdbcCompliant();
}
/**
* Wraps the call to the underlying driver's connect method.
*
* @param url the URL of the database
* @param info a collection of string/value pairs
* @return a Connection object
* @throws SQLException thrown if there is an error connecting to the database
* @see java.sql.Driver#connect(java.lang.String, java.util.Properties)
*/
@Override
public Connection connect(String url, Properties info) throws SQLException {
return this.driver.connect(url, info);
}
/**
* Wraps the call to the underlying driver's getPropertyInfo method.
*
* @param url the URL of the database
* @param info a collection of string/value pairs
* @return an array of DriverPropertyInfo objects
* @throws SQLException thrown if there is an error accessing the database
* @see java.sql.Driver#getPropertyInfo(java.lang.String, java.util.Properties)
*/
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
return this.driver.getPropertyInfo(url, info);
}
/**
* Wraps the call to the underlying driver's getParentLogger method.
*
* @return the parent's Logger
* @throws SQLFeatureNotSupportedException thrown if the feature is not supported
* @see java.sql.Driver#getParentLogger()
*/
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return this.driver.getParentLogger();
}
/**
* Standard implementation of hashCode.
*
* @return the hashCode of the object
*/
@Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + (this.driver != null ? this.driver.hashCode() : 0);
return hash;
}
/**
* Standard implementation of equals.
*
* @param obj the object to compare
* @return returns true if the objects are equal; otherwise false
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DriverShim other = (DriverShim) obj;
return this.driver == other.driver || (this.driver != null && this.driver.equals(other.driver));
}
/**
* Standard implementation of toString().
*
* @return the String representation of the object
*/
@Override
public String toString() {
return "DriverShim{" + "driver=" + driver + '}';
}
}

View File

@@ -1,12 +0,0 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.data</title>
* </head>
* <body>
* Contains classes used to work with the data sources.
* </body>
* </html>
*/
package org.owasp.dependencycheck.data;

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

@@ -16,23 +16,25 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data;
package org.owasp.dependencycheck.data.update;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
/**
* Defines an Index who's data is retrieved from the Internet. This data can be
* downloaded and the index updated.
* Defines a data source who's data is retrieved from the Internet. This data
* can be downloaded and the local cache updated.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public interface CachedWebDataSource {
/**
* Determines if an update to the current index is needed, if it is the new
* data is downloaded from the Internet and imported into the current Lucene
* Index.
* Determines if an update to the current data store is needed, if it is the
* new data is downloaded from the Internet and imported into the current
* cached data store.
*
* @throws UpdateException is thrown if there is an exception updating the
* index.
* @throws UpdateException is thrown if there is an exception downloading
* the data or updating the data store.
*/
void update() throws UpdateException;
}

View File

@@ -1,241 +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.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Properties;
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.Settings;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class DataStoreMetaInfo {
/**
* Batch key word, used as key to store information about batch mode.
*/
public static final String BATCH = "batch";
/**
* Modified key word, used as a key to store information about the modified
* file (i.e. the containing the last 8 days of updates)..
*/
public static final String MODIFIED = "modified";
/**
* The name of the properties file containing the timestamp of the last
* update.
*/
private static final String UPDATE_PROPERTIES_FILE = "data.properties";
/**
* The properties file key for the last updated field - used to store the
* last updated time of the Modified NVD CVE xml file.
*/
public static final String LAST_UPDATED = "lastupdated.modified";
/**
* Stores the last updated time for each of the NVD CVE files. These
* timestamps should be updated if we process the modified file within 7
* days of the last update.
*/
public static final String LAST_UPDATED_BASE = "lastupdated.";
/**
* A collection of properties about the data.
*/
private Properties properties = new Properties();
/**
* Indicates whether or not the updates are using a batch update mode or
* not.
*/
private boolean batchUpdateMode;
/**
* Get the value of batchUpdateMode.
*
* @return the value of batchUpdateMode
*/
protected boolean isBatchUpdateMode() {
return batchUpdateMode;
}
/**
* Set the value of batchUpdateMode.
*
* @param batchUpdateMode new value of batchUpdateMode
*/
protected void setBatchUpdateMode(boolean batchUpdateMode) {
this.batchUpdateMode = batchUpdateMode;
}
/**
* Constructs a new data properties object.
*/
public DataStoreMetaInfo() {
batchUpdateMode = !Settings.getString(Settings.KEYS.BATCH_UPDATE_URL, "").isEmpty();
loadProperties();
}
/**
* Loads the data's meta properties.
*/
private void loadProperties() {
final File file = getPropertiesFile();
if (file.exists()) {
InputStream is = null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException ignore) {
//we will never get here as we check for existence above.
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINEST, null, ignore);
}
try {
properties.load(is);
} catch (IOException ex) {
final String msg = String.format("Unable to load properties file '%s'", file.getPath());
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINE, null, ex);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
final String msg = String.format("Unable to close properties file '%s'", file.getPath());
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINE, null, ex);
}
}
}
}
}
/**
* Returns whether or not any properties are set.
*
* @return whether or not any properties are set
*/
public boolean isEmpty() {
return properties.isEmpty();
}
/**
* Writes a properties file containing the last updated date to the
* VULNERABLE_CPE directory.
*
* @param updatedValue the updated nvdcve entry
* @throws UpdateException is thrown if there is an update exception
*/
public void save(NvdCveInfo updatedValue) throws UpdateException {
if (updatedValue == null) {
return;
}
final File cveProp = getPropertiesFile();
final Properties prop = new Properties();
if (cveProp.exists()) {
FileInputStream in = null;
try {
in = new FileInputStream(cveProp);
prop.load(in);
} catch (Exception ignoreMe) {
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINEST, null, ignoreMe);
} finally {
if (in != null) {
try {
in.close();
} catch (Exception ignoreMeToo) {
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINEST, null, ignoreMeToo);
}
}
}
}
prop.put("version", CveDB.DB_SCHEMA_VERSION);
prop.put(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
OutputStream os = null;
OutputStreamWriter out = null;
try {
os = new FileOutputStream(cveProp);
out = new OutputStreamWriter(os, "UTF-8");
prop.store(out, "Meta data about data and data sources used by dependency-check");
} catch (FileNotFoundException ex) {
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINE, null, ex);
throw new UpdateException("Unable to find last updated properties file.", ex);
} catch (IOException ex) {
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINE, null, ex);
throw new UpdateException("Unable to update last updated properties file.", ex);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ex) {
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINEST, null, ex);
}
}
if (os != null) {
try {
os.close();
} catch (IOException ex) {
Logger.getLogger(DataStoreMetaInfo.class.getName()).log(Level.FINEST, null, ex);
}
}
}
}
/**
* Returns the property value for the given key. If the key is not contained
* in the underlying properties null is returned.
*
* @param key the property key
* @return the value of the property
*/
public String getProperty(String key) {
return properties.getProperty(key);
}
/**
* Returns the property value for the given key. If the key is not contained
* in the underlying properties the default value is returned.
*
* @param key the property key
* @param defaultValue the default value
* @return the value of the property
*/
public String getProperty(String key, String defaultValue) {
return properties.getProperty(key, defaultValue);
}
/**
* Retrieves the properties file.
*
* @return the properties file
*/
public static File getPropertiesFile() {
final File dataDirectory = Settings.getFile(Settings.KEYS.DATA_DIRECTORY);
final File file = new File(dataDirectory, UPDATE_PROPERTIES_FILE);
return file;
}
}

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) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.io.IOException;
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;
import org.owasp.dependencycheck.utils.Settings;
/**
* Class responsible for updating the CPE and NVDCVE data stores.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public class DatabaseUpdater implements CachedWebDataSource {
/**
* <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 {
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();
if (task.isUpdateNeeded()) {
lock.release();
lock.obtainExclusiveLock();
if (task.shouldDeleteAndRecreate()) {
try {
deleteExistingData();
} catch (IOException ex) {
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.WARNING, "Unable to delete the existing data directory");
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
}
}
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.");
Logger.getLogger(DatabaseUpdater.class.getName()).log(Level.FINE, null, ex);
} catch (DownloadFailedException ex) {
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();
}
}
}
/**
* 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);
}
}
}

View File

@@ -21,7 +21,7 @@ package org.owasp.dependencycheck.data.update;
/**
* A pojo that contains the Url and timestamp of the current NvdCve XML files.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class NvdCveInfo {

View File

@@ -0,0 +1,58 @@
/*
* 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.update.exception.UpdateException;
import java.net.MalformedURLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.utils.DownloadFailedException;
/**
* Class responsible for updating the NVD CVE and CPE data stores.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class NvdCveUpdater implements CachedWebDataSource {
/**
* <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 {
final StandardUpdate task = new StandardUpdate();
if (task.isUpdateNeeded()) {
task.update();
}
} catch (MalformedURLException ex) {
Logger.getLogger(NvdCveUpdater.class.getName()).log(Level.WARNING,
"NVD CVE properties files contain an invalid URL, unable to update the data to use the most current data.");
Logger.getLogger(NvdCveUpdater.class.getName()).log(Level.FINE, null, ex);
} catch (DownloadFailedException ex) {
Logger.getLogger(NvdCveUpdater.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(NvdCveUpdater.class.getName()).log(Level.FINE, null, ex);
}
}
}

View File

@@ -0,0 +1,347 @@
/*
* 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.update.task.ProcessTask;
import org.owasp.dependencycheck.data.update.task.CallableDownloadTask;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import java.net.MalformedURLException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
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.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.nvdcve.DatabaseProperties.MODIFIED;
/**
* 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 DatabaseProperties properties;
/**
* A collection of updateable NVD CVE items.
*/
private UpdateableNvdCve updateable;
/**
* 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();
}
/**
* 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 {
openDataStores();
properties = cveDB.getDatabaseProperties();
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 downloadExecutors = Executors.newFixedThreadPool(poolSize);
final ExecutorService processExecutor = Executors.newSingleThreadExecutor();
final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<Future<Future<ProcessTask>>>(maxUpdates);
for (NvdCveInfo cve : updateable) {
if (cve.getNeedsUpdate()) {
final CallableDownloadTask call = new CallableDownloadTask(cve, processExecutor, cveDB);
downloadFutures.add(downloadExecutors.submit(call));
}
}
downloadExecutors.shutdown();
//next, move the future future processTasks to just future processTasks
final Set<Future<ProcessTask>> processFutures = new HashSet<Future<ProcessTask>>(maxUpdates);
for (Future<Future<ProcessTask>> future : downloadFutures) {
Future<ProcessTask> task = null;
try {
task = future.get();
} catch (InterruptedException ex) {
downloadExecutors.shutdownNow();
processExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during download", ex);
throw new UpdateException("The download was interupted", ex);
} catch (ExecutionException ex) {
downloadExecutors.shutdownNow();
processExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during download execution", ex);
throw new UpdateException("The execution of the download was interupted", ex);
}
if (task == null) {
downloadExecutors.shutdownNow();
processExecutor.shutdownNow();
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during download");
throw new UpdateException("The download was interupted; unable to complete the update");
} else {
processFutures.add(task);
}
}
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 (we may not have actually updated it)
properties.save(updateable.get(MODIFIED));
cveDB.cleanupDatabase();
}
} 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
*/
protected final UpdateableNvdCve updatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
UpdateableNvdCve 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 {
final long lastUpdated = Long.parseLong(properties.getProperty(DatabaseProperties.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(DatabaseProperties.LAST_UPDATED_BASE + entry.getId(), "0"));
} catch (NumberFormatException ex) {
final String msg = String.format("Error parsing '%s' '%s' from nvdcve.lastupdated",
DatabaseProperties.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 UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
final UpdateableNvdCve updates = new UpdateableNvdCve();
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;
}
/**
* 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 final void openDataStores() throws UpdateException {
if (cveDB != null) {
return;
}
try {
cveDB = new CveDB();
cveDB.open();
} 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.");
}
}
/**
* 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;
}
}

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

@@ -16,14 +16,14 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data;
package org.owasp.dependencycheck.data.update;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public final class UpdateService {

View File

@@ -1,51 +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.UpdateException;
/**
* An interface defining an update task.
*
* @author Jeremy Long (jeremy.long@owasp.org)
*/
public interface UpdateTask {
/**
* <p>Updates the data store to the latest version.</p>
*
* @throws UpdateException is thrown if there is an error updating the
* database
*/
void update() throws UpdateException;
/**
* Get the value of deleteAndRecreate.
*
* @return the value of deleteAndRecreate
*/
boolean shouldDeleteAndRecreate();
/**
* Gets whether or not an update is needed.
*
* @return true or false depending on whether an update is needed
*/
boolean isUpdateNeeded();
}

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

@@ -31,9 +31,9 @@ import org.owasp.dependencycheck.utils.Downloader;
* Contains a collection of updateable NvdCveInfo objects. This is used to
* determine which files need to be downloaded and processed.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class Updateable implements java.lang.Iterable<NvdCveInfo>, Iterator<NvdCveInfo> {
public class UpdateableNvdCve implements java.lang.Iterable<NvdCveInfo>, Iterator<NvdCveInfo> {
/**
* A collection of sources of data.

View File

@@ -16,18 +16,18 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.nvdcve;
package org.owasp.dependencycheck.data.update.exception;
/**
* An InvalidDataDataException is a generic exception used when trying to load
* the nvd cve meta data.
* the NVD CVE meta data.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class InvalidDataException extends Exception {
/**
* the serial version uid.
* The serial version UID.
*/
private static final long serialVersionUID = 1L;

View File

@@ -16,14 +16,14 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data;
package org.owasp.dependencycheck.data.update.exception;
import java.io.IOException;
/**
* An exception used when an error occurs reading a setting.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class UpdateException extends IOException {

View File

@@ -0,0 +1,11 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.data.update.exception</title>
* </head>
* <body>
* <p>A collection of exception classes used within the application.</p>
* </body>
* </html>
*/
package org.owasp.dependencycheck.data.update.exception;

View File

@@ -1,18 +1,15 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.data.nvdcve.xml</title>
* <title>org.owasp.dependencycheck.data.update</title>
* </head>
* <body>
* <p>Contains classes used to parse the NVD CVE XML file.</p>
* <p>The basic use is that the Importer is called to import
* an NVD CVE file. The Importer instantiates an Indexer object
* (which extends Index). The Indexer creates a partial-unmarshalling
* SAX parser (implemented in the NvdCveXmlFilter) that extracts
* VulnerabilityTypes (aka Entry) from the NVD CVE data file and
* stores these into a Lucene Index.</p>
* <p>Contains classes used to update the data stores.</p>
* <p>The UpdateService will load, any correctly defined CachedWebDataSource(s)
* and call update() on them. The Cached Data Source must determine if it needs
* to be updated and if so perform the update. The sub packages contain classes
* used to perform the actual updates.</p>
* </body>
* </html>
*/
*/
package org.owasp.dependencycheck.data.update;

View File

@@ -0,0 +1,220 @@
/*
* 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.task;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.update.NvdCveInfo;
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<Future<ProcessTask>> {
/**
* Simple constructor for the callable download task.
*
* @param nvdCveInfo the NVD CVE info
* @param processor the processor service to submit the downloaded files to
* @param cveDB the CVE DB to use to store the vulnerability data
*/
public CallableDownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB) {
this.nvdCveInfo = nvdCveInfo;
this.processorService = processor;
this.cveDB = cveDB;
final File file1;
final File file2;
try {
file1 = File.createTempFile("cve" + nvdCveInfo.getId() + "_", ".xml");
file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + "_", ".xml");
} catch (IOException ex) {
return;
}
this.first = file1;
this.second = file2;
}
/**
* The CVE DB to use when processing the files.
*/
private CveDB cveDB;
/**
* The processor service to pass the results of the download to.
*/
private ExecutorService processorService;
/**
* 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 Future<ProcessTask> 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);
try {
Downloader.fetchFile(url1, first);
Downloader.fetchFile(url2, second);
} catch (DownloadFailedException ex) {
msg = String.format("Download Failed for NVD CVE - %s%nSome CVEs may not be reported.", nvdCveInfo.getId());
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.FINE, null, ex);
return null;
}
msg = String.format("Download Complete for NVD CVE - %s", nvdCveInfo.getId());
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.INFO, msg);
final ProcessTask task = new ProcessTask(cveDB, this);
return this.processorService.submit(task);
} catch (Throwable ex) {
final String msg = String.format("An exception occurred downloading NVD CVE - %s%nSome CVEs may not be reported.", nvdCveInfo.getId());
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.WARNING, msg);
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.FINE, "Download Task Failed", ex);
}
return null;
}
/**
* 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

@@ -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.task;
import org.owasp.dependencycheck.data.update.xml.NvdCve20Handler;
import org.owasp.dependencycheck.data.update.xml.NvdCve12Handler;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
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.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.update.StandardUpdate;
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;
}
/**
* A reference to the CveDB.
*/
private final CveDB cveDB;
/**
* A reference to the callable download task.
*/
private final CallableDownloadTask filePair;
/**
* A reference to the properties.
*/
private final DatabaseProperties properties;
/**
* Constructs a new ProcessTask used to process an NVD CVE update.
*
* @param cveDB the data store object
* @param filePair the download task that contains the URL references to
* download
*/
public ProcessTask(final CveDB cveDB, final CallableDownloadTask filePair) {
this.cveDB = cveDB;
this.filePair = filePair;
this.properties = cveDB.getDatabaseProperties();
}
/**
* Implements the callable interface.
*
* @return this object
* @throws Exception thrown if there is an exception; note that any
* UpdateExceptions are simply added to the tasks exception collection
*/
@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);
}
/**
* Processes the NVD CVE XML file and imports the data into the DB.
*
* @throws UpdateException thrown if there is an error loading the data into
* the database
*/
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,12 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.data.update.task</title>
* </head>
* <body>
* <p>A collection of callable/runnable tasks used to speed up the update
* process.</p>
* </body>
* </html>
*/
package org.owasp.dependencycheck.data.update.task;

View File

@@ -16,7 +16,7 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.nvdcve;
package org.owasp.dependencycheck.data.update.xml;
import java.util.ArrayList;
import java.util.HashMap;
@@ -35,7 +35,7 @@ import org.xml.sax.helpers.DefaultHandler;
* schema and is useful to ensure accurate identification (or at least
* complete).
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class NvdCve12Handler extends DefaultHandler {

View File

@@ -16,7 +16,7 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.data.nvdcve;
package org.owasp.dependencycheck.data.update.xml;
import java.io.IOException;
import java.util.List;
@@ -24,7 +24,8 @@ 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.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Reference;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
@@ -36,7 +37,7 @@ import org.xml.sax.helpers.DefaultHandler;
/**
* A SAX Handler that will parse the NVD CVE XML (schema version 2.0).
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class NvdCve20Handler extends DefaultHandler {
@@ -208,6 +209,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 +264,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

@@ -0,0 +1,16 @@
/**
* <html>
* <head>
* <title>org.owasp.dependencycheck.data.nvdcve.xml</title>
* </head>
* <body>
* <p>Contains classes used to parse the NVD CVE XML file.</p>
* <p>The basic use is that the Importer is called to import an NVD CVE file.
* The Importer instantiates an Indexer object (which extends Index). The
* Indexer creates a partial-unmarshalling SAX parser (implemented in the
* NvdCveXmlFilter) that extracts VulnerabilityTypes (aka Entry) from the NVD
* CVE data file and stores these into a Lucene Index.</p>
* </body>
* </html>
*/
package org.owasp.dependencycheck.data.update.xml;

View File

@@ -37,7 +37,7 @@ import org.owasp.dependencycheck.utils.FileUtils;
* the form of evidence. The Evidence is then used to determine if there are any
* known, published, vulnerabilities associated with the program dependency.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class Dependency implements Comparable<Dependency> {

View File

@@ -21,7 +21,7 @@ package org.owasp.dependencycheck.dependency;
/**
* Evidence is a piece of information about a Dependency.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class Evidence implements Comparable<Evidence> {

View File

@@ -35,7 +35,7 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
/**
* Used to maintain a collection of Evidence.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class EvidenceCollection implements Iterable<Evidence> {
@@ -89,7 +89,7 @@ public class EvidenceCollection implements Iterable<Evidence> {
*
* @param confidence the confidence level for the evidence to be iterated
* over.
* @return Iterable<Evidence> an iterable collectoin of evidence
* @return Iterable<Evidence> an iterable collection of evidence
*/
public final Iterable<Evidence> iterator(Evidence.Confidence confidence) {
if (confidence == Evidence.Confidence.HIGHEST) {

View File

@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.dependency;
/**
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class Identifier implements Comparable<Identifier> {

View File

@@ -24,7 +24,7 @@ import java.io.Serializable;
* An external reference for a vulnerability. This contains a name, URL, and a
* source.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class Reference implements Serializable, Comparable<Reference> {

View File

@@ -26,7 +26,7 @@ import java.util.TreeSet;
/**
* Contains the information about a vulnerability.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class Vulnerability implements Serializable, Comparable<Vulnerability> {

View File

@@ -24,7 +24,7 @@ import java.util.Comparator;
/**
* Comparator for Vulnerability objects.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class VulnerabilityComparator implements Comparator<Vulnerability>, Serializable {

View File

@@ -29,7 +29,7 @@ import org.owasp.dependencycheck.data.cpe.IndexEntry;
* A record containing information about vulnerable software. This is referenced
* from a vulnerability.
*
* @author Jeremy Long (jeremy.long@owasp.org)
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class VulnerableSoftware extends IndexEntry implements Serializable, Comparable<VulnerableSoftware> {

Some files were not shown because too many files have changed in this diff Show More