Skip to content

Commit a64bc46

Browse files
authored
send refreshCredentials on token refresh request failure (#4604)
1 parent ca342d3 commit a64bc46

File tree

2 files changed

+73
-29
lines changed

2 files changed

+73
-29
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mockito = "5.11.0"
2222
mockitoKotlin = "5.2.1"
2323
mockk = "1.13.10"
2424
node-gradle = "7.0.2"
25-
telemetryGenerator = "1.0.212"
25+
telemetryGenerator = "1.0.216"
2626
testLogger = "4.0.0"
2727
testRetry = "1.5.2"
2828
# test-only; platform provides slf4j transitively at runtime. <233, 1.7.36; >=233, 2.0.9

plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/credentials/sso/SsoAccessTokenProvider.kt

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import com.intellij.openapi.progress.ProgressIndicator
1010
import com.intellij.openapi.progress.ProgressManager
1111
import com.intellij.openapi.util.registry.Registry
1212
import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider
13+
import software.amazon.awssdk.awscore.exception.AwsServiceException
1314
import software.amazon.awssdk.services.ssooidc.SsoOidcClient
1415
import software.amazon.awssdk.services.ssooidc.model.AuthorizationPendingException
1516
import software.amazon.awssdk.services.ssooidc.model.CreateTokenResponse
1617
import software.amazon.awssdk.services.ssooidc.model.InvalidClientException
1718
import software.amazon.awssdk.services.ssooidc.model.InvalidRequestException
1819
import software.amazon.awssdk.services.ssooidc.model.SlowDownException
20+
import software.amazon.awssdk.services.ssooidc.model.SsoOidcException
1921
import software.aws.toolkits.core.utils.getLogger
2022
import software.aws.toolkits.core.utils.warn
2123
import software.aws.toolkits.jetbrains.core.credentials.sono.SONO_URL
@@ -335,45 +337,87 @@ class SsoAccessTokenProvider(
335337
}
336338
}
337339

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+
338363
fun refreshToken(currentToken: AccessToken): AccessToken {
339364
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()
355372
}
356373

357374
val registration = when (currentToken) {
358375
is DeviceAuthorizationGrantToken -> loadDagClientRegistration()
359376
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)
367377
}
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()
372386
}
373387

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+
}
375395

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+
}
377421
}
378422

379423
private fun loadDagClientRegistration(): ClientRegistration? =

0 commit comments

Comments
 (0)