Skip to content

Commit 255214c

Browse files
yuxianrzliramon1
andauthored
feat(auth): add STS credential management and mfa verification (#7811)
## Problem The webview does not support STS credentials input (sessionToken and roleArn) and endpoint to LSP does not support STS credentials and profiles. ## Solution This is part of #7507 and is built on top of #7797. - Add STS credentials input box webview, enabling mfa verification if credentials has assume role with mfa permission - Modify AuthUtils and auth2.ts to accommodate new IAM profile type - Add stsCache and other sts handlers to connect to LSP --- - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: Ramon Li <[email protected]>
1 parent 754f87e commit 255214c

File tree

18 files changed

+455
-166
lines changed

18 files changed

+455
-166
lines changed

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/amazonq/package.json

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,106 +1196,134 @@
11961196
"description": "AWS Contributed Icon",
11971197
"default": {
11981198
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1199-
"fontCharacter": "\\f1d1"
1199+
"fontCharacter": "\\f1d3"
12001200
}
12011201
},
12021202
"aws-mynah-MynahIconBlack": {
12031203
"description": "AWS Contributed Icon",
12041204
"default": {
12051205
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1206-
"fontCharacter": "\\f1d2"
1206+
"fontCharacter": "\\f1d4"
12071207
}
12081208
},
12091209
"aws-mynah-MynahIconWhite": {
12101210
"description": "AWS Contributed Icon",
12111211
"default": {
12121212
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1213-
"fontCharacter": "\\f1d3"
1213+
"fontCharacter": "\\f1d5"
12141214
}
12151215
},
12161216
"aws-mynah-logo": {
12171217
"description": "AWS Contributed Icon",
12181218
"default": {
12191219
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1220-
"fontCharacter": "\\f1d4"
1220+
"fontCharacter": "\\f1d6"
12211221
}
12221222
},
12231223
"aws-redshift-cluster": {
12241224
"description": "AWS Contributed Icon",
12251225
"default": {
12261226
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1227-
"fontCharacter": "\\f1d5"
1227+
"fontCharacter": "\\f1d7"
12281228
}
12291229
},
12301230
"aws-redshift-cluster-connected": {
12311231
"description": "AWS Contributed Icon",
12321232
"default": {
12331233
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1234-
"fontCharacter": "\\f1d6"
1234+
"fontCharacter": "\\f1d8"
12351235
}
12361236
},
12371237
"aws-redshift-database": {
12381238
"description": "AWS Contributed Icon",
12391239
"default": {
12401240
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1241-
"fontCharacter": "\\f1d7"
1241+
"fontCharacter": "\\f1d9"
12421242
}
12431243
},
12441244
"aws-redshift-redshift-cluster-connected": {
12451245
"description": "AWS Contributed Icon",
12461246
"default": {
12471247
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1248-
"fontCharacter": "\\f1d8"
1248+
"fontCharacter": "\\f1da"
12491249
}
12501250
},
12511251
"aws-redshift-schema": {
12521252
"description": "AWS Contributed Icon",
12531253
"default": {
12541254
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1255-
"fontCharacter": "\\f1d9"
1255+
"fontCharacter": "\\f1db"
12561256
}
12571257
},
12581258
"aws-redshift-table": {
12591259
"description": "AWS Contributed Icon",
12601260
"default": {
12611261
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1262-
"fontCharacter": "\\f1da"
1262+
"fontCharacter": "\\f1dc"
12631263
}
12641264
},
12651265
"aws-s3-bucket": {
12661266
"description": "AWS Contributed Icon",
12671267
"default": {
12681268
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1269-
"fontCharacter": "\\f1db"
1269+
"fontCharacter": "\\f1dd"
12701270
}
12711271
},
12721272
"aws-s3-create-bucket": {
12731273
"description": "AWS Contributed Icon",
12741274
"default": {
12751275
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1276-
"fontCharacter": "\\f1dc"
1276+
"fontCharacter": "\\f1de"
12771277
}
12781278
},
12791279
"aws-schemas-registry": {
12801280
"description": "AWS Contributed Icon",
12811281
"default": {
12821282
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1283-
"fontCharacter": "\\f1dd"
1283+
"fontCharacter": "\\f1e1"
12841284
}
12851285
},
12861286
"aws-schemas-schema": {
12871287
"description": "AWS Contributed Icon",
12881288
"default": {
12891289
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1290-
"fontCharacter": "\\f1de"
1290+
"fontCharacter": "\\f1e2"
12911291
}
12921292
},
12931293
"aws-stepfunctions-preview": {
1294+
"description": "AWS Contributed Icon",
1295+
"default": {
1296+
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1297+
"fontCharacter": "\\f1e3"
1298+
}
1299+
},
1300+
"aws-lambda-create-stack": {
1301+
"description": "AWS Contributed Icon",
1302+
"default": {
1303+
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1304+
"fontCharacter": "\\f1d1"
1305+
}
1306+
},
1307+
"aws-lambda-create-stack-light": {
1308+
"description": "AWS Contributed Icon",
1309+
"default": {
1310+
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1311+
"fontCharacter": "\\f1d2"
1312+
}
1313+
},
1314+
"aws-sagemaker-code-editor": {
12941315
"description": "AWS Contributed Icon",
12951316
"default": {
12961317
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
12971318
"fontCharacter": "\\f1df"
12981319
}
1320+
},
1321+
"aws-sagemaker-jupyter-lab": {
1322+
"description": "AWS Contributed Icon",
1323+
"default": {
1324+
"fontPath": "./resources/fonts/aws-toolkit-icons.woff",
1325+
"fontCharacter": "\\f1e0"
1326+
}
12991327
}
13001328
},
13011329
"walkthroughs": [

packages/amazonq/src/lsp/client.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ export async function startLanguageServer(
164164
},
165165
credentials: {
166166
providesBearerToken: true,
167+
// Add IAM credentials support
168+
providesIamCredentials: true,
169+
supportsAssumeRole: true,
167170
},
168171
},
169172
/**
@@ -211,9 +214,10 @@ export async function startLanguageServer(
211214

212215
/** All must be setup before {@link AuthUtil.restore} otherwise they may not trigger when expected */
213216
AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(async () => {
217+
const activeProfile = AuthUtil.instance.regionProfileManager.activeRegionProfile
214218
void pushConfigUpdate(client, {
215219
type: 'profile',
216-
profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn,
220+
profileArn: activeProfile?.arn,
217221
})
218222
})
219223

packages/amazonq/test/unit/codewhisperer/util/authUtil.test.ts

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,29 @@ import { createTestAuthUtil, TestFolder } from 'aws-core-vscode/test'
1111
import { constants, cache } from 'aws-core-vscode/auth'
1212
import { auth2 } from 'aws-core-vscode/auth'
1313
import { mementoUtils, fs } from 'aws-core-vscode/shared'
14+
import { GetIamCredentialResult } from '@aws/language-server-runtimes/protocol'
1415

1516
describe('AuthUtil', async function () {
1617
let auth: any
18+
let mockResponse: GetIamCredentialResult
1719

1820
beforeEach(async function () {
1921
await createTestAuthUtil()
2022
auth = AuthUtil.instance
23+
mockResponse = {
24+
credential: {
25+
id: 'test-credential-id',
26+
kinds: [],
27+
credentials: {
28+
accessKeyId: 'encrypted-access-key',
29+
secretAccessKey: 'encrypted-secret-key',
30+
sessionToken: 'encrypted-session-token',
31+
},
32+
},
33+
updateCredentialsParams: {
34+
data: 'credential-data',
35+
},
36+
} satisfies GetIamCredentialResult
2137
})
2238

2339
afterEach(async function () {
@@ -412,36 +428,51 @@ describe('AuthUtil', async function () {
412428

413429
describe('loginIam', function () {
414430
it('creates IAM session and logs in', async function () {
415-
const mockResponse = {
416-
id: 'test-credential-id',
417-
credentials: {
418-
accessKeyId: 'encrypted-access-key',
419-
secretAccessKey: 'encrypted-secret-key',
420-
sessionToken: 'encrypted-session-token',
421-
},
422-
updateCredentialsParams: {
423-
data: 'credential-data',
424-
},
425-
}
426-
427431
const mockIamLogin = {
428432
login: sinon.stub().resolves(mockResponse),
429433
loginType: 'iam',
430434
}
431435

432436
sinon.stub(auth2, 'IamLogin').returns(mockIamLogin as any)
433437

434-
const response = await auth.loginIam('accessKey', 'secretKey', 'sessionToken')
438+
const response = await auth.loginIam({
439+
accessKey: 'testAccessKey',
440+
secretKey: 'testSecretKey',
441+
sessionToken: 'testSessionToken',
442+
})
435443

436444
assert.ok(mockIamLogin.login.calledOnce)
437445
assert.ok(
438-
mockIamLogin.login.calledWith({
439-
accessKey: 'accessKey',
440-
secretKey: 'secretKey',
446+
mockIamLogin.login.calledWithMatch({
447+
accessKey: 'testAccessKey',
448+
secretKey: 'testSecretKey',
449+
sessionToken: 'testSessionToken',
441450
})
442451
)
443452
assert.strictEqual(response, mockResponse)
444453
})
454+
455+
it('creates IAM session with role ARN', async function () {
456+
const mockIamLoginArn = {
457+
login: sinon.stub().resolves(mockResponse),
458+
loginType: 'iam',
459+
}
460+
461+
sinon.stub(auth2, 'IamLogin').returns(mockIamLoginArn as any)
462+
463+
const opts: auth2.IamProfileOptions = {
464+
accessKey: 'testAccessKey',
465+
secretKey: 'testSecretKey',
466+
sessionToken: 'testSessionToken',
467+
roleArn: 'arn:aws:iam::123456789012:role/TestRole',
468+
}
469+
470+
const response = await auth.loginIam(opts)
471+
472+
assert.ok(mockIamLoginArn.login.calledOnce)
473+
assert.ok(mockIamLoginArn.login.calledWith(opts))
474+
assert.strictEqual(response, mockResponse)
475+
})
445476
})
446477

447478
describe('getIamCredential', function () {

packages/core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,8 @@
443443
"@aws-sdk/types": "^3.13.1",
444444
"@aws/chat-client": "^0.1.4",
445445
"@aws/chat-client-ui-types": "^0.1.53",
446-
"@aws/language-server-runtimes": "^0.2.111",
447-
"@aws/language-server-runtimes-types": "^0.1.47",
446+
"@aws/language-server-runtimes": "^0.2.120",
447+
"@aws/language-server-runtimes-types": "^0.1.52",
448448
"@cspotcode/source-map-support": "^0.8.1",
449449
"@sinonjs/fake-timers": "^10.0.2",
450450
"@types/adm-zip": "^0.4.34",

0 commit comments

Comments
 (0)