1
15
16 package software.amazon.awssdk.auth.credentials;
17
18 import static java.util.Collections.singletonMap;
19 import static java.util.Collections.unmodifiableSet;
20
21 import java.io.IOException;
22 import java.net.URI;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashSet;
26 import java.util.Map;
27 import java.util.Set;
28 import software.amazon.awssdk.annotations.SdkPublicApi;
29 import software.amazon.awssdk.annotations.SdkTestInternalApi;
30 import software.amazon.awssdk.auth.credentials.internal.ContainerCredentialsRetryPolicy;
31 import software.amazon.awssdk.core.SdkSystemSetting;
32 import software.amazon.awssdk.core.exception.SdkClientException;
33 import software.amazon.awssdk.regions.util.ResourcesEndpointProvider;
34 import software.amazon.awssdk.regions.util.ResourcesEndpointRetryPolicy;
35 import software.amazon.awssdk.utils.StringUtils;
36 import software.amazon.awssdk.utils.ToString;
37
38
54 @SdkPublicApi
55 public final class ContainerCredentialsProvider extends HttpCredentialsProvider {
56 private final ResourcesEndpointProvider credentialsEndpointProvider;
57
58
61 private ContainerCredentialsProvider(BuilderImpl builder) {
62 super(builder);
63 this.credentialsEndpointProvider = builder.credentialsEndpointProvider;
64 }
65
66
69 public static Builder builder() {
70 return new BuilderImpl();
71 }
72
73 @Override
74 protected ResourcesEndpointProvider getCredentialsEndpointProvider() {
75 return credentialsEndpointProvider;
76 }
77
78 @Override
79 public String toString() {
80 return ToString.create("ContainerCredentialsProvider");
81 }
82
83 static final class ContainerCredentialsEndpointProvider implements ResourcesEndpointProvider {
84 private static final Set<String> ALLOWED_HOSTS = unmodifiableSet(new HashSet<>(Arrays.asList("localhost", "127.0.0.1")));
85
86 @Override
87 public URI endpoint() throws IOException {
88
89 if (!SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI.getStringValue().isPresent() &&
90 !SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_FULL_URI.getStringValue().isPresent()) {
91 throw SdkClientException.builder()
92 .message(String.format("Cannot fetch credentials from container - neither %s or %s " +
93 "environment variables are set.",
94 SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_FULL_URI.environmentVariable(),
95 SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI.environmentVariable()))
96 .build();
97 }
98
99 try {
100 return SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI.getStringValue()
101 .map(this::createUri)
102 .orElseGet(this::createGenericContainerUrl);
103 } catch (SdkClientException e) {
104 throw e;
105 } catch (Exception e) {
106 throw SdkClientException.builder()
107 .message("Unable to fetch credentials from container.")
108 .cause(e)
109 .build();
110 }
111 }
112
113 @Override
114 public ResourcesEndpointRetryPolicy retryPolicy() {
115 return new ContainerCredentialsRetryPolicy();
116 }
117
118 @Override
119 public Map<String, String> headers() {
120 return SdkSystemSetting.AWS_CONTAINER_AUTHORIZATION_TOKEN.getStringValue()
121 .filter(StringUtils::isNotBlank)
122 .map(t -> singletonMap("Authorization", t))
123 .orElseGet(Collections::emptyMap);
124 }
125
126 private URI createUri(String relativeUri) {
127 return URI.create(SdkSystemSetting.AWS_CONTAINER_SERVICE_ENDPOINT.getStringValueOrThrow() + relativeUri);
128 }
129
130 private URI createGenericContainerUrl() {
131 URI uri = URI.create(SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_FULL_URI.getStringValueOrThrow());
132 if (!ALLOWED_HOSTS.contains(uri.getHost())) {
133
134 throw SdkClientException.builder()
135 .message(String.format("The full URI (%s) contained within environment " +
136 "variable %s has an invalid host. Host can only be one of [%s].",
137 uri,
138 SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_FULL_URI
139 .environmentVariable(),
140 String.join(",", ALLOWED_HOSTS)))
141 .build();
142 }
143 return uri;
144 }
145 }
146
147
150 public interface Builder extends HttpCredentialsProvider.Builder<ContainerCredentialsProvider, Builder> {
151
152
155 @Override
156 ContainerCredentialsProvider build();
157 }
158
159 static final class BuilderImpl extends HttpCredentialsProvider.BuilderImpl<ContainerCredentialsProvider, Builder>
160 implements Builder {
161
162 private ResourcesEndpointProvider credentialsEndpointProvider = new ContainerCredentialsEndpointProvider();
163
164 BuilderImpl() {
165 super.asyncThreadName("container-credentials-provider");
166 }
167
168 @SdkTestInternalApi
169 Builder credentialsEndpointProvider(ResourcesEndpointProvider credentialsEndpointProvider) {
170 this.credentialsEndpointProvider = credentialsEndpointProvider;
171 return this;
172 }
173
174 @Override
175 public ContainerCredentialsProvider build() {
176 return new ContainerCredentialsProvider(this);
177 }
178 }
179 }
180