@@ -135,6 +135,7 @@ describe('AuthUtil', async function () {
135135 it ( 'returns credentials form for IAM credentials' , async function ( ) {
136136 sinon . stub ( auth , 'isSsoSession' ) . returns ( false )
137137 sinon . stub ( auth , 'isConnected' ) . returns ( true )
138+ sinon . stub ( auth , 'isIamSession' ) . returns ( true )
138139
139140 const forms = await auth . getAuthFormIds ( )
140141 assert . deepStrictEqual ( forms , [ 'credentials' ] )
@@ -406,4 +407,189 @@ describe('AuthUtil', async function () {
406407 )
407408 } )
408409 } )
409- } )
410+
411+ describe ( 'login_iam' , function ( ) {
412+ it ( 'creates IAM session and logs in' , async function ( ) {
413+ const mockResponse = {
414+ id : 'test-credential-id' ,
415+ credentials : {
416+ accessKeyId : 'encrypted-access-key' ,
417+ secretAccessKey : 'encrypted-secret-key' ,
418+ sessionToken : 'encrypted-session-token' ,
419+ } ,
420+ updateCredentialsParams : {
421+ data : 'credential-data' ,
422+ } ,
423+ }
424+
425+ const mockIamLogin = {
426+ login : sinon . stub ( ) . resolves ( mockResponse ) ,
427+ loginType : 'iam' ,
428+ }
429+
430+ sinon . stub ( auth2 , 'IamLogin' ) . returns ( mockIamLogin as any )
431+
432+ const response = await auth . login_iam ( 'accessKey' , 'secretKey' , 'sessionToken' )
433+
434+ assert . ok ( mockIamLogin . login . calledOnce )
435+ assert . ok ( mockIamLogin . login . calledWith ( {
436+ accessKey : 'accessKey' ,
437+ secretKey : 'secretKey' ,
438+ sessionToken : 'sessionToken' ,
439+ roleArn : undefined ,
440+ } ) )
441+ assert . strictEqual ( response , mockResponse )
442+ } )
443+
444+ it ( 'creates IAM session with role ARN' , async function ( ) {
445+ const mockResponse = {
446+ id : 'test-credential-id' ,
447+ credentials : {
448+ accessKeyId : 'encrypted-access-key' ,
449+ secretAccessKey : 'encrypted-secret-key' ,
450+ sessionToken : 'encrypted-session-token' ,
451+ } ,
452+ updateCredentialsParams : {
453+ data : 'credential-data' ,
454+ } ,
455+ }
456+
457+ const mockIamLogin = {
458+ login : sinon . stub ( ) . resolves ( mockResponse ) ,
459+ loginType : 'iam' ,
460+ }
461+
462+ sinon . stub ( auth2 , 'IamLogin' ) . returns ( mockIamLogin as any )
463+
464+ const response = await auth . login_iam ( 'accessKey' , 'secretKey' , 'sessionToken' , 'arn:aws:iam::123456789012:role/TestRole' )
465+
466+ assert . ok ( mockIamLogin . login . calledOnce )
467+ assert . ok ( mockIamLogin . login . calledWith ( {
468+ accessKey : 'accessKey' ,
469+ secretKey : 'secretKey' ,
470+ sessionToken : 'sessionToken' ,
471+ roleArn : 'arn:aws:iam::123456789012:role/TestRole' ,
472+ } ) )
473+ assert . strictEqual ( response , mockResponse )
474+ } )
475+ } )
476+
477+ describe ( 'getIamCredential' , function ( ) {
478+ it ( 'returns IAM credentials from session' , async function ( ) {
479+ const mockCredentials = {
480+ accessKeyId : 'test-access-key' ,
481+ secretAccessKey : 'test-secret-key' ,
482+ sessionToken : 'test-session-token' ,
483+ }
484+
485+ const mockSession = {
486+ getCredential : sinon . stub ( ) . resolves ( {
487+ credential : mockCredentials ,
488+ updateCredentialsParams : { data : 'test' } ,
489+ } ) ,
490+ loginType : 'iam' ,
491+ }
492+
493+ ; ( auth as any ) . session = mockSession
494+
495+ const result = await auth . getIamCredential ( )
496+
497+ assert . ok ( mockSession . getCredential . calledOnce )
498+ assert . deepStrictEqual ( result , mockCredentials )
499+ } )
500+
501+ it ( 'throws error for SSO session' , async function ( ) {
502+ const mockSession = {
503+ getCredential : sinon . stub ( ) . resolves ( {
504+ credential : 'sso-token' ,
505+ updateCredentialsParams : { data : 'test' } ,
506+ } ) ,
507+ loginType : 'sso' ,
508+ }
509+
510+ ; ( auth as any ) . session = mockSession
511+
512+ try {
513+ await auth . getIamCredential ( )
514+ assert . fail ( 'Should have thrown an error' )
515+ } catch ( err ) {
516+ assert . strictEqual ( ( err as Error ) . message , 'Cannot get token with SSO session' )
517+ }
518+ } )
519+
520+ it ( 'throws error when not logged in' , async function ( ) {
521+ ; ( auth as any ) . session = undefined
522+
523+ try {
524+ await auth . getIamCredential ( )
525+ assert . fail ( 'Should have thrown an error' )
526+ } catch ( err ) {
527+ assert . strictEqual ( ( err as Error ) . message , 'Cannot get credential without logging in.' )
528+ }
529+ } )
530+ } )
531+
532+ describe ( 'isIamSession' , function ( ) {
533+ it ( 'returns true for IAM session' , function ( ) {
534+ const mockSession = { loginType : 'iam' }
535+ ; ( auth as any ) . session = mockSession
536+
537+ assert . strictEqual ( auth . isIamSession ( ) , true )
538+ } )
539+
540+ it ( 'returns false for SSO session' , function ( ) {
541+ const mockSession = { loginType : 'sso' }
542+ ; ( auth as any ) . session = mockSession
543+
544+ assert . strictEqual ( auth . isIamSession ( ) , false )
545+ } )
546+
547+ it ( 'returns false when no session' , function ( ) {
548+ ; ( auth as any ) . session = undefined
549+
550+ assert . strictEqual ( auth . isIamSession ( ) , false )
551+ } )
552+ } )
553+
554+ describe ( 'IAM session state changes' , function ( ) {
555+ let mockLspAuth : any
556+
557+ beforeEach ( function ( ) {
558+ mockLspAuth = ( auth as any ) . lspAuth
559+ } )
560+
561+ it ( 'updates IAM credential when state is refreshed' , async function ( ) {
562+ const mockSession = {
563+ getCredential : sinon . stub ( ) . resolves ( {
564+ credential : { accessKeyId : 'key' , secretAccessKey : 'secret' } ,
565+ updateCredentialsParams : { data : 'fake-data' } ,
566+ } ) ,
567+ loginType : 'iam' ,
568+ }
569+ ; ( auth as any ) . session = mockSession
570+
571+ await ( auth as any ) . stateChangeHandler ( { state : 'refreshed' } )
572+
573+ assert . ok ( mockLspAuth . updateIamCredential . called )
574+ assert . strictEqual ( mockLspAuth . updateIamCredential . firstCall . args [ 0 ] . data , 'fake-data' )
575+ } )
576+
577+ it ( 'cleans up IAM credential when connection expires' , async function ( ) {
578+ const mockSession = { loginType : 'iam' }
579+ ; ( auth as any ) . session = mockSession
580+
581+ await ( auth as any ) . stateChangeHandler ( { state : 'expired' } )
582+
583+ assert . ok ( mockLspAuth . deleteIamCredential . called )
584+ } )
585+
586+ it ( 'deletes IAM credential when disconnected' , async function ( ) {
587+ const mockSession = { loginType : 'iam' }
588+ ; ( auth as any ) . session = mockSession
589+
590+ await ( auth as any ) . stateChangeHandler ( { state : 'notConnected' } )
591+
592+ assert . ok ( mockLspAuth . deleteIamCredential . called )
593+ } )
594+ } )
595+ } )
0 commit comments