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 2 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
8 changes: 4 additions & 4 deletions auth/package-lock.json

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

2 changes: 1 addition & 1 deletion auth/package.json
Original file line number Diff line number Diff line change
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
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. This is optional as we only need the account if there are duplicate subscriptions.
*/
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 session - Optionally pass in a specific vscode sesssion to get tenants for.
*
* @returns A list of tenants.
*/
getTenants(): Promise<TenantIdDescription[]>;
getTenants(session?: vscode.AuthenticationSession): Promise<TenantIdDescription[]>;

/**
* Gets a list of Azure subscriptions available to the user.
Expand Down
65 changes: 39 additions & 26 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 @@ -58,8 +58,8 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement
*
* @returns A list of tenants.
*/
public async getTenants(): Promise<TenantIdDescription[]> {
const { client } = await this.getSubscriptionClient();
public async getTenants(session?: vscode.AuthenticationSession): Promise<TenantIdDescription[]> {
const { client } = await this.getSubscriptionClient(undefined, undefined, session);

const results: TenantIdDescription[] = [];

Expand Down Expand Up @@ -91,24 +91,29 @@ 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;
// Get the list of tenants from each account
const accounts = await vscode.authentication.getAccounts(getConfiguredAuthProviderId());
for (const account of accounts) {
const session = await vscode.authentication.getSession(getConfiguredAuthProviderId(), ['https://management.azure.com/.default'], { account: account });
for (const tenant of await this.getTenants(session)) {
// 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));
}

// 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));
}

} finally {
this.suppressSignInEvents = false;
}
Expand Down Expand Up @@ -207,8 +212,8 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement
*
* @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(tenantId, undefined, undefined, account);
const environment = getConfiguredAzureEnv();

const subscriptions: AzureSubscription[] = [];
Expand All @@ -224,6 +229,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 @@ -237,9 +243,16 @@ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable implement
*
* @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(tenantId?: string, scopes?: string[], session?: vscode.AuthenticationSession, account?: vscode.AuthenticationSessionAccountInformation): 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 });
if (!session) {
if (account) {
session = await getSessionFromVSCode(scopes, tenantId, { createIfNone: false, silent: true, account: account }); //pass in account
} else {
session = await getSessionFromVSCode(scopes, tenantId, { createIfNone: false, silent: true });
}
}

if (!session) {
throw new NotSignedInError();
}
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
1 change: 1 addition & 0 deletions auth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './AzureAuthentication';
export * from './AzureDevOpsSubscriptionProvider';
export * from './AzureSubscription';
export * from './AzureSubscriptionProvider';
export * from './getSessionFromVSCode';
export * from './NotSignedInError';
export * from './signInToTenant';
export * from './utils/configuredAzureEnv';
Expand Down
Loading