1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.aether;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23
24 import java.io.File;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.LinkedHashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.stream.Collectors;
34
35 import org.apache.maven.RepositoryUtils;
36 import org.apache.maven.api.services.TypeRegistry;
37 import org.apache.maven.api.xml.XmlNode;
38 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
39 import org.apache.maven.artifact.repository.ArtifactRepository;
40 import org.apache.maven.artifact.repository.Authentication;
41 import org.apache.maven.bridge.MavenRepositorySystem;
42 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
43 import org.apache.maven.execution.MavenExecutionRequest;
44 import org.apache.maven.internal.xml.XmlNodeImpl;
45 import org.apache.maven.internal.xml.XmlPlexusConfiguration;
46 import org.apache.maven.model.ModelBase;
47 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
48 import org.apache.maven.rtinfo.RuntimeInformation;
49 import org.apache.maven.settings.Mirror;
50 import org.apache.maven.settings.Proxy;
51 import org.apache.maven.settings.Server;
52 import org.apache.maven.settings.building.SettingsProblem;
53 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
54 import org.apache.maven.settings.crypto.SettingsDecrypter;
55 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
56 import org.codehaus.plexus.configuration.PlexusConfiguration;
57 import org.eclipse.aether.ConfigurationProperties;
58 import org.eclipse.aether.RepositoryListener;
59 import org.eclipse.aether.RepositorySystem;
60 import org.eclipse.aether.RepositorySystemSession;
61 import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
62 import org.eclipse.aether.repository.AuthenticationContext;
63 import org.eclipse.aether.repository.AuthenticationSelector;
64 import org.eclipse.aether.repository.ProxySelector;
65 import org.eclipse.aether.repository.RemoteRepository;
66 import org.eclipse.aether.repository.RepositoryPolicy;
67 import org.eclipse.aether.repository.WorkspaceReader;
68 import org.eclipse.aether.resolution.ResolutionErrorPolicy;
69 import org.eclipse.aether.util.listener.ChainedRepositoryListener;
70 import org.eclipse.aether.util.repository.AuthenticationBuilder;
71 import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager;
72 import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
73 import org.eclipse.aether.util.repository.DefaultMirrorSelector;
74 import org.eclipse.aether.util.repository.DefaultProxySelector;
75 import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
76 import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy;
77 import org.eclipse.sisu.Nullable;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81
82
83
84 @Named
85 public class DefaultRepositorySystemSessionFactory {
86
87
88
89
90
91
92
93 private static final String MAVEN_REPO_LOCAL_TAIL = "maven.repo.local.tail";
94
95
96
97
98
99
100
101
102
103 private static final String MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE = "maven.repo.local.recordReverseTree";
104
105 private static final String MAVEN_RESOLVER_TRANSPORT_KEY = "maven.resolver.transport";
106
107 private static final String MAVEN_RESOLVER_TRANSPORT_DEFAULT = "default";
108
109 private static final String MAVEN_RESOLVER_TRANSPORT_WAGON = "wagon";
110
111 private static final String MAVEN_RESOLVER_TRANSPORT_APACHE = "apache";
112
113 private static final String MAVEN_RESOLVER_TRANSPORT_JDK = "jdk";
114
115
116
117
118
119
120 @Deprecated
121 private static final String MAVEN_RESOLVER_TRANSPORT_NATIVE = "native";
122
123 private static final String MAVEN_RESOLVER_TRANSPORT_AUTO = "auto";
124
125 private static final String WAGON_TRANSPORTER_PRIORITY_KEY = "aether.priority.WagonTransporterFactory";
126
127 private static final String APACHE_HTTP_TRANSPORTER_PRIORITY_KEY = "aether.priority.ApacheTransporterFactory";
128
129 private static final String JDK_HTTP_TRANSPORTER_PRIORITY_KEY = "aether.priority.JdkTransporterFactory";
130
131 private static final String FILE_TRANSPORTER_PRIORITY_KEY = "aether.priority.FileTransporterFactory";
132
133 private static final String RESOLVER_MAX_PRIORITY = String.valueOf(Float.MAX_VALUE);
134
135 private final Logger logger = LoggerFactory.getLogger(getClass());
136
137 private final ArtifactHandlerManager artifactHandlerManager;
138
139 private final RepositorySystem repoSystem;
140
141 private final WorkspaceReader workspaceRepository;
142
143 private final SettingsDecrypter settingsDecrypter;
144
145 private final EventSpyDispatcher eventSpyDispatcher;
146
147 private final RuntimeInformation runtimeInformation;
148
149 private final TypeRegistry typeRegistry;
150
151 @SuppressWarnings("checkstyle:ParameterNumber")
152 @Inject
153 public DefaultRepositorySystemSessionFactory(
154 ArtifactHandlerManager artifactHandlerManager,
155 RepositorySystem repoSystem,
156 @Nullable @Named("ide") WorkspaceReader workspaceRepository,
157 SettingsDecrypter settingsDecrypter,
158 EventSpyDispatcher eventSpyDispatcher,
159 RuntimeInformation runtimeInformation,
160 TypeRegistry typeRegistry) {
161 this.artifactHandlerManager = artifactHandlerManager;
162 this.repoSystem = repoSystem;
163 this.workspaceRepository = workspaceRepository;
164 this.settingsDecrypter = settingsDecrypter;
165 this.eventSpyDispatcher = eventSpyDispatcher;
166 this.runtimeInformation = runtimeInformation;
167 this.typeRegistry = typeRegistry;
168 }
169
170 @Deprecated
171 public RepositorySystemSession newRepositorySession(MavenExecutionRequest request) {
172 return newRepositorySessionBuilder(request).build();
173 }
174
175 @SuppressWarnings("checkstyle:methodLength")
176 public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request) {
177 SessionBuilder session = MavenRepositorySystemUtils.newSession(
178 repoSystem.createSessionBuilder(), new TypeRegistryAdapter(typeRegistry));
179 session.setCache(request.getRepositoryCache());
180
181 Map<Object, Object> configProps = new LinkedHashMap<>();
182 configProps.put(ConfigurationProperties.USER_AGENT, getUserAgent());
183 configProps.put(ConfigurationProperties.INTERACTIVE, request.isInteractiveMode());
184 configProps.put("maven.startTime", request.getStartTime());
185
186 configProps.putAll(getPropertiesFromRequestedProfiles(request));
187
188 configProps.putAll(request.getSystemProperties());
189 configProps.putAll(request.getUserProperties());
190
191 session.setOffline(request.isOffline());
192 session.setChecksumPolicy(request.getGlobalChecksumPolicy());
193 session.setUpdatePolicy(
194 request.isNoSnapshotUpdates()
195 ? RepositoryPolicy.UPDATE_POLICY_NEVER
196 : request.isUpdateSnapshots() ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : null);
197
198 int errorPolicy = 0;
199 errorPolicy |= request.isCacheNotFound()
200 ? ResolutionErrorPolicy.CACHE_NOT_FOUND
201 : ResolutionErrorPolicy.CACHE_DISABLED;
202 errorPolicy |= request.isCacheTransferError()
203 ? ResolutionErrorPolicy.CACHE_TRANSFER_ERROR
204 : ResolutionErrorPolicy.CACHE_DISABLED;
205 session.setResolutionErrorPolicy(
206 new SimpleResolutionErrorPolicy(errorPolicy, errorPolicy | ResolutionErrorPolicy.CACHE_NOT_FOUND));
207
208 session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(
209 request.isIgnoreMissingArtifactDescriptor(), request.isIgnoreInvalidArtifactDescriptor()));
210
211 session.setArtifactTypeRegistry(RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager));
212
213 session.setWorkspaceReader(
214 request.getWorkspaceReader() != null ? request.getWorkspaceReader() : workspaceRepository);
215
216 DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
217 decrypt.setProxies(request.getProxies());
218 decrypt.setServers(request.getServers());
219 SettingsDecryptionResult decrypted = settingsDecrypter.decrypt(decrypt);
220
221 if (logger.isDebugEnabled()) {
222 for (SettingsProblem problem : decrypted.getProblems()) {
223 logger.debug(problem.getMessage(), problem.getException());
224 }
225 }
226
227 DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
228 for (Mirror mirror : request.getMirrors()) {
229 mirrorSelector.add(
230 mirror.getId(),
231 mirror.getUrl(),
232 mirror.getLayout(),
233 false,
234 mirror.isBlocked(),
235 mirror.getMirrorOf(),
236 mirror.getMirrorOfLayouts());
237 }
238 session.setMirrorSelector(mirrorSelector);
239
240 DefaultProxySelector proxySelector = new DefaultProxySelector();
241 for (Proxy proxy : decrypted.getProxies()) {
242 AuthenticationBuilder authBuilder = new AuthenticationBuilder();
243 authBuilder.addUsername(proxy.getUsername()).addPassword(proxy.getPassword());
244 proxySelector.add(
245 new org.eclipse.aether.repository.Proxy(
246 proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build()),
247 proxy.getNonProxyHosts());
248 }
249 session.setProxySelector(proxySelector);
250
251
252
253 DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector();
254 for (Server server : decrypted.getServers()) {
255 AuthenticationBuilder authBuilder = new AuthenticationBuilder();
256 authBuilder.addUsername(server.getUsername()).addPassword(server.getPassword());
257 authBuilder.addPrivateKey(server.getPrivateKey(), server.getPassphrase());
258 authSelector.add(server.getId(), authBuilder.build());
259
260 if (server.getConfiguration() != null) {
261 XmlNode dom = server.getDelegate().getConfiguration();
262 List<XmlNode> children = dom.getChildren().stream()
263 .filter(c -> !"wagonProvider".equals(c.getName()))
264 .collect(Collectors.toList());
265 dom = new XmlNodeImpl(dom.getName(), null, null, children, null);
266 PlexusConfiguration config = XmlPlexusConfiguration.toPlexusConfiguration(dom);
267 configProps.put("aether.transport.wagon.config." + server.getId(), config);
268
269
270
271
272 Map<String, String> headers = null;
273 Integer connectTimeout = null;
274 Integer requestTimeout = null;
275
276 PlexusConfiguration httpHeaders = config.getChild("httpHeaders", false);
277 if (httpHeaders != null) {
278 PlexusConfiguration[] properties = httpHeaders.getChildren("property");
279 if (properties != null && properties.length > 0) {
280 headers = new HashMap<>();
281 for (PlexusConfiguration property : properties) {
282 headers.put(
283 property.getChild("name").getValue(),
284 property.getChild("value").getValue());
285 }
286 }
287 }
288
289 PlexusConfiguration connectTimeoutXml = config.getChild("connectTimeout", false);
290 if (connectTimeoutXml != null) {
291 connectTimeout = Integer.parseInt(connectTimeoutXml.getValue());
292 } else {
293
294 PlexusConfiguration httpConfiguration = config.getChild("httpConfiguration", false);
295 if (httpConfiguration != null) {
296 PlexusConfiguration httpConfigurationAll = httpConfiguration.getChild("all", false);
297 if (httpConfigurationAll != null) {
298 connectTimeoutXml = httpConfigurationAll.getChild("connectionTimeout", false);
299 if (connectTimeoutXml != null) {
300 connectTimeout = Integer.parseInt(connectTimeoutXml.getValue());
301 logger.warn("Settings for server {} uses legacy format", server.getId());
302 }
303 }
304 }
305 }
306
307 PlexusConfiguration requestTimeoutXml = config.getChild("requestTimeout", false);
308 if (requestTimeoutXml != null) {
309 requestTimeout = Integer.parseInt(requestTimeoutXml.getValue());
310 } else {
311
312 PlexusConfiguration httpConfiguration = config.getChild("httpConfiguration", false);
313 if (httpConfiguration != null) {
314 PlexusConfiguration httpConfigurationAll = httpConfiguration.getChild("all", false);
315 if (httpConfigurationAll != null) {
316 requestTimeoutXml = httpConfigurationAll.getChild("readTimeout", false);
317 if (requestTimeoutXml != null) {
318 requestTimeout = Integer.parseInt(requestTimeoutXml.getValue());
319 logger.warn("Settings for server {} uses legacy format", server.getId());
320 }
321 }
322 }
323 }
324
325
326 if (headers != null) {
327 configProps.put(ConfigurationProperties.HTTP_HEADERS + "." + server.getId(), headers);
328 }
329
330 if (connectTimeout != null) {
331 configProps.put(ConfigurationProperties.CONNECT_TIMEOUT + "." + server.getId(), connectTimeout);
332 }
333
334 if (requestTimeout != null) {
335 configProps.put(ConfigurationProperties.REQUEST_TIMEOUT + "." + server.getId(), requestTimeout);
336 }
337 }
338
339 configProps.put("aether.transport.wagon.perms.fileMode." + server.getId(), server.getFilePermissions());
340 configProps.put("aether.transport.wagon.perms.dirMode." + server.getId(), server.getDirectoryPermissions());
341 }
342 session.setAuthenticationSelector(authSelector);
343
344 Object transport = configProps.getOrDefault(MAVEN_RESOLVER_TRANSPORT_KEY, MAVEN_RESOLVER_TRANSPORT_DEFAULT);
345 if (MAVEN_RESOLVER_TRANSPORT_DEFAULT.equals(transport)) {
346
347 } else if (MAVEN_RESOLVER_TRANSPORT_JDK.equals(transport)) {
348
349 configProps.put(FILE_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
350 configProps.put(JDK_HTTP_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
351 } else if (MAVEN_RESOLVER_TRANSPORT_APACHE.equals(transport)
352 || MAVEN_RESOLVER_TRANSPORT_NATIVE.equals(transport)) {
353 if (MAVEN_RESOLVER_TRANSPORT_NATIVE.equals(transport)) {
354 logger.warn(
355 "Transport name '{}' is DEPRECATED/RENAMED, use '{}' instead",
356 MAVEN_RESOLVER_TRANSPORT_NATIVE,
357 MAVEN_RESOLVER_TRANSPORT_APACHE);
358 }
359
360 configProps.put(FILE_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
361 configProps.put(APACHE_HTTP_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
362 } else if (MAVEN_RESOLVER_TRANSPORT_WAGON.equals(transport)) {
363
364 configProps.put(WAGON_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
365 } else if (!MAVEN_RESOLVER_TRANSPORT_AUTO.equals(transport)) {
366 throw new IllegalArgumentException("Unknown resolver transport '" + transport
367 + "'. Supported transports are: " + MAVEN_RESOLVER_TRANSPORT_WAGON + ", "
368 + MAVEN_RESOLVER_TRANSPORT_APACHE + ", " + MAVEN_RESOLVER_TRANSPORT_JDK + ", "
369 + MAVEN_RESOLVER_TRANSPORT_AUTO);
370 }
371
372 session.setUserProperties(request.getUserProperties());
373 session.setSystemProperties(request.getSystemProperties());
374 session.setConfigProperties(configProps);
375
376 session.setTransferListener(request.getTransferListener());
377
378 RepositoryListener repositoryListener = eventSpyDispatcher.chainListener(new LoggingRepositoryListener(logger));
379
380 boolean recordReverseTree = configProps.containsKey(MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE)
381 && Boolean.parseBoolean((String) configProps.get(MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE));
382 if (recordReverseTree) {
383 repositoryListener = new ChainedRepositoryListener(repositoryListener, new ReverseTreeRepositoryListener());
384 }
385 session.setRepositoryListener(repositoryListener);
386
387 injectMirror(request.getRemoteRepositories(), request.getMirrors());
388 injectProxy(proxySelector, request.getRemoteRepositories());
389 injectAuthentication(authSelector, request.getRemoteRepositories());
390
391 injectMirror(request.getPluginArtifactRepositories(), request.getMirrors());
392 injectProxy(proxySelector, request.getPluginArtifactRepositories());
393 injectAuthentication(authSelector, request.getPluginArtifactRepositories());
394
395 ArrayList<File> paths = new ArrayList<>();
396 paths.add(new File(request.getLocalRepository().getBasedir()));
397 String localRepoTail = (String) configProps.get(MAVEN_REPO_LOCAL_TAIL);
398 if (localRepoTail != null) {
399 Arrays.stream(localRepoTail.split(","))
400 .filter(p -> p != null && !p.trim().isEmpty())
401 .map(File::new)
402 .forEach(paths::add);
403 }
404 session.withLocalRepositoryBaseDirectories(paths);
405
406 return session;
407 }
408
409 private Map<?, ?> getPropertiesFromRequestedProfiles(MavenExecutionRequest request) {
410 HashSet<String> activeProfileId =
411 new HashSet<>(request.getProfileActivation().getRequiredActiveProfileIds());
412 activeProfileId.addAll(request.getProfileActivation().getOptionalActiveProfileIds());
413
414 return request.getProfiles().stream()
415 .filter(profile -> activeProfileId.contains(profile.getId()))
416 .map(ModelBase::getProperties)
417 .flatMap(properties -> properties.entrySet().stream())
418 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k1, k2) -> k2));
419 }
420
421 private String getUserAgent() {
422 String version = runtimeInformation.getMavenVersion();
423 version = version.isEmpty() ? version : "/" + version;
424 return "Apache-Maven" + version + " (Java " + System.getProperty("java.version") + "; "
425 + System.getProperty("os.name") + " " + System.getProperty("os.version") + ")";
426 }
427
428 private void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {
429 if (repositories != null && mirrors != null) {
430 for (ArtifactRepository repository : repositories) {
431 Mirror mirror = MavenRepositorySystem.getMirror(repository, mirrors);
432 injectMirror(repository, mirror);
433 }
434 }
435 }
436
437 private void injectMirror(ArtifactRepository repository, Mirror mirror) {
438 if (mirror != null) {
439 ArtifactRepository original = MavenRepositorySystem.createArtifactRepository(
440 repository.getId(),
441 repository.getUrl(),
442 repository.getLayout(),
443 repository.getSnapshots(),
444 repository.getReleases());
445
446 repository.setMirroredRepositories(Collections.singletonList(original));
447
448 repository.setId(mirror.getId());
449 repository.setUrl(mirror.getUrl());
450
451 if (mirror.getLayout() != null && !mirror.getLayout().isEmpty()) {
452 repository.setLayout(original.getLayout());
453 }
454
455 repository.setBlocked(mirror.isBlocked());
456 }
457 }
458
459 private void injectProxy(ProxySelector selector, List<ArtifactRepository> repositories) {
460 if (repositories != null && selector != null) {
461 for (ArtifactRepository repository : repositories) {
462 repository.setProxy(getProxy(selector, repository));
463 }
464 }
465 }
466
467 private org.apache.maven.repository.Proxy getProxy(ProxySelector selector, ArtifactRepository repository) {
468 if (selector != null) {
469 RemoteRepository repo = RepositoryUtils.toRepo(repository);
470 org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
471 if (proxy != null) {
472 org.apache.maven.repository.Proxy p = new org.apache.maven.repository.Proxy();
473 p.setHost(proxy.getHost());
474 p.setProtocol(proxy.getType());
475 p.setPort(proxy.getPort());
476 if (proxy.getAuthentication() != null) {
477 repo = new RemoteRepository.Builder(repo).setProxy(proxy).build();
478 AuthenticationContext authCtx = AuthenticationContext.forProxy(null, repo);
479 p.setUserName(authCtx.get(AuthenticationContext.USERNAME));
480 p.setPassword(authCtx.get(AuthenticationContext.PASSWORD));
481 p.setNtlmDomain(authCtx.get(AuthenticationContext.NTLM_DOMAIN));
482 p.setNtlmHost(authCtx.get(AuthenticationContext.NTLM_WORKSTATION));
483 authCtx.close();
484 }
485 return p;
486 }
487 }
488 return null;
489 }
490
491 public void injectAuthentication(AuthenticationSelector selector, List<ArtifactRepository> repositories) {
492 if (repositories != null && selector != null) {
493 for (ArtifactRepository repository : repositories) {
494 repository.setAuthentication(getAuthentication(selector, repository));
495 }
496 }
497 }
498
499 private Authentication getAuthentication(AuthenticationSelector selector, ArtifactRepository repository) {
500 if (selector != null) {
501 RemoteRepository repo = RepositoryUtils.toRepo(repository);
502 org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
503 if (auth != null) {
504 repo = new RemoteRepository.Builder(repo)
505 .setAuthentication(auth)
506 .build();
507 AuthenticationContext authCtx = AuthenticationContext.forRepository(null, repo);
508 Authentication result = new Authentication(
509 authCtx.get(AuthenticationContext.USERNAME), authCtx.get(AuthenticationContext.PASSWORD));
510 result.setPrivateKey(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH));
511 result.setPassphrase(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
512 authCtx.close();
513 return result;
514 }
515 }
516 return null;
517 }
518 }