|
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.InetAddress; |
21 | 20 | import java.net.URI;
|
| 21 | +import java.net.UnknownHostException; |
22 | 22 | import java.time.Instant;
|
23 | 23 | import java.time.temporal.ChronoUnit;
|
24 | 24 | import java.util.Arrays;
|
25 | 25 | import java.util.HashMap;
|
26 |
| -import java.util.HashSet; |
27 | 26 | import java.util.Map;
|
28 |
| -import java.util.Set; |
| 27 | +import java.util.Objects; |
| 28 | +import java.util.function.Predicate; |
29 | 29 | import software.amazon.awssdk.annotations.SdkPublicApi;
|
30 | 30 | import software.amazon.awssdk.auth.credentials.internal.ContainerCredentialsRetryPolicy;
|
31 | 31 | import software.amazon.awssdk.auth.credentials.internal.HttpCredentialsLoader;
|
|
65 | 65 | public final class ContainerCredentialsProvider
|
66 | 66 | implements HttpCredentialsProvider,
|
67 | 67 | ToCopyableBuilder<ContainerCredentialsProvider.Builder, ContainerCredentialsProvider> {
|
68 |
| - private static final Set<String> ALLOWED_HOSTS = unmodifiableSet(new HashSet<>(Arrays.asList("localhost", "127.0.0.1"))); |
| 68 | + private static final Predicate<InetAddress> IS_LOOPBACK_ADDRESS = InetAddress::isLoopbackAddress; |
| 69 | + private static final Predicate<InetAddress> ALLOWED_HOSTS_RULES = IS_LOOPBACK_ADDRESS; |
| 70 | + private static final String HTTPS = "https"; |
69 | 71 |
|
70 | 72 | private final String endpoint;
|
71 | 73 | private final HttpCredentialsLoader httpCredentialsLoader;
|
@@ -207,18 +209,49 @@ private URI createUri(String relativeUri) {
|
207 | 209 |
|
208 | 210 | private URI createGenericContainerUrl() {
|
209 | 211 | URI uri = URI.create(SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_FULL_URI.getStringValueOrThrow());
|
210 |
| - if (!ALLOWED_HOSTS.contains(uri.getHost())) { |
| 212 | + if (!isHttps(uri) && !isAllowedHost(uri.getHost())) { |
211 | 213 | String envVarName = SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_FULL_URI.environmentVariable();
|
212 | 214 | 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))) |
| 215 | + .message(String.format("The full URI (%s) contained within environment variable " + |
| 216 | + "%s has an invalid host. Host should resolve to a loopback " + |
| 217 | + "address or have the full URI be HTTPS.", |
| 218 | + uri, envVarName)) |
218 | 219 | .build();
|
219 | 220 | }
|
220 | 221 | return uri;
|
221 | 222 | }
|
| 223 | + |
| 224 | + private boolean isHttps(URI endpoint) { |
| 225 | + return Objects.equals(HTTPS, endpoint.getScheme()); |
| 226 | + } |
| 227 | + |
| 228 | + /** |
| 229 | + * Determines if the addresses for a given host are resolved to a loopback address. |
| 230 | + * <p> |
| 231 | + * This is a best-effort in determining what address a host will be resolved to. DNS caching might be disabled, |
| 232 | + * or could expire between this check and when the API is invoked. |
| 233 | + * </p> |
| 234 | + * @param host The name or IP address of the host. |
| 235 | + * @return A boolean specifying whether the host is allowed as an endpoint for credentials loading. |
| 236 | + */ |
| 237 | + private boolean isAllowedHost(String host) { |
| 238 | + try { |
| 239 | + InetAddress[] addresses = InetAddress.getAllByName(host); |
| 240 | + |
| 241 | + return addresses.length > 0 && Arrays.stream(addresses) |
| 242 | + .allMatch(this::matchesAllowedHostRules); |
| 243 | + |
| 244 | + } catch (UnknownHostException e) { |
| 245 | + throw SdkClientException.builder() |
| 246 | + .cause(e) |
| 247 | + .message(String.format("host (%s) could not be resolved to an IP address.", host)) |
| 248 | + .build(); |
| 249 | + } |
| 250 | + } |
| 251 | + |
| 252 | + private boolean matchesAllowedHostRules(InetAddress inetAddress) { |
| 253 | + return ALLOWED_HOSTS_RULES.test(inetAddress); |
| 254 | + } |
222 | 255 | }
|
223 | 256 |
|
224 | 257 | /**
|
|
0 commit comments