From 097963c1b7c02b8b02d6596887d226816a284679 Mon Sep 17 00:00:00 2001 From: Megan Mott <59709511+motm32@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:52:05 -0700 Subject: [PATCH] auth: Add changes to be compatible with the new tenant view (#1789) * Add changes for tenant view * change * pass in account instead of session * use getSessionFromVSCode * changes * make account required * get build to pass * add requested changes * requested change * change documentation --- auth/package-lock.json | 12 ++-- auth/package.json | 4 +- auth/src/AzureDevOpsSubscriptionProvider.ts | 4 ++ auth/src/AzureSubscription.ts | 8 ++- auth/src/AzureSubscriptionProvider.ts | 6 +- auth/src/VSCodeAzureSubscriptionProvider.ts | 72 ++++++++++++--------- auth/src/getSessionFromVSCode.ts | 2 +- 7 files changed, 66 insertions(+), 42 deletions(-) diff --git a/auth/package-lock.json b/auth/package-lock.json index d517048acc..430ed5e193 100644 --- a/auth/package-lock.json +++ b/auth/package-lock.json @@ -1,12 +1,12 @@ { "name": "@microsoft/vscode-azext-azureauth", - "version": "2.5.0", + "version": "2.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@microsoft/vscode-azext-azureauth", - "version": "2.5.0", + "version": "2.6.0", "license": "MIT", "dependencies": { "@azure/arm-resources-subscriptions": "^2.1.0", @@ -25,7 +25,7 @@ "@types/node-fetch": "2.6.7", "@types/semver": "^7.3.9", "@types/uuid": "^9.0.1", - "@types/vscode": "1.76.0", + "@types/vscode": "1.93.0", "@typescript-eslint/eslint-plugin": "^5.53.0", "@vscode/test-electron": "^2.3.8", "eslint": "^8.34.0", @@ -581,9 +581,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.76.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.76.0.tgz", - "integrity": "sha512-CQcY3+Fe5hNewHnOEAVYj4dd1do/QHliXaknAEYSXx2KEHUzFibDZSKptCon+HPgK55xx20pR+PBJjf0MomnBA==", + "version": "1.93.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.93.0.tgz", + "integrity": "sha512-kUK6jAHSR5zY8ps42xuW89NLcBpw1kOabah7yv38J8MyiYuOHxLQBi0e7zeXbQgVefDy/mZZetqEFC+Fl5eIEQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { diff --git a/auth/package.json b/auth/package.json index 1bfec98eb1..3c3cd84694 100644 --- a/auth/package.json +++ b/auth/package.json @@ -1,7 +1,7 @@ { "name": "@microsoft/vscode-azext-azureauth", "author": "Microsoft Corporation", - "version": "2.5.0", + "version": "2.6.0", "description": "Azure authentication helpers for Visual Studio Code", "tags": [ "azure", @@ -41,7 +41,7 @@ "@types/node-fetch": "2.6.7", "@types/semver": "^7.3.9", "@types/uuid": "^9.0.1", - "@types/vscode": "1.76.0", + "@types/vscode": "1.93.0", "@typescript-eslint/eslint-plugin": "^5.53.0", "@vscode/test-electron": "^2.3.8", "eslint": "^8.34.0", diff --git a/auth/src/AzureDevOpsSubscriptionProvider.ts b/auth/src/AzureDevOpsSubscriptionProvider.ts index d890f9cd3a..757d6b4492 100644 --- a/auth/src/AzureDevOpsSubscriptionProvider.ts +++ b/auth/src/AzureDevOpsSubscriptionProvider.ts @@ -132,6 +132,10 @@ export class AzureDevOpsSubscriptionProvider implements AzureSubscriptionProvide subscriptionId: subscription.subscriptionId!, /* eslint-enable @typescript-eslint/no-non-null-assertion */ tenantId, + account: { + id: "test-account-id", + label: "test-account", + }, }); } diff --git a/auth/src/AzureSubscription.ts b/auth/src/AzureSubscription.ts index 8a3039f778..45c70426d9 100644 --- a/auth/src/AzureSubscription.ts +++ b/auth/src/AzureSubscription.ts @@ -5,7 +5,8 @@ import type { TokenCredential } from '@azure/core-auth'; import type { Environment } from '@azure/ms-rest-azure-env'; -import type { AzureAuthentication } from './AzureAuthentication'; +import * as vscode from "vscode"; +import { AzureAuthentication } from './AzureAuthentication'; /** * A type representing an Azure subscription ID, not including the tenant ID. @@ -55,4 +56,9 @@ export interface AzureSubscription { * The credential for authentication to this subscription. Compatible with Azure track 2 SDKs. */ readonly credential: TokenCredential; + + /** + * The account associated with this subscription. + */ + readonly account: vscode.AuthenticationSessionAccountInformation; } diff --git a/auth/src/AzureSubscriptionProvider.ts b/auth/src/AzureSubscriptionProvider.ts index ff08dea3e3..0f2d45ea62 100644 --- a/auth/src/AzureSubscriptionProvider.ts +++ b/auth/src/AzureSubscriptionProvider.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import type { TenantIdDescription } from '@azure/arm-resources-subscriptions'; import type * as vscode from 'vscode'; import type { AzureSubscription } from './AzureSubscription'; -import type { TenantIdDescription } from '@azure/arm-resources-subscriptions'; /** * An interface for obtaining Azure subscription information @@ -15,9 +15,11 @@ export interface AzureSubscriptionProvider { * Gets a list of tenants available to the user. * Use {@link isSignedIn} to check if the user is signed in to a particular tenant. * + * @param account - Optionally pass in a specific account to get tenants for. + * * @returns A list of tenants. */ - getTenants(): Promise; + getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise; /** * Gets a list of Azure subscriptions available to the user. diff --git a/auth/src/VSCodeAzureSubscriptionProvider.ts b/auth/src/VSCodeAzureSubscriptionProvider.ts index 9b04dbd0e2..042bf7aab4 100644 --- a/auth/src/VSCodeAzureSubscriptionProvider.ts +++ b/auth/src/VSCodeAzureSubscriptionProvider.ts @@ -6,11 +6,11 @@ import type { SubscriptionClient, TenantIdDescription } from '@azure/arm-resources-subscriptions'; // Keep this as `import type` to avoid actually loading the package before necessary import type { TokenCredential } from '@azure/core-auth'; // Keep this as `import type` to avoid actually loading the package (at all, this one is dev-only) import * as vscode from 'vscode'; -import type { AzureAuthentication } from './AzureAuthentication'; -import type { AzureSubscription, SubscriptionId, TenantId } from './AzureSubscription'; -import type { AzureSubscriptionProvider } from './AzureSubscriptionProvider'; -import { NotSignedInError } from './NotSignedInError'; +import { AzureAuthentication } from './AzureAuthentication'; +import { AzureSubscription, SubscriptionId, TenantId } from './AzureSubscription'; +import { AzureSubscriptionProvider } from './AzureSubscriptionProvider'; import { getSessionFromVSCode } from './getSessionFromVSCode'; +import { NotSignedInError } from './NotSignedInError'; import { getConfiguredAuthProviderId, getConfiguredAzureEnv } from './utils/configuredAzureEnv'; const EventDebounce = 5 * 1000; // 5 seconds @@ -56,15 +56,19 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement * Gets a list of tenants available to the user. * Use {@link isSignedIn} to check if the user is signed in to a particular tenant. * + * @param account (Optional) A specific account to get tenants for. If not provided, all accounts will be used. + * * @returns A list of tenants. */ - public async getTenants(): Promise { - const { client } = await this.getSubscriptionClient(); - + public async getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise { const results: TenantIdDescription[] = []; - for await (const tenant of client.tenants.list()) { - results.push(tenant); + for await (account of account ? [account] : await vscode.authentication.getAccounts(getConfiguredAuthProviderId())) { + const { client } = await this.getSubscriptionClient(account, undefined, undefined); + + for await (const tenant of client.tenants.list()) { + results.push(tenant); + } } return results; @@ -91,23 +95,26 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement try { this.suppressSignInEvents = true; - // Get the list of tenants - for (const tenant of await this.getTenants()) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const tenantId = tenant.tenantId!; - - // If filtering is enabled, and the current tenant is not in that list, then skip it - if (shouldFilterTenants && !tenantIds.includes(tenantId)) { - continue; - } - - // If the user is not signed in to this tenant, then skip it - if (!(await this.isSignedIn(tenantId))) { - continue; + // Get the list of tenants from each account + const accounts = await vscode.authentication.getAccounts(getConfiguredAuthProviderId()); + for (const account of accounts) { + for (const tenant of await this.getTenants(account)) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const tenantId = tenant.tenantId!; + + // If filtering is enabled, and the current tenant is not in that list, then skip it + if (shouldFilterTenants && !tenantIds.includes(tenantId)) { + continue; + } + + // If the user is not signed in to this tenant, then skip it + if (!(await this.isSignedIn(tenantId))) { + continue; + } + + // For each tenant, get the list of subscriptions + results.push(...await this.getSubscriptionsForTenant(tenantId, account)); } - - // For each tenant, get the list of subscriptions - results.push(...await this.getSubscriptionsForTenant(tenantId)); } } finally { this.suppressSignInEvents = false; @@ -204,11 +211,12 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement * Gets the subscriptions for a given tenant. * * @param tenantId The tenant ID to get subscriptions for. + * @param account The account to get the subscriptions for. * * @returns The list of subscriptions for the tenant. */ - private async getSubscriptionsForTenant(tenantId: string): Promise { - const { client, credential, authentication } = await this.getSubscriptionClient(tenantId); + private async getSubscriptionsForTenant(tenantId: string, account: vscode.AuthenticationSessionAccountInformation): Promise { + const { client, credential, authentication } = await this.getSubscriptionClient(account, tenantId, undefined); const environment = getConfiguredAzureEnv(); const subscriptions: AzureSubscription[] = []; @@ -224,6 +232,7 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement subscriptionId: subscription.subscriptionId!, /* eslint-enable @typescript-eslint/no-non-null-assertion */ tenantId: tenantId, + account: account }); } @@ -234,12 +243,15 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement * Gets a fully-configured subscription client for a given tenant ID * * @param tenantId (Optional) The tenant ID to get a client for + * @param account The account that you would like to get the session for * * @returns A client, the credential used by the client, and the authentication function */ - private async getSubscriptionClient(tenantId?: string, scopes?: string[]): Promise<{ client: SubscriptionClient, credential: TokenCredential, authentication: AzureAuthentication }> { + private async getSubscriptionClient(account: vscode.AuthenticationSessionAccountInformation, tenantId?: string, scopes?: string[]): Promise<{ client: SubscriptionClient, credential: TokenCredential, authentication: AzureAuthentication }> { const armSubs = await import('@azure/arm-resources-subscriptions'); - const session = await getSessionFromVSCode(scopes, tenantId, { createIfNone: false, silent: true }); + + const session = await getSessionFromVSCode(scopes, tenantId, { createIfNone: false, silent: true, account }); + if (!session) { throw new NotSignedInError(); } @@ -262,7 +274,7 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement authentication: { getSession: () => session, getSessionWithScopes: (scopes) => { - return getSessionFromVSCode(scopes, tenantId, { createIfNone: false, silent: true }) + return getSessionFromVSCode(scopes, tenantId, { createIfNone: false, silent: true, account }); }, } }; diff --git a/auth/src/getSessionFromVSCode.ts b/auth/src/getSessionFromVSCode.ts index 1a24ba8649..d58c3fca55 100644 --- a/auth/src/getSessionFromVSCode.ts +++ b/auth/src/getSessionFromVSCode.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getConfiguredAuthProviderId, getConfiguredAzureEnv } from "./utils/configuredAzureEnv"; import * as vscode from "vscode"; +import { getConfiguredAuthProviderId, getConfiguredAzureEnv } from "./utils/configuredAzureEnv"; function ensureEndingSlash(value: string): string { return value.endsWith('/') ? value : `${value}/`;