From 1eeb2a484c379d1606c57d7df356d24d50a13df8 Mon Sep 17 00:00:00 2001 From: Alex Weininger Date: Wed, 4 Oct 2023 17:33:50 -0400 Subject: [PATCH] Remove use of AAD Graph for cloud shell (#851) --- src/cloudConsole/cloudConsole.ts | 89 ++++++++++---------------------- 1 file changed, 28 insertions(+), 61 deletions(-) diff --git a/src/cloudConsole/cloudConsole.ts b/src/cloudConsole/cloudConsole.ts index 17640ad..dd4add0 100644 --- a/src/cloudConsole/cloudConsole.ts +++ b/src/cloudConsole/cloudConsole.ts @@ -9,7 +9,6 @@ import * as FormData from 'form-data'; import { ReadStream } from 'fs'; import * as http from 'http'; import { ClientRequest } from 'http'; -import { DeviceTokenCredentials } from 'ms-rest-azure'; import { Socket } from 'net'; import { Response } from 'node-fetch'; import * as path from 'path'; @@ -380,7 +379,7 @@ export function createCloudConsole(api: AzureAccountExtensionApi, osName: OSName .then(tenantDetails => tenantDetails.map(details => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const tenantDetails: TenantDetails = details!.tenantDetails; - const defaultDomainName: string | undefined = (tenantDetails.verifiedDomains.find(domain => domain.default))?.name; + const defaultDomainName: string | undefined = tenantDetails.defaultDomain; return { label: tenantDetails.displayName, description: defaultDomainName, @@ -388,9 +387,9 @@ export function createCloudConsole(api: AzureAccountExtensionApi, osName: OSName session: details!.session }; }).sort((a, b) => a.label.localeCompare(b.label))), { - placeHolder: localize('azure-account.selectDirectoryPlaceholder', "Select directory"), - ignoreFocusOut: true // The terminal opens concurrently and can steal focus (https://github.com/microsoft/vscode-azure-account/issues/77). - }); + placeHolder: localize('azure-account.selectDirectoryPlaceholder', "Select directory"), + ignoreFocusOut: true // The terminal opens concurrently and can steal focus (https://github.com/microsoft/vscode-azure-account/issues/77). + }); if (!pick) { context.telemetry.properties.outcome = 'noTenantPicked'; serverQueue.push({ type: 'exit' }); @@ -442,17 +441,12 @@ export function createCloudConsole(api: AzureAccountExtensionApi, osName: OSName } } - // Additional tokens - const [graphToken, keyVaultToken] = await Promise.all([ - tokenFromRefreshToken(session.environment, result.token.refreshToken, session.tenantId, session.environment.activeDirectoryGraphResourceId), - session.environment.keyVaultDnsSuffix + const keyVaultToken = session.environment.keyVaultDnsSuffix // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - ? tokenFromRefreshToken(session.environment, result.token.refreshToken, session.tenantId, `https://${session.environment.keyVaultDnsSuffix!.substr(1)}`) - : Promise.resolve(undefined) - ]); + ? await tokenFromRefreshToken(session.environment, result.token.refreshToken, session.tenantId, `https://${session.environment.keyVaultDnsSuffix!.substr(1)}`) + : undefined; const accessTokens: AccessTokens = { resource: accessToken, - graph: graphToken.accessToken, keyVault: keyVaultToken && keyVaultToken.accessToken }; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -566,7 +560,7 @@ async function acquireToken(session: AzureSession): Promise { const environment: any = session.environment; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call credentials.context.acquireToken(environment.activeDirectoryResourceId, credentials.username, credentials.clientId, function (err: any, result: any) { - /* eslint-enable @typescript-eslint/no-explicit-any */ + /* eslint-enable @typescript-eslint/no-explicit-any */ if (err) { reject(err); } else { @@ -585,54 +579,27 @@ async function acquireToken(session: AzureSession): Promise { interface TenantDetails { objectId: string; displayName: string; - verifiedDomains: { name: string; default: boolean; }[]; + domains: string; + defaultDomain: string; } async function fetchTenantDetails(session: AzureSession): Promise<{ session: AzureSession, tenantDetails: TenantDetails }> { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any - const { username, clientId, tokenCache, domain } = (session).credentials; - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const graphCredentials: DeviceTokenCredentials = new DeviceTokenCredentials({ username, clientId, tokenCache, domain, tokenAudience: 'graph' }); - const apiVersion: string = '1.6'; - const requestUrl: string = `https://graph.windows.net/${encodeURIComponent(session.tenantId)}/tenantDetails?api-version=${encodeURIComponent(apiVersion)}`; - - return new Promise((resolve, reject) => { - // eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/no-explicit-any - graphCredentials.getToken(async (err: Error, result: any) => { - if (err) { - reject(err); - return; - } - - if (result) { - try { - const response: Response = await fetchWithLogging(requestUrl, { - headers: { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - Authorization: `Bearer ${result.accessToken}`, - "x-ms-client-request-id": uuid(), - "Content-Type": 'application/json; charset=utf-8' - } - }); - - if (response.ok) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const json = await response.json(); - resolve({ - session, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access - tenantDetails: json.value[0] - }); - } else { - reject(response.statusText) - } - } catch (e) { - reject(e); - } - } - }); + const response: Response = await fetchWithLogging('https://management.azure.com/tenants?api-version=2022-12-01', { + headers: { + Authorization: `Bearer ${(await session.credentials2.getToken([]))?.token}`, + "x-ms-client-request-id": uuid(), + "Content-Type": 'application/json; charset=utf-8' + } }); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const json = await response.json(); + return { + session, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access + tenantDetails: json.value[0] + }; } export interface ExecResult { @@ -670,7 +637,7 @@ export interface UserSettings { export interface AccessTokens { resource: string; - graph: string; + // graph: string; keyVault?: string; } @@ -697,7 +664,7 @@ async function requestWithLogging(requestOptions: request.Options): Promise return response; } catch (e) { const error = parseError(e); - ext.outputChannel.error({...error, name: 'Request Error: CloudConsoleLauncher'}); + ext.outputChannel.error({ ...error, name: 'Request Error: CloudConsoleLauncher' }); } } @@ -734,7 +701,7 @@ export async function getUserSettings(accessToken: string, armEndpoint: string): /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */ export async function provisionConsole(accessToken: string, armEndpoint: string, userSettings: UserSettings, osType: string): Promise { let response = await createTerminal(accessToken, armEndpoint, userSettings, osType, true); - for (let i = 0; i < 10; i++ , response = await createTerminal(accessToken, armEndpoint, userSettings, osType, false)) { + for (let i = 0; i < 10; i++, response = await createTerminal(accessToken, armEndpoint, userSettings, osType, false)) { if (response.statusCode < 200 || response.statusCode > 299) { if (response.statusCode === 409 && response.body && response.body.error && response.body.error.code === Errors.DeploymentOsTypeConflict) { throw new Error(Errors.DeploymentOsTypeConflict); @@ -851,7 +818,7 @@ async function initializeTerminal(accessTokens: AccessTokens, consoleUri: string resolveWithFullResponse: true, json: true, body: { - tokens: accessTokens.keyVault ? [accessTokens.graph, accessTokens.keyVault] : [accessTokens.graph] + tokens: accessTokens.keyVault ? [accessTokens.keyVault] : [] } }); } \ No newline at end of file