1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.analyzer;
19
20 import org.apache.commons.io.FileUtils;
21 import org.owasp.dependencycheck.Engine;
22 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
23 import org.owasp.dependencycheck.data.nexus.MavenArtifact;
24 import org.owasp.dependencycheck.data.nexus.NexusSearch;
25 import org.owasp.dependencycheck.dependency.Confidence;
26 import org.owasp.dependencycheck.dependency.Dependency;
27 import org.owasp.dependencycheck.dependency.Evidence;
28 import org.owasp.dependencycheck.xml.pom.PomUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import java.io.File;
33 import java.io.FileFilter;
34 import java.io.FileNotFoundException;
35 import java.io.IOException;
36 import java.net.MalformedURLException;
37 import java.net.URL;
38 import org.owasp.dependencycheck.utils.DownloadFailedException;
39 import org.owasp.dependencycheck.utils.Downloader;
40 import org.owasp.dependencycheck.utils.FileFilterBuilder;
41 import org.owasp.dependencycheck.utils.InvalidSettingException;
42 import org.owasp.dependencycheck.utils.Settings;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
59
60
61
62
63 public static final String DEFAULT_URL = "https://repository.sonatype.org/service/local/";
64
65
66
67
68 private static final Logger LOGGER = LoggerFactory.getLogger(NexusAnalyzer.class);
69
70
71
72
73 private static final String ANALYZER_NAME = "Nexus Analyzer";
74
75
76
77
78 private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
79
80
81
82
83 private static final String SUPPORTED_EXTENSIONS = "jar";
84
85
86
87
88 private NexusSearch searcher;
89
90
91
92
93 private final boolean enabled = checkEnabled();
94
95
96
97
98
99
100 private boolean checkEnabled() {
101
102
103
104
105 boolean retval = false;
106 try {
107 if (!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))
108 && Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
109 LOGGER.info("Enabling Nexus analyzer");
110 retval = true;
111 } else {
112 LOGGER.debug("Nexus analyzer disabled, using Central instead");
113 }
114 } catch (InvalidSettingException ise) {
115 LOGGER.warn("Invalid setting. Disabling Nexus analyzer");
116 }
117
118 return retval;
119 }
120
121
122
123
124
125
126 @Override
127 public boolean isEnabled() {
128 return enabled;
129 }
130
131
132
133
134
135
136 @Override
137 public void initializeFileTypeAnalyzer() throws Exception {
138 LOGGER.debug("Initializing Nexus Analyzer");
139 LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
140 if (isEnabled()) {
141 final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
142 LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
143 try {
144 searcher = new NexusSearch(new URL(searchUrl));
145 if (!searcher.preflightRequest()) {
146 LOGGER.warn("There was an issue getting Nexus status. Disabling analyzer.");
147 setEnabled(false);
148 }
149 } catch (MalformedURLException mue) {
150
151
152 LOGGER.warn("Property {} not a valid URL. Nexus Analyzer disabled", searchUrl);
153 setEnabled(false);
154 }
155 }
156 }
157
158
159
160
161
162
163 @Override
164 public String getName() {
165 return ANALYZER_NAME;
166 }
167
168
169
170
171
172
173 @Override
174 protected String getAnalyzerEnabledSettingKey() {
175 return Settings.KEYS.ANALYZER_NEXUS_ENABLED;
176 }
177
178
179
180
181
182
183 @Override
184 public AnalysisPhase getAnalysisPhase() {
185 return ANALYSIS_PHASE;
186 }
187
188
189
190
191 private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
192
193
194
195
196
197
198 @Override
199 protected FileFilter getFileFilter() {
200 return FILTER;
201 }
202
203
204
205
206
207
208
209
210 @Override
211 public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
212 if (!isEnabled()) {
213 return;
214 }
215 try {
216 final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
217 dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
218 boolean pomAnalyzed = false;
219 LOGGER.debug("POM URL {}", ma.getPomUrl());
220 for (Evidence e : dependency.getVendorEvidence()) {
221 if ("pom".equals(e.getSource())) {
222 pomAnalyzed = true;
223 break;
224 }
225 }
226 if (!pomAnalyzed && ma.getPomUrl() != null) {
227 File pomFile = null;
228 try {
229 final File baseDir = Settings.getTempDirectory();
230 pomFile = File.createTempFile("pom", ".xml", baseDir);
231 if (!pomFile.delete()) {
232 LOGGER.warn("Unable to fetch pom.xml for {} from Nexus repository; "
233 + "this could result in undetected CPE/CVEs.", dependency.getFileName());
234 LOGGER.debug("Unable to delete temp file");
235 }
236 LOGGER.debug("Downloading {}", ma.getPomUrl());
237 Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
238 PomUtils.analyzePOM(dependency, pomFile);
239 } catch (DownloadFailedException ex) {
240 LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; "
241 + "this could result in undetected CPE/CVEs.", dependency.getFileName());
242 } finally {
243 if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
244 pomFile.deleteOnExit();
245 }
246 }
247 }
248 } catch (IllegalArgumentException iae) {
249
250 LOGGER.info("invalid sha-1 hash on {}", dependency.getFileName());
251 } catch (FileNotFoundException fnfe) {
252
253 LOGGER.debug("Artifact not found in repository '{}'", dependency.getFileName());
254 LOGGER.debug(fnfe.getMessage(), fnfe);
255 } catch (IOException ioe) {
256
257 LOGGER.debug("Could not connect to nexus repository", ioe);
258 }
259 }
260 }