@microsoft/vscode-azext-azureauth 3.1.0 → 4.0.1

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.
package/CHANGELOG.md CHANGED
@@ -1,9 +1,25 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.0.1 - 2024-12-17
4
+
5
+ * [#1856](https://github.com/microsoft/vscode-azuretools/pull/1856) Fix tenantId undefined error
6
+
7
+ ## 4.0.0 - 2024-12-06
8
+
9
+ ### What's new
10
+ Pass in a `vscode.LogOutputChannel` to the `VSCodeAzureSubscriptionProvider` constructor to enable logging. [#1851](https://github.com/microsoft/vscode-azuretools/pull/1851)
11
+
12
+ `AzureSubscriptionProvider.getTenants()` now returns `AzureTenant[]` instead of `TenantIdDescription[]`. This is a breaking change for implementors of `AzureSubscriptionProvider`. [#1849](https://github.com/microsoft/vscode-azuretools/pull/1849)
13
+
14
+ ### All Changes
15
+ * [#1849](https://github.com/microsoft/vscode-azuretools/pull/1849) Create `AzureTenant` interface which includes account property
16
+ * [#1850](https://github.com/microsoft/vscode-azuretools/pull/1850) Clean up `isSignedIn` implementation
17
+ * [#1851](https://github.com/microsoft/vscode-azuretools/pull/1851) Add logging to `VSCodeAzureSubscriptionProvider`
18
+
3
19
  ## 3.1.0 - 2024-11-26
4
20
 
5
- * [#1827](https://github.com/microsoft/vscode-azuretools/pull/1827) Add more comprehensive support for multi-account scenarios
6
- * [#1815](https://github.com/microsoft/vscode-azuretools/issues/1815) Fix `VSCodeAzureSubscriptionProvider.getSubscriptions()` returning empty
21
+ * [#1827](https://github.com/microsoft/vscode-azuretools/pull/1827) Add more comprehensive support for multi-account scenarios
22
+ * [#1815](https://github.com/microsoft/vscode-azuretools/issues/1815) Fix `VSCodeAzureSubscriptionProvider.getSubscriptions()` returning empty
7
23
 
8
24
  ## 3.0.1 - 2024-11-19
9
25
  * [#1819](https://github.com/microsoft/vscode-azuretools/pull/1819) Add account parameter to `AzureSubscriptionProvider.isSignedIn()` function to fix a multi-account issue [#1809](https://github.com/microsoft/vscode-azuretools/issues/1809)
@@ -1,7 +1,7 @@
1
- import type { TenantIdDescription } from '@azure/arm-resources-subscriptions';
2
1
  import { Event } from 'vscode';
3
2
  import { AzureSubscription } from './AzureSubscription';
4
3
  import { AzureSubscriptionProvider } from './AzureSubscriptionProvider';
4
+ import { AzureTenant } from './AzureTenant';
5
5
  export interface AzureDevOpsSubscriptionProviderInitializer {
6
6
  /**
7
7
  * The resource ID of the Azure DevOps federated service connection,
@@ -46,7 +46,7 @@ export declare class AzureDevOpsSubscriptionProvider implements AzureSubscriptio
46
46
  isSignedIn(): Promise<boolean>;
47
47
  signIn(): Promise<boolean>;
48
48
  signOut(): Promise<void>;
49
- getTenants(): Promise<TenantIdDescription[]>;
49
+ getTenants(): Promise<AzureTenant[]>;
50
50
  /**
51
51
  * Gets the subscriptions for a given tenant.
52
52
  *
@@ -87,6 +87,10 @@ class AzureDevOpsSubscriptionProvider {
87
87
  return __awaiter(this, void 0, void 0, function* () {
88
88
  return [{
89
89
  tenantId: (_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.tenantId,
90
+ account: {
91
+ id: "test-account-id",
92
+ label: "test-account",
93
+ }
90
94
  }];
91
95
  });
92
96
  }
@@ -1,6 +1,6 @@
1
- import type { TenantIdDescription } from '@azure/arm-resources-subscriptions';
2
1
  import type * as vscode from 'vscode';
3
2
  import type { AzureSubscription } from './AzureSubscription';
3
+ import type { AzureTenant } from './AzureTenant';
4
4
  /**
5
5
  * An interface for obtaining Azure subscription information
6
6
  */
@@ -13,7 +13,7 @@ export interface AzureSubscriptionProvider {
13
13
  *
14
14
  * @returns A list of tenants.
15
15
  */
16
- getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise<TenantIdDescription[]>;
16
+ getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise<AzureTenant[]>;
17
17
  /**
18
18
  * Gets a list of Azure subscriptions available to the user.
19
19
  *
@@ -0,0 +1,5 @@
1
+ import { TenantIdDescription } from "@azure/arm-resources-subscriptions";
2
+ import * as vscode from 'vscode';
3
+ export interface AzureTenant extends TenantIdDescription {
4
+ account: vscode.AuthenticationSessionAccountInformation;
5
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Microsoft Corporation. All rights reserved.
4
+ * Licensed under the MIT License. See License.txt in the project root for license information.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=AzureTenant.js.map
@@ -1,18 +1,19 @@
1
- import type { TenantIdDescription } from '@azure/arm-resources-subscriptions';
2
1
  import * as vscode from 'vscode';
3
2
  import { AzureSubscription, SubscriptionId, TenantId } from './AzureSubscription';
4
3
  import { AzureSubscriptionProvider } from './AzureSubscriptionProvider';
4
+ import { AzureTenant } from './AzureTenant';
5
5
  /**
6
6
  * A class for obtaining Azure subscription information using VSCode's built-in authentication
7
7
  * provider.
8
8
  */
9
9
  export declare class VSCodeAzureSubscriptionProvider extends vscode.Disposable implements AzureSubscriptionProvider {
10
+ private readonly logger?;
10
11
  private readonly onDidSignInEmitter;
11
12
  private lastSignInEventFired;
12
13
  private suppressSignInEvents;
13
14
  private readonly onDidSignOutEmitter;
14
15
  private lastSignOutEventFired;
15
- constructor();
16
+ constructor(logger?: vscode.LogOutputChannel | undefined);
16
17
  /**
17
18
  * Gets a list of tenants available to the user.
18
19
  * Use {@link isSignedIn} to check if the user is signed in to a particular tenant.
@@ -21,7 +22,7 @@ export declare class VSCodeAzureSubscriptionProvider extends vscode.Disposable i
21
22
  *
22
23
  * @returns A list of tenants.
23
24
  */
24
- getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise<TenantIdDescription[]>;
25
+ getTenants(account?: vscode.AuthenticationSessionAccountInformation): Promise<AzureTenant[]>;
25
26
  /**
26
27
  * Gets a list of Azure subscriptions available to the user.
27
28
  *
@@ -31,7 +31,8 @@ const EventDebounce = 5 * 1000; // 5 seconds
31
31
  * provider.
32
32
  */
33
33
  class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
34
- constructor() {
34
+ // So that customers can easily share logs, try to only log PII using trace level
35
+ constructor(logger) {
35
36
  const disposable = vscode.authentication.onDidChangeSessions((e) => __awaiter(this, void 0, void 0, function* () {
36
37
  // Ignore any sign in that isn't for the configured auth provider
37
38
  if (e.provider.id !== (0, configuredAzureEnv_1.getConfiguredAuthProviderId)()) {
@@ -53,6 +54,7 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
53
54
  this.onDidSignOutEmitter.dispose();
54
55
  disposable.dispose();
55
56
  });
57
+ this.logger = logger;
56
58
  this.onDidSignInEmitter = new vscode.EventEmitter();
57
59
  this.lastSignInEventFired = 0;
58
60
  this.suppressSignInEvents = false;
@@ -77,51 +79,55 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
77
79
  */
78
80
  getTenants(account) {
79
81
  var _a, e_1, _b, _c, _d, e_2, _e, _f;
82
+ var _g;
80
83
  return __awaiter(this, void 0, void 0, function* () {
84
+ const startTimeMs = Date.now();
81
85
  const results = [];
82
86
  try {
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;
87
+ for (var _h = true, _j = __asyncValues(account ? [account] : yield vscode.authentication.getAccounts((0, configuredAzureEnv_1.getConfiguredAuthProviderId)())), _k; _k = yield _j.next(), _a = _k.done, !_a;) {
88
+ _c = _k.value;
89
+ _h = false;
86
90
  try {
87
91
  account = _c;
88
92
  // Added check. Without this the getSubscriptionClient function throws the NotSignedInError
89
93
  if (yield this.isSignedIn(undefined, account)) {
90
94
  const { client } = yield this.getSubscriptionClient(account, undefined, undefined);
91
95
  try {
92
- for (var _k = true, _l = (e_2 = void 0, __asyncValues(client.tenants.list())), _m; _m = yield _l.next(), _d = _m.done, !_d;) {
93
- _f = _m.value;
94
- _k = false;
96
+ for (var _l = true, _m = (e_2 = void 0, __asyncValues(client.tenants.list())), _o; _o = yield _m.next(), _d = _o.done, !_d;) {
97
+ _f = _o.value;
98
+ _l = false;
95
99
  try {
96
100
  const tenant = _f;
97
- results.push(tenant);
101
+ results.push(Object.assign(Object.assign({}, tenant), { account }));
98
102
  }
99
103
  finally {
100
- _k = true;
104
+ _l = true;
101
105
  }
102
106
  }
103
107
  }
104
108
  catch (e_2_1) { e_2 = { error: e_2_1 }; }
105
109
  finally {
106
110
  try {
107
- if (!_k && !_d && (_e = _l.return)) yield _e.call(_l);
111
+ if (!_l && !_d && (_e = _m.return)) yield _e.call(_m);
108
112
  }
109
113
  finally { if (e_2) throw e_2.error; }
110
114
  }
111
115
  }
112
116
  }
113
117
  finally {
114
- _g = true;
118
+ _h = true;
115
119
  }
116
120
  }
117
121
  }
118
122
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
119
123
  finally {
120
124
  try {
121
- if (!_g && !_a && (_b = _h.return)) yield _b.call(_h);
125
+ if (!_h && !_a && (_b = _j.return)) yield _b.call(_j);
122
126
  }
123
127
  finally { if (e_1) throw e_1.error; }
124
128
  }
129
+ const endTimeMs = Date.now();
130
+ (_g = this.logger) === null || _g === void 0 ? void 0 : _g.debug(`auth: Got ${results.length} tenants for account "${account === null || account === void 0 ? void 0 : account.label}" in ${endTimeMs - startTimeMs}ms`);
125
131
  return results;
126
132
  });
127
133
  }
@@ -139,14 +145,19 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
139
145
  * the user is signed in.
140
146
  */
141
147
  getSubscriptions(filter = true) {
148
+ var _a, _b;
142
149
  return __awaiter(this, void 0, void 0, function* () {
150
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('auth: Loading subscriptions...');
151
+ const startTime = Date.now();
143
152
  const tenantIds = yield this.getTenantFilters();
144
153
  const shouldFilterTenants = filter && !!tenantIds.length; // If the list is empty it is treated as "no filter"
145
154
  const allSubscriptions = [];
155
+ let accountCount; // only used for logging
146
156
  try {
147
157
  this.suppressSignInEvents = true;
148
158
  // Get the list of tenants from each account
149
159
  const accounts = yield vscode.authentication.getAccounts((0, configuredAzureEnv_1.getConfiguredAuthProviderId)());
160
+ accountCount = accounts.length;
150
161
  for (const account of accounts) {
151
162
  for (const tenant of yield this.getTenants(account)) {
152
163
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -170,6 +181,8 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
170
181
  const subscriptionMap = new Map();
171
182
  allSubscriptions.forEach(sub => subscriptionMap.set(`${sub.account.id}/${sub.subscriptionId}`, sub));
172
183
  const uniqueSubscriptions = Array.from(subscriptionMap.values());
184
+ const endTime = Date.now();
185
+ (_b = this.logger) === null || _b === void 0 ? void 0 : _b.debug(`auth: Got ${uniqueSubscriptions.length} subscriptions from ${accountCount} accounts in ${endTime - startTime}ms`);
173
186
  const sortSubscriptions = (subscriptions) => subscriptions.sort((a, b) => a.name.localeCompare(b.name));
174
187
  const subscriptionIds = yield this.getSubscriptionFilters();
175
188
  if (filter && !!subscriptionIds.length) { // If the list is empty it is treated as "no filter"
@@ -190,21 +203,32 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
190
203
  * checks all accounts for a session.
191
204
  */
192
205
  isSignedIn(tenantId, account) {
206
+ var _a, _b;
193
207
  return __awaiter(this, void 0, void 0, function* () {
194
- // If no tenant or account is provided, then check all accounts for a session
195
- if (!account && !tenantId) {
196
- const accounts = yield vscode.authentication.getAccounts((0, configuredAzureEnv_1.getConfiguredAuthProviderId)());
197
- if (accounts.length === 0) {
198
- return false;
199
- }
200
- for (const account of accounts) {
201
- if (yield this.isSignedIn(undefined, account)) {
202
- return true;
208
+ function silentlyCheckForSession(tenantId, account) {
209
+ return __awaiter(this, void 0, void 0, function* () {
210
+ return !!(yield (0, getSessionFromVSCode_1.getSessionFromVSCode)([], tenantId, { createIfNone: false, silent: true, account }));
211
+ });
212
+ }
213
+ const innerIsSignedIn = () => __awaiter(this, void 0, void 0, function* () {
214
+ // If no tenant or account is provided, then check all accounts for a session
215
+ if (!account && !tenantId) {
216
+ const accounts = yield vscode.authentication.getAccounts((0, configuredAzureEnv_1.getConfiguredAuthProviderId)());
217
+ if (accounts.length === 0) {
218
+ return false;
219
+ }
220
+ for (const account of accounts) {
221
+ if (yield silentlyCheckForSession(tenantId, account)) {
222
+ // If any account has a session, then return true because the user is signed in
223
+ return true;
224
+ }
203
225
  }
204
226
  }
205
- }
206
- const session = yield (0, getSessionFromVSCode_1.getSessionFromVSCode)([], tenantId, { createIfNone: false, silent: true, account });
207
- return !!session;
227
+ return silentlyCheckForSession(tenantId, account);
228
+ });
229
+ const result = yield innerIsSignedIn();
230
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.trace(`auth: isSignedIn returned ${result} (account="${(_b = account === null || account === void 0 ? void 0 : account.label) !== null && _b !== void 0 ? _b : 'none'}") (tenantId="${tenantId !== null && tenantId !== void 0 ? tenantId : 'none'}")`);
231
+ return result;
208
232
  });
209
233
  }
210
234
  /**
@@ -216,7 +240,9 @@ class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
216
240
  * @returns True if the user is signed in, false otherwise.
217
241
  */
218
242
  signIn(tenantId, account) {
243
+ var _a, _b;
219
244
  return __awaiter(this, void 0, void 0, function* () {
245
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`auth: Signing in (account="${(_b = account === null || account === void 0 ? void 0 : account.label) !== null && _b !== void 0 ? _b : 'none'}") (tenantId="${tenantId !== null && tenantId !== void 0 ? tenantId : 'none'}")`);
220
246
  const session = yield (0, getSessionFromVSCode_1.getSessionFromVSCode)([], tenantId, {
221
247
  createIfNone: true,
222
248
  // If no account is provided, then clear the session preference which tells VS Code to show the account picker
@@ -1,5 +1,6 @@
1
1
  export * from './AzureAuthentication';
2
2
  export * from './AzureDevOpsSubscriptionProvider';
3
+ export * from './AzureTenant';
3
4
  export * from './AzureSubscription';
4
5
  export * from './AzureSubscriptionProvider';
5
6
  export * from './NotSignedInError';
package/out/src/index.js CHANGED
@@ -20,6 +20,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  __exportStar(require("./AzureAuthentication"), exports);
22
22
  __exportStar(require("./AzureDevOpsSubscriptionProvider"), exports);
23
+ __exportStar(require("./AzureTenant"), exports);
23
24
  __exportStar(require("./AzureSubscription"), exports);
24
25
  __exportStar(require("./AzureSubscriptionProvider"), exports);
25
26
  __exportStar(require("./NotSignedInError"), exports);
@@ -32,7 +32,7 @@ exports.signInToTenant = signInToTenant;
32
32
  function pickTenant(subscriptionProvider) {
33
33
  return __awaiter(this, void 0, void 0, function* () {
34
34
  const pick = yield vscode.window.showQuickPick(getPicks(subscriptionProvider), {
35
- placeHolder: 'Select Directory to Sign In To',
35
+ placeHolder: 'Select a Tenant (Directory) to Sign In To',
36
36
  matchOnDescription: true,
37
37
  ignoreFocusOut: true,
38
38
  });
@@ -42,7 +42,10 @@ function pickTenant(subscriptionProvider) {
42
42
  function getPicks(subscriptionProvider) {
43
43
  return __awaiter(this, void 0, void 0, function* () {
44
44
  const unauthenticatedTenants = yield (0, getUnauthenticatedTenants_1.getUnauthenticatedTenants)(subscriptionProvider);
45
- const picks = unauthenticatedTenants.map(tenant => {
45
+ const picks = unauthenticatedTenants
46
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
47
+ .sort((a, b) => (a.displayName).localeCompare(b.displayName))
48
+ .map(tenant => {
46
49
  var _a, _b, _c;
47
50
  return ({
48
51
  label: (_a = tenant.displayName) !== null && _a !== void 0 ? _a : '',
@@ -35,8 +35,11 @@ function getUnauthenticatedTenants(subscriptionProvider) {
35
35
  _d = false;
36
36
  try {
37
37
  const tenant = _c;
38
- if (!(yield subscriptionProvider.isSignedIn(tenant.tenantId))) {
39
- unauthenticatedTenants.push(tenant);
38
+ // Occasiounally users have run into one of their tenants being undefined https://github.com/microsoft/vscode-azureresourcegroups/issues/966
39
+ if (tenant) {
40
+ if (!(yield subscriptionProvider.isSignedIn(tenant.tenantId, tenant.account))) {
41
+ unauthenticatedTenants.push(tenant);
42
+ }
40
43
  }
41
44
  }
42
45
  finally {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@microsoft/vscode-azext-azureauth",
3
3
  "author": "Microsoft Corporation",
4
- "version": "3.1.0",
4
+ "version": "4.0.1",
5
5
  "description": "Azure authentication helpers for Visual Studio Code",
6
6
  "tags": [
7
7
  "azure",