@microsoft/vscode-azext-azureauth 2.4.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,174 @@
1
+ # Setting up workflow identity federation with Azure DevOps
2
+
3
+ This guide describes how to set up your Azure DevOps (ADO) and Azure environment to leverage [workflow identity federation](https://learn.microsoft.com/entra/workload-id/workload-identity-federation), enabling you to use
4
+ `AzureDevOpsSubscriptionProvider` provided in this section. See the [README](README.md#azure-devops-subscription-provider) for more details.
5
+
6
+ ## 1. Create a new service principal
7
+
8
+ Create a new service principal on which you will assign the necessary permissions. In this example, we use an app registration:
9
+
10
+ 1. Navigate to the [App Registrations](https://ms.portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade) page on the Azure portal
11
+ 2. Click on `New Registration`
12
+
13
+ ![New Registration](guide-imgs/app_registration.jpg)
14
+
15
+ 3. Assign any name
16
+ 4. Make sure to select the first option for the account type (`Accounts in this organization directory only (Microsoft only - Single tenant)`)
17
+ 5. Leave the Redirect URI and Service Tree ID fields empty
18
+ 6. Click on `Register`
19
+
20
+ ![Register an application](guide-imgs/app_registration_2.jpg)
21
+
22
+ ## 2. Create a new Azure DevOps (ADO) Service Connection:
23
+
24
+ Create a new ADO service connection under your organization's project. In this example, we create it under the DevDiv project:
25
+
26
+ 1. Navigate to the [organization's (DevDiv) ADO page](https://devdiv.visualstudio.com/DevDiv)
27
+ 2. Navigate to the settings page by clicking on the gear icon on the bottom left
28
+ 3. Select the ["service connections"](https://devdiv.visualstudio.com/DevDiv/_settings/adminservices) blade from the panel on the left
29
+
30
+ ![Select service connection](guide-imgs/service_connection_1.jpg)
31
+
32
+ 4. Create a new service connection by clicking on the `New service connection` button
33
+
34
+ ![Click on new service connection](guide-imgs/service_connection_2.jpg)
35
+
36
+ 5. Select `Azure Resource Manager` as the type
37
+ 6. Select `Workload Identity federation (manual)` for the authentication type
38
+ 7. Provide a new name for your new service connection
39
+ 8. Click on `Next`
40
+ 9. This will create a new draft service connection, with the `issuer` and `subject identifier` fields already filled in.
41
+ 10. Leave this window open while you finish the next step, which will require those `issuer` and `subject identifier` fields, then you will return to this window to finish creating the service principal
42
+
43
+ ![Draft service connectoin screen](guide-imgs/service_connection_3.jpg)
44
+
45
+ ## 3. Create a federated credential:
46
+
47
+ Create a new "federated credential" on your service principal to connect it to your new service connection:
48
+
49
+ 1. Navigate back to the Azure Portal page for your service connection (app registration) from step 1
50
+ 2. Navigate to the `Certificates & secrets` blade
51
+ 3. Navigate to the `Federated credentials` tab
52
+ 4. Click on the `Add credential` button
53
+
54
+ ![Add federated credential](guide-imgs/credential_1.jpg)
55
+
56
+ 5. For the scenario, select `Other issuer`
57
+ 6. For the `issuer` and `subject identifier` fields, fill in with the details of your draft service connection from the previous step
58
+ 7. Select a new name for your new federated credential
59
+
60
+ ![Fill in issuer, subject identifier, and name fields](guide-imgs/credential_2.jpg)
61
+
62
+ 8. Click on `Add`
63
+
64
+ ## 4. (Temporary but required) Grant your service principal reader role on the desired subscription:
65
+
66
+ This step is not required for running your tests, but _is_ required to finish creating the service connection. This should be revoked after successful creation of the service connection and only necessary roles applied to the service principal.
67
+
68
+ 1. On the Azure Portal, navigate to the page for the subscription you want the service principal to have access to.
69
+ 2. Navigate to the `Access control (IAM)` blade
70
+
71
+ ![access control tab](guide-imgs/subscription_1.jpg)
72
+
73
+ 3. Navigate to the `Roles` tab
74
+ 4. Click on the `+ Add` button, and choose `Add role assignment`
75
+
76
+ ![add role](guide-imgs/subscription_2.jpg)
77
+
78
+ 5. Choose `Reader` and click `Next`
79
+ 6. Choose `User, group, or service principal`, then click on `+ Select members`
80
+
81
+ ![select members](guide-imgs/subscription_3.jpg)
82
+
83
+ 7. Select your service principal from step 1
84
+ 8. Click on `Review and assign`
85
+
86
+ ## 5. Finish creating your service connection:
87
+
88
+ Finish creating the draft service connection you created in step 2.
89
+
90
+ 1. Navigate back to your draft service connection from step 2
91
+ 2. For Environment, select `Azure Cloud`
92
+ 3. For Scope Level, choose `Subscription`
93
+ 4. Under `Subscription Id`, and `Subscription Name`, write the subscription ID and name (must provide both) for the desired subscription
94
+ 5. For `Service Principal Id`, provide the `Application (client) ID` of your app registration from step 1 (can be found in the `Overview` blade)
95
+ 6. For the `Tenant ID`, provide the `Directory (tenant) ID` of your app registration from step 1 (can be found in `Overview` blade)
96
+ 7. Click on `Verify and save`
97
+
98
+ ## 6. Revoke unnecessary read access and assign only necessary roles
99
+
100
+ Revoke the `Reader` role on the subscription for the service connection after it is created. This is no longer necessary.
101
+
102
+ 1. Navigate to `Access control (IAM)` blade.
103
+ 2. Under the `Role assignments` tab, find the role assignment corresponding to the App registered on step 1
104
+ 3. Click on `Remove` then `Yes`
105
+ 4. You can then assign the required roles to specific resources only if required, instead of assigning `Reader` role to the entire subscription.
106
+
107
+ ## 7. Create a dummy Key Vault
108
+
109
+ A dummy Key vault step is required to propagate the necessary environment variables in the context of the pipeline.
110
+
111
+ 1. Create a new Key Vault resource in the subscription you want to test on
112
+ 2. Give it a new name as appropriate. You can keep the default settings
113
+
114
+ ![Create key vault](guide-imgs/dummy_kv.jpg)
115
+
116
+ ## 8. Assign your service principal "key vault reader" role on the dummy Key Vault:
117
+
118
+ 1. Navigate to `Access control (IAM)` blade on your newly created dummy key vault
119
+
120
+ ![access control tab](guide-imgs/subscription_1.jpg)
121
+
122
+ 2. Navigate to the `Roles` tab
123
+ 3. Click on the `+ Add` button, and choose `Add role assignment`
124
+
125
+ ![add role](guide-imgs/subscription_2.jpg)
126
+
127
+ 4. Choose `Key Vault Reader` (**NOT** `Reader`) and click `Next`
128
+ 5. Choose `User, group, or service principal`, then click on `+ Select members`
129
+
130
+ ![select members](guide-imgs/subscription_3.jpg)
131
+
132
+ 6. Select your app registration from step 1
133
+ 7. Click on `Review and assign`
134
+
135
+ ## 9. Add the dummy Key Vault step in the pipeline
136
+
137
+ To ensure that the appropriate env variables are propagated in the context of running the pipeline, a dummy Key Vault step is required in that pipeline:
138
+
139
+ 1. In the desired pipeline's `.yml` file, add a step as below. The `azureSubscription` field should correspond to the name of your service connection from step 2, while the `keyVaultName` field should correspond to the dummy key vault created in step 7:
140
+
141
+ ```yml
142
+ # This gives the TestServiceConnection service connection access to this pipeline.
143
+ - task: AzureKeyVault@1
144
+ displayName: 'Authorize TestServiceConnection service connection'
145
+ inputs:
146
+ azureSubscription: 'TestServiceConnection'
147
+ KeyVaultName: 'TestDummyKeyVault'
148
+ ```
149
+
150
+ 2. In the step which runs your code (e.g., the npm test step), make sure that the `$(System.AccessToken)` variable is manually propagated as a `SYSTEM_ACCESSTOKEN` environment variable. All other required environment variables should be propagated automatically:
151
+
152
+ ```yml
153
+ - task: Npm@1
154
+ displayName: "Test"
155
+ inputs:
156
+ command: custom
157
+ customCommand: test
158
+ env:
159
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
160
+ ```
161
+
162
+ ## 10. Pass the appropriate values to identify your service connection:
163
+
164
+ The constructor for `AzureDevOpsSubscriptionProvider` expects three arguments in an initializer object in order to identify your service connection you setup in step 5.
165
+
166
+ These are:
167
+
168
+ - `serviceConnectionId`: The resource ID of the service connection created in step 2, which can be found on the `resourceId` field of the URL at the address bar, when viewing the service connection in the Azure DevOps portal
169
+ - `domain`: The `Tenant ID` field of the service connection properties, which can be accessed by clicking "Edit" on the service connection page
170
+ - `clientId`: The `Service Principal Id` field of the service connection properties, which can be accessed by clicking "Edit" on the service connection page
171
+
172
+ ![identifier values for service connection](guide-imgs/identifier_values.jpg)
173
+
174
+ Make sure you pass an object containing these variables for the `new AzureDevOpsServiceProvider()` constructor. These values are _not_ secrets, so they can be set as environment variables, assigned as pipeline variables in ADO, accessed and assigned using an Azure Key Vault step, or even manually hardcoded in code (not recommended).
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.0.0 - 2024-09-19
4
+ * [#1789](https://github.com/microsoft/vscode-azuretools/pull/1789) Change `getTenants` to be compatible with the new Azure Resources tenants view. This also includes a possible breaking change where an optional parameter `account` which when passed in `getTenants` will return the tenants associated with that single account. Otherwise `getTenants` will return the tenants for all authenticated accounts.
5
+
6
+ ## 2.5.0 - 2024-08-06
7
+
8
+ * Add `getSessionWithScopes` to get a session that has the proper scoping instead of always the default management plane
9
+
10
+ ## 2.4.1 - 2024-05-15
11
+
12
+ * [#1729](https://github.com/microsoft/vscode-azuretools/pull/1729) Change AzureDevOpsSubscriptionProvider so that it accepts values as arguments
13
+
14
+ ## 2.4.0 - 2024-05-07
15
+
16
+ * [#1723](https://github.com/microsoft/vscode-azuretools/pull/1723) Implementation fo AzureSub provider that leverages federated credentials
17
+
18
+ ## 2.1.0 - 2023-12-13
19
+
20
+ * Use management endpoint for scope by default to fix deploying app service projects with sovereign clouds
21
+
22
+ ## 2.0.0 - 2023-11-20
23
+
24
+ * Switches to use `@azure/arm-resources-subscriptions` instead of `@azure/arm-subscriptions`. Potentially a breaking change so I revved the major version.
25
+ * Fixes an issue where the `endpoint` wasn't set for the subscription client, breaking sovereign clouds
26
+
3
27
  ## 1.4.0 - 2023-11-03
4
28
  * [#1619](https://github.com/microsoft/vscode-azuretools/pull/1619) Make `getSession` synchronous to fix an issue that broke app service deployments
5
29
 
package/README.md CHANGED
@@ -100,6 +100,47 @@ export declare function getConfiguredAzureEnv(): azureEnv.Environment & {
100
100
  export declare function setConfiguredAzureEnv(cloud: string | azureEnv.EnvironmentParameters, target?: vscode.ConfigurationTarget): Promise<void>;
101
101
  ```
102
102
 
103
+ ## Azure DevOps Subscription Provider
104
+
105
+ The auth package also exports `AzureDevOpsSubscriptionProvider`, a class which implements the `AzureSubscriptionProvider` interface, which authenticates via
106
+ a federated Azure DevOps service connection, using [workflow identity federation](https://learn.microsoft.com/entra/workload-id/workload-identity-federation).
107
+
108
+ This provider only works when running in the context of an Azure DevOps pipeline. It can be used to run end-to-end tests that require authentication to Azure,
109
+ without having to manage any secrets, passwords or connection strings.
110
+
111
+ The constructor expects an initializer object with three values set to identify your ADO service connection to be used for authentication.
112
+ These are:
113
+
114
+ - `serviceConnectionId`: The resource ID of your service connection, which can be found on the `resourceId` field of the URL at the address bar, when viewing the service connection in the Azure DevOps portal
115
+ - `domain`: The `Tenant ID` field of the service connection properties, which can be accessed by clicking "Edit" on the service connection page
116
+ - `clientId`: The `Service Principal Id` field of the service connection properties, which can be accessed by clicking "Edit" on the service connection page
117
+
118
+ Here is an example code of how you might use `AzureDevOpsSubscriptionProvider`:
119
+
120
+ ```typescript
121
+ import { AzureDevOpsSubscriptionProviderInitializer, AzureDevOpsSubscriptionProvider } from "@microsoft/vscode-azext-azureauth";
122
+
123
+ const initializer: AzureDevOpsSubscriptionProviderInitializer = {
124
+ serviceConnectionId: "<REPLACE_WITH_SERVICE_CONNECTION_ID>",
125
+ domain: "<REPLACE_WITH_DOMAIN>",
126
+ clientId: "<REPLACE_WITH_CLIENT_ID>",
127
+ }
128
+
129
+ const subscriptionProvider = new AzureDevOpsSubscriptionProvider(initializer);
130
+
131
+ const signedIn = await subscriptionProvider.signIn();
132
+ if (!signedIn) {
133
+ throw new Error("Couldn't sign in");
134
+ }
135
+
136
+ const subscriptions = await subscriptionProvider.getSubscriptions();
137
+
138
+ // logic on the subscriptions object
139
+ ```
140
+
141
+ For more detailed steps on how to setup your Azure environment to use workflow identity federation and use this `AzureDevOpsSubscriptionProvider` object effectively,
142
+ as well as the values needed to pass to `new AzureDevOpsSubscriptionProvider()`, please navigate to the workflow identity federation [guide](AzureFederatedCredentialsGuide.md).
143
+
103
144
  ## Logs
104
145
 
105
146
  View the Microsoft Authentication extension logs by running the `Developer: Show Logs...` command from the VS Code command palette.
@@ -3,6 +3,13 @@ import type * as vscode from 'vscode';
3
3
  * Represents a means of obtaining authentication data for an Azure subscription.
4
4
  */
5
5
  export interface AzureAuthentication {
6
+ /**
7
+ * Gets a VS Code authentication session for an Azure subscription.
8
+ * Always uses the default scope, `https://management.azure.com/.default/` and respects `microsoft-sovereign-cloud.environment` setting.
9
+ *
10
+ * @returns A VS Code authentication session or undefined, if none could be obtained.
11
+ */
12
+ getSession(): vscode.ProviderResult<vscode.AuthenticationSession>;
6
13
  /**
7
14
  * Gets a VS Code authentication session for an Azure subscription.
8
15
  *
@@ -10,5 +17,5 @@ export interface AzureAuthentication {
10
17
  *
11
18
  * @returns A VS Code authentication session or undefined, if none could be obtained.
12
19
  */
13
- getSession(scopes?: string[]): vscode.ProviderResult<vscode.AuthenticationSession>;
20
+ getSessionWithScopes(scopes: string[]): vscode.ProviderResult<vscode.AuthenticationSession>;
14
21
  }
@@ -119,6 +119,10 @@ class AzureDevOpsSubscriptionProvider {
119
119
  subscriptionId: subscription.subscriptionId,
120
120
  /* eslint-enable @typescript-eslint/no-non-null-assertion */
121
121
  tenantId,
122
+ account: {
123
+ id: "test-account-id",
124
+ label: "test-account",
125
+ },
122
126
  });
123
127
  }
124
128
  finally {
@@ -151,23 +155,25 @@ class AzureDevOpsSubscriptionProvider {
151
155
  throw new Error('Not signed in');
152
156
  }
153
157
  const accessToken = ((_b = (yield ((_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.getToken("https://management.azure.com/.default")))) === null || _b === void 0 ? void 0 : _b.token) || '';
158
+ const getSession = () => {
159
+ var _a, _b, _c, _d;
160
+ return {
161
+ accessToken,
162
+ id: ((_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.tenantId) || '',
163
+ account: {
164
+ id: ((_b = this._tokenCredential) === null || _b === void 0 ? void 0 : _b.tenantId) || '',
165
+ label: ((_c = this._tokenCredential) === null || _c === void 0 ? void 0 : _c.tenantId) || '',
166
+ },
167
+ tenantId: ((_d = this._tokenCredential) === null || _d === void 0 ? void 0 : _d.tenantId) || '',
168
+ scopes: scopes || [],
169
+ };
170
+ };
154
171
  return {
155
172
  client: new armSubs.SubscriptionClient(this._tokenCredential),
156
173
  credential: this._tokenCredential,
157
174
  authentication: {
158
- getSession: (_scopes) => {
159
- var _a, _b, _c, _d;
160
- return {
161
- accessToken,
162
- id: ((_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.tenantId) || '',
163
- account: {
164
- id: ((_b = this._tokenCredential) === null || _b === void 0 ? void 0 : _b.tenantId) || '',
165
- label: ((_c = this._tokenCredential) === null || _c === void 0 ? void 0 : _c.tenantId) || '',
166
- },
167
- tenantId: ((_d = this._tokenCredential) === null || _d === void 0 ? void 0 : _d.tenantId) || '',
168
- scopes: scopes || [],
169
- };
170
- }
175
+ getSession,
176
+ getSessionWithScopes: getSession,
171
177
  }
172
178
  };
173
179
  });
@@ -1,6 +1,7 @@
1
1
  import type { TokenCredential } from '@azure/core-auth';
2
2
  import type { Environment } from '@azure/ms-rest-azure-env';
3
- import type { AzureAuthentication } from './AzureAuthentication';
3
+ import * as vscode from "vscode";
4
+ import { AzureAuthentication } from './AzureAuthentication';
4
5
  /**
5
6
  * A type representing an Azure subscription ID, not including the tenant ID.
6
7
  */
@@ -41,4 +42,8 @@ export interface AzureSubscription {
41
42
  * The credential for authentication to this subscription. Compatible with Azure track 2 SDKs.
42
43
  */
43
44
  readonly credential: TokenCredential;
45
+ /**
46
+ * The account associated with this subscription.
47
+ */
48
+ readonly account: vscode.AuthenticationSessionAccountInformation;
44
49
  }
@@ -1,6 +1,6 @@
1
+ import type { TenantIdDescription } from '@azure/arm-resources-subscriptions';
1
2
  import type * as vscode from 'vscode';
2
3
  import type { AzureSubscription } from './AzureSubscription';
3
- import type { TenantIdDescription } from '@azure/arm-resources-subscriptions';
4
4
  /**
5
5
  * An interface for obtaining Azure subscription information
6
6
  */
@@ -9,9 +9,11 @@ export interface AzureSubscriptionProvider {
9
9
  * Gets a list of tenants available to the user.
10
10
  * Use {@link isSignedIn} to check if the user is signed in to a particular tenant.
11
11
  *
12
+ * @param account - Optionally pass in a specific account to get tenants for.
13
+ *
12
14
  * @returns A list of tenants.
13
15
  */
14
- getTenants(): Promise<TenantIdDescription[]>;
16
+ getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise<TenantIdDescription[]>;
15
17
  /**
16
18
  * Gets a list of Azure subscriptions available to the user.
17
19
  *
@@ -1,7 +1,7 @@
1
1
  import type { TenantIdDescription } from '@azure/arm-resources-subscriptions';
2
2
  import * as vscode from 'vscode';
3
- import type { AzureSubscription, SubscriptionId, TenantId } from './AzureSubscription';
4
- import type { AzureSubscriptionProvider } from './AzureSubscriptionProvider';
3
+ import { AzureSubscription, SubscriptionId, TenantId } from './AzureSubscription';
4
+ import { AzureSubscriptionProvider } from './AzureSubscriptionProvider';
5
5
  /**
6
6
  * A class for obtaining Azure subscription information using VSCode's built-in authentication
7
7
  * provider.
@@ -17,9 +17,11 @@ export declare class VSCodeAzureSubscriptionProvider extends vscode.Disposable i
17
17
  * Gets a list of tenants available to the user.
18
18
  * Use {@link isSignedIn} to check if the user is signed in to a particular tenant.
19
19
  *
20
+ * @param account (Optional) A specific account to get tenants for. If not provided, all accounts will be used.
21
+ *
20
22
  * @returns A list of tenants.
21
23
  */
22
- getTenants(): Promise<TenantIdDescription[]>;
24
+ getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise<TenantIdDescription[]>;
23
25
  /**
24
26
  * Gets a list of Azure subscriptions available to the user.
25
27
  *
@@ -87,6 +89,7 @@ export declare class VSCodeAzureSubscriptionProvider extends vscode.Disposable i
87
89
  * Gets the subscriptions for a given tenant.
88
90
  *
89
91
  * @param tenantId The tenant ID to get subscriptions for.
92
+ * @param account The account to get the subscriptions for.
90
93
  *
91
94
  * @returns The list of subscriptions for the tenant.
92
95
  */
@@ -95,6 +98,7 @@ export declare class VSCodeAzureSubscriptionProvider extends vscode.Disposable i
95
98
  * Gets a fully-configured subscription client for a given tenant ID
96
99
  *
97
100
  * @param tenantId (Optional) The tenant ID to get a client for
101
+ * @param account The account that you would like to get the session for
98
102
  *
99
103
  * @returns A client, the credential used by the client, and the authentication function
100
104
  */
@@ -22,8 +22,8 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
23
  exports.VSCodeAzureSubscriptionProvider = void 0;
24
24
  const vscode = require("vscode");
25
- const NotSignedInError_1 = require("./NotSignedInError");
26
25
  const getSessionFromVSCode_1 = require("./getSessionFromVSCode");
26
+ const NotSignedInError_1 = require("./NotSignedInError");
27
27
  const configuredAzureEnv_1 = require("./utils/configuredAzureEnv");
28
28
  const EventDebounce = 5 * 1000; // 5 seconds
29
29
  /**
@@ -71,30 +71,51 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
71
71
  * Gets a list of tenants available to the user.
72
72
  * Use {@link isSignedIn} to check if the user is signed in to a particular tenant.
73
73
  *
74
+ * @param account (Optional) A specific account to get tenants for. If not provided, all accounts will be used.
75
+ *
74
76
  * @returns A list of tenants.
75
77
  */
76
- getTenants() {
77
- var _a, e_1, _b, _c;
78
+ getTenants(account) {
79
+ var _a, e_1, _b, _c, _d, e_2, _e, _f;
78
80
  return __awaiter(this, void 0, void 0, function* () {
79
- const { client } = yield this.getSubscriptionClient();
80
81
  const results = [];
81
82
  try {
82
- for (var _d = true, _e = __asyncValues(client.tenants.list()), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
83
- _c = _f.value;
84
- _d = false;
83
+ for (var _g = true, _h = __asyncValues(account ? [account] : yield vscode.authentication.getAccounts((0, configuredAzureEnv_1.getConfiguredAuthProviderId)())), _j; _j = yield _h.next(), _a = _j.done, !_a;) {
84
+ _c = _j.value;
85
+ _g = false;
85
86
  try {
86
- const tenant = _c;
87
- results.push(tenant);
87
+ account = _c;
88
+ const { client } = yield this.getSubscriptionClient(account, undefined, undefined);
89
+ try {
90
+ for (var _k = true, _l = (e_2 = void 0, __asyncValues(client.tenants.list())), _m; _m = yield _l.next(), _d = _m.done, !_d;) {
91
+ _f = _m.value;
92
+ _k = false;
93
+ try {
94
+ const tenant = _f;
95
+ results.push(tenant);
96
+ }
97
+ finally {
98
+ _k = true;
99
+ }
100
+ }
101
+ }
102
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
103
+ finally {
104
+ try {
105
+ if (!_k && !_d && (_e = _l.return)) yield _e.call(_l);
106
+ }
107
+ finally { if (e_2) throw e_2.error; }
108
+ }
88
109
  }
89
110
  finally {
90
- _d = true;
111
+ _g = true;
91
112
  }
92
113
  }
93
114
  }
94
115
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
95
116
  finally {
96
117
  try {
97
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
118
+ if (!_g && !_a && (_b = _h.return)) yield _b.call(_h);
98
119
  }
99
120
  finally { if (e_1) throw e_1.error; }
100
121
  }
@@ -120,20 +141,23 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
120
141
  const results = [];
121
142
  try {
122
143
  this.suppressSignInEvents = true;
123
- // Get the list of tenants
124
- for (const tenant of yield this.getTenants()) {
125
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
126
- const tenantId = tenant.tenantId;
127
- // If filtering is enabled, and the current tenant is not in that list, then skip it
128
- if (shouldFilterTenants && !tenantIds.includes(tenantId)) {
129
- continue;
130
- }
131
- // If the user is not signed in to this tenant, then skip it
132
- if (!(yield this.isSignedIn(tenantId))) {
133
- continue;
144
+ // Get the list of tenants from each account
145
+ const accounts = yield vscode.authentication.getAccounts((0, configuredAzureEnv_1.getConfiguredAuthProviderId)());
146
+ for (const account of accounts) {
147
+ for (const tenant of yield this.getTenants(account)) {
148
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
149
+ const tenantId = tenant.tenantId;
150
+ // If filtering is enabled, and the current tenant is not in that list, then skip it
151
+ if (shouldFilterTenants && !tenantIds.includes(tenantId)) {
152
+ continue;
153
+ }
154
+ // If the user is not signed in to this tenant, then skip it
155
+ if (!(yield this.isSignedIn(tenantId))) {
156
+ continue;
157
+ }
158
+ // For each tenant, get the list of subscriptions
159
+ results.push(...yield this.getSubscriptionsForTenant(tenantId, account));
134
160
  }
135
- // For each tenant, get the list of subscriptions
136
- results.push(...yield this.getSubscriptionsForTenant(tenantId));
137
161
  }
138
162
  }
139
163
  finally {
@@ -217,13 +241,14 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
217
241
  * Gets the subscriptions for a given tenant.
218
242
  *
219
243
  * @param tenantId The tenant ID to get subscriptions for.
244
+ * @param account The account to get the subscriptions for.
220
245
  *
221
246
  * @returns The list of subscriptions for the tenant.
222
247
  */
223
- getSubscriptionsForTenant(tenantId) {
224
- var _a, e_2, _b, _c;
248
+ getSubscriptionsForTenant(tenantId, account) {
249
+ var _a, e_3, _b, _c;
225
250
  return __awaiter(this, void 0, void 0, function* () {
226
- const { client, credential, authentication } = yield this.getSubscriptionClient(tenantId);
251
+ const { client, credential, authentication } = yield this.getSubscriptionClient(account, tenantId, undefined);
227
252
  const environment = (0, configuredAzureEnv_1.getConfiguredAzureEnv)();
228
253
  const subscriptions = [];
229
254
  try {
@@ -242,6 +267,7 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
242
267
  subscriptionId: subscription.subscriptionId,
243
268
  /* eslint-enable @typescript-eslint/no-non-null-assertion */
244
269
  tenantId: tenantId,
270
+ account: account
245
271
  });
246
272
  }
247
273
  finally {
@@ -249,12 +275,12 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
249
275
  }
250
276
  }
251
277
  }
252
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
278
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
253
279
  finally {
254
280
  try {
255
281
  if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
256
282
  }
257
- finally { if (e_2) throw e_2.error; }
283
+ finally { if (e_3) throw e_3.error; }
258
284
  }
259
285
  return subscriptions;
260
286
  });
@@ -263,13 +289,14 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
263
289
  * Gets a fully-configured subscription client for a given tenant ID
264
290
  *
265
291
  * @param tenantId (Optional) The tenant ID to get a client for
292
+ * @param account The account that you would like to get the session for
266
293
  *
267
294
  * @returns A client, the credential used by the client, and the authentication function
268
295
  */
269
- getSubscriptionClient(tenantId, scopes) {
296
+ getSubscriptionClient(account, tenantId, scopes) {
270
297
  return __awaiter(this, void 0, void 0, function* () {
271
298
  const armSubs = yield Promise.resolve().then(() => require('@azure/arm-resources-subscriptions'));
272
- const session = yield (0, getSessionFromVSCode_1.getSessionFromVSCode)(scopes, tenantId, { createIfNone: false, silent: true });
299
+ const session = yield (0, getSessionFromVSCode_1.getSessionFromVSCode)(scopes, tenantId, { createIfNone: false, silent: true, account });
273
300
  if (!session) {
274
301
  throw new NotSignedInError_1.NotSignedInError();
275
302
  }
@@ -287,7 +314,10 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
287
314
  client: new armSubs.SubscriptionClient(credential, { endpoint }),
288
315
  credential: credential,
289
316
  authentication: {
290
- getSession: () => session
317
+ getSession: () => session,
318
+ getSessionWithScopes: (scopes) => {
319
+ return (0, getSessionFromVSCode_1.getSessionFromVSCode)(scopes, tenantId, { createIfNone: false, silent: true, account });
320
+ },
291
321
  }
292
322
  };
293
323
  });
@@ -14,8 +14,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
14
14
  };
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.getSessionFromVSCode = void 0;
17
- const configuredAzureEnv_1 = require("./utils/configuredAzureEnv");
18
17
  const vscode = require("vscode");
18
+ const configuredAzureEnv_1 = require("./utils/configuredAzureEnv");
19
19
  function ensureEndingSlash(value) {
20
20
  return value.endsWith('/') ? value : `${value}/`;
21
21
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@microsoft/vscode-azext-azureauth",
3
3
  "author": "Microsoft Corporation",
4
- "version": "2.4.1",
4
+ "version": "3.0.0",
5
5
  "description": "Azure authentication helpers for Visual Studio Code",
6
6
  "tags": [
7
7
  "azure",
@@ -41,7 +41,7 @@
41
41
  "@types/node-fetch": "2.6.7",
42
42
  "@types/semver": "^7.3.9",
43
43
  "@types/uuid": "^9.0.1",
44
- "@types/vscode": "1.76.0",
44
+ "@types/vscode": "1.93.0",
45
45
  "@typescript-eslint/eslint-plugin": "^5.53.0",
46
46
  "@vscode/test-electron": "^2.3.8",
47
47
  "eslint": "^8.34.0",