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