15
15
16
16
package software .amazon .awssdk .auth .credentials ;
17
17
18
+ import java .util .Objects ;
18
19
import java .util .Optional ;
19
20
import java .util .function .Consumer ;
20
21
import java .util .function .Supplier ;
23
24
import software .amazon .awssdk .auth .credentials .internal .ProfileCredentialsUtils ;
24
25
import software .amazon .awssdk .core .exception .SdkClientException ;
25
26
import software .amazon .awssdk .profiles .ProfileFile ;
27
+ import software .amazon .awssdk .profiles .ProfileFileSupplier ;
26
28
import software .amazon .awssdk .profiles .ProfileFileSystemSetting ;
27
29
import software .amazon .awssdk .utils .IoUtils ;
28
30
import software .amazon .awssdk .utils .SdkAutoCloseable ;
@@ -46,55 +48,42 @@ public final class ProfileCredentialsProvider
46
48
implements AwsCredentialsProvider ,
47
49
SdkAutoCloseable ,
48
50
ToCopyableBuilder <ProfileCredentialsProvider .Builder , ProfileCredentialsProvider > {
49
- private final AwsCredentialsProvider credentialsProvider ;
50
- private final RuntimeException loadException ;
51
51
52
- private final ProfileFile profileFile ;
52
+ private AwsCredentialsProvider credentialsProvider ;
53
+ private final RuntimeException loadException ;
54
+ private final ProfileFileSupplier profileFileSupplier ;
55
+ private volatile ProfileFile currentProfileFile ;
53
56
private final String profileName ;
54
-
55
57
private final Supplier <ProfileFile > defaultProfileFileLoader ;
56
58
57
59
/**
58
60
* @see #builder()
59
61
*/
60
62
private ProfileCredentialsProvider (BuilderImpl builder ) {
61
- AwsCredentialsProvider credentialsProvider = null ;
62
- RuntimeException loadException = null ;
63
- ProfileFile profileFile = null ;
64
- String profileName = null ;
63
+ this .defaultProfileFileLoader = builder .defaultProfileFileLoader ;
64
+
65
+ RuntimeException thrownException = null ;
66
+ String selectedProfileName = null ;
67
+ ProfileFileSupplier selectedProfileSupplier = null ;
65
68
66
69
try {
67
- profileName = builder .profileName != null ? builder .profileName
68
- : ProfileFileSystemSetting .AWS_PROFILE .getStringValueOrThrow ();
69
-
70
- // Load the profiles file
71
- profileFile = Optional .ofNullable (builder .profileFile )
72
- .orElseGet (builder .defaultProfileFileLoader );
73
-
74
- // Load the profile and credentials provider
75
- String finalProfileName = profileName ;
76
- ProfileFile finalProfileFile = profileFile ;
77
- credentialsProvider =
78
- profileFile .profile (profileName )
79
- .flatMap (p -> new ProfileCredentialsUtils (finalProfileFile , p , finalProfileFile ::profile )
80
- .credentialsProvider ())
81
- .orElseThrow (() -> {
82
- String errorMessage = String .format ("Profile file contained no credentials for " +
83
- "profile '%s': %s" , finalProfileName , finalProfileFile );
84
- return SdkClientException .builder ().message (errorMessage ).build ();
85
- });
70
+ selectedProfileName = Optional .ofNullable (builder .profileName )
71
+ .orElseGet (ProfileFileSystemSetting .AWS_PROFILE ::getStringValueOrThrow );
72
+
73
+ selectedProfileSupplier = Optional .ofNullable (builder .profileFileSupplier )
74
+ .orElseGet (() -> ProfileFileSupplier
75
+ .fixedProfileFile (builder .defaultProfileFileLoader .get ()));
76
+
86
77
} catch (RuntimeException e ) {
87
78
// If we couldn't load the credentials provider for some reason, save an exception describing why. This exception
88
- // will only be raised on calls to getCredentials . We don't want to raise an exception here because it may be
79
+ // will only be raised on calls to resolveCredentials . We don't want to raise an exception here because it may be
89
80
// expected (eg. in the default credential chain).
90
- loadException = e ;
81
+ thrownException = e ;
91
82
}
92
83
93
- this .loadException = loadException ;
94
- this .credentialsProvider = credentialsProvider ;
95
- this .profileFile = profileFile ;
96
- this .profileName = profileName ;
97
- this .defaultProfileFileLoader = builder .defaultProfileFileLoader ;
84
+ this .loadException = thrownException ;
85
+ this .profileName = selectedProfileName ;
86
+ this .profileFileSupplier = selectedProfileSupplier ;
98
87
}
99
88
100
89
/**
@@ -127,19 +116,39 @@ public AwsCredentials resolveCredentials() {
127
116
if (loadException != null ) {
128
117
throw loadException ;
129
118
}
119
+
120
+ ProfileFile cachedOrRefreshedProfileFile = refreshProfileFile ();
121
+ if (isNewProfileFile (cachedOrRefreshedProfileFile )) {
122
+ currentProfileFile = cachedOrRefreshedProfileFile ;
123
+ handleProfileFileReload (cachedOrRefreshedProfileFile );
124
+ }
125
+
130
126
return credentialsProvider .resolveCredentials ();
131
127
}
132
128
129
+ private void handleProfileFileReload (ProfileFile profileFile ) {
130
+ credentialsProvider = createCredentialsProvider (profileFile , profileName );
131
+ }
132
+
133
+ private ProfileFile refreshProfileFile () {
134
+ return profileFileSupplier .get ();
135
+ }
136
+
137
+ private boolean isNewProfileFile (ProfileFile profileFile ) {
138
+ return !Objects .equals (currentProfileFile , profileFile );
139
+ }
140
+
133
141
@ Override
134
142
public String toString () {
135
143
return ToString .builder ("ProfileCredentialsProvider" )
136
144
.add ("profileName" , profileName )
137
- .add ("profileFile" , profileFile )
145
+ .add ("profileFile" , currentProfileFile )
138
146
.build ();
139
147
}
140
148
141
149
@ Override
142
150
public void close () {
151
+ profileFileSupplier .close ();
143
152
// The delegate credentials provider may be closeable (eg. if it's an STS credentials provider). In this case, we should
144
153
// clean it up when this credentials provider is closed.
145
154
IoUtils .closeIfCloseable (credentialsProvider , null );
@@ -150,6 +159,17 @@ public Builder toBuilder() {
150
159
return new BuilderImpl (this );
151
160
}
152
161
162
+ private AwsCredentialsProvider createCredentialsProvider (ProfileFile profileFile , String profileName ) {
163
+ // Load the profile and credentials provider
164
+ return profileFile .profile (profileName )
165
+ .flatMap (p -> new ProfileCredentialsUtils (profileFile , p , profileFile ::profile ).credentialsProvider ())
166
+ .orElseThrow (() -> {
167
+ String errorMessage = String .format ("Profile file contained no credentials for " +
168
+ "profile '%s': %s" , profileName , profileFile );
169
+ return SdkClientException .builder ().message (errorMessage ).build ();
170
+ });
171
+ }
172
+
153
173
/**
154
174
* A builder for creating a custom {@link ProfileCredentialsProvider}.
155
175
*/
@@ -158,6 +178,7 @@ public interface Builder extends CopyableBuilder<Builder, ProfileCredentialsProv
158
178
/**
159
179
* Define the profile file that should be used by this credentials provider. By default, the
160
180
* {@link ProfileFile#defaultProfileFile()} is used.
181
+ * @see #profileFile(ProfileFileSupplier)
161
182
*/
162
183
Builder profileFile (ProfileFile profileFile );
163
184
@@ -167,6 +188,14 @@ public interface Builder extends CopyableBuilder<Builder, ProfileCredentialsProv
167
188
*/
168
189
Builder profileFile (Consumer <ProfileFile .Builder > profileFile );
169
190
191
+ /**
192
+ * Define the mechanism for loading profile files.
193
+ *
194
+ * @param profileFileSupplier Supplier interface for generating a ProfileFile instance.
195
+ * @see #profileFile(ProfileFile)
196
+ */
197
+ Builder profileFile (ProfileFileSupplier profileFileSupplier );
198
+
170
199
/**
171
200
* Define the name of the profile that should be used by this credentials provider. By default, the value in
172
201
* {@link ProfileFileSystemSetting#AWS_PROFILE} is used.
@@ -176,27 +205,27 @@ public interface Builder extends CopyableBuilder<Builder, ProfileCredentialsProv
176
205
/**
177
206
* Create a {@link ProfileCredentialsProvider} using the configuration applied to this builder.
178
207
*/
208
+ @ Override
179
209
ProfileCredentialsProvider build ();
180
210
}
181
211
182
212
static final class BuilderImpl implements Builder {
183
- private ProfileFile profileFile ;
213
+ private ProfileFileSupplier profileFileSupplier ;
184
214
private String profileName ;
185
215
private Supplier <ProfileFile > defaultProfileFileLoader = ProfileFile ::defaultProfileFile ;
186
216
187
217
BuilderImpl () {
188
218
}
189
219
190
220
BuilderImpl (ProfileCredentialsProvider provider ) {
191
- this .profileFile = provider .profileFile ;
192
221
this .profileName = provider .profileName ;
193
222
this .defaultProfileFileLoader = provider .defaultProfileFileLoader ;
223
+ this .profileFileSupplier = provider .profileFileSupplier ;
194
224
}
195
225
196
226
@ Override
197
227
public Builder profileFile (ProfileFile profileFile ) {
198
- this .profileFile = profileFile ;
199
- return this ;
228
+ return profileFile (ProfileFileSupplier .wrapIntoNullableSupplier (profileFile ));
200
229
}
201
230
202
231
public void setProfileFile (ProfileFile profileFile ) {
@@ -208,6 +237,16 @@ public Builder profileFile(Consumer<ProfileFile.Builder> profileFile) {
208
237
return profileFile (ProfileFile .builder ().applyMutation (profileFile ).build ());
209
238
}
210
239
240
+ @ Override
241
+ public Builder profileFile (ProfileFileSupplier profileFileSupplier ) {
242
+ this .profileFileSupplier = profileFileSupplier ;
243
+ return this ;
244
+ }
245
+
246
+ public void setProfileFile (ProfileFileSupplier supplier ) {
247
+ profileFile (supplier );
248
+ }
249
+
211
250
@ Override
212
251
public Builder profileName (String profileName ) {
213
252
this .profileName = profileName ;
@@ -225,13 +264,15 @@ public ProfileCredentialsProvider build() {
225
264
226
265
/**
227
266
* Override the default configuration file to be used when the customer does not explicitly set
228
- * profileName(profileName);
229
- * {@link #profileFile(ProfileFile)}. Use of this method is only useful for testing the default behavior.
267
+ * profileFile(ProfileFile) or profileFileSupplier(supplier);
268
+ * {@link #profileFile(ProfileFile)}. Use of this method is
269
+ * only useful for testing the default behavior.
230
270
*/
231
271
@ SdkTestInternalApi
232
272
Builder defaultProfileFileLoader (Supplier <ProfileFile > defaultProfileFileLoader ) {
233
273
this .defaultProfileFileLoader = defaultProfileFileLoader ;
234
274
return this ;
235
275
}
236
276
}
277
+
237
278
}
0 commit comments