@@ -10,12 +10,14 @@ import com.intellij.openapi.progress.ProgressIndicator
10
10
import com.intellij.openapi.progress.ProgressManager
11
11
import com.intellij.openapi.util.registry.Registry
12
12
import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider
13
+ import software.amazon.awssdk.awscore.exception.AwsServiceException
13
14
import software.amazon.awssdk.services.ssooidc.SsoOidcClient
14
15
import software.amazon.awssdk.services.ssooidc.model.AuthorizationPendingException
15
16
import software.amazon.awssdk.services.ssooidc.model.CreateTokenResponse
16
17
import software.amazon.awssdk.services.ssooidc.model.InvalidClientException
17
18
import software.amazon.awssdk.services.ssooidc.model.InvalidRequestException
18
19
import software.amazon.awssdk.services.ssooidc.model.SlowDownException
20
+ import software.amazon.awssdk.services.ssooidc.model.SsoOidcException
19
21
import software.aws.toolkits.core.utils.getLogger
20
22
import software.aws.toolkits.core.utils.warn
21
23
import software.aws.toolkits.jetbrains.core.credentials.sono.SONO_URL
@@ -335,45 +337,87 @@ class SsoAccessTokenProvider(
335
337
}
336
338
}
337
339
340
+ private fun sendFailedRefreshCredentialsMetricIfNeeded (
341
+ currentToken : AccessToken ,
342
+ reason : String ,
343
+ reasonDesc : String ,
344
+ requestId : String? = null
345
+ ) {
346
+ val tokenCreationTime = currentToken.createdAt
347
+ val sessionDuration = Duration .between(Instant .now(clock), tokenCreationTime)
348
+ val credentialSourceId = if (currentToken.ssoUrl == SONO_URL ) CredentialSourceId .AwsId else CredentialSourceId .IamIdentityCenter
349
+
350
+ if (tokenCreationTime != Instant .EPOCH ) {
351
+ AwsTelemetry .refreshCredentials(
352
+ project = null ,
353
+ result = Result .Failed ,
354
+ sessionDuration = sessionDuration.toHours().toInt(),
355
+ credentialSourceId = credentialSourceId,
356
+ reason = reason,
357
+ reasonDesc = reasonDesc,
358
+ requestId = requestId
359
+ )
360
+ }
361
+ }
362
+
338
363
fun refreshToken (currentToken : AccessToken ): AccessToken {
339
364
if (currentToken.refreshToken == null ) {
340
- val tokenCreationTime = currentToken.createdAt
341
-
342
- if (tokenCreationTime != Instant .EPOCH ) {
343
- val sessionDuration = Duration .between(Instant .now(clock), tokenCreationTime)
344
- val credentialSourceId = if (currentToken.ssoUrl == SONO_URL ) CredentialSourceId .AwsId else CredentialSourceId .IamIdentityCenter
345
- AwsTelemetry .refreshCredentials(
346
- project = null ,
347
- result = Result .Failed ,
348
- sessionDuration = sessionDuration.toHours().toInt(),
349
- credentialSourceId = credentialSourceId,
350
- reason = " Null refresh token"
351
- )
352
- }
353
-
354
- throw InvalidRequestException .builder().message(" Requested token refresh, but refresh token was null" ).build()
365
+ val message = " Requested token refresh, but refresh token was null"
366
+ sendFailedRefreshCredentialsMetricIfNeeded(
367
+ currentToken,
368
+ reason = " Null refresh token" ,
369
+ reasonDesc = message
370
+ )
371
+ throw InvalidRequestException .builder().message(message).build()
355
372
}
356
373
357
374
val registration = when (currentToken) {
358
375
is DeviceAuthorizationGrantToken -> loadDagClientRegistration()
359
376
is PKCEAuthorizationGrantToken -> loadPkceClientRegistration()
360
- } ? : throw InvalidClientException .builder().message(" Unable to load client registration" ).build()
361
-
362
- val newToken = client.createToken {
363
- it.clientId(registration.clientId)
364
- it.clientSecret(registration.clientSecret)
365
- it.grantType(REFRESH_GRANT_TYPE )
366
- it.refreshToken(currentToken.refreshToken)
367
377
}
368
-
369
- val token = when (currentToken) {
370
- is DeviceAuthorizationGrantToken -> newToken.toDAGAccessToken(currentToken.createdAt)
371
- is PKCEAuthorizationGrantToken -> newToken.toPKCEAccessToken(currentToken.createdAt)
378
+ if (registration == null ) {
379
+ val message = " Unable to load client registration"
380
+ sendFailedRefreshCredentialsMetricIfNeeded(
381
+ currentToken,
382
+ reason = " Null client registration" ,
383
+ reasonDesc = message
384
+ )
385
+ throw InvalidClientException .builder().message(message).build()
372
386
}
373
387
374
- saveAccessToken(token)
388
+ try {
389
+ val newToken = client.createToken {
390
+ it.clientId(registration.clientId)
391
+ it.clientSecret(registration.clientSecret)
392
+ it.grantType(REFRESH_GRANT_TYPE )
393
+ it.refreshToken(currentToken.refreshToken)
394
+ }
375
395
376
- return token
396
+ val token = when (currentToken) {
397
+ is DeviceAuthorizationGrantToken -> newToken.toDAGAccessToken(currentToken.createdAt)
398
+ is PKCEAuthorizationGrantToken -> newToken.toPKCEAccessToken(currentToken.createdAt)
399
+ }
400
+
401
+ saveAccessToken(token)
402
+
403
+ return token
404
+ } catch (e: Exception ) {
405
+ val requestId = when (e) {
406
+ is AwsServiceException -> e.requestId()
407
+ else -> null
408
+ }
409
+ val message = when (e) {
410
+ is AwsServiceException -> e.awsErrorDetails().errorMessage()
411
+ else -> e.message ? : " Unknown error"
412
+ }
413
+ sendFailedRefreshCredentialsMetricIfNeeded(
414
+ currentToken,
415
+ reason = " Refresh access token request failed" ,
416
+ reasonDesc = message,
417
+ requestId = requestId
418
+ )
419
+ throw e
420
+ }
377
421
}
378
422
379
423
private fun loadDagClientRegistration (): ClientRegistration ? =
0 commit comments