|
15 | 15 |
|
16 | 16 | package software.amazon.awssdk.auth.credentials;
|
17 | 17 |
|
18 |
| -import static java.util.Collections.unmodifiableSet; |
19 |
| - |
20 | 18 | import java.io.IOException;
|
| 19 | +import java.net.Inet6Address; |
| 20 | +import java.net.InetAddress; |
21 | 21 | import java.net.URI;
|
| 22 | +import java.net.UnknownHostException; |
22 | 23 | import java.time.Instant;
|
23 | 24 | import java.time.temporal.ChronoUnit;
|
24 | 25 | import java.util.Arrays;
|
25 | 26 | import java.util.HashMap;
|
26 |
| -import java.util.HashSet; |
27 | 27 | import java.util.Map;
|
28 |
| -import java.util.Set; |
| 28 | +import java.util.Objects; |
| 29 | +import java.util.function.Predicate; |
29 | 30 | import software.amazon.awssdk.annotations.SdkPublicApi;
|
30 | 31 | import software.amazon.awssdk.auth.credentials.internal.ContainerCredentialsRetryPolicy;
|
31 | 32 | import software.amazon.awssdk.auth.credentials.internal.HttpCredentialsLoader;
|
|
65 | 66 | public final class ContainerCredentialsProvider
|
66 | 67 | implements HttpCredentialsProvider,
|
67 | 68 | ToCopyableBuilder<ContainerCredentialsProvider.Builder, ContainerCredentialsProvider> {
|
68 |
| - private static final Set<String> ALLOWED_HOSTS = unmodifiableSet(new HashSet<>(Arrays.asList("localhost", "127.0.0.1"))); |
| 69 | + private static final Predicate<InetAddress> ALLOWED_HOSTS_IPv4_RULES = InetAddress::isLoopbackAddress; |
| 70 | + private static final Predicate<InetAddress> ALLOWED_HOSTS_IPv6_RULES = InetAddress::isLoopbackAddress; |
| 71 | + private static final String HTTPS = "https"; |
69 | 72 |
|
70 | 73 | private final String endpoint;
|
71 | 74 | private final HttpCredentialsLoader httpCredentialsLoader;
|
@@ -207,18 +210,44 @@ private URI createUri(String relativeUri) {
|
207 | 210 |
|
208 | 211 | private URI createGenericContainerUrl() {
|
209 | 212 | URI uri = URI.create(SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_FULL_URI.getStringValueOrThrow());
|
210 |
| - if (!ALLOWED_HOSTS.contains(uri.getHost())) { |
| 213 | + if (!isHttps(uri) && !isAllowedHost(uri.getHost())) { |
211 | 214 | String envVarName = SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_FULL_URI.environmentVariable();
|
212 | 215 | throw SdkClientException.builder()
|
213 |
| - .message(String.format("The full URI (%s) contained within environment " + |
214 |
| - "variable %s has an invalid host. Host can only be one of [%s].", |
215 |
| - uri, |
216 |
| - envVarName, |
217 |
| - String.join(",", ALLOWED_HOSTS))) |
| 216 | + .message(String.format("The full URI (%s) contained within environment variable " + |
| 217 | + "%s has an invalid host. Host should resolve to a loopback" + |
| 218 | + " address.", |
| 219 | + uri, envVarName)) |
218 | 220 | .build();
|
219 | 221 | }
|
220 | 222 | return uri;
|
221 | 223 | }
|
| 224 | + |
| 225 | + private boolean isHttps(URI endpoint) { |
| 226 | + return Objects.equals(HTTPS, endpoint.getScheme()); |
| 227 | + } |
| 228 | + |
| 229 | + private boolean isAllowedHost(String host) { |
| 230 | + try { |
| 231 | + InetAddress[] addresses = InetAddress.getAllByName(host); |
| 232 | + |
| 233 | + return addresses.length > 0 && Arrays.stream(addresses) |
| 234 | + .allMatch(this::matchesAllowedHostRules); |
| 235 | + |
| 236 | + } catch (UnknownHostException e) { |
| 237 | + throw SdkClientException.builder() |
| 238 | + .cause(e) |
| 239 | + .message(String.format("host (%s) could not be resolved to an IP address.", host)) |
| 240 | + .build(); |
| 241 | + } |
| 242 | + } |
| 243 | + |
| 244 | + private boolean matchesAllowedHostRules(InetAddress inetAddress) { |
| 245 | + if (inetAddress instanceof Inet6Address) { |
| 246 | + return ALLOWED_HOSTS_IPv6_RULES.test(inetAddress); |
| 247 | + } |
| 248 | + |
| 249 | + return ALLOWED_HOSTS_IPv4_RULES.test(inetAddress); |
| 250 | + } |
222 | 251 | }
|
223 | 252 |
|
224 | 253 | /**
|
|
0 commit comments