@@ -12,16 +12,20 @@ import {
1212 GetIamCredentialParams ,
1313 getIamCredentialRequestType ,
1414 GetIamCredentialResult ,
15+ InvalidateStsCredentialResult ,
1516 IamIdentityCenterSsoTokenSource ,
1617 InvalidateSsoTokenParams ,
18+ InvalidateStsCredentialParams ,
1719 invalidateSsoTokenRequestType ,
20+ invalidateStsCredentialRequestType ,
1821 ProfileKind ,
1922 UpdateProfileParams ,
2023 updateProfileRequestType ,
2124 SsoTokenChangedParams ,
22- // StsCredentialChangedParams,
25+ StsCredentialChangedParams ,
26+ StsCredentialChangedKind ,
2327 ssoTokenChangedRequestType ,
24- // stsCredentialChangedRequestType,
28+ stsCredentialChangedRequestType ,
2529 AwsBuilderIdSsoTokenSource ,
2630 UpdateCredentialsParams ,
2731 AwsErrorCodes ,
@@ -36,6 +40,7 @@ import {
3640 iamCredentialsDeleteNotificationType ,
3741 bearerCredentialsDeleteNotificationType ,
3842 bearerCredentialsUpdateRequestType ,
43+ SsoTokenChangedKind ,
3944 RequestType ,
4045 ResponseMessage ,
4146 NotificationType ,
@@ -44,16 +49,12 @@ import {
4449 iamCredentialsUpdateRequestType ,
4550 Profile ,
4651 SsoSession ,
47- SsoTokenChangedKind ,
48- // invalidateStsCredentialRequestType,
49- // InvalidateStsCredentialParams,
50- // InvalidateStsCredentialResult,
5152} from '@aws/language-server-runtimes/protocol'
5253import { LanguageClient } from 'vscode-languageclient'
5354import { getLogger } from '../shared/logger/logger'
5455import { ToolkitError } from '../shared/errors'
5556import { useDeviceFlow } from './sso/ssoAccessTokenProvider'
56- import { getCacheDir , getCacheFileWatcher , getFlareCacheFileName } from './sso/cache'
57+ import { getCacheDir , getCacheFileWatcher , getFlareCacheFileName , getStsCacheDir } from './sso/cache'
5758import { VSCODE_EXTENSION_ID } from '../shared/extensions'
5859import { IamCredentials } from '@aws/language-server-runtimes-types'
5960
@@ -83,6 +84,8 @@ export type LoginType = (typeof LoginTypes)[keyof typeof LoginTypes]
8384
8485export type cacheChangedEvent = 'delete' | 'create'
8586
87+ export type stsCacheChangedEvent = 'delete' | 'create'
88+
8689export type Login = SsoLogin | IamLogin
8790
8891export type TokenSource = IamIdentityCenterSsoTokenSource | AwsBuilderIdSsoTokenSource
@@ -92,6 +95,7 @@ export type TokenSource = IamIdentityCenterSsoTokenSource | AwsBuilderIdSsoToken
9295 */
9396export class LanguageClientAuth {
9497 readonly #ssoCacheWatcher = getCacheFileWatcher ( getCacheDir ( ) , getFlareCacheFileName ( VSCODE_EXTENSION_ID . amazonq ) )
98+ readonly #stsCacheWatcher = getCacheFileWatcher ( getStsCacheDir ( ) , getFlareCacheFileName ( VSCODE_EXTENSION_ID . amazonq ) )
9599
96100 constructor (
97101 private readonly client : LanguageClient ,
@@ -103,6 +107,10 @@ export class LanguageClientAuth {
103107 return this . #ssoCacheWatcher
104108 }
105109
110+ public get stsCacheWatcher ( ) {
111+ return this . #stsCacheWatcher
112+ }
113+
106114 getSsoToken (
107115 tokenSource : TokenSource ,
108116 login : boolean = false ,
@@ -155,6 +163,7 @@ export class LanguageClientAuth {
155163 sso_session : profileName ,
156164 aws_access_key_id : '' ,
157165 aws_secret_access_key : '' ,
166+ role_arn : '' ,
158167 } ,
159168 } ,
160169 ssoSession : {
@@ -259,24 +268,29 @@ export class LanguageClientAuth {
259268 } satisfies InvalidateSsoTokenParams ) as Promise < InvalidateSsoTokenResult >
260269 }
261270
262- // invalidateStsCredential(tokenId: string) {
263- // return this.client.sendRequest(invalidateStsCredentialRequestType.method, {
264- // stsCredentialId : tokenId,
265- // } satisfies InvalidateStsCredentialParams) as Promise<InvalidateStsCredentialResult>
266- // }
271+ invalidateStsCredential ( tokenId : string ) {
272+ return this . client . sendRequest ( invalidateStsCredentialRequestType . method , {
273+ profileName : tokenId ,
274+ } satisfies InvalidateStsCredentialParams ) as Promise < InvalidateStsCredentialResult >
275+ }
267276
268277 registerSsoTokenChangedHandler ( ssoTokenChangedHandler : ( params : SsoTokenChangedParams ) => any ) {
269278 this . client . onNotification ( ssoTokenChangedRequestType . method , ssoTokenChangedHandler )
270279 }
271280
272- // registerStsCredentialChangedHandler(stsCredentialChangedHandler: (params: StsCredentialChangedParams) => any) {
273- // this.client.onNotification(stsCredentialChangedRequestType.method, stsCredentialChangedHandler)
274- // }
281+ registerStsCredentialChangedHandler ( stsCredentialChangedHandler : ( params : StsCredentialChangedParams ) => any ) {
282+ this . client . onNotification ( stsCredentialChangedRequestType . method , stsCredentialChangedHandler )
283+ }
275284
276285 registerCacheWatcher ( cacheChangedHandler : ( event : cacheChangedEvent ) => any ) {
277286 this . cacheWatcher . onDidCreate ( ( ) => cacheChangedHandler ( 'create' ) )
278287 this . cacheWatcher . onDidDelete ( ( ) => cacheChangedHandler ( 'delete' ) )
279288 }
289+
290+ registerStsCacheWatcher ( stsCacheChangedHandler : ( event : stsCacheChangedEvent ) => any ) {
291+ this . stsCacheWatcher . onDidCreate ( ( ) => stsCacheChangedHandler ( 'create' ) )
292+ this . stsCacheWatcher . onDidDelete ( ( ) => stsCacheChangedHandler ( 'delete' ) )
293+ }
280294}
281295
282296/**
@@ -286,7 +300,7 @@ export abstract class BaseLogin {
286300 protected loginType : LoginType | undefined
287301 protected connectionState : AuthState = 'notConnected'
288302 protected cancellationToken : CancellationTokenSource | undefined
289- protected _data : { startUrl ?: string ; region ?: string ; accessKey ?: string ; secretKey ?: string } | undefined
303+ protected _data : { startUrl ?: string ; region ?: string ; accessKey ?: string ; secretKey ?: string ; sessionToken ?: string } | undefined
290304
291305 constructor (
292306 public readonly profileName : string ,
@@ -504,16 +518,16 @@ export class SsoLogin extends BaseLogin {
504518export class IamLogin extends BaseLogin {
505519 // Cached information from the identity server for easy reference
506520 override readonly loginType = LoginTypes . IAM
507- // private iamCredentialId: string | undefined
521+ private iamCredentialId : string | undefined
508522
509523 constructor ( profileName : string , lspAuth : LanguageClientAuth , eventEmitter : vscode . EventEmitter < AuthStateEvent > ) {
510524 super ( profileName , lspAuth , eventEmitter )
511- // lspAuth.registerStsCredentialChangedHandler((params: StsCredentialChangedParams) =>
512- // this.stsCredentialChangedHandler(params)
513- // )
525+ lspAuth . registerStsCredentialChangedHandler ( ( params : StsCredentialChangedParams ) =>
526+ this . stsCredentialChangedHandler ( params )
527+ )
514528 }
515529
516- async login ( opts : { accessKey : string ; secretKey : string } ) {
530+ async login ( opts : { accessKey : string ; secretKey : string , sessionToken ?: string , roleArn ?: string } ) {
517531 await this . updateProfile ( opts )
518532 return this . _getIamCredential ( true )
519533 }
@@ -526,36 +540,30 @@ export class IamLogin extends BaseLogin {
526540 }
527541
528542 async logout ( ) {
529- // if (this.iamCredentialId) {
530- // await this.lspAuth.invalidateIamCredential (this.iamCredentialId)
531- // }
543+ if ( this . iamCredentialId ) {
544+ await this . lspAuth . invalidateStsCredential ( this . iamCredentialId )
545+ }
532546 await this . lspAuth . updateIamProfile ( this . profileName , '' , '' , '' , '' , '' )
533547 await this . lspAuth . updateIamProfile ( this . profileName + '-source' , '' , '' , '' , '' , '' )
534548 this . updateConnectionState ( 'notConnected' )
535549 this . _data = undefined
536550 // TODO: DeleteProfile api in Identity Service (this doesn't exist yet)
537551 }
538552
539- async updateProfile ( opts : { accessKey : string ; secretKey : string } ) {
540- await this . lspAuth . updateIamProfile ( this . profileName , opts . accessKey , opts . secretKey )
541- this . _data = {
542- accessKey : opts . accessKey ,
543- secretKey : opts . secretKey ,
553+ async updateProfile ( opts : { accessKey : string ; secretKey : string , sessionToken ?: string , roleArn ?: string } ) {
554+ if ( opts . roleArn ) {
555+ const sourceProfile = this . profileName + '-source'
556+ await this . lspAuth . updateIamProfile ( sourceProfile , opts . accessKey , opts . secretKey , opts . sessionToken , '' , '' )
557+ await this . lspAuth . updateIamProfile ( this . profileName , '' , '' , '' , opts . roleArn , sourceProfile )
558+ } else {
559+ await this . lspAuth . updateIamProfile ( this . profileName , opts . accessKey , opts . secretKey , opts . sessionToken , '' , '' )
544560 }
545561 }
546562
547563 /**
548564 * Restore the connection state and connection details to memory, if they exist.
549565 */
550566 async restore ( ) {
551- const sessionData = await this . getProfile ( )
552- const credentials = sessionData ?. profile ?. settings
553- if ( credentials ?. aws_access_key_id && credentials ?. aws_secret_access_key ) {
554- this . _data = {
555- accessKey : credentials . aws_access_key_id ,
556- secretKey : credentials . aws_secret_access_key ,
557- }
558- }
559567 try {
560568 await this . _getIamCredential ( false )
561569 } catch ( err ) {
@@ -595,8 +603,10 @@ export class IamLogin extends BaseLogin {
595603 } catch ( err : any ) {
596604 switch ( err . data ?. awsErrorCode ) {
597605 case AwsErrorCodes . E_CANCELLED :
598- case AwsErrorCodes . E_SSO_SESSION_NOT_FOUND :
606+ case AwsErrorCodes . E_INVALID_PROFILE :
599607 case AwsErrorCodes . E_PROFILE_NOT_FOUND :
608+ case AwsErrorCodes . E_CANNOT_CREATE_STS_CREDENTIAL :
609+ case AwsErrorCodes . E_INVALID_STS_CREDENTIAL :
600610 this . updateConnectionState ( 'notConnected' )
601611 break
602612 default :
@@ -609,19 +619,27 @@ export class IamLogin extends BaseLogin {
609619 this . cancellationToken = undefined
610620 }
611621
612- // this.iamCredentialId = response.id
622+ // Update cached credentials and credential ID
623+ if ( response . credentials . accessKeyId && response . credentials . secretAccessKey ) {
624+ this . _data = {
625+ accessKey : response . credentials . accessKeyId ,
626+ secretKey : response . credentials . secretAccessKey ,
627+ sessionToken : response . credentials . sessionToken ,
628+ }
629+ this . iamCredentialId = response . id
630+ }
613631 this . updateConnectionState ( 'connected' )
614632 return response
615633 }
616634
617- // private stsCredentialChangedHandler(params: StsCredentialChangedParams) {
618- // if (params.stsCredentialId === this.iamCredentialId) {
619- // if (params.kind === CredentialChangedKind .Expired) {
620- // this.updateConnectionState('expired')
621- // return
622- // } else if (params.kind === CredentialChangedKind .Refreshed) {
623- // this.eventEmitter.fire({ id: this.profileName, state: 'refreshed' })
624- // }
625- // }
626- // }
635+ private stsCredentialChangedHandler ( params : StsCredentialChangedParams ) {
636+ if ( params . stsCredentialId === this . iamCredentialId ) {
637+ if ( params . kind === StsCredentialChangedKind . Expired ) {
638+ this . updateConnectionState ( 'expired' )
639+ return
640+ } else if ( params . kind === StsCredentialChangedKind . Refreshed ) {
641+ this . eventEmitter . fire ( { id : this . profileName , state : 'refreshed' } )
642+ }
643+ }
644+ }
627645}
0 commit comments