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 java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.HashSet;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap;
28
29 import org.codehaus.plexus.logging.Logger;
30 import org.eclipse.aether.repository.Authentication;
31 import org.eclipse.aether.repository.AuthenticationSelector;
32 import org.eclipse.aether.repository.RemoteRepository;
33
34 import static java.util.Objects.requireNonNull;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 class OriginBoundAuthenticationSelector implements AuthenticationSelector {
50
51
52
53
54 static final String SCOPE_ORIGIN = "origin";
55
56
57
58
59
60 static final String SCOPE_STRICT = "strict";
61
62
63
64
65 static final String SCOPE_ID = "id";
66
67 private final AuthenticationSelector delegate;
68
69 private final Map<String, Set<String>> declaredOrigins;
70
71 private final boolean strict;
72
73 private final Logger logger;
74
75 private final Set<String> reported = ConcurrentHashMap.newKeySet();
76
77 private OriginBoundAuthenticationSelector(
78 AuthenticationSelector delegate, Map<String, Set<String>> declaredOrigins, boolean strict, Logger logger) {
79 this.delegate = requireNonNull(delegate, "delegate");
80 this.declaredOrigins = requireNonNull(declaredOrigins, "declaredOrigins");
81 this.strict = strict;
82 this.logger = requireNonNull(logger, "logger");
83 }
84
85
86
87
88
89
90
91
92
93
94 static AuthenticationSelector wrap(
95 AuthenticationSelector delegate,
96 String credentialScope,
97 Map<String, Set<String>> declaredOrigins,
98 Logger logger) {
99 if (SCOPE_ID.equals(credentialScope)) {
100 return delegate;
101 } else if (SCOPE_ORIGIN.equals(credentialScope) || SCOPE_STRICT.equals(credentialScope)) {
102 return new OriginBoundAuthenticationSelector(
103 delegate, declaredOrigins, SCOPE_STRICT.equals(credentialScope), logger);
104 } else {
105 throw new IllegalArgumentException("Unknown value '" + credentialScope + "' for "
106 + DefaultRepositorySystemSessionFactory.MAVEN_REPOSITORY_CREDENTIAL_SCOPE
107 + ". Supported values are: " + SCOPE_ORIGIN + ", " + SCOPE_STRICT + ", " + SCOPE_ID);
108 }
109 }
110
111
112
113
114
115 static void addOrigin(Map<String, Set<String>> declaredOrigins, String id, String url) {
116 String origin = originOf(url);
117 if (id != null && origin != null) {
118 declaredOrigins.computeIfAbsent(id, k -> new HashSet<>()).add(origin);
119 }
120 }
121
122 @Override
123 public Authentication getAuthentication(RemoteRepository repository) {
124 Authentication auth = delegate.getAuthentication(repository);
125 if (auth == null) {
126 return null;
127 }
128 String id = repository.getId();
129 String origin = originOf(repository.getUrl());
130 Set<String> origins = declaredOrigins.get(id);
131 if (origins != null && !origins.isEmpty()) {
132 if (origin != null && origins.contains(origin)) {
133 return auth;
134 }
135 warnOnce(
136 id,
137 origin,
138 "Not using credentials of server '" + id + "' for repository " + repository.getUrl()
139 + ": the origins declared for this id are " + origins
140 + ". Add " + originHint(origin)
141 + " to <repositoryOrigins> of that server in settings if these credentials belong"
142 + " there, or set "
143 + DefaultRepositorySystemSessionFactory.MAVEN_REPOSITORY_CREDENTIAL_SCOPE + "="
144 + SCOPE_ID + " to restore legacy id-only credential matching.");
145 return null;
146 }
147 if (strict) {
148 warnOnce(
149 id,
150 origin,
151 "Not using credentials of server '" + id + "' for repository " + repository.getUrl()
152 + ": no repository or mirror with this id is declared in settings or on the command"
153 + " line and the server declares no <repositoryOrigins>, and "
154 + DefaultRepositorySystemSessionFactory.MAVEN_REPOSITORY_CREDENTIAL_SCOPE
155 + "=" + SCOPE_STRICT + " is in effect. Declare " + originHint(origin)
156 + " in <repositoryOrigins> of that server in settings to allow it.");
157 return null;
158 }
159 warnOnce(
160 id,
161 origin,
162 "Using credentials of server '" + id + "' for repository " + repository.getUrl()
163 + ", although no repository or mirror with this id is declared in settings or on the"
164 + " command line and the server declares no <repositoryOrigins>. Declare "
165 + originHint(origin)
166 + " in <repositoryOrigins> of that server in settings to bind these credentials"
167 + " explicitly, or set "
168 + DefaultRepositorySystemSessionFactory.MAVEN_REPOSITORY_CREDENTIAL_SCOPE
169 + "=" + SCOPE_STRICT + " to refuse such credential use.");
170 return auth;
171 }
172
173 private static String originHint(String origin) {
174 return origin != null ? "'" + origin + "'" : "its origin";
175 }
176
177 private void warnOnce(String id, String origin, String message) {
178 if (reported.add(id + "->" + origin)) {
179 logger.warn(message);
180 }
181 }
182
183
184
185
186
187 static String originOf(String url) {
188 if (url == null) {
189 return null;
190 }
191 try {
192 URI uri = new URI(url).parseServerAuthority();
193 String scheme = uri.getScheme();
194 String host = uri.getHost();
195 if (scheme == null || host == null) {
196 return null;
197 }
198 scheme = scheme.toLowerCase(Locale.ROOT);
199 host = host.toLowerCase(Locale.ROOT);
200 int port = uri.getPort();
201 if ((port == 80 && "http".equals(scheme)) || (port == 443 && "https".equals(scheme))) {
202 port = -1;
203 }
204 return port >= 0 ? scheme + "://" + host + ":" + port : scheme + "://" + host;
205 } catch (URISyntaxException e) {
206 return null;
207 }
208 }
209 }