1 /*
2 * This file is part of dependency-check-core.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Copyright (c) 2014 Steve Springett. All Rights Reserved.
17 */
18 package org.owasp.dependencycheck.agent;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.util.List;
23 import org.owasp.dependencycheck.Engine;
24 import org.owasp.dependencycheck.data.nvdcve.CveDB;
25 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
26 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
27 import org.owasp.dependencycheck.dependency.Dependency;
28 import org.owasp.dependencycheck.dependency.Identifier;
29 import org.owasp.dependencycheck.dependency.Vulnerability;
30 import org.owasp.dependencycheck.exception.ScanAgentException;
31 import org.owasp.dependencycheck.reporting.ReportGenerator;
32 import org.owasp.dependencycheck.utils.Settings;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37 * This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting evidence
38 * from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it takes a list of
39 * dependencies that can be programmatically added from data in a spreadsheet, database or some other datasource and conduct a
40 * scan based on this pre-defined evidence.
41 *
42 * <h2>Example:</h2>
43 * <pre>
44 * List<Dependency> dependencies = new ArrayList<Dependency>();
45 * Dependency dependency = new Dependency(new File(FileUtils.getBitBucket()));
46 * dependency.getProductEvidence().addEvidence("my-datasource", "name", "Jetty", Confidence.HIGH);
47 * dependency.getVersionEvidence().addEvidence("my-datasource", "version", "5.1.10", Confidence.HIGH);
48 * dependency.getVendorEvidence().addEvidence("my-datasource", "vendor", "mortbay", Confidence.HIGH);
49 * dependencies.add(dependency);
50 *
51 * DependencyCheckScanAgent scan = new DependencyCheckScanAgent();
52 * scan.setDependencies(dependencies);
53 * scan.setReportFormat(ReportGenerator.Format.ALL);
54 * scan.setReportOutputDirectory(System.getProperty("user.home"));
55 * scan.execute();
56 * </pre>
57 *
58 * @author Steve Springett <steve.springett@owasp.org>
59 */
60 @SuppressWarnings("unused")
61 public class DependencyCheckScanAgent {
62
63 /**
64 * System specific new line character.
65 */
66 private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
67 /**
68 * Logger for use throughout the class.
69 */
70 private static final Logger LOGGER = LoggerFactory.getLogger(DependencyCheckScanAgent.class);
71 /**
72 * The application name for the report.
73 */
74 private String applicationName = "Dependency-Check";
75
76 /**
77 * Get the value of applicationName.
78 *
79 * @return the value of applicationName
80 */
81 public String getApplicationName() {
82 return applicationName;
83 }
84
85 /**
86 * Set the value of applicationName.
87 *
88 * @param applicationName new value of applicationName
89 */
90 public void setApplicationName(String applicationName) {
91 this.applicationName = applicationName;
92 }
93
94 /**
95 * The pre-determined dependencies to scan
96 */
97 private List<Dependency> dependencies;
98
99 /**
100 * Returns a list of pre-determined dependencies.
101 *
102 * @return returns a list of dependencies
103 */
104 public List<Dependency> getDependencies() {
105 return dependencies;
106 }
107
108 /**
109 * Sets the list of dependencies to scan.
110 *
111 * @param dependencies new value of dependencies
112 */
113 public void setDependencies(List<Dependency> dependencies) {
114 this.dependencies = dependencies;
115 }
116
117 /**
118 * The location of the data directory that contains
119 */
120 private String dataDirectory = null;
121
122 /**
123 * Get the value of dataDirectory.
124 *
125 * @return the value of dataDirectory
126 */
127 public String getDataDirectory() {
128 return dataDirectory;
129 }
130
131 /**
132 * Set the value of dataDirectory.
133 *
134 * @param dataDirectory new value of dataDirectory
135 */
136 public void setDataDirectory(String dataDirectory) {
137 this.dataDirectory = dataDirectory;
138 }
139
140 /**
141 * Specifies the destination directory for the generated Dependency-Check report.
142 */
143 private String reportOutputDirectory;
144
145 /**
146 * Get the value of reportOutputDirectory.
147 *
148 * @return the value of reportOutputDirectory
149 */
150 public String getReportOutputDirectory() {
151 return reportOutputDirectory;
152 }
153
154 /**
155 * Set the value of reportOutputDirectory.
156 *
157 * @param reportOutputDirectory new value of reportOutputDirectory
158 */
159 public void setReportOutputDirectory(String reportOutputDirectory) {
160 this.reportOutputDirectory = reportOutputDirectory;
161 }
162
163 /**
164 * Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which
165 * means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11. The valid range
166 * for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
167 */
168 private float failBuildOnCVSS = 11;
169
170 /**
171 * Get the value of failBuildOnCVSS.
172 *
173 * @return the value of failBuildOnCVSS
174 */
175 public float getFailBuildOnCVSS() {
176 return failBuildOnCVSS;
177 }
178
179 /**
180 * Set the value of failBuildOnCVSS.
181 *
182 * @param failBuildOnCVSS new value of failBuildOnCVSS
183 */
184 public void setFailBuildOnCVSS(float failBuildOnCVSS) {
185 this.failBuildOnCVSS = failBuildOnCVSS;
186 }
187
188 /**
189 * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
190 * is true.
191 */
192 private boolean autoUpdate = true;
193
194 /**
195 * Get the value of autoUpdate.
196 *
197 * @return the value of autoUpdate
198 */
199 public boolean isAutoUpdate() {
200 return autoUpdate;
201 }
202
203 /**
204 * Set the value of autoUpdate.
205 *
206 * @param autoUpdate new value of autoUpdate
207 */
208 public void setAutoUpdate(boolean autoUpdate) {
209 this.autoUpdate = autoUpdate;
210 }
211
212 /**
213 * flag indicating whether or not to generate a report of findings.
214 */
215 private boolean generateReport = true;
216
217 /**
218 * Get the value of generateReport.
219 *
220 * @return the value of generateReport
221 */
222 public boolean isGenerateReport() {
223 return generateReport;
224 }
225
226 /**
227 * Set the value of generateReport.
228 *
229 * @param generateReport new value of generateReport
230 */
231 public void setGenerateReport(boolean generateReport) {
232 this.generateReport = generateReport;
233 }
234
235 /**
236 * The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the
237 * Site plugin unless the externalReport is set to true. Default is HTML.
238 */
239 private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
240
241 /**
242 * Get the value of reportFormat.
243 *
244 * @return the value of reportFormat
245 */
246 public ReportGenerator.Format getReportFormat() {
247 return reportFormat;
248 }
249
250 /**
251 * Set the value of reportFormat.
252 *
253 * @param reportFormat new value of reportFormat
254 */
255 public void setReportFormat(ReportGenerator.Format reportFormat) {
256 this.reportFormat = reportFormat;
257 }
258
259 /**
260 * The Proxy Server.
261 */
262 private String proxyServer;
263
264 /**
265 * Get the value of proxyServer.
266 *
267 * @return the value of proxyServer
268 */
269 public String getProxyServer() {
270 return proxyServer;
271 }
272
273 /**
274 * Set the value of proxyServer.
275 *
276 * @param proxyServer new value of proxyServer
277 */
278 public void setProxyServer(String proxyServer) {
279 this.proxyServer = proxyServer;
280 }
281
282 /**
283 * Get the value of proxyServer.
284 *
285 * @return the value of proxyServer
286 * @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()} instead
287 */
288 @Deprecated
289 public String getProxyUrl() {
290 return proxyServer;
291 }
292
293 /**
294 * Set the value of proxyServer.
295 *
296 * @param proxyUrl new value of proxyServer
297 * @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#setProxyServer(java.lang.String)
298 * } instead
299 */
300 @Deprecated
301 public void setProxyUrl(String proxyUrl) {
302 this.proxyServer = proxyUrl;
303 }
304
305 /**
306 * The Proxy Port.
307 */
308 private String proxyPort;
309
310 /**
311 * Get the value of proxyPort.
312 *
313 * @return the value of proxyPort
314 */
315 public String getProxyPort() {
316 return proxyPort;
317 }
318
319 /**
320 * Set the value of proxyPort.
321 *
322 * @param proxyPort new value of proxyPort
323 */
324 public void setProxyPort(String proxyPort) {
325 this.proxyPort = proxyPort;
326 }
327
328 /**
329 * The Proxy username.
330 */
331 private String proxyUsername;
332
333 /**
334 * Get the value of proxyUsername.
335 *
336 * @return the value of proxyUsername
337 */
338 public String getProxyUsername() {
339 return proxyUsername;
340 }
341
342 /**
343 * Set the value of proxyUsername.
344 *
345 * @param proxyUsername new value of proxyUsername
346 */
347 public void setProxyUsername(String proxyUsername) {
348 this.proxyUsername = proxyUsername;
349 }
350
351 /**
352 * The Proxy password.
353 */
354 private String proxyPassword;
355
356 /**
357 * Get the value of proxyPassword.
358 *
359 * @return the value of proxyPassword
360 */
361 public String getProxyPassword() {
362 return proxyPassword;
363 }
364
365 /**
366 * Set the value of proxyPassword.
367 *
368 * @param proxyPassword new value of proxyPassword
369 */
370 public void setProxyPassword(String proxyPassword) {
371 this.proxyPassword = proxyPassword;
372 }
373
374 /**
375 * The Connection Timeout.
376 */
377 private String connectionTimeout;
378
379 /**
380 * Get the value of connectionTimeout.
381 *
382 * @return the value of connectionTimeout
383 */
384 public String getConnectionTimeout() {
385 return connectionTimeout;
386 }
387
388 /**
389 * Set the value of connectionTimeout.
390 *
391 * @param connectionTimeout new value of connectionTimeout
392 */
393 public void setConnectionTimeout(String connectionTimeout) {
394 this.connectionTimeout = connectionTimeout;
395 }
396
397 /**
398 * The file path used for verbose logging.
399 */
400 private String logFile = null;
401
402 /**
403 * Get the value of logFile.
404 *
405 * @return the value of logFile
406 */
407 public String getLogFile() {
408 return logFile;
409 }
410
411 /**
412 * Set the value of logFile.
413 *
414 * @param logFile new value of logFile
415 */
416 public void setLogFile(String logFile) {
417 this.logFile = logFile;
418 }
419
420 /**
421 * The path to the suppression file.
422 */
423 private String suppressionFile;
424
425 /**
426 * Get the value of suppressionFile.
427 *
428 * @return the value of suppressionFile
429 */
430 public String getSuppressionFile() {
431 return suppressionFile;
432 }
433
434 /**
435 * Set the value of suppressionFile.
436 *
437 * @param suppressionFile new value of suppressionFile
438 */
439 public void setSuppressionFile(String suppressionFile) {
440 this.suppressionFile = suppressionFile;
441 }
442
443 /**
444 * flag indicating whether or not to show a summary of findings.
445 */
446 private boolean showSummary = true;
447
448 /**
449 * Get the value of showSummary.
450 *
451 * @return the value of showSummary
452 */
453 public boolean isShowSummary() {
454 return showSummary;
455 }
456
457 /**
458 * Set the value of showSummary.
459 *
460 * @param showSummary new value of showSummary
461 */
462 public void setShowSummary(boolean showSummary) {
463 this.showSummary = showSummary;
464 }
465
466 /**
467 * Whether or not the Maven Central analyzer is enabled.
468 */
469 private boolean centralAnalyzerEnabled = true;
470
471 /**
472 * Get the value of centralAnalyzerEnabled.
473 *
474 * @return the value of centralAnalyzerEnabled
475 */
476 public boolean isCentralAnalyzerEnabled() {
477 return centralAnalyzerEnabled;
478 }
479
480 /**
481 * Set the value of centralAnalyzerEnabled.
482 *
483 * @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
484 */
485 public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
486 this.centralAnalyzerEnabled = centralAnalyzerEnabled;
487 }
488
489 /**
490 * The URL of Maven Central.
491 */
492 private String centralUrl;
493
494 /**
495 * Get the value of centralUrl.
496 *
497 * @return the value of centralUrl
498 */
499 public String getCentralUrl() {
500 return centralUrl;
501 }
502
503 /**
504 * Set the value of centralUrl.
505 *
506 * @param centralUrl new value of centralUrl
507 */
508 public void setCentralUrl(String centralUrl) {
509 this.centralUrl = centralUrl;
510 }
511
512 /**
513 * Whether or not the nexus analyzer is enabled.
514 */
515 private boolean nexusAnalyzerEnabled = true;
516
517 /**
518 * Get the value of nexusAnalyzerEnabled.
519 *
520 * @return the value of nexusAnalyzerEnabled
521 */
522 public boolean isNexusAnalyzerEnabled() {
523 return nexusAnalyzerEnabled;
524 }
525
526 /**
527 * Set the value of nexusAnalyzerEnabled.
528 *
529 * @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
530 */
531 public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
532 this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
533 }
534
535 /**
536 * The URL of the Nexus server.
537 */
538 private String nexusUrl;
539
540 /**
541 * Get the value of nexusUrl.
542 *
543 * @return the value of nexusUrl
544 */
545 public String getNexusUrl() {
546 return nexusUrl;
547 }
548
549 /**
550 * Set the value of nexusUrl.
551 *
552 * @param nexusUrl new value of nexusUrl
553 */
554 public void setNexusUrl(String nexusUrl) {
555 this.nexusUrl = nexusUrl;
556 }
557
558 /**
559 * Whether or not the defined proxy should be used when connecting to Nexus.
560 */
561 private boolean nexusUsesProxy = true;
562
563 /**
564 * Get the value of nexusUsesProxy.
565 *
566 * @return the value of nexusUsesProxy
567 */
568 public boolean isNexusUsesProxy() {
569 return nexusUsesProxy;
570 }
571
572 /**
573 * Set the value of nexusUsesProxy.
574 *
575 * @param nexusUsesProxy new value of nexusUsesProxy
576 */
577 public void setNexusUsesProxy(boolean nexusUsesProxy) {
578 this.nexusUsesProxy = nexusUsesProxy;
579 }
580
581 /**
582 * The database driver name; such as org.h2.Driver.
583 */
584 private String databaseDriverName;
585
586 /**
587 * Get the value of databaseDriverName.
588 *
589 * @return the value of databaseDriverName
590 */
591 public String getDatabaseDriverName() {
592 return databaseDriverName;
593 }
594
595 /**
596 * Set the value of databaseDriverName.
597 *
598 * @param databaseDriverName new value of databaseDriverName
599 */
600 public void setDatabaseDriverName(String databaseDriverName) {
601 this.databaseDriverName = databaseDriverName;
602 }
603
604 /**
605 * The path to the database driver JAR file if it is not on the class path.
606 */
607 private String databaseDriverPath;
608
609 /**
610 * Get the value of databaseDriverPath.
611 *
612 * @return the value of databaseDriverPath
613 */
614 public String getDatabaseDriverPath() {
615 return databaseDriverPath;
616 }
617
618 /**
619 * Set the value of databaseDriverPath.
620 *
621 * @param databaseDriverPath new value of databaseDriverPath
622 */
623 public void setDatabaseDriverPath(String databaseDriverPath) {
624 this.databaseDriverPath = databaseDriverPath;
625 }
626
627 /**
628 * The database connection string.
629 */
630 private String connectionString;
631
632 /**
633 * Get the value of connectionString.
634 *
635 * @return the value of connectionString
636 */
637 public String getConnectionString() {
638 return connectionString;
639 }
640
641 /**
642 * Set the value of connectionString.
643 *
644 * @param connectionString new value of connectionString
645 */
646 public void setConnectionString(String connectionString) {
647 this.connectionString = connectionString;
648 }
649
650 /**
651 * The user name for connecting to the database.
652 */
653 private String databaseUser;
654
655 /**
656 * Get the value of databaseUser.
657 *
658 * @return the value of databaseUser
659 */
660 public String getDatabaseUser() {
661 return databaseUser;
662 }
663
664 /**
665 * Set the value of databaseUser.
666 *
667 * @param databaseUser new value of databaseUser
668 */
669 public void setDatabaseUser(String databaseUser) {
670 this.databaseUser = databaseUser;
671 }
672
673 /**
674 * The password to use when connecting to the database.
675 */
676 private String databasePassword;
677
678 /**
679 * Get the value of databasePassword.
680 *
681 * @return the value of databasePassword
682 */
683 public String getDatabasePassword() {
684 return databasePassword;
685 }
686
687 /**
688 * Set the value of databasePassword.
689 *
690 * @param databasePassword new value of databasePassword
691 */
692 public void setDatabasePassword(String databasePassword) {
693 this.databasePassword = databasePassword;
694 }
695
696 /**
697 * Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
698 * files.
699 */
700 private String zipExtensions;
701
702 /**
703 * Get the value of zipExtensions.
704 *
705 * @return the value of zipExtensions
706 */
707 public String getZipExtensions() {
708 return zipExtensions;
709 }
710
711 /**
712 * Set the value of zipExtensions.
713 *
714 * @param zipExtensions new value of zipExtensions
715 */
716 public void setZipExtensions(String zipExtensions) {
717 this.zipExtensions = zipExtensions;
718 }
719
720 /**
721 * The url for the modified NVD CVE (1.2 schema).
722 */
723 private String cveUrl12Modified;
724
725 /**
726 * Get the value of cveUrl12Modified.
727 *
728 * @return the value of cveUrl12Modified
729 */
730 public String getCveUrl12Modified() {
731 return cveUrl12Modified;
732 }
733
734 /**
735 * Set the value of cveUrl12Modified.
736 *
737 * @param cveUrl12Modified new value of cveUrl12Modified
738 */
739 public void setCveUrl12Modified(String cveUrl12Modified) {
740 this.cveUrl12Modified = cveUrl12Modified;
741 }
742
743 /**
744 * The url for the modified NVD CVE (2.0 schema).
745 */
746 private String cveUrl20Modified;
747
748 /**
749 * Get the value of cveUrl20Modified.
750 *
751 * @return the value of cveUrl20Modified
752 */
753 public String getCveUrl20Modified() {
754 return cveUrl20Modified;
755 }
756
757 /**
758 * Set the value of cveUrl20Modified.
759 *
760 * @param cveUrl20Modified new value of cveUrl20Modified
761 */
762 public void setCveUrl20Modified(String cveUrl20Modified) {
763 this.cveUrl20Modified = cveUrl20Modified;
764 }
765
766 /**
767 * Base Data Mirror URL for CVE 1.2.
768 */
769 private String cveUrl12Base;
770
771 /**
772 * Get the value of cveUrl12Base.
773 *
774 * @return the value of cveUrl12Base
775 */
776 public String getCveUrl12Base() {
777 return cveUrl12Base;
778 }
779
780 /**
781 * Set the value of cveUrl12Base.
782 *
783 * @param cveUrl12Base new value of cveUrl12Base
784 */
785 public void setCveUrl12Base(String cveUrl12Base) {
786 this.cveUrl12Base = cveUrl12Base;
787 }
788
789 /**
790 * Data Mirror URL for CVE 2.0.
791 */
792 private String cveUrl20Base;
793
794 /**
795 * Get the value of cveUrl20Base.
796 *
797 * @return the value of cveUrl20Base
798 */
799 public String getCveUrl20Base() {
800 return cveUrl20Base;
801 }
802
803 /**
804 * Set the value of cveUrl20Base.
805 *
806 * @param cveUrl20Base new value of cveUrl20Base
807 */
808 public void setCveUrl20Base(String cveUrl20Base) {
809 this.cveUrl20Base = cveUrl20Base;
810 }
811
812 /**
813 * The path to Mono for .NET assembly analysis on non-windows systems.
814 */
815 private String pathToMono;
816
817 /**
818 * Get the value of pathToMono.
819 *
820 * @return the value of pathToMono
821 */
822 public String getPathToMono() {
823 return pathToMono;
824 }
825
826 /**
827 * Set the value of pathToMono.
828 *
829 * @param pathToMono new value of pathToMono
830 */
831 public void setPathToMono(String pathToMono) {
832 this.pathToMono = pathToMono;
833 }
834
835 /**
836 * Executes the Dependency-Check on the dependent libraries.
837 *
838 * @return the Engine used to scan the dependencies.
839 * @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the database
840 */
841 private Engine executeDependencyCheck() throws DatabaseException {
842 populateSettings();
843 final Engine engine = new Engine();
844 engine.setDependencies(this.dependencies);
845 engine.analyzeDependencies();
846 return engine;
847 }
848
849 /**
850 * Generates the reports for a given dependency-check engine.
851 *
852 * @param engine a dependency-check engine
853 * @param outDirectory the directory to write the reports to
854 */
855 private void generateExternalReports(Engine engine, File outDirectory) {
856 DatabaseProperties prop = null;
857 CveDB cve = null;
858 try {
859 cve = new CveDB();
860 cve.open();
861 prop = cve.getDatabaseProperties();
862 } catch (DatabaseException ex) {
863 LOGGER.debug("Unable to retrieve DB Properties", ex);
864 } finally {
865 if (cve != null) {
866 cve.close();
867 }
868 }
869 final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
870 try {
871 r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
872 } catch (IOException ex) {
873 LOGGER.error(
874 "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
875 LOGGER.debug("", ex);
876 } catch (Throwable ex) {
877 LOGGER.error(
878 "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
879 LOGGER.debug("", ex);
880 }
881 }
882
883 /**
884 * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
885 * required to change the proxy server, port, and connection timeout.
886 */
887 private void populateSettings() {
888 Settings.initialize();
889 if (dataDirectory != null) {
890 Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
891 } else {
892 final File jarPath = new File(DependencyCheckScanAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath());
893 final File base = jarPath.getParentFile();
894 final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
895 final File dataDir = new File(base, sub);
896 Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
897 }
898
899 Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
900 Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
901 Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
902 Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
903 Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
904 Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
905 Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
906 Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
907 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
908 Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
909 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
910 Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
911 Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
912 Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
913 Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
914 Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
915 Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
916 Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
917 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
918 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
919 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
920 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
921 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
922 }
923
924 /**
925 * Executes the dependency-check and generates the report.
926 *
927 * @return a reference to the engine used to perform the scan.
928 * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
929 */
930 public Engine execute() throws ScanAgentException {
931 Engine engine = null;
932 try {
933 engine = executeDependencyCheck();
934 if (this.generateReport) {
935 generateExternalReports(engine, new File(this.reportOutputDirectory));
936 }
937 if (this.showSummary) {
938 showSummary(engine.getDependencies());
939 }
940 if (this.failBuildOnCVSS <= 10) {
941 checkForFailure(engine.getDependencies());
942 }
943 } catch (DatabaseException ex) {
944 LOGGER.error(
945 "Unable to connect to the dependency-check database; analysis has stopped");
946 LOGGER.debug("", ex);
947 } finally {
948 Settings.cleanup(true);
949 if (engine != null) {
950 engine.cleanup();
951 }
952 }
953 return engine;
954 }
955
956 /**
957 * Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
958 * configuration.
959 *
960 * @param dependencies the list of dependency objects
961 * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
962 */
963 private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
964 final StringBuilder ids = new StringBuilder();
965 for (Dependency d : dependencies) {
966 boolean addName = true;
967 for (Vulnerability v : d.getVulnerabilities()) {
968 if (v.getCvssScore() >= failBuildOnCVSS) {
969 if (addName) {
970 addName = false;
971 ids.append(NEW_LINE).append(d.getFileName()).append(": ");
972 ids.append(v.getName());
973 } else {
974 ids.append(", ").append(v.getName());
975 }
976 }
977 }
978 }
979 if (ids.length() > 0) {
980 final String msg = String.format("%n%nDependency-Check Failure:%n"
981 + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
982 + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
983
984 throw new ScanAgentException(msg);
985 }
986 }
987
988 /**
989 * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
990 *
991 * @param dependencies a list of dependency objects
992 */
993 private void showSummary(List<Dependency> dependencies) {
994 final StringBuilder summary = new StringBuilder();
995 for (Dependency d : dependencies) {
996 boolean firstEntry = true;
997 final StringBuilder ids = new StringBuilder();
998 for (Vulnerability v : d.getVulnerabilities()) {
999 if (firstEntry) {
1000 firstEntry = false;
1001 } else {
1002 ids.append(", ");
1003 }
1004 ids.append(v.getName());
1005 }
1006 if (ids.length() > 0) {
1007 summary.append(d.getFileName()).append(" (");
1008 firstEntry = true;
1009 for (Identifier id : d.getIdentifiers()) {
1010 if (firstEntry) {
1011 firstEntry = false;
1012 } else {
1013 summary.append(", ");
1014 }
1015 summary.append(id.getValue());
1016 }
1017 summary.append(") : ").append(ids).append(NEW_LINE);
1018 }
1019 }
1020 if (summary.length() > 0) {
1021 LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\n"
1022 + "See the dependency-check report for more details.\n\n",
1023 summary.toString());
1024 }
1025 }
1026
1027 }