2424import java .time .Duration ;
2525import java .time .Instant ;
2626import java .util .Optional ;
27+ import software .amazon .awssdk .annotations .NotThreadSafe ;
28+ import software .amazon .awssdk .annotations .SdkInternalApi ;
2729import software .amazon .awssdk .annotations .SdkPublicApi ;
2830import software .amazon .awssdk .annotations .ThreadSafe ;
2931import software .amazon .awssdk .auth .credentials .AwsCredentials ;
3840import software .amazon .awssdk .services .signin .internal .LoginAccessToken ;
3941import software .amazon .awssdk .services .signin .internal .LoginCacheDirectorySystemSetting ;
4042import software .amazon .awssdk .services .signin .internal .OnDiskTokenManager ;
43+ import software .amazon .awssdk .services .signin .model .AccessDeniedException ;
4144import software .amazon .awssdk .services .signin .model .CreateOAuth2TokenRequest ;
4245import software .amazon .awssdk .services .signin .model .CreateOAuth2TokenResponse ;
43- import software .amazon .awssdk .services .signin .model .SigninException ;
4446import software .amazon .awssdk .utils .Logger ;
4547import software .amazon .awssdk .utils .SdkAutoCloseable ;
4648import software .amazon .awssdk .utils .StringUtils ;
5557 * It periodically sends a {@link CreateOAuth2TokenRequest} to the AWS
5658 * Sign-On Service to refresh short-lived sessions to use for authentication. These sessions are updated using a single
5759 * calling thread (by default) or asynchronously (if {@link Builder#asyncCredentialUpdateEnabled(Boolean)} is set).
58- *
60+ * <p>
5961 * If the credentials are not successfully updated before expiration, calls to {@link #resolveCredentials()} will block until
6062 * they are updated successfully.
61- *
63+ * <p>
6264 * Users of this provider must {@link #close()} it when they are finished using it.
63- *
65+ * <p>
6466 * This is created using {@link LoginCredentialsProvider#builder()}.
6567 */
6668@ SdkPublicApi
6769@ ThreadSafe
68- public class LoginCredentialsProvider implements
70+ public final class LoginCredentialsProvider implements
6971 AwsCredentialsProvider , SdkAutoCloseable ,
7072 ToCopyableBuilder <LoginCredentialsProvider .Builder , LoginCredentialsProvider > {
7173 private static final Logger log = Logger .loggerFor (LoginCredentialsProvider .class );
@@ -196,10 +198,32 @@ private RefreshResult<AwsCredentials> refreshFromSigninService(LoginAccessToken
196198 .staleTime (newExpiration .minus (staleTime ))
197199 .prefetchTime (newExpiration .minus (prefetchTime ))
198200 .build ();
199- } catch (SigninException serviceException ) {
200- throw SdkClientException .create (
201- "Unable to refresh AWS Signin Access Token: You must re-authenticate." ,
202- serviceException );
201+ } catch (AccessDeniedException accessDeniedException ) {
202+ if (accessDeniedException .error () == null ) {
203+ throw accessDeniedException ;
204+ }
205+
206+ switch (accessDeniedException .error ()) {
207+ case TOKEN_EXPIRED :
208+ throw SdkClientException .create (
209+ "Your session has expired. Please reauthenticate." ,
210+ accessDeniedException );
211+ case USER_CREDENTIALS_CHANGED :
212+ throw SdkClientException .create (
213+ "Unable to refresh credentials because of a change in your password. "
214+ + "Please reauthenticate with your new password." ,
215+ accessDeniedException
216+ );
217+ case INSUFFICIENT_PERMISSIONS :
218+ throw SdkClientException .create (
219+ "Unable to refresh credentials due to insufficient permissions. You may be missing permission "
220+ + "for the 'CreateOAuth2Token' action." ,
221+ accessDeniedException
222+ );
223+ default :
224+ throw accessDeniedException ;
225+
226+ }
203227 }
204228 }
205229
@@ -222,7 +246,7 @@ public Duration prefetchTime() {
222246 /**
223247 * Get a builder for creating a custom {@link LoginCredentialsProvider}.
224248 */
225- public static BuilderImpl builder () {
249+ public static Builder builder () {
226250 return new BuilderImpl ();
227251 }
228252
@@ -243,7 +267,6 @@ public Builder toBuilder() {
243267
244268
245269 /**
246- *
247270 * @return true if the token does NOT need to be refreshed - it is after the given refresh window, eg stale/prefetch time.
248271 */
249272 private static boolean shouldNotRefresh (Instant expiration , Duration refreshWindow ) {
@@ -254,6 +277,7 @@ private static boolean shouldNotRefresh(Instant expiration, Duration refreshWind
254277 /**
255278 * A builder for creating a custom {@link LoginCredentialsProvider}.
256279 */
280+ @ NotThreadSafe
257281 public interface Builder extends CopyableBuilder <Builder , LoginCredentialsProvider > {
258282 /**
259283 * Configure the {@link SigninClient} to use when calling Signin to update the session. This client should not be shut
@@ -265,15 +289,15 @@ public interface Builder extends CopyableBuilder<Builder, LoginCredentialsProvid
265289 * Configure whether the provider should fetch credentials asynchronously in the background. If this is true, threads are
266290 * less likely to block when credentials are loaded, but additional resources are used to maintain the provider.
267291 *
268- * <p>By default, this is disabled.</p>
292+ * <p>By default, this is enabled.
269293 */
270294 Builder asyncCredentialUpdateEnabled (Boolean asyncCredentialUpdateEnabled );
271295
272296 /**
273- * Configure the amount of time, relative to signin token expiration, that the cached credentials are considered stale and
297+ * Configure the amount of time, relative to login token expiration, that the cached credentials are considered stale and
274298 * should no longer be used. All threads will block until the value is updated.
275299 *
276- * <p>By default, this is 1 minute.</p>
300+ * <p>By default, this is 1 minute.
277301 */
278302 Builder staleTime (Duration staleTime );
279303
@@ -284,7 +308,7 @@ public interface Builder extends CopyableBuilder<Builder, LoginCredentialsProvid
284308 * Prefetch updates will occur between the specified time and the stale time of the provider. Prefetch updates may be
285309 * asynchronous. See {@link #asyncCredentialUpdateEnabled}.
286310 *
287- * <p>By default, this is 5 minutes.</p>
311+ * <p>By default, this is 5 minutes.
288312 */
289313 Builder prefetchTime (Duration prefetchTime );
290314
@@ -303,19 +327,18 @@ public interface Builder extends CopyableBuilder<Builder, LoginCredentialsProvid
303327 * An optional string denoting previous credentials providers that are chained with this one. This method is primarily
304328 * intended for use by AWS SDK internal components and should not be used directly by external users.
305329 */
330+ @ SdkInternalApi
306331 Builder sourceChain (String sourceChain );
307332
308333 /**
309334 * Create a {@link LoginCredentialsProvider} using the configuration applied to this builder.
310- *
311- * @return
312335 */
313336 @ Override
314337 LoginCredentialsProvider build ();
315338 }
316339
317340 protected static final class BuilderImpl implements Builder {
318- private Boolean asyncCredentialUpdateEnabled = false ;
341+ private Boolean asyncCredentialUpdateEnabled = true ;
319342 private SigninClient signinClient ;
320343 private Duration staleTime ;
321344 private Duration prefetchTime ;
0 commit comments