Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion runtimes/protocol/identity-management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export interface ListProfilesResult {
// Potential error codes: E_UNKNOWN | E_TIMEOUT | E_RUNTIME_NOT_SUPPORTED | E_CANNOT_READ_SHARED_CONFIG
export const listProfilesRequestType = new ProtocolRequestType<
ListProfilesParams,
ListProfilesResult,
ListProfilesResult | string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid having two different types of responses? Clients written in different languages will receive a json blob, and cannot reliably differentiate a structured type from a string.

never,
AwsResponseError,
void
Expand Down Expand Up @@ -400,3 +400,13 @@ export interface StsCredentialChangedParams {
export const stsCredentialChangedRequestType = new ProtocolNotificationType<StsCredentialChangedParams, void>(
'aws/identity/stsCredentialChanged'
)

// profileChanged
export interface ProfileChangedParams {
profiles: Profile[]
ssoSessions: SsoSession[]
}

export const profileChangedRequestType = new ProtocolNotificationType<ProfileChangedParams | string, void>(
'aws/identity/stsCredentialChanged'
)
21 changes: 15 additions & 6 deletions runtimes/runtimes/auth/standalone/encryption.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Readable } from 'stream'
import { CompactEncrypt } from 'jose'
import { compactDecrypt, CompactEncrypt } from 'jose'
import { GetIamCredentialResult, GetSsoTokenResult } from '../../../protocol'

export function shouldWaitForEncryptionKey(): boolean {
Expand Down Expand Up @@ -99,6 +99,15 @@ export function encryptObjectWithKey(request: Object, key: string, alg?: string,
.encrypt(keyBuffer)
}

/**
* Decrypt an object with the provided key
*/
export async function decryptObjectWithKey<T>(request: string, key: string): Promise<T> {
const keyBuffer = Buffer.from(key, 'base64')
const result = await compactDecrypt(request, keyBuffer)
return JSON.parse(new TextDecoder().decode(result.plaintext)) as T
}

/**
* Encrypts the SSO access tokens inside the result object with the provided key
*/
Expand All @@ -124,12 +133,12 @@ export async function encryptIamResultWithKey(
request: GetIamCredentialResult,
key: string
): Promise<GetIamCredentialResult> {
const { accessKeyId, secretAccessKey, sessionToken, expiration } = request.credential.credentials
request.credential.credentials = {
accessKeyId: await encryptObjectWithKey(request.credential.credentials.accessKeyId, key),
secretAccessKey: await encryptObjectWithKey(request.credential.credentials.secretAccessKey, key),
...(request.credential.credentials.sessionToken
? { sessionToken: await encryptObjectWithKey(request.credential.credentials.sessionToken, key) }
: {}),
accessKeyId: await encryptObjectWithKey(accessKeyId, key),
secretAccessKey: await encryptObjectWithKey(secretAccessKey, key),
sessionToken: sessionToken ? await encryptObjectWithKey(sessionToken, key) : undefined,
expiration: expiration,
}
if (!request.updateCredentialsParams.encrypted) {
request.updateCredentialsParams.data = await encryptObjectWithKey(
Expand Down
2 changes: 2 additions & 0 deletions runtimes/runtimes/base-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ import {
updateProfileRequestType,
stsCredentialChangedRequestType,
getMfaCodeRequestType,
profileChangedRequestType,
} from '../protocol/identity-management'
import { IdentityManagement } from '../server-interface/identity-management'
import { WebBase64Encoding } from './encoding'
Expand Down Expand Up @@ -218,6 +219,7 @@ export const baseRuntime = (connections: { reader: MessageReader; writer: Messag
onInvalidateStsCredential: handler => lspConnection.onRequest(invalidateStsCredentialRequestType, handler),
sendSsoTokenChanged: params => lspConnection.sendNotification(ssoTokenChangedRequestType, params),
sendStsCredentialChanged: params => lspConnection.sendNotification(stsCredentialChangedRequestType, params),
sendProfileChanged: params => lspConnection.sendNotification(profileChangedRequestType, params),
sendGetMfaCode: params => lspConnection.sendRequest(getMfaCodeRequestType, params),
}

Expand Down
30 changes: 28 additions & 2 deletions runtimes/runtimes/standalone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ import {
ShowOpenDialogRequestType,
stsCredentialChangedRequestType,
getMfaCodeRequestType,
profileChangedRequestType,
UpdateProfileParams,
ListProfilesParams,
} from '../protocol'
import { ProposedFeatures, createConnection } from 'vscode-languageserver/node'
import {
decryptObjectWithKey,
encryptIamResultWithKey,
EncryptionInitialization,
encryptObjectWithKey,
Expand Down Expand Up @@ -304,8 +308,26 @@ export const standalone = (props: RuntimeProps) => {
}

const identityManagement: IdentityManagement = {
onListProfiles: handler => lspConnection.onRequest(listProfilesRequestType, handler),
onUpdateProfile: handler => lspConnection.onRequest(updateProfileRequestType, handler),
onListProfiles: handler =>
lspConnection.onRequest(
listProfilesRequestType,
async (params: ListProfilesParams, token: CancellationToken) => {
let result = await handler(params, token)
if (result && !(result instanceof Error) && encryptionKey) {
return await encryptObjectWithKey(result, encryptionKey)
}
return result
}
),
onUpdateProfile: handler =>
lspConnection.onRequest(
updateProfileRequestType,
async (params: UpdateProfileParams | string, token: CancellationToken) => {
const decrypted: UpdateProfileParams =
typeof params === 'string' ? await decryptObjectWithKey(params, encryptionKey!) : params
return await handler(decrypted, token)
}
),
onGetSsoToken: handler =>
lspConnection.onRequest(
getSsoTokenRequestType,
Expand All @@ -332,6 +354,10 @@ export const standalone = (props: RuntimeProps) => {
onInvalidateStsCredential: handler => lspConnection.onRequest(invalidateStsCredentialRequestType, handler),
sendSsoTokenChanged: params => lspConnection.sendNotification(ssoTokenChangedRequestType, params),
sendStsCredentialChanged: params => lspConnection.sendNotification(stsCredentialChangedRequestType, params),
sendProfileChanged: async params => {
const encrypted = encryptionKey ? await encryptObjectWithKey(params, encryptionKey) : params
lspConnection.sendNotification(profileChangedRequestType, encrypted)
},
sendGetMfaCode: params => lspConnection.sendRequest(getMfaCodeRequestType, params),
}

Expand Down
3 changes: 3 additions & 0 deletions runtimes/server-interface/identity-management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
UpdateProfileParams,
UpdateProfileResult,
GetMfaCodeResult,
ProfileChangedParams,
} from '../protocol/identity-management'
import { RequestHandler } from '../protocol'

Expand Down Expand Up @@ -54,5 +55,7 @@ export type IdentityManagement = {

sendStsCredentialChanged: (params: StsCredentialChangedParams) => void

sendProfileChanged: (params: ProfileChangedParams) => void

sendGetMfaCode: (params: GetMfaCodeParams) => Promise<GetMfaCodeResult>
}
Loading