@@ -9,14 +9,19 @@ import {
99 GetSsoTokenParams ,
1010 getSsoTokenRequestType ,
1111 GetSsoTokenResult ,
12+ GetStsCredentialParams ,
13+ getStsCredentialRequestType ,
14+ GetStsCredentialResult ,
1215 IamIdentityCenterSsoTokenSource ,
1316 InvalidateSsoTokenParams ,
1417 invalidateSsoTokenRequestType ,
1518 ProfileKind ,
1619 UpdateProfileParams ,
1720 updateProfileRequestType ,
1821 SsoTokenChangedParams ,
22+ StsCredentialChangedParams ,
1923 ssoTokenChangedRequestType ,
24+ stsCredentialChangedRequestType ,
2025 AwsBuilderIdSsoTokenSource ,
2126 UpdateCredentialsParams ,
2227 AwsErrorCodes ,
@@ -28,16 +33,17 @@ import {
2833 AuthorizationFlowKind ,
2934 CancellationToken ,
3035 CancellationTokenSource ,
31- iamCredentialsUpdateRequestType ,
3236 iamCredentialsDeleteNotificationType ,
3337 bearerCredentialsDeleteNotificationType ,
3438 bearerCredentialsUpdateRequestType ,
35- SsoTokenChangedKind ,
39+ CredentialChangedKind ,
3640 RequestType ,
3741 ResponseMessage ,
3842 NotificationType ,
3943 ConnectionMetadata ,
4044 getConnectionMetadataRequestType ,
45+ iamCredentialsUpdateRequestType ,
46+ IamSession ,
4147} from '@aws/language-server-runtimes/protocol'
4248import { LanguageClient } from 'vscode-languageclient'
4349import { getLogger } from '../shared/logger/logger'
@@ -79,7 +85,7 @@ export type TokenSource = IamIdentityCenterSsoTokenSource | AwsBuilderIdSsoToken
7985/**
8086 * Interface for authentication management
8187 */
82- interface BaseLogin {
88+ export interface BaseLogin {
8389 readonly loginType : LoginType
8490}
8591
@@ -118,7 +124,20 @@ export class LanguageClientAuth {
118124 )
119125 }
120126
121- updateProfile (
127+ getStsCredential ( login : boolean = false , cancellationToken ?: CancellationToken ) : Promise < GetStsCredentialResult > {
128+ return this . client . sendRequest (
129+ getStsCredentialRequestType . method ,
130+ {
131+ clientName : this . clientName ,
132+ options : {
133+ loginOnInvalidToken : login ,
134+ } ,
135+ } satisfies GetStsCredentialParams ,
136+ cancellationToken
137+ )
138+ }
139+
140+ updateSsoProfile (
122141 profileName : string ,
123142 startUrl : string ,
124143 region : string ,
@@ -144,12 +163,28 @@ export class LanguageClientAuth {
144163 } satisfies UpdateProfileParams )
145164 }
146165
166+ updateIamProfile ( profileName : string , accessKey : string , secretKey : string ) : Promise < UpdateProfileResult > {
167+ return this . client . sendRequest ( updateProfileRequestType . method , {
168+ profile : {
169+ kinds : [ ProfileKind . SsoTokenProfile ] ,
170+ name : profileName ,
171+ } ,
172+ iamSession : {
173+ name : profileName ,
174+ credentials : {
175+ accessKeyId : accessKey ,
176+ secretAccessKey : secretKey ,
177+ } ,
178+ } ,
179+ } satisfies UpdateProfileParams )
180+ }
181+
147182 listProfiles ( ) {
148183 return this . client . sendRequest ( listProfilesRequestType . method , { } ) as Promise < ListProfilesResult >
149184 }
150185
151186 /**
152- * Returns a profile by name along with its linked sso_session .
187+ * Returns a profile by name along with its linked session .
153188 * Does not currently exist as an API in the Identity Service.
154189 */
155190 async getProfile ( profileName : string ) {
@@ -158,8 +193,11 @@ export class LanguageClientAuth {
158193 const ssoSession = profile ?. settings ?. sso_session
159194 ? response . ssoSessions . find ( ( session ) => session . name === profile ! . settings ! . sso_session )
160195 : undefined
196+ const iamSession = profile ?. settings ?. sso_session
197+ ? response . iamSessions ?. find ( ( session ) => session . name === profile ! . settings ! . sso_session )
198+ : undefined
161199
162- return { profile, ssoSession }
200+ return { profile, ssoSession, iamSession }
163201 }
164202
165203 updateBearerToken ( request : UpdateCredentialsParams ) {
@@ -170,6 +208,14 @@ export class LanguageClientAuth {
170208 return this . client . sendNotification ( bearerCredentialsDeleteNotificationType . method )
171209 }
172210
211+ updateStsCredential ( request : UpdateCredentialsParams ) {
212+ return this . client . sendRequest ( iamCredentialsUpdateRequestType . method , request )
213+ }
214+
215+ deleteStsCredential ( ) {
216+ return this . client . sendNotification ( iamCredentialsDeleteNotificationType . method )
217+ }
218+
173219 invalidateSsoToken ( tokenId : string ) {
174220 return this . client . sendRequest ( invalidateSsoTokenRequestType . method , {
175221 ssoTokenId : tokenId ,
@@ -180,6 +226,10 @@ export class LanguageClientAuth {
180226 this . client . onNotification ( ssoTokenChangedRequestType . method , ssoTokenChangedHandler )
181227 }
182228
229+ registerStsCredentialChangedHandler ( stsCredentialChangedHandler : ( params : StsCredentialChangedParams ) => any ) {
230+ this . client . onNotification ( stsCredentialChangedRequestType . method , stsCredentialChangedHandler )
231+ }
232+
183233 registerCacheWatcher ( cacheChangedHandler : ( event : cacheChangedEvent ) => any ) {
184234 this . cacheWatcher . onDidCreate ( ( ) => cacheChangedHandler ( 'create' ) )
185235 this . cacheWatcher . onDidDelete ( ( ) => cacheChangedHandler ( 'delete' ) )
@@ -195,7 +245,7 @@ export class SsoLogin implements BaseLogin {
195245 // Cached information from the identity server for easy reference
196246 private ssoTokenId : string | undefined
197247 private connectionState : AuthState = 'notConnected'
198- private _data : { startUrl : string ; region : string } | undefined
248+ private _data : { startUrl ? : string ; region ?: string ; accessKey ?: string ; secretKey ? : string } | undefined
199249
200250 private cancellationToken : CancellationTokenSource | undefined
201251
@@ -237,7 +287,7 @@ export class SsoLogin implements BaseLogin {
237287 }
238288
239289 async updateProfile ( opts : { startUrl : string ; region : string ; scopes : string [ ] } ) {
240- await this . lspAuth . updateProfile ( this . profileName , opts . startUrl , opts . region , opts . scopes )
290+ await this . lspAuth . updateSsoProfile ( this . profileName , opts . startUrl , opts . region , opts . scopes )
241291 this . _data = {
242292 startUrl : opts . startUrl ,
243293 region : opts . region ,
@@ -357,10 +407,10 @@ export class SsoLogin implements BaseLogin {
357407
358408 private ssoTokenChangedHandler ( params : SsoTokenChangedParams ) {
359409 if ( params . ssoTokenId === this . ssoTokenId ) {
360- if ( params . kind === SsoTokenChangedKind . Expired ) {
410+ if ( params . kind === CredentialChangedKind . Expired ) {
361411 this . updateConnectionState ( 'expired' )
362412 return
363- } else if ( params . kind === SsoTokenChangedKind . Refreshed ) {
413+ } else if ( params . kind === CredentialChangedKind . Refreshed ) {
364414 this . eventEmitter . fire ( { id : this . profileName , state : 'refreshed' } )
365415 }
366416 }
@@ -374,9 +424,9 @@ export class IamLogin implements BaseLogin {
374424 readonly loginType = LoginTypes . IAM
375425
376426 // Cached information from the identity server for easy reference
377- private ssoTokenId : string | undefined
427+ private stsCredentialId : string | undefined
378428 private connectionState : AuthState = 'notConnected'
379- private _data : { startUrl : string ; region : string } | undefined
429+ private _data : { startUrl ? : string ; region ?: string ; accessKey ?: string ; secretKey ? : string } | undefined
380430
381431 private cancellationToken : CancellationTokenSource | undefined
382432
@@ -385,28 +435,30 @@ export class IamLogin implements BaseLogin {
385435 private readonly lspAuth : LanguageClientAuth ,
386436 private readonly eventEmitter : vscode . EventEmitter < AuthStateEvent >
387437 ) {
388- lspAuth . registerSsoTokenChangedHandler ( ( params : SsoTokenChangedParams ) => this . ssoTokenChangedHandler ( params ) )
438+ lspAuth . registerStsCredentialChangedHandler ( ( params : StsCredentialChangedParams ) =>
439+ this . stsCredentialChangedHandler ( params )
440+ )
389441 }
390442
391443 get data ( ) {
392444 return this . _data
393445 }
394446
395447 async login ( opts : { accessKey : string ; secretKey : string } ) {
396- // await this.updateProfile(opts)
397- return this . _getSsoToken ( true )
448+ await this . updateProfile ( opts )
449+ return this . _getStsCredential ( true )
398450 }
399451
400452 async reauthenticate ( ) {
401453 if ( this . connectionState === 'notConnected' ) {
402454 throw new ToolkitError ( 'Cannot reauthenticate when not connected.' )
403455 }
404- return this . _getSsoToken ( true )
456+ return this . _getStsCredential ( true )
405457 }
406458
407459 async logout ( ) {
408- if ( this . ssoTokenId ) {
409- await this . lspAuth . invalidateSsoToken ( this . ssoTokenId )
460+ if ( this . stsCredentialId ) {
461+ await this . lspAuth . invalidateSsoToken ( this . stsCredentialId )
410462 }
411463 this . updateConnectionState ( 'notConnected' )
412464 this . _data = undefined
@@ -417,31 +469,31 @@ export class IamLogin implements BaseLogin {
417469 return await this . lspAuth . getProfile ( this . profileName )
418470 }
419471
420- async updateProfile ( opts : { startUrl : string ; region : string ; scopes : string [ ] } ) {
421- await this . lspAuth . updateProfile ( this . profileName , opts . startUrl , opts . region , opts . scopes )
472+ async updateProfile ( opts : { accessKey : string ; secretKey : string } ) {
473+ await this . lspAuth . updateIamProfile ( this . profileName , opts . accessKey , opts . secretKey )
422474 this . _data = {
423- startUrl : opts . startUrl ,
424- region : opts . region ,
475+ accessKey : opts . accessKey ,
476+ secretKey : opts . secretKey ,
425477 }
426478 }
427479
428480 /**
429481 * Restore the connection state and connection details to memory, if they exist.
430482 */
431483 async restore ( ) {
432- // const sessionData = await this.getProfile()
433- // const ssoSession = sessionData?.ssoSession?.settings
434- // if (ssoSession?.sso_region && ssoSession?.sso_start_url ) {
435- // this._data = {
436- // startUrl: ssoSession.sso_start_url ,
437- // region: ssoSession.sso_region ,
438- // }
439- // }
440- // try {
441- // await this._getSsoToken (false)
442- // } catch (err) {
443- // getLogger().error('Restoring connection failed: %s', err)
444- // }
484+ const sessionData = await this . getProfile ( )
485+ const credentials = sessionData ?. iamSession ?. credentials
486+ if ( credentials ?. accessKeyId && credentials ?. secretAccessKey ) {
487+ this . _data = {
488+ accessKey : credentials . accessKeyId ,
489+ secretKey : credentials . secretAccessKey ,
490+ }
491+ }
492+ try {
493+ await this . _getStsCredential ( false )
494+ } catch ( err ) {
495+ getLogger ( ) . error ( 'Restoring connection failed: %s' , err )
496+ }
445497 }
446498
447499 /**
@@ -458,8 +510,9 @@ export class IamLogin implements BaseLogin {
458510 * with encrypted token
459511 */
460512 async getToken ( ) {
461- const response = await this . _getSsoToken ( false )
462- const decryptedKey = await jose . compactDecrypt ( response . ssoToken . accessToken , this . lspAuth . encryptionKey )
513+ // TODO: fix STS credential decryption
514+ const response = await this . _getStsCredential ( false )
515+ const decryptedKey = await jose . compactDecrypt ( response . stsCredential . id , this . lspAuth . encryptionKey )
463516 return {
464517 token : decryptedKey . plaintext . toString ( ) . replaceAll ( '"' , '' ) ,
465518 updateCredentialsParams : response . updateCredentialsParams ,
@@ -470,25 +523,12 @@ export class IamLogin implements BaseLogin {
470523 * Returns the response from `getSsoToken` LSP API and sets the connection state based on the errors/result
471524 * of the call.
472525 */
473- private async _getSsoToken ( login : boolean ) {
474- let response : GetSsoTokenResult
526+ private async _getStsCredential ( login : boolean ) {
527+ let response : GetStsCredentialResult
475528 this . cancellationToken = new CancellationTokenSource ( )
476529
477530 try {
478- response = await this . lspAuth . getSsoToken (
479- {
480- /**
481- * Note that we do not use SsoTokenSourceKind.AwsBuilderId here.
482- * This is because it does not leave any state behind on disk, so
483- * we cannot infer that a builder ID connection exists via the
484- * Identity Server alone.
485- */
486- kind : SsoTokenSourceKind . IamIdentityCenter ,
487- profileName : this . profileName ,
488- } satisfies IamIdentityCenterSsoTokenSource ,
489- login ,
490- this . cancellationToken . token
491- )
531+ response = await this . lspAuth . getStsCredential ( login , this . cancellationToken . token )
492532 } catch ( err : any ) {
493533 switch ( err . data ?. awsErrorCode ) {
494534 case AwsErrorCodes . E_CANCELLED :
@@ -515,7 +555,7 @@ export class IamLogin implements BaseLogin {
515555 this . cancellationToken = undefined
516556 }
517557
518- this . ssoTokenId = response . ssoToken . id
558+ this . stsCredentialId = response . stsCredential . id
519559 this . updateConnectionState ( 'connected' )
520560 return response
521561 }
@@ -535,12 +575,12 @@ export class IamLogin implements BaseLogin {
535575 }
536576 }
537577
538- private ssoTokenChangedHandler ( params : SsoTokenChangedParams ) {
539- if ( params . ssoTokenId === this . ssoTokenId ) {
540- if ( params . kind === SsoTokenChangedKind . Expired ) {
578+ private stsCredentialChangedHandler ( params : StsCredentialChangedParams ) {
579+ if ( params . stsCredentialId === this . stsCredentialId ) {
580+ if ( params . kind === CredentialChangedKind . Expired ) {
541581 this . updateConnectionState ( 'expired' )
542582 return
543- } else if ( params . kind === SsoTokenChangedKind . Refreshed ) {
583+ } else if ( params . kind === CredentialChangedKind . Refreshed ) {
544584 this . eventEmitter . fire ( { id : this . profileName , state : 'refreshed' } )
545585 }
546586 }
0 commit comments