diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/credentials/sso/AccessToken2.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/credentials/sso/AccessToken2.kt new file mode 100644 index 00000000000..971aebe3435 --- /dev/null +++ b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/credentials/sso/AccessToken2.kt @@ -0,0 +1,94 @@ +// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.jetbrains.core.credentials.sso + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonSubTypes +import com.fasterxml.jackson.annotation.JsonTypeInfo +import com.intellij.collaboration.auth.credentials.Credentials +import software.amazon.awssdk.auth.token.credentials.SdkToken +import software.amazon.awssdk.services.sso.SsoClient +import software.amazon.awssdk.services.ssooidc.SsoOidcClient +import software.aws.toolkits.core.utils.SensitiveField +import software.aws.toolkits.core.utils.redactedString +import java.time.Instant +import java.util.Optional + +/** + * Access token returned from [SsoOidcClient.createToken] used to retrieve AWS Credentials from [SsoClient.getRoleCredentials]. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION) +@JsonSubTypes(value = [JsonSubTypes.Type(DeviceAuthorizationGrantToken::class), JsonSubTypes.Type(PKCEAuthorizationGrantToken::class) ]) +sealed interface AccessToken : SdkToken, Credentials { + val region: String + + @SensitiveField + override val accessToken: String + + @SensitiveField + @get:JsonInclude(JsonInclude.Include.NON_NULL) + val refreshToken: String? + + val expiresAt: Instant + val createdAt: Instant + + override fun token() = accessToken + + override fun expirationTime() = Optional.of(expiresAt) + + @get:JsonIgnore + val ssoUrl: String +} + +data class DeviceAuthorizationGrantToken( + val startUrl: String, + override val region: String, + override val accessToken: String, + override val refreshToken: String? = null, + override val expiresAt: Instant, + override val createdAt: Instant = Instant.EPOCH, +) : AccessToken { + override val ssoUrl: String + get() = startUrl + + override fun toString() = redactedString(this) +} + +data class PKCEAuthorizationGrantToken( + val issuerUrl: String, + override val region: String, + override val accessToken: String, + override val refreshToken: String, + override val expiresAt: Instant, + override val createdAt: Instant, +) : AccessToken { + override val ssoUrl: String + get() = issuerUrl + + override fun toString() = redactedString(this) +} + +// we really don't need to differentitate since they refresh the same way, but to save some mental cycles, +// treat them as independent so we don't need to worry about intermingling the token/registration combos +@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION) +@JsonSubTypes(value = [JsonSubTypes.Type(DeviceGrantAccessTokenCacheKey::class), JsonSubTypes.Type(PKCEAccessTokenCacheKey::class) ]) +sealed interface AccessTokenCacheKey { + val scopes: List +} + +// diverging from SDK/CLI impl here since they do: sha1sum(sessionName ?: startUrl) +// which isn't good enough for us +// only used in scoped case +data class DeviceGrantAccessTokenCacheKey( + val connectionId: String, + val startUrl: String, + override val scopes: List, +) : AccessTokenCacheKey + +data class PKCEAccessTokenCacheKey( + val issuerUrl: String, + val region: String, + override val scopes: List, +) : AccessTokenCacheKey diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/utils/TextUtils.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/utils/TextUtils.kt index dd247556d10..73d3919755c 100644 --- a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/utils/TextUtils.kt +++ b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/utils/TextUtils.kt @@ -25,6 +25,19 @@ fun formatText(project: Project, language: Language, content: String): String { return result } +fun formatText2(project: Project, language: Language, content: String): String { + var result = content + CommandProcessor.getInstance().runUndoTransparentAction { + PsiFileFactory.getInstance(project) + .createFileFromText("foo.bar", language, content, false, true)?.let { + result = CodeStyleManager.getInstance(project).reformat(it).text + } + } + + return result +} + + /** * Designed to convert underscore separated words (e.g. UPDATE_COMPLETE) into title cased human readable text * (e.g. Update Complete) diff --git a/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/lambda/execution/remote/RemoteLambdaState.kt b/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/lambda/execution/remote/RemoteLambdaState.kt index 28626f2a2d2..48aa4d9350b 100644 --- a/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/lambda/execution/remote/RemoteLambdaState.kt +++ b/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/lambda/execution/remote/RemoteLambdaState.kt @@ -20,7 +20,7 @@ import software.amazon.awssdk.core.SdkBytes import software.amazon.awssdk.services.lambda.LambdaClient import software.amazon.awssdk.services.lambda.model.LogType import software.aws.toolkits.jetbrains.core.AwsClientManager -import software.aws.toolkits.jetbrains.utils.formatText +import software.aws.toolkits.jetbrains.utils.formatText2 import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread import software.aws.toolkits.resources.message import software.aws.toolkits.telemetry.LambdaTelemetry @@ -128,7 +128,7 @@ class RemoteLambdaState( } private fun formatJson(input: String) = if (input.isNotEmpty() && input.first() == '{' && input.last() == '}') { - formatText(environment.project, JsonLanguage.INSTANCE, input) + formatText2(environment.project, JsonLanguage.INSTANCE, input) } else { input }