15
15
16
16
package software .amazon .awssdk .auth .credentials ;
17
17
18
+ import static java .util .Collections .singletonMap ;
18
19
import static java .util .Collections .unmodifiableSet ;
19
20
20
21
import java .io .IOException ;
21
22
import java .net .URI ;
22
- import java .time .Instant ;
23
- import java .time .temporal .ChronoUnit ;
24
23
import java .util .Arrays ;
25
- import java .util .HashMap ;
24
+ import java .util .Collections ;
26
25
import java .util .HashSet ;
27
26
import java .util .Map ;
28
27
import java .util .Set ;
29
28
import software .amazon .awssdk .annotations .SdkPublicApi ;
29
+ import software .amazon .awssdk .annotations .SdkTestInternalApi ;
30
30
import software .amazon .awssdk .auth .credentials .internal .ContainerCredentialsRetryPolicy ;
31
- import software .amazon .awssdk .auth .credentials .internal .HttpCredentialsLoader ;
32
- import software .amazon .awssdk .auth .credentials .internal .HttpCredentialsLoader .LoadedCredentials ;
33
31
import software .amazon .awssdk .core .SdkSystemSetting ;
34
32
import software .amazon .awssdk .core .exception .SdkClientException ;
35
- import software .amazon .awssdk .core .util .SdkUserAgent ;
36
33
import software .amazon .awssdk .regions .util .ResourcesEndpointProvider ;
37
34
import software .amazon .awssdk .regions .util .ResourcesEndpointRetryPolicy ;
38
- import software .amazon .awssdk .utils .ComparableUtils ;
39
35
import software .amazon .awssdk .utils .StringUtils ;
40
36
import software .amazon .awssdk .utils .ToString ;
41
- import software .amazon .awssdk .utils .Validate ;
42
- import software .amazon .awssdk .utils .cache .CachedSupplier ;
43
- import software .amazon .awssdk .utils .cache .NonBlocking ;
44
- import software .amazon .awssdk .utils .cache .RefreshResult ;
45
37
46
38
/**
47
39
* {@link AwsCredentialsProvider} implementation that loads credentials from a local metadata service.
60
52
* Service (ECS)</a>
61
53
*/
62
54
@ SdkPublicApi
63
- public final class ContainerCredentialsProvider implements HttpCredentialsProvider {
64
- private static final Set <String > ALLOWED_HOSTS = unmodifiableSet (new HashSet <>(Arrays .asList ("localhost" , "127.0.0.1" )));
65
-
66
- private final String endpoint ;
67
- private final HttpCredentialsLoader httpCredentialsLoader ;
68
- private final CachedSupplier <AwsCredentials > credentialsCache ;
55
+ public final class ContainerCredentialsProvider extends HttpCredentialsProvider {
56
+ private final ResourcesEndpointProvider credentialsEndpointProvider ;
69
57
70
58
/**
71
59
* @see #builder()
72
60
*/
73
61
private ContainerCredentialsProvider (BuilderImpl builder ) {
74
- this .endpoint = builder .endpoint ;
75
- this .httpCredentialsLoader = HttpCredentialsLoader .create ();
76
-
77
- if (Boolean .TRUE .equals (builder .asyncCredentialUpdateEnabled )) {
78
- Validate .paramNotBlank (builder .asyncThreadName , "asyncThreadName" );
79
- this .credentialsCache = CachedSupplier .builder (this ::refreshCredentials )
80
- .prefetchStrategy (new NonBlocking (builder .asyncThreadName ))
81
- .build ();
82
- } else {
83
- this .credentialsCache = CachedSupplier .builder (this ::refreshCredentials ).build ();
84
- }
62
+ super (builder );
63
+ this .credentialsEndpointProvider = builder .credentialsEndpointProvider ;
85
64
}
86
65
87
66
/**
@@ -92,60 +71,21 @@ public static Builder builder() {
92
71
}
93
72
94
73
@ Override
95
- public String toString () {
96
- return ToString .create ("ContainerCredentialsProvider" );
97
- }
98
-
99
- private RefreshResult <AwsCredentials > refreshCredentials () {
100
- LoadedCredentials loadedCredentials =
101
- httpCredentialsLoader .loadCredentials (new ContainerCredentialsEndpointProvider (endpoint ));
102
- Instant expiration = loadedCredentials .getExpiration ().orElse (null );
103
-
104
- return RefreshResult .builder (loadedCredentials .getAwsCredentials ())
105
- .staleTime (staleTime (expiration ))
106
- .prefetchTime (prefetchTime (expiration ))
107
- .build ();
108
- }
109
-
110
- private Instant staleTime (Instant expiration ) {
111
- if (expiration == null ) {
112
- return null ;
113
- }
114
-
115
- return expiration .minus (1 , ChronoUnit .MINUTES );
116
- }
117
-
118
- private Instant prefetchTime (Instant expiration ) {
119
- Instant oneHourFromNow = Instant .now ().plus (1 , ChronoUnit .HOURS );
120
-
121
- if (expiration == null ) {
122
- return oneHourFromNow ;
123
- }
124
-
125
- Instant fifteenMinutesBeforeExpiration = expiration .minus (15 , ChronoUnit .MINUTES );
126
-
127
- return ComparableUtils .minimum (oneHourFromNow , fifteenMinutesBeforeExpiration );
128
- }
129
-
130
- @ Override
131
- public AwsCredentials resolveCredentials () {
132
- return credentialsCache .get ();
74
+ protected ResourcesEndpointProvider getCredentialsEndpointProvider () {
75
+ return credentialsEndpointProvider ;
133
76
}
134
77
135
78
@ Override
136
- public void close () {
137
- credentialsCache . close ( );
79
+ public String toString () {
80
+ return ToString . create ( "ContainerCredentialsProvider" );
138
81
}
139
82
140
83
static final class ContainerCredentialsEndpointProvider implements ResourcesEndpointProvider {
141
- private final String endpoint ;
142
-
143
- ContainerCredentialsEndpointProvider (String endpoint ) {
144
- this .endpoint = endpoint ;
145
- }
84
+ private static final Set <String > ALLOWED_HOSTS = unmodifiableSet (new HashSet <>(Arrays .asList ("localhost" , "127.0.0.1" )));
146
85
147
86
@ Override
148
87
public URI endpoint () throws IOException {
88
+
149
89
if (!SdkSystemSetting .AWS_CONTAINER_CREDENTIALS_RELATIVE_URI .getStringValue ().isPresent () &&
150
90
!SdkSystemSetting .AWS_CONTAINER_CREDENTIALS_FULL_URI .getStringValue ().isPresent ()) {
151
91
throw SdkClientException .builder ()
@@ -177,28 +117,26 @@ public ResourcesEndpointRetryPolicy retryPolicy() {
177
117
178
118
@ Override
179
119
public Map <String , String > headers () {
180
- Map <String , String > requestHeaders = new HashMap <>();
181
- requestHeaders .put ("User-Agent" , SdkUserAgent .create ().userAgent ());
182
- SdkSystemSetting .AWS_CONTAINER_AUTHORIZATION_TOKEN .getStringValue ()
183
- .filter (StringUtils ::isNotBlank )
184
- .ifPresent (t -> requestHeaders .put ("Authorization" , t ));
185
- return requestHeaders ;
120
+ return SdkSystemSetting .AWS_CONTAINER_AUTHORIZATION_TOKEN .getStringValue ()
121
+ .filter (StringUtils ::isNotBlank )
122
+ .map (t -> singletonMap ("Authorization" , t ))
123
+ .orElseGet (Collections ::emptyMap );
186
124
}
187
125
188
126
private URI createUri (String relativeUri ) {
189
- String host = endpoint != null ? endpoint : SdkSystemSetting .AWS_CONTAINER_SERVICE_ENDPOINT .getStringValueOrThrow ();
190
- return URI .create (host + relativeUri );
127
+ return URI .create (SdkSystemSetting .AWS_CONTAINER_SERVICE_ENDPOINT .getStringValueOrThrow () + relativeUri );
191
128
}
192
129
193
130
private URI createGenericContainerUrl () {
194
131
URI uri = URI .create (SdkSystemSetting .AWS_CONTAINER_CREDENTIALS_FULL_URI .getStringValueOrThrow ());
195
132
if (!ALLOWED_HOSTS .contains (uri .getHost ())) {
196
- String envVarName = SdkSystemSetting . AWS_CONTAINER_CREDENTIALS_FULL_URI . environmentVariable ();
133
+
197
134
throw SdkClientException .builder ()
198
135
.message (String .format ("The full URI (%s) contained within environment " +
199
- "variable %s has an invalid host. Host can only be one of [%s]." ,
200
- uri ,
201
- envVarName ,
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 (),
202
140
String .join ("," , ALLOWED_HOSTS )))
203
141
.build ();
204
142
}
@@ -210,47 +148,29 @@ private URI createGenericContainerUrl() {
210
148
* A builder for creating a custom a {@link ContainerCredentialsProvider}.
211
149
*/
212
150
public interface Builder extends HttpCredentialsProvider .Builder <ContainerCredentialsProvider , Builder > {
213
- }
214
-
215
- private static final class BuilderImpl implements Builder {
216
- private String endpoint ;
217
- private Boolean asyncCredentialUpdateEnabled ;
218
- private String asyncThreadName ;
219
-
220
- BuilderImpl () {
221
- asyncThreadName ("container-credentials-provider" );
222
- }
223
151
152
+ /**
153
+ * Build a {@link ContainerCredentialsProvider} from the provided configuration.
154
+ */
224
155
@ Override
225
- public Builder endpoint (String endpoint ) {
226
- this .endpoint = endpoint ;
227
- return this ;
228
- }
156
+ ContainerCredentialsProvider build ();
157
+ }
229
158
230
- public void setEndpoint (String endpoint ) {
231
- endpoint (endpoint );
232
- }
159
+ static final class BuilderImpl extends HttpCredentialsProvider .BuilderImpl <ContainerCredentialsProvider , Builder >
160
+ implements Builder {
233
161
234
- @ Override
235
- public Builder asyncCredentialUpdateEnabled (Boolean asyncCredentialUpdateEnabled ) {
236
- this .asyncCredentialUpdateEnabled = asyncCredentialUpdateEnabled ;
237
- return this ;
238
- }
162
+ private ResourcesEndpointProvider credentialsEndpointProvider = new ContainerCredentialsEndpointProvider ();
239
163
240
- public void setAsyncCredentialUpdateEnabled ( boolean asyncCredentialUpdateEnabled ) {
241
- asyncCredentialUpdateEnabled ( asyncCredentialUpdateEnabled );
164
+ BuilderImpl ( ) {
165
+ super . asyncThreadName ( "container-credentials-provider" );
242
166
}
243
167
244
- @ Override
245
- public Builder asyncThreadName ( String asyncThreadName ) {
246
- this .asyncThreadName = asyncThreadName ;
168
+ @ SdkTestInternalApi
169
+ Builder credentialsEndpointProvider ( ResourcesEndpointProvider credentialsEndpointProvider ) {
170
+ this .credentialsEndpointProvider = credentialsEndpointProvider ;
247
171
return this ;
248
172
}
249
173
250
- public void setAsyncThreadName (String asyncThreadName ) {
251
- asyncThreadName (asyncThreadName );
252
- }
253
-
254
174
@ Override
255
175
public ContainerCredentialsProvider build () {
256
176
return new ContainerCredentialsProvider (this );
0 commit comments