1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.ExceptionCollection;
31 import org.owasp.dependencycheck.exception.ScanAgentException;
32 import org.owasp.dependencycheck.reporting.ReportGenerator;
33 import org.owasp.dependencycheck.utils.Settings;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 @SuppressWarnings("unused")
64 public class DependencyCheckScanAgent {
65
66
67
68
69 private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
70
71
72
73 private static final Logger LOGGER = LoggerFactory.getLogger(DependencyCheckScanAgent.class);
74
75
76
77 private String applicationName = "Dependency-Check";
78
79
80
81
82
83
84 public String getApplicationName() {
85 return applicationName;
86 }
87
88
89
90
91
92
93 public void setApplicationName(String applicationName) {
94 this.applicationName = applicationName;
95 }
96
97
98
99
100 private List<Dependency> dependencies;
101
102
103
104
105
106
107 public List<Dependency> getDependencies() {
108 return dependencies;
109 }
110
111
112
113
114
115
116 public void setDependencies(List<Dependency> dependencies) {
117 this.dependencies = dependencies;
118 }
119
120
121
122
123 private String dataDirectory = null;
124
125
126
127
128
129
130 public String getDataDirectory() {
131 return dataDirectory;
132 }
133
134
135
136
137
138
139 public void setDataDirectory(String dataDirectory) {
140 this.dataDirectory = dataDirectory;
141 }
142
143
144
145
146
147 private String reportOutputDirectory;
148
149
150
151
152
153
154 public String getReportOutputDirectory() {
155 return reportOutputDirectory;
156 }
157
158
159
160
161
162
163 public void setReportOutputDirectory(String reportOutputDirectory) {
164 this.reportOutputDirectory = reportOutputDirectory;
165 }
166
167
168
169
170
171
172
173
174 private float failBuildOnCVSS = 11;
175
176
177
178
179
180
181 public float getFailBuildOnCVSS() {
182 return failBuildOnCVSS;
183 }
184
185
186
187
188
189
190 public void setFailBuildOnCVSS(float failBuildOnCVSS) {
191 this.failBuildOnCVSS = failBuildOnCVSS;
192 }
193
194
195
196
197
198 private boolean autoUpdate = true;
199
200
201
202
203
204
205 public boolean isAutoUpdate() {
206 return autoUpdate;
207 }
208
209
210
211
212
213
214 public void setAutoUpdate(boolean autoUpdate) {
215 this.autoUpdate = autoUpdate;
216 }
217
218
219
220
221 private boolean generateReport = true;
222
223
224
225
226
227
228 public boolean isGenerateReport() {
229 return generateReport;
230 }
231
232
233
234
235
236
237 public void setGenerateReport(boolean generateReport) {
238 this.generateReport = generateReport;
239 }
240
241
242
243
244
245
246 private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
247
248
249
250
251
252
253 public ReportGenerator.Format getReportFormat() {
254 return reportFormat;
255 }
256
257
258
259
260
261
262 public void setReportFormat(ReportGenerator.Format reportFormat) {
263 this.reportFormat = reportFormat;
264 }
265
266
267
268
269 private String proxyServer;
270
271
272
273
274
275
276 public String getProxyServer() {
277 return proxyServer;
278 }
279
280
281
282
283
284
285 public void setProxyServer(String proxyServer) {
286 this.proxyServer = proxyServer;
287 }
288
289
290
291
292
293
294
295
296
297 @Deprecated
298 public String getProxyUrl() {
299 return proxyServer;
300 }
301
302
303
304
305
306
307
308
309 @Deprecated
310 public void setProxyUrl(String proxyUrl) {
311 this.proxyServer = proxyUrl;
312 }
313
314
315
316
317 private String proxyPort;
318
319
320
321
322
323
324 public String getProxyPort() {
325 return proxyPort;
326 }
327
328
329
330
331
332
333 public void setProxyPort(String proxyPort) {
334 this.proxyPort = proxyPort;
335 }
336
337
338
339
340 private String proxyUsername;
341
342
343
344
345
346
347 public String getProxyUsername() {
348 return proxyUsername;
349 }
350
351
352
353
354
355
356 public void setProxyUsername(String proxyUsername) {
357 this.proxyUsername = proxyUsername;
358 }
359
360
361
362
363 private String proxyPassword;
364
365
366
367
368
369
370 public String getProxyPassword() {
371 return proxyPassword;
372 }
373
374
375
376
377
378
379 public void setProxyPassword(String proxyPassword) {
380 this.proxyPassword = proxyPassword;
381 }
382
383
384
385
386 private String connectionTimeout;
387
388
389
390
391
392
393 public String getConnectionTimeout() {
394 return connectionTimeout;
395 }
396
397
398
399
400
401
402 public void setConnectionTimeout(String connectionTimeout) {
403 this.connectionTimeout = connectionTimeout;
404 }
405
406
407
408
409 private String logFile = null;
410
411
412
413
414
415
416 public String getLogFile() {
417 return logFile;
418 }
419
420
421
422
423
424
425 public void setLogFile(String logFile) {
426 this.logFile = logFile;
427 }
428
429
430
431
432 private String suppressionFile;
433
434
435
436
437
438
439 public String getSuppressionFile() {
440 return suppressionFile;
441 }
442
443
444
445
446
447
448 public void setSuppressionFile(String suppressionFile) {
449 this.suppressionFile = suppressionFile;
450 }
451
452
453
454
455 private boolean showSummary = true;
456
457
458
459
460
461
462 public boolean isShowSummary() {
463 return showSummary;
464 }
465
466
467
468
469
470
471 public void setShowSummary(boolean showSummary) {
472 this.showSummary = showSummary;
473 }
474
475
476
477
478 private boolean centralAnalyzerEnabled = true;
479
480
481
482
483
484
485 public boolean isCentralAnalyzerEnabled() {
486 return centralAnalyzerEnabled;
487 }
488
489
490
491
492
493
494 public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
495 this.centralAnalyzerEnabled = centralAnalyzerEnabled;
496 }
497
498
499
500
501 private String centralUrl;
502
503
504
505
506
507
508 public String getCentralUrl() {
509 return centralUrl;
510 }
511
512
513
514
515
516
517 public void setCentralUrl(String centralUrl) {
518 this.centralUrl = centralUrl;
519 }
520
521
522
523
524 private boolean nexusAnalyzerEnabled = true;
525
526
527
528
529
530
531 public boolean isNexusAnalyzerEnabled() {
532 return nexusAnalyzerEnabled;
533 }
534
535
536
537
538
539
540 public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
541 this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
542 }
543
544
545
546
547 private String nexusUrl;
548
549
550
551
552
553
554 public String getNexusUrl() {
555 return nexusUrl;
556 }
557
558
559
560
561
562
563 public void setNexusUrl(String nexusUrl) {
564 this.nexusUrl = nexusUrl;
565 }
566
567
568
569
570 private boolean nexusUsesProxy = true;
571
572
573
574
575
576
577 public boolean isNexusUsesProxy() {
578 return nexusUsesProxy;
579 }
580
581
582
583
584
585
586 public void setNexusUsesProxy(boolean nexusUsesProxy) {
587 this.nexusUsesProxy = nexusUsesProxy;
588 }
589
590
591
592
593 private String databaseDriverName;
594
595
596
597
598
599
600 public String getDatabaseDriverName() {
601 return databaseDriverName;
602 }
603
604
605
606
607
608
609 public void setDatabaseDriverName(String databaseDriverName) {
610 this.databaseDriverName = databaseDriverName;
611 }
612
613
614
615
616 private String databaseDriverPath;
617
618
619
620
621
622
623 public String getDatabaseDriverPath() {
624 return databaseDriverPath;
625 }
626
627
628
629
630
631
632 public void setDatabaseDriverPath(String databaseDriverPath) {
633 this.databaseDriverPath = databaseDriverPath;
634 }
635
636
637
638
639 private String connectionString;
640
641
642
643
644
645
646 public String getConnectionString() {
647 return connectionString;
648 }
649
650
651
652
653
654
655 public void setConnectionString(String connectionString) {
656 this.connectionString = connectionString;
657 }
658
659
660
661
662 private String databaseUser;
663
664
665
666
667
668
669 public String getDatabaseUser() {
670 return databaseUser;
671 }
672
673
674
675
676
677
678 public void setDatabaseUser(String databaseUser) {
679 this.databaseUser = databaseUser;
680 }
681
682
683
684
685 private String databasePassword;
686
687
688
689
690
691
692 public String getDatabasePassword() {
693 return databasePassword;
694 }
695
696
697
698
699
700
701 public void setDatabasePassword(String databasePassword) {
702 this.databasePassword = databasePassword;
703 }
704
705
706
707
708
709 private String zipExtensions;
710
711
712
713
714
715
716 public String getZipExtensions() {
717 return zipExtensions;
718 }
719
720
721
722
723
724
725 public void setZipExtensions(String zipExtensions) {
726 this.zipExtensions = zipExtensions;
727 }
728
729
730
731
732 private String cveUrl12Modified;
733
734
735
736
737
738
739 public String getCveUrl12Modified() {
740 return cveUrl12Modified;
741 }
742
743
744
745
746
747
748 public void setCveUrl12Modified(String cveUrl12Modified) {
749 this.cveUrl12Modified = cveUrl12Modified;
750 }
751
752
753
754
755 private String cveUrl20Modified;
756
757
758
759
760
761
762 public String getCveUrl20Modified() {
763 return cveUrl20Modified;
764 }
765
766
767
768
769
770
771 public void setCveUrl20Modified(String cveUrl20Modified) {
772 this.cveUrl20Modified = cveUrl20Modified;
773 }
774
775
776
777
778 private String cveUrl12Base;
779
780
781
782
783
784
785 public String getCveUrl12Base() {
786 return cveUrl12Base;
787 }
788
789
790
791
792
793
794 public void setCveUrl12Base(String cveUrl12Base) {
795 this.cveUrl12Base = cveUrl12Base;
796 }
797
798
799
800
801 private String cveUrl20Base;
802
803
804
805
806
807
808 public String getCveUrl20Base() {
809 return cveUrl20Base;
810 }
811
812
813
814
815
816
817 public void setCveUrl20Base(String cveUrl20Base) {
818 this.cveUrl20Base = cveUrl20Base;
819 }
820
821
822
823
824 private String pathToMono;
825
826
827
828
829
830
831 public String getPathToMono() {
832 return pathToMono;
833 }
834
835
836
837
838
839
840 public void setPathToMono(String pathToMono) {
841 this.pathToMono = pathToMono;
842 }
843
844
845
846
847
848
849
850
851 private Engine executeDependencyCheck() throws ExceptionCollection {
852 populateSettings();
853 final Engine engine;
854 try {
855 engine = new Engine();
856 } catch (DatabaseException ex) {
857 throw new ExceptionCollection(ex, true);
858 }
859 engine.setDependencies(this.dependencies);
860 engine.analyzeDependencies();
861 return engine;
862 }
863
864
865
866
867
868
869
870 private void generateExternalReports(Engine engine, File outDirectory) {
871 DatabaseProperties prop = null;
872 CveDB cve = null;
873 try {
874 cve = new CveDB();
875 cve.open();
876 prop = cve.getDatabaseProperties();
877 } catch (DatabaseException ex) {
878 LOGGER.debug("Unable to retrieve DB Properties", ex);
879 } finally {
880 if (cve != null) {
881 cve.close();
882 }
883 }
884 final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
885 try {
886 r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
887 } catch (IOException ex) {
888 LOGGER.error(
889 "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
890 LOGGER.debug("", ex);
891 } catch (Throwable ex) {
892 LOGGER.error(
893 "Unexpected exception occurred during analysis; please see the verbose error log for more details.");
894 LOGGER.debug("", ex);
895 }
896 }
897
898
899
900
901
902
903 private void populateSettings() {
904 Settings.initialize();
905 if (dataDirectory != null) {
906 Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
907 } else {
908 final File jarPath = new File(DependencyCheckScanAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath());
909 final File base = jarPath.getParentFile();
910 final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
911 final File dataDir = new File(base, sub);
912 Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
913 }
914
915 Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
916 Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
917 Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
918 Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
919 Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
920 Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
921 Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
922 Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
923 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
924 Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
925 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
926 Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
927 Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
928 Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
929 Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
930 Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
931 Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
932 Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
933 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
934 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
935 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
936 Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
937 Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
938 }
939
940
941
942
943
944
945
946
947 public Engine execute() throws ScanAgentException {
948 Engine engine = null;
949 try {
950 engine = executeDependencyCheck();
951 if (this.generateReport) {
952 generateExternalReports(engine, new File(this.reportOutputDirectory));
953 }
954 if (this.showSummary) {
955 showSummary(engine.getDependencies());
956 }
957 if (this.failBuildOnCVSS <= 10) {
958 checkForFailure(engine.getDependencies());
959 }
960 } catch (ExceptionCollection ex) {
961 if (ex.isFatal()) {
962 LOGGER.error("A fatal exception occurred during analysis; analysis has stopped. Please see the debug log for more details.");
963 LOGGER.debug("", ex);
964 }
965 throw new ScanAgentException("One or more exceptions occurred during analysis; please see the debug log for more details.", ex);
966 } finally {
967 Settings.cleanup(true);
968 if (engine != null) {
969 engine.cleanup();
970 }
971 }
972 return engine;
973 }
974
975
976
977
978
979
980
981
982
983 private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
984 final StringBuilder ids = new StringBuilder();
985 for (Dependency d : dependencies) {
986 boolean addName = true;
987 for (Vulnerability v : d.getVulnerabilities()) {
988 if (v.getCvssScore() >= failBuildOnCVSS) {
989 if (addName) {
990 addName = false;
991 ids.append(NEW_LINE).append(d.getFileName()).append(": ");
992 ids.append(v.getName());
993 } else {
994 ids.append(", ").append(v.getName());
995 }
996 }
997 }
998 }
999 if (ids.length() > 0) {
1000 final String msg = String.format("%n%nDependency-Check Failure:%n"
1001 + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
1002 + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
1003
1004 throw new ScanAgentException(msg);
1005 }
1006 }
1007
1008
1009
1010
1011
1012
1013
1014 private void showSummary(List<Dependency> dependencies) {
1015 final StringBuilder summary = new StringBuilder();
1016 for (Dependency d : dependencies) {
1017 boolean firstEntry = true;
1018 final StringBuilder ids = new StringBuilder();
1019 for (Vulnerability v : d.getVulnerabilities()) {
1020 if (firstEntry) {
1021 firstEntry = false;
1022 } else {
1023 ids.append(", ");
1024 }
1025 ids.append(v.getName());
1026 }
1027 if (ids.length() > 0) {
1028 summary.append(d.getFileName()).append(" (");
1029 firstEntry = true;
1030 for (Identifier id : d.getIdentifiers()) {
1031 if (firstEntry) {
1032 firstEntry = false;
1033 } else {
1034 summary.append(", ");
1035 }
1036 summary.append(id.getValue());
1037 }
1038 summary.append(") : ").append(ids).append(NEW_LINE);
1039 }
1040 }
1041 if (summary.length() > 0) {
1042 LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\n"
1043 + "See the dependency-check report for more details.\n\n",
1044 summary.toString());
1045 }
1046 }
1047
1048 }