Skip to content

Commit 0ef9118

Browse files
committed
add sts management and mfa
1 parent 6722fb3 commit 0ef9118

File tree

18 files changed

+388
-100
lines changed

18 files changed

+388
-100
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/src/lsp/client.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import {
3030
ResponseError,
3131
LSPErrorCodes,
3232
updateConfigurationRequestType,
33+
GetMfaCodeParams,
34+
GetMfaCodeResult,
3335
} from '@aws/language-server-runtimes/protocol'
3436
import {
3537
AuthUtil,
@@ -56,7 +58,7 @@ import { processUtils } from 'aws-core-vscode/shared'
5658
import { activate as activateChat } from './chat/activation'
5759
import { activate as activeInlineChat } from '../inlineChat/activation'
5860
import { AmazonQResourcePaths } from './lspInstaller'
59-
import { auth2 } from 'aws-core-vscode/auth'
61+
import { auth2, getMfaTokenFromUser, getMfaSerialFromUser } from 'aws-core-vscode/auth'
6062
import { ConfigSection, isValidConfigSection, pushConfigUpdate, toAmazonQLSPLogLevel } from './config'
6163
import { telemetry } from 'aws-core-vscode/telemetry'
6264
import { SessionManager } from '../app/inline/sessionManager'
@@ -164,6 +166,9 @@ export async function startLanguageServer(
164166
},
165167
credentials: {
166168
providesBearerToken: true,
169+
// Add IAM credentials support
170+
providesIamCredentials: true,
171+
supportsAssumeRole: true,
167172
},
168173
},
169174
/**
@@ -211,9 +216,10 @@ export async function startLanguageServer(
211216

212217
/** All must be setup before {@link AuthUtil.restore} otherwise they may not trigger when expected */
213218
AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(async () => {
219+
const activeProfile = AuthUtil.instance.regionProfileManager.activeRegionProfile
214220
void pushConfigUpdate(client, {
215221
type: 'profile',
216-
profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn,
222+
profileArn: activeProfile?.arn,
217223
})
218224
})
219225

@@ -333,6 +339,24 @@ async function postStartLanguageServer(
333339
}
334340
)
335341

342+
// Handler for when Flare needs to assume a role with MFA code
343+
client.onRequest(
344+
auth2.notificationTypes.getMfaCode.method,
345+
async (params: GetMfaCodeParams): Promise<GetMfaCodeResult> => {
346+
if (params.mfaSerial) {
347+
globals.globalState.update('recentMfaSerial', { mfaSerial: params.mfaSerial })
348+
}
349+
const defaultMfaSerial = globals.globalState.tryGet('recentMfaSerial', Object, {
350+
mfaSerial: '',
351+
}).mfaSerial
352+
let mfaSerial = await getMfaSerialFromUser(defaultMfaSerial, params.profileName)
353+
mfaSerial = mfaSerial.trim()
354+
await globals.globalState.update('recentMfaSerial', { mfaSerial: mfaSerial })
355+
const mfaCode = await getMfaTokenFromUser(mfaSerial, params.profileName)
356+
return { code: mfaCode ?? '', mfaSerial: mfaSerial ?? '' }
357+
}
358+
)
359+
336360
const sendProfileToLsp = async () => {
337361
try {
338362
const result = await client.sendRequest(updateConfigurationRequestType.method, {

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

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,50 @@ describe('AuthUtil', async function () {
435435

436436
assert.ok(mockIamLogin.login.calledOnce)
437437
assert.ok(
438-
mockIamLogin.login.calledWith({
438+
mockIamLogin.login.calledWithMatch({
439439
accessKey: 'accessKey',
440440
secretKey: 'secretKey',
441+
sessionToken: 'sessionToken',
442+
})
443+
)
444+
assert.strictEqual(response, mockResponse)
445+
})
446+
447+
it('creates IAM session with role ARN', async function () {
448+
const mockResponse = {
449+
id: 'test-credential-id',
450+
credentials: {
451+
accessKeyId: 'encrypted-access-key',
452+
secretAccessKey: 'encrypted-secret-key',
453+
sessionToken: 'encrypted-session-token',
454+
roleArn: 'arn:aws:iam::123456789012:role/TestRole',
455+
},
456+
updateCredentialsParams: {
457+
data: 'credential-data',
458+
},
459+
}
460+
461+
const mockIamLoginArn = {
462+
login: sinon.stub().resolves(mockResponse),
463+
loginType: 'iam',
464+
}
465+
466+
sinon.stub(auth2, 'IamLogin').returns(mockIamLoginArn as any)
467+
468+
const response = await auth.loginIam(
469+
'accessKey',
470+
'secretKey',
471+
'sessionToken',
472+
'arn:aws:iam::123456789012:role/TestRole'
473+
)
474+
475+
assert.ok(mockIamLoginArn.login.calledOnce)
476+
assert.ok(
477+
mockIamLoginArn.login.calledWith({
478+
accessKey: 'accessKey',
479+
secretKey: 'secretKey',
480+
sessionToken: 'sessionToken',
481+
roleArn: 'arn:aws:iam::123456789012:role/TestRole',
441482
})
442483
)
443484
assert.strictEqual(response, mockResponse)

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)