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