Skip to content

Commit c1f5118

Browse files
committed
Add updated error handling / messages
1 parent 06f6b1d commit c1f5118

File tree

2 files changed

+84
-17
lines changed

2 files changed

+84
-17
lines changed

services/signin/src/main/java/software/amazon/awssdk/services/signin/auth/LoginCredentialsProvider.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
import software.amazon.awssdk.services.signin.internal.LoginAccessToken;
4141
import software.amazon.awssdk.services.signin.internal.LoginCacheDirectorySystemSetting;
4242
import software.amazon.awssdk.services.signin.internal.OnDiskTokenManager;
43+
import software.amazon.awssdk.services.signin.model.AccessDeniedException;
4344
import software.amazon.awssdk.services.signin.model.CreateOAuth2TokenRequest;
4445
import software.amazon.awssdk.services.signin.model.CreateOAuth2TokenResponse;
45-
import software.amazon.awssdk.services.signin.model.SigninException;
4646
import software.amazon.awssdk.utils.Logger;
4747
import software.amazon.awssdk.utils.SdkAutoCloseable;
4848
import software.amazon.awssdk.utils.StringUtils;
@@ -198,10 +198,32 @@ private RefreshResult<AwsCredentials> refreshFromSigninService(LoginAccessToken
198198
.staleTime(newExpiration.minus(staleTime))
199199
.prefetchTime(newExpiration.minus(prefetchTime))
200200
.build();
201-
} catch (SigninException serviceException) {
202-
throw SdkClientException.create(
203-
"Unable to refresh AWS Signin Access Token: You must re-authenticate.",
204-
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+
}
205227
}
206228
}
207229

services/signin/src/test/java/software/amazon/awssdk/services/signin/auth/LoginCredentialsProviderTest.java

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@
2020
import static org.junit.jupiter.api.Assertions.assertNotNull;
2121
import static org.junit.jupiter.api.Assertions.assertThrows;
2222
import static org.junit.jupiter.api.Assertions.assertTrue;
23-
import static org.mockito.ArgumentMatchers.any;
24-
import static org.mockito.Mockito.mock;
25-
import static org.mockito.Mockito.never;
26-
import static org.mockito.Mockito.times;
27-
import static org.mockito.Mockito.verify;
28-
import static org.mockito.Mockito.when;
23+
2924
import static software.amazon.awssdk.services.signin.auth.internal.DpopTestUtils.VALID_TEST_PEM;
3025
import static software.amazon.awssdk.services.signin.auth.internal.DpopTestUtils.getJwtPayloadFromEncodedDpopHeader;
3126
import static software.amazon.awssdk.services.signin.auth.internal.DpopTestUtils.verifySignature;
@@ -41,10 +36,8 @@
4136
import org.junit.jupiter.api.BeforeEach;
4237
import org.junit.jupiter.api.Test;
4338
import org.junit.jupiter.api.io.TempDir;
44-
import org.mockito.ArgumentCaptor;
4539
import software.amazon.awssdk.auth.credentials.AwsCredentials;
4640
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
47-
import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute;
4841
import software.amazon.awssdk.core.SdkRequest;
4942
import software.amazon.awssdk.core.exception.SdkClientException;
5043
import software.amazon.awssdk.core.interceptor.Context;
@@ -61,10 +54,10 @@
6154
import software.amazon.awssdk.services.signin.internal.LoginAccessToken;
6255
import software.amazon.awssdk.services.signin.internal.OnDiskTokenManager;
6356
import software.amazon.awssdk.services.signin.model.CreateOAuth2TokenRequest;
64-
import software.amazon.awssdk.services.signin.model.CreateOAuth2TokenResponse;
57+
import software.amazon.awssdk.services.signin.model.OAuth2ErrorCode;
6558
import software.amazon.awssdk.services.signin.model.SigninException;
66-
import software.amazon.awssdk.testutils.service.http.MockAsyncHttpClient;
6759
import software.amazon.awssdk.testutils.service.http.MockSyncHttpClient;
60+
import software.amazon.awssdk.utils.StringInputStream;
6861

6962
public class LoginCredentialsProviderTest {
7063
private static final String LOGIN_SESSION_ID = "loginSessionId";
@@ -188,7 +181,7 @@ public void resolveCredentials_whenCredentialsExpired_refreshesAndUpdatesCache()
188181
}
189182

190183
@Test
191-
public void resolveCredentials_whenCredentialsExpired_serviceCallFails_raisesException() {
184+
public void resolveCredentials_whenCredentialsExpired_serviceCallFailsWithGeneric500_raisesException() {
192185
// expired
193186
AwsSessionCredentials creds = buildCredentials(Instant.now().minusSeconds(60));
194187
LoginAccessToken token = buildAccessToken(creds);
@@ -199,7 +192,43 @@ public void resolveCredentials_whenCredentialsExpired_serviceCallFails_raisesExc
199192
.response(SdkHttpResponse.builder().statusCode(500).build())
200193
.build()
201194
);
202-
assertThrows(SdkClientException.class, () -> loginCredentialsProvider.resolveCredentials());
195+
assertThrows(SigninException.class, () -> loginCredentialsProvider.resolveCredentials());
196+
}
197+
198+
@Test
199+
public void resolveCredentials_whenCredentialsExpired_serviceCallFailsWithTokenExpired_raisesException() {
200+
// expired
201+
AwsSessionCredentials creds = buildCredentials(Instant.now().minusSeconds(60));
202+
LoginAccessToken token = buildAccessToken(creds);
203+
tokenManager.storeToken(token);
204+
205+
stubAccessDeniedException(OAuth2ErrorCode.TOKEN_EXPIRED);
206+
SdkClientException e = assertThrows(SdkClientException.class, () -> loginCredentialsProvider.resolveCredentials());
207+
assertTrue(e.getMessage().contains("Your session has expired"));
208+
}
209+
210+
@Test
211+
public void resolveCredentials_whenCredentialsExpired_serviceCallFailsWithUserExpired_raisesException() {
212+
// expired
213+
AwsSessionCredentials creds = buildCredentials(Instant.now().minusSeconds(60));
214+
LoginAccessToken token = buildAccessToken(creds);
215+
tokenManager.storeToken(token);
216+
217+
stubAccessDeniedException(OAuth2ErrorCode.USER_CREDENTIALS_CHANGED);
218+
SdkClientException e = assertThrows(SdkClientException.class, () -> loginCredentialsProvider.resolveCredentials());
219+
assertTrue(e.getMessage().contains("change in your password"));
220+
}
221+
222+
@Test
223+
public void resolveCredentials_whenCredentialsExpired_serviceCallFailsWithInsufficentPermissions_raisesException() {
224+
// expired
225+
AwsSessionCredentials creds = buildCredentials(Instant.now().minusSeconds(60));
226+
LoginAccessToken token = buildAccessToken(creds);
227+
tokenManager.storeToken(token);
228+
229+
stubAccessDeniedException(OAuth2ErrorCode.INSUFFICIENT_PERMISSIONS);
230+
SdkClientException e = assertThrows(SdkClientException.class, () -> loginCredentialsProvider.resolveCredentials());
231+
assertTrue(e.getMessage().contains("insufficient permissions"));
203232
}
204233

205234
private static void verifyResolvedCredentialsAreUpdated(AwsCredentials resolvedCredentials) {
@@ -254,6 +283,22 @@ private void stubSuccessfulRefreshResponse() {
254283
);
255284
}
256285

286+
private void stubAccessDeniedException(OAuth2ErrorCode errorCode) {
287+
String errorBody = "{\"error\":\"" + errorCode + "\",\"message\":\"The refresh token has expired.\"}";
288+
mockHttpClient.stubNextResponse(
289+
HttpExecuteResponse
290+
.builder()
291+
.response(
292+
SdkHttpResponse
293+
.builder()
294+
.putHeader("X-Amzn-Errortype", "AccessDeniedException")
295+
.statusCode(401)
296+
.build())
297+
.responseBody(AbortableInputStream.create(new StringInputStream(errorBody)))
298+
.build()
299+
);
300+
}
301+
257302
private AwsSessionCredentials buildCredentials(Instant expirationTime) {
258303
return AwsSessionCredentials.builder()
259304
.accessKeyId("akid")

0 commit comments

Comments
 (0)