Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auth: Add changes to be compatible with the new tenant view #1789

Merged
merged 10 commits into from
Sep 19, 2024
Merged
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: 6 additions & 6 deletions auth/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions auth/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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",
Expand Down
4 changes: 4 additions & 0 deletions auth/src/AzureDevOpsSubscriptionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
});
}

Expand Down
8 changes: 7 additions & 1 deletion auth/src/AzureSubscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
6 changes: 4 additions & 2 deletions auth/src/AzureSubscriptionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<TenantIdDescription[]>;
getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise<TenantIdDescription[]>;

/**
* Gets a list of Azure subscriptions available to the user.
Expand Down
72 changes: 42 additions & 30 deletions auth/src/VSCodeAzureSubscriptionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<TenantIdDescription[]> {
const { client } = await this.getSubscriptionClient();

public async getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise<TenantIdDescription[]> {
alexweininger marked this conversation as resolved.
Show resolved Hide resolved
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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<AzureSubscription[]> {
const { client, credential, authentication } = await this.getSubscriptionClient(tenantId);
private async getSubscriptionsForTenant(tenantId: string, account: vscode.AuthenticationSessionAccountInformation): Promise<AzureSubscription[]> {
const { client, credential, authentication } = await this.getSubscriptionClient(account, tenantId, undefined);
const environment = getConfiguredAzureEnv();

const subscriptions: AzureSubscription[] = [];
Expand All @@ -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
});
}

Expand All @@ -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();
}
Expand All @@ -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 });
},
}
};
Expand Down
2 changes: 1 addition & 1 deletion auth/src/getSessionFromVSCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}/`;
Expand Down
Loading