@microsoft/vscode-azext-azureauth 4.2.2 → 5.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.
Files changed (59) hide show
  1. package/{out → dist/cjs}/src/AzureAuthentication.d.ts +2 -2
  2. package/dist/cjs/src/AzureDevOpsSubscriptionProvider.js +216 -0
  3. package/dist/cjs/src/NotSignedInError.js +63 -0
  4. package/dist/cjs/src/VSCodeAzureSubscriptionProvider.js +342 -0
  5. package/{out → dist/cjs}/src/getSessionFromVSCode.d.ts +3 -3
  6. package/dist/cjs/src/getSessionFromVSCode.js +108 -0
  7. package/dist/cjs/src/index.d.ts +56 -0
  8. package/{out → dist/cjs}/src/index.js +1 -1
  9. package/dist/cjs/src/signInToTenant.js +79 -0
  10. package/dist/cjs/src/utils/configuredAzureEnv.js +128 -0
  11. package/dist/cjs/src/utils/getUnauthenticatedTenants.js +21 -0
  12. package/dist/esm/src/AzureAuthentication.d.ts +21 -0
  13. package/dist/esm/src/AzureAuthentication.js +6 -0
  14. package/dist/esm/src/AzureDevOpsSubscriptionProvider.d.ts +68 -0
  15. package/dist/esm/src/AzureDevOpsSubscriptionProvider.js +211 -0
  16. package/dist/esm/src/AzureSubscription.d.ts +49 -0
  17. package/dist/esm/src/AzureSubscription.js +6 -0
  18. package/dist/esm/src/AzureSubscriptionProvider.d.ts +82 -0
  19. package/dist/esm/src/AzureSubscriptionProvider.js +6 -0
  20. package/dist/esm/src/AzureTenant.d.ts +5 -0
  21. package/dist/esm/src/AzureTenant.js +6 -0
  22. package/dist/esm/src/NotSignedInError.d.ts +15 -0
  23. package/{out → dist/esm}/src/NotSignedInError.js +4 -9
  24. package/dist/esm/src/VSCodeAzureSubscriptionProvider.d.ts +117 -0
  25. package/dist/esm/src/VSCodeAzureSubscriptionProvider.js +305 -0
  26. package/dist/esm/src/getSessionFromVSCode.d.ts +13 -0
  27. package/dist/esm/src/getSessionFromVSCode.js +72 -0
  28. package/dist/esm/src/index.d.ts +56 -0
  29. package/{out/src/index.d.ts → dist/esm/src/index.js} +6 -1
  30. package/dist/esm/src/signInToTenant.d.ts +6 -0
  31. package/dist/esm/src/signInToTenant.js +43 -0
  32. package/dist/esm/src/utils/configuredAzureEnv.d.ts +24 -0
  33. package/dist/esm/src/utils/configuredAzureEnv.js +90 -0
  34. package/dist/esm/src/utils/getUnauthenticatedTenants.d.ts +6 -0
  35. package/dist/esm/src/utils/getUnauthenticatedTenants.js +18 -0
  36. package/dist/esm/src/utils/isAuthenticationWwwAuthenticateRequest.d.ts +2 -0
  37. package/dist/esm/src/utils/isAuthenticationWwwAuthenticateRequest.js +12 -0
  38. package/package.json +13 -12
  39. package/out/src/AzureDevOpsSubscriptionProvider.js +0 -252
  40. package/out/src/VSCodeAzureSubscriptionProvider.js +0 -384
  41. package/out/src/getSessionFromVSCode.js +0 -76
  42. package/out/src/signInToTenant.js +0 -64
  43. package/out/src/utils/configuredAzureEnv.js +0 -94
  44. package/out/src/utils/getUnauthenticatedTenants.js +0 -52
  45. /package/{out → dist/cjs}/src/AzureAuthentication.js +0 -0
  46. /package/{out → dist/cjs}/src/AzureDevOpsSubscriptionProvider.d.ts +0 -0
  47. /package/{out → dist/cjs}/src/AzureSubscription.d.ts +0 -0
  48. /package/{out → dist/cjs}/src/AzureSubscription.js +0 -0
  49. /package/{out → dist/cjs}/src/AzureSubscriptionProvider.d.ts +0 -0
  50. /package/{out → dist/cjs}/src/AzureSubscriptionProvider.js +0 -0
  51. /package/{out → dist/cjs}/src/AzureTenant.d.ts +0 -0
  52. /package/{out → dist/cjs}/src/AzureTenant.js +0 -0
  53. /package/{out → dist/cjs}/src/NotSignedInError.d.ts +0 -0
  54. /package/{out → dist/cjs}/src/VSCodeAzureSubscriptionProvider.d.ts +0 -0
  55. /package/{out → dist/cjs}/src/signInToTenant.d.ts +0 -0
  56. /package/{out → dist/cjs}/src/utils/configuredAzureEnv.d.ts +0 -0
  57. /package/{out → dist/cjs}/src/utils/getUnauthenticatedTenants.d.ts +0 -0
  58. /package/{out → dist/cjs}/src/utils/isAuthenticationWwwAuthenticateRequest.d.ts +0 -0
  59. /package/{out → dist/cjs}/src/utils/isAuthenticationWwwAuthenticateRequest.js +0 -0
@@ -0,0 +1,305 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import * as vscode from 'vscode';
6
+ import { getSessionFromVSCode } from './getSessionFromVSCode';
7
+ import { NotSignedInError } from './NotSignedInError';
8
+ import { getConfiguredAuthProviderId, getConfiguredAzureEnv } from './utils/configuredAzureEnv';
9
+ import { isAuthenticationWwwAuthenticateRequest } from './utils/isAuthenticationWwwAuthenticateRequest';
10
+ const EventDebounce = 5 * 1000; // 5 seconds
11
+ /**
12
+ * A class for obtaining Azure subscription information using VSCode's built-in authentication
13
+ * provider.
14
+ */
15
+ export class VSCodeAzureSubscriptionProvider extends vscode.Disposable {
16
+ logger;
17
+ onDidSignInEmitter = new vscode.EventEmitter();
18
+ lastSignInEventFired = 0;
19
+ suppressSignInEvents = false;
20
+ onDidSignOutEmitter = new vscode.EventEmitter();
21
+ lastSignOutEventFired = 0;
22
+ // So that customers can easily share logs, try to only log PII using trace level
23
+ constructor(logger) {
24
+ const disposable = vscode.authentication.onDidChangeSessions(async (e) => {
25
+ // Ignore any sign in that isn't for the configured auth provider
26
+ if (e.provider.id !== getConfiguredAuthProviderId()) {
27
+ return;
28
+ }
29
+ if (await this.isSignedIn()) {
30
+ if (!this.suppressSignInEvents && Date.now() > this.lastSignInEventFired + EventDebounce) {
31
+ this.lastSignInEventFired = Date.now();
32
+ this.onDidSignInEmitter.fire();
33
+ }
34
+ }
35
+ else if (Date.now() > this.lastSignOutEventFired + EventDebounce) {
36
+ this.lastSignOutEventFired = Date.now();
37
+ this.onDidSignOutEmitter.fire();
38
+ }
39
+ });
40
+ super(() => {
41
+ this.onDidSignInEmitter.dispose();
42
+ this.onDidSignOutEmitter.dispose();
43
+ disposable.dispose();
44
+ });
45
+ this.logger = logger;
46
+ }
47
+ /**
48
+ * Gets a list of tenants available to the user.
49
+ * Use {@link isSignedIn} to check if the user is signed in to a particular tenant.
50
+ *
51
+ * @param account (Optional) A specific account to get tenants for. If not provided, all accounts will be used.
52
+ *
53
+ * @returns A list of tenants.
54
+ */
55
+ async getTenants(account) {
56
+ const startTimeMs = Date.now();
57
+ const results = [];
58
+ for await (account of account ? [account] : await vscode.authentication.getAccounts(getConfiguredAuthProviderId())) {
59
+ // Added check. Without this the getSubscriptionClient function throws the NotSignedInError
60
+ if (await this.isSignedIn(undefined, account)) {
61
+ const { client } = await this.getSubscriptionClient(account, undefined, undefined);
62
+ for await (const tenant of client.tenants.list()) {
63
+ results.push({ ...tenant, account });
64
+ }
65
+ }
66
+ }
67
+ const endTimeMs = Date.now();
68
+ this.logger?.debug(`auth: Got ${results.length} tenants for account "${account?.label}" in ${endTimeMs - startTimeMs}ms`);
69
+ return results;
70
+ }
71
+ /**
72
+ * Gets a list of Azure subscriptions available to the user.
73
+ *
74
+ * @param filter - Whether to filter the list returned. When:
75
+ * - `true`: according to the list returned by `getTenantFilters()` and `getSubscriptionFilters()`.
76
+ * - `false`: return all subscriptions.
77
+ * - `GetSubscriptionsFilter`: according to the values in the filter.
78
+ *
79
+ * Optional, default true.
80
+ *
81
+ * @returns A list of Azure subscriptions. The list is sorted by subscription name.
82
+ * The list can contain duplicate subscriptions if they come from different accounts.
83
+ *
84
+ * @throws A {@link NotSignedInError} If the user is not signed in to Azure.
85
+ * Use {@link isSignedIn} and/or {@link signIn} before this method to ensure
86
+ * the user is signed in.
87
+ */
88
+ async getSubscriptions(filter = true) {
89
+ this.logger?.debug('auth: Loading subscriptions...');
90
+ const startTime = Date.now();
91
+ const configuredTenantFilter = await this.getTenantFilters();
92
+ const tenantIdsToFilterBy =
93
+ // Only filter by the tenant ID option if it is provided
94
+ (typeof filter === 'object' && filter.tenantId ? [filter.tenantId] :
95
+ // Only filter by the configured filter if `filter` is true AND there are tenants in the configured filter
96
+ filter === true && configuredTenantFilter.length > 0 ? configuredTenantFilter :
97
+ undefined);
98
+ const allSubscriptions = [];
99
+ let accountCount; // only used for logging
100
+ try {
101
+ this.suppressSignInEvents = true;
102
+ // Get the list of tenants from each account (filtered or all)
103
+ const accounts = typeof filter === 'object' && filter.account ? [filter.account] : await vscode.authentication.getAccounts(getConfiguredAuthProviderId());
104
+ accountCount = accounts.length;
105
+ for (const account of accounts) {
106
+ for (const tenant of await this.getTenants(account)) {
107
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
108
+ const tenantId = tenant.tenantId;
109
+ if (tenantIdsToFilterBy?.includes(tenantId) === false) {
110
+ continue;
111
+ }
112
+ // For each tenant, get the list of subscriptions
113
+ allSubscriptions.push(...await this.getSubscriptionsForTenant(account, tenantId));
114
+ }
115
+ // list subscriptions for the home tenant
116
+ allSubscriptions.push(...await this.getSubscriptionsForTenant(account));
117
+ }
118
+ }
119
+ finally {
120
+ this.suppressSignInEvents = false;
121
+ }
122
+ // It's possible that by listing subscriptions in all tenants and the "home" tenant there could be duplicate subscriptions
123
+ // Thus, we remove duplicate subscriptions. However, if multiple accounts have the same subscription, we keep them.
124
+ const subscriptionMap = new Map();
125
+ allSubscriptions.forEach(sub => subscriptionMap.set(`${sub.account.id}/${sub.subscriptionId}`, sub));
126
+ const uniqueSubscriptions = Array.from(subscriptionMap.values());
127
+ const endTime = Date.now();
128
+ this.logger?.debug(`auth: Got ${uniqueSubscriptions.length} subscriptions from ${accountCount} accounts in ${endTime - startTime}ms`);
129
+ const sortSubscriptions = (subscriptions) => subscriptions.sort((a, b) => a.name.localeCompare(b.name));
130
+ const subscriptionIds = await this.getSubscriptionFilters();
131
+ if (filter === true && !!subscriptionIds.length) { // If the list is empty it is treated as "no filter"
132
+ return sortSubscriptions(uniqueSubscriptions.filter(sub => subscriptionIds.includes(sub.subscriptionId)));
133
+ }
134
+ return sortSubscriptions(uniqueSubscriptions);
135
+ }
136
+ /**
137
+ * Checks to see if a user is signed in.
138
+ *
139
+ * @param tenantId (Optional) Provide to check if a user is signed in to a specific tenant.
140
+ * @param account (Optional) Provide to check if a user is signed in to a specific account.
141
+ *
142
+ * @returns True if the user is signed in, false otherwise.
143
+ *
144
+ * If no tenant or account is provided, then
145
+ * checks all accounts for a session.
146
+ */
147
+ async isSignedIn(tenantId, account) {
148
+ async function silentlyCheckForSession(tenantId, account) {
149
+ return !!await getSessionFromVSCode([], tenantId, { createIfNone: false, silent: true, account });
150
+ }
151
+ const innerIsSignedIn = async () => {
152
+ // If no tenant or account is provided, then check all accounts for a session
153
+ if (!account && !tenantId) {
154
+ const accounts = await vscode.authentication.getAccounts(getConfiguredAuthProviderId());
155
+ if (accounts.length === 0) {
156
+ return false;
157
+ }
158
+ for (const account of accounts) {
159
+ if (await silentlyCheckForSession(tenantId, account)) {
160
+ // If any account has a session, then return true because the user is signed in
161
+ return true;
162
+ }
163
+ }
164
+ }
165
+ return silentlyCheckForSession(tenantId, account);
166
+ };
167
+ const result = await innerIsSignedIn();
168
+ this.logger?.trace(`auth: isSignedIn returned ${result} (account="${account?.label ?? 'none'}") (tenantId="${tenantId ?? 'none'}")`);
169
+ return result;
170
+ }
171
+ /**
172
+ * Asks the user to sign in or pick an account to use.
173
+ *
174
+ * @param tenantId (Optional) Provide to sign in to a specific tenant.
175
+ * @param account (Optional) Provide to sign in to a specific account.
176
+ *
177
+ * @returns True if the user is signed in, false otherwise.
178
+ */
179
+ async signIn(tenantId, account) {
180
+ this.logger?.debug(`auth: Signing in (account="${account?.label ?? 'none'}") (tenantId="${tenantId ?? 'none'}")`);
181
+ const session = await getSessionFromVSCode([], tenantId, {
182
+ createIfNone: true,
183
+ // If no account is provided, then clear the session preference which tells VS Code to show the account picker
184
+ clearSessionPreference: !account,
185
+ account,
186
+ });
187
+ return !!session;
188
+ }
189
+ /**
190
+ * An event that is fired when the user signs in. Debounced to fire at most once every 5 seconds.
191
+ */
192
+ onDidSignIn = this.onDidSignInEmitter.event;
193
+ /**
194
+ * Signs the user out
195
+ *
196
+ * @deprecated Not currently supported by VS Code auth providers
197
+ */
198
+ signOut() {
199
+ throw new Error(vscode.l10n.t('Signing out programmatically is not supported. You must sign out by selecting the account in the Accounts menu and choosing Sign Out.'));
200
+ }
201
+ /**
202
+ * An event that is fired when the user signs out. Debounced to fire at most once every 5 seconds.
203
+ */
204
+ onDidSignOut = this.onDidSignOutEmitter.event;
205
+ /**
206
+ * Gets the tenant filters that are configured in `azureResourceGroups.selectedSubscriptions`. To
207
+ * override the settings with a custom filter, implement a child class with `getSubscriptionFilters()`
208
+ * and/or `getTenantFilters()` overridden.
209
+ *
210
+ * If no values are returned by `getTenantFilters()`, then all tenants will be scanned for subscriptions.
211
+ *
212
+ * @returns A list of tenant IDs that are configured in `azureResourceGroups.selectedSubscriptions`.
213
+ */
214
+ async getTenantFilters() {
215
+ const config = vscode.workspace.getConfiguration('azureResourceGroups');
216
+ const fullSubscriptionIds = config.get('selectedSubscriptions', []);
217
+ return fullSubscriptionIds.map(id => id.split('/')[0]);
218
+ }
219
+ /**
220
+ * Gets the subscription filters that are configured in `azureResourceGroups.selectedSubscriptions`. To
221
+ * override the settings with a custom filter, implement a child class with `getSubscriptionFilters()`
222
+ * and/or `getTenantFilters()` overridden.
223
+ *
224
+ * If no values are returned by `getSubscriptionFilters()`, then all subscriptions will be returned.
225
+ *
226
+ * @returns A list of subscription IDs that are configured in `azureResourceGroups.selectedSubscriptions`.
227
+ */
228
+ async getSubscriptionFilters() {
229
+ const config = vscode.workspace.getConfiguration('azureResourceGroups');
230
+ const fullSubscriptionIds = config.get('selectedSubscriptions', []);
231
+ return fullSubscriptionIds.map(id => id.split('/')[1]);
232
+ }
233
+ /**
234
+ * Gets the subscriptions for a given tenant.
235
+ *
236
+ * @param tenantId The tenant ID to get subscriptions for.
237
+ * @param account The account to get the subscriptions for.
238
+ *
239
+ * @returns The list of subscriptions for the tenant.
240
+ */
241
+ async getSubscriptionsForTenant(account, tenantId) {
242
+ // If the user is not signed in to this tenant or account, then return an empty list
243
+ // This is to prevent the NotSignedInError from being thrown in getSubscriptionClient
244
+ if (!await this.isSignedIn(tenantId, account)) {
245
+ return [];
246
+ }
247
+ const { client, credential, authentication } = await this.getSubscriptionClient(account, tenantId, undefined);
248
+ const environment = getConfiguredAzureEnv();
249
+ const subscriptions = [];
250
+ for await (const subscription of client.subscriptions.list()) {
251
+ subscriptions.push({
252
+ authentication: authentication,
253
+ environment: environment,
254
+ credential: credential,
255
+ isCustomCloud: environment.isCustomCloud,
256
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
257
+ name: subscription.displayName,
258
+ subscriptionId: subscription.subscriptionId,
259
+ tenantId: tenantId ?? subscription.tenantId,
260
+ /* eslint-enable @typescript-eslint/no-non-null-assertion */
261
+ account: account
262
+ });
263
+ }
264
+ return subscriptions;
265
+ }
266
+ /**
267
+ * Gets a fully-configured subscription client for a given tenant ID
268
+ *
269
+ * @param tenantId (Optional) The tenant ID to get a client for
270
+ * @param account The account that you would like to get the session for
271
+ *
272
+ * @returns A client, the credential used by the client, and the authentication function
273
+ */
274
+ async getSubscriptionClient(account, tenantId, scopes) {
275
+ const armSubs = await import('@azure/arm-resources-subscriptions');
276
+ const session = await getSessionFromVSCode(scopes, tenantId, { createIfNone: false, silent: true, account });
277
+ if (!session) {
278
+ throw new NotSignedInError();
279
+ }
280
+ const credential = {
281
+ getToken: async () => {
282
+ return {
283
+ token: session.accessToken,
284
+ expiresOnTimestamp: 0
285
+ };
286
+ }
287
+ };
288
+ const configuredAzureEnv = getConfiguredAzureEnv();
289
+ const endpoint = configuredAzureEnv.resourceManagerEndpointUrl;
290
+ return {
291
+ client: new armSubs.SubscriptionClient(credential, { endpoint }),
292
+ credential: credential,
293
+ authentication: {
294
+ getSession: () => session,
295
+ getSessionWithScopes: (scopeListOrRequest) => {
296
+ // in order to handle a challenge, we must enable createIfNone so
297
+ // that we can prompt the user to step-up their session with MFA
298
+ // otherwise, never prompt the user
299
+ return getSessionFromVSCode(scopeListOrRequest, tenantId, { ...(isAuthenticationWwwAuthenticateRequest(scopeListOrRequest) ? { createIfNone: true } : { silent: true }), account });
300
+ },
301
+ }
302
+ };
303
+ }
304
+ }
305
+ //# sourceMappingURL=VSCodeAzureSubscriptionProvider.js.map
@@ -0,0 +1,13 @@
1
+ import * as vscode from "vscode";
2
+ /**
3
+ * Wraps {@link vscode.authentication.getSession} and handles:
4
+ * * Passing the configured auth provider id
5
+ * * Getting the list of scopes, adding the tenant id to the scope list if needed
6
+ *
7
+ * @param scopeOrListOrRequest - top-level resource scopes (e.g. http://management.azure.com, http://storage.azure.com) or .default scopes. All resources/scopes will be normalized to the `.default` scope for each resource.
8
+ * Use `vscode.AuthenticationWwwAuthenticateRequest` if you need to pass in a challenge (WWW-Authenticate header). Note: Use of `vscode.AuthenticationWwwAuthenticateRequest` requires VS Code 1.105.0 or newer.
9
+ * @param tenantId - (Optional) The tenant ID, will be added to the scopes
10
+ * @param options - see {@link vscode.AuthenticationGetSessionOptions}
11
+ * @returns An authentication session if available, or undefined if there are no sessions
12
+ */
13
+ export declare function getSessionFromVSCode(scopeOrListOrRequest?: string | string[] | vscode.AuthenticationWwwAuthenticateRequest, tenantId?: string, options?: vscode.AuthenticationGetSessionOptions): Promise<vscode.AuthenticationSession | undefined>;
@@ -0,0 +1,72 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import * as vscode from "vscode";
6
+ import { getConfiguredAuthProviderId, getConfiguredAzureEnv } from "./utils/configuredAzureEnv";
7
+ import { isAuthenticationWwwAuthenticateRequest } from "./utils/isAuthenticationWwwAuthenticateRequest";
8
+ function ensureEndingSlash(value) {
9
+ return value.endsWith('/') ? value : `${value}/`;
10
+ }
11
+ function getResourceScopes(scopes) {
12
+ if (scopes === undefined || scopes === "" || scopes.length === 0) {
13
+ scopes = ensureEndingSlash(getConfiguredAzureEnv().managementEndpointUrl);
14
+ }
15
+ const arrScopes = (Array.isArray(scopes) ? scopes : [scopes])
16
+ .map((scope) => {
17
+ if (scope.endsWith('.default')) {
18
+ return scope;
19
+ }
20
+ else {
21
+ return `${scope}.default`;
22
+ }
23
+ });
24
+ return Array.from(new Set(arrScopes));
25
+ }
26
+ function addTenantIdScope(scopes, tenantId) {
27
+ const scopeSet = new Set(scopes);
28
+ scopeSet.add(`VSCODE_TENANT:${tenantId}`);
29
+ return Array.from(scopeSet);
30
+ }
31
+ function getModifiedScopes(scopes, tenantId) {
32
+ let scopeArr = getResourceScopes(scopes);
33
+ if (tenantId) {
34
+ scopeArr = addTenantIdScope(scopeArr, tenantId);
35
+ }
36
+ return scopeArr;
37
+ }
38
+ /**
39
+ * Deconstructs and rebuilds the scopes arg in order to use the above utils to modify the scopes array.
40
+ * And then returns the proper type to pass directly to vscode.authentication.getSession
41
+ */
42
+ function formScopesArg(scopeOrListOrRequest, tenantId) {
43
+ const isChallenge = isAuthenticationWwwAuthenticateRequest(scopeOrListOrRequest);
44
+ let initialScopeList = undefined;
45
+ if (typeof scopeOrListOrRequest === 'string' && !!scopeOrListOrRequest) {
46
+ initialScopeList = [scopeOrListOrRequest];
47
+ }
48
+ else if (Array.isArray(scopeOrListOrRequest)) {
49
+ initialScopeList = scopeOrListOrRequest;
50
+ }
51
+ else if (isChallenge) {
52
+ // `scopeOrListOrRequest.fallbackScopes` being readonly forces us to rebuild the array
53
+ initialScopeList = scopeOrListOrRequest.fallbackScopes ? Array.from(scopeOrListOrRequest.fallbackScopes) : undefined;
54
+ }
55
+ const modifiedScopeList = getModifiedScopes(initialScopeList, tenantId);
56
+ return isChallenge ? { fallbackScopes: modifiedScopeList, wwwAuthenticate: scopeOrListOrRequest.wwwAuthenticate } : modifiedScopeList;
57
+ }
58
+ /**
59
+ * Wraps {@link vscode.authentication.getSession} and handles:
60
+ * * Passing the configured auth provider id
61
+ * * Getting the list of scopes, adding the tenant id to the scope list if needed
62
+ *
63
+ * @param scopeOrListOrRequest - top-level resource scopes (e.g. http://management.azure.com, http://storage.azure.com) or .default scopes. All resources/scopes will be normalized to the `.default` scope for each resource.
64
+ * Use `vscode.AuthenticationWwwAuthenticateRequest` if you need to pass in a challenge (WWW-Authenticate header). Note: Use of `vscode.AuthenticationWwwAuthenticateRequest` requires VS Code 1.105.0 or newer.
65
+ * @param tenantId - (Optional) The tenant ID, will be added to the scopes
66
+ * @param options - see {@link vscode.AuthenticationGetSessionOptions}
67
+ * @returns An authentication session if available, or undefined if there are no sessions
68
+ */
69
+ export async function getSessionFromVSCode(scopeOrListOrRequest, tenantId, options) {
70
+ return await vscode.authentication.getSession(getConfiguredAuthProviderId(), formScopesArg(scopeOrListOrRequest, tenantId), options);
71
+ }
72
+ //# sourceMappingURL=getSessionFromVSCode.js.map
@@ -0,0 +1,56 @@
1
+ export * from './AzureAuthentication';
2
+ export * from './AzureDevOpsSubscriptionProvider';
3
+ export * from './AzureSubscription';
4
+ export * from './AzureSubscriptionProvider';
5
+ export * from './AzureTenant';
6
+ export * from './NotSignedInError';
7
+ export * from './signInToTenant';
8
+ export * from './utils/configuredAzureEnv';
9
+ export * from './utils/getUnauthenticatedTenants';
10
+ export * from './VSCodeAzureSubscriptionProvider';
11
+ declare module 'vscode' {
12
+ /**
13
+ * Represents parameters for creating a session based on a WWW-Authenticate header value.
14
+ * This is used when an API returns a 401 with a WWW-Authenticate header indicating
15
+ * that additional authentication is required. The details of which will be passed down
16
+ * to the authentication provider to create a session.
17
+ *
18
+ * @note The authorization provider must support handling challenges and specifically
19
+ * the challenges in this WWW-Authenticate value.
20
+ * @note For more information on WWW-Authenticate please see https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/WWW-Authenticate
21
+ */
22
+ interface AuthenticationWwwAuthenticateRequest {
23
+ /**
24
+ * The raw WWW-Authenticate header value that triggered this challenge.
25
+ * This will be parsed by the authentication provider to extract the necessary
26
+ * challenge information.
27
+ */
28
+ readonly wwwAuthenticate: string;
29
+ /**
30
+ * The fallback scopes to use if no scopes are found in the WWW-Authenticate header.
31
+ */
32
+ readonly fallbackScopes?: readonly string[];
33
+ }
34
+ /**
35
+ * Namespace for authentication.
36
+ */
37
+ namespace authentication {
38
+ /**
39
+ * Get an authentication session matching the desired scopes or request. Rejects if a provider with providerId is not
40
+ * registered, or if the user does not consent to sharing authentication information with the extension. If there
41
+ * are multiple sessions with the same scopes, the user will be shown a quickpick to select which account they would like to use.
42
+ *
43
+ * Built-in auth providers include:
44
+ * * 'github' - For GitHub.com
45
+ * * 'microsoft' For both personal & organizational Microsoft accounts
46
+ * * (less common) 'github-enterprise' - for alternative GitHub hostings, GHE.com, GitHub Enterprise Server
47
+ * * (less common) 'microsoft-sovereign-cloud' - for alternative Microsoft clouds
48
+ *
49
+ * @param providerId The id of the provider to use
50
+ * @param scopeListOrRequest A scope list of permissions requested or a WWW-Authenticate request. These are dependent on the authentication provider.
51
+ * @param options The {@link AuthenticationGetSessionOptions} to use
52
+ * @returns A thenable that resolves to an authentication session or undefined if a silent flow was used and no session was found
53
+ */
54
+ function getSession(providerId: string, scopeListOrRequest: ReadonlyArray<string> | AuthenticationWwwAuthenticateRequest, options?: AuthenticationGetSessionOptions): Thenable<AuthenticationSession | undefined>;
55
+ }
56
+ }
@@ -1,10 +1,15 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
1
5
  export * from './AzureAuthentication';
2
6
  export * from './AzureDevOpsSubscriptionProvider';
3
- export * from './AzureTenant';
4
7
  export * from './AzureSubscription';
5
8
  export * from './AzureSubscriptionProvider';
9
+ export * from './AzureTenant';
6
10
  export * from './NotSignedInError';
7
11
  export * from './signInToTenant';
8
12
  export * from './utils/configuredAzureEnv';
9
13
  export * from './utils/getUnauthenticatedTenants';
10
14
  export * from './VSCodeAzureSubscriptionProvider';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,6 @@
1
+ import type { AzureSubscriptionProvider } from "./AzureSubscriptionProvider";
2
+ /**
3
+ * Prompts user to select from a list of unauthenticated tenants.
4
+ * Once selected, requests a new session from VS Code specifially for this tenant.
5
+ */
6
+ export declare function signInToTenant(subscriptionProvider: AzureSubscriptionProvider): Promise<void>;
@@ -0,0 +1,43 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import * as vscode from "vscode";
6
+ import { getUnauthenticatedTenants } from "./utils/getUnauthenticatedTenants";
7
+ /**
8
+ * Prompts user to select from a list of unauthenticated tenants.
9
+ * Once selected, requests a new session from VS Code specifially for this tenant.
10
+ */
11
+ export async function signInToTenant(subscriptionProvider) {
12
+ const tenantId = await pickTenant(subscriptionProvider);
13
+ if (tenantId) {
14
+ await subscriptionProvider.signIn(tenantId);
15
+ }
16
+ }
17
+ async function pickTenant(subscriptionProvider) {
18
+ const pick = await vscode.window.showQuickPick(getPicks(subscriptionProvider), {
19
+ placeHolder: 'Select a Tenant (Directory) to Sign In To', // TODO: localize
20
+ matchOnDescription: true, // allow searching by tenantId
21
+ ignoreFocusOut: true,
22
+ });
23
+ return pick?.tenant.tenantId;
24
+ }
25
+ async function getPicks(subscriptionProvider) {
26
+ const unauthenticatedTenants = await getUnauthenticatedTenants(subscriptionProvider);
27
+ const duplicateTenants = new Set(unauthenticatedTenants
28
+ .filter((tenant, index, self) => index !== self.findIndex(t => t.tenantId === tenant.tenantId))
29
+ .map(tenant => tenant.tenantId));
30
+ const isDuplicate = (tenantId) => duplicateTenants.has(tenantId);
31
+ const picks = unauthenticatedTenants
32
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
33
+ .sort((a, b) => (a.displayName).localeCompare(b.displayName))
34
+ .map(tenant => ({
35
+ label: tenant.displayName ?? '',
36
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
37
+ description: `${tenant.tenantId}${isDuplicate(tenant.tenantId) ? ` (${tenant.account.label})` : ''}`,
38
+ detail: tenant.defaultDomain ?? '',
39
+ tenant,
40
+ }));
41
+ return picks;
42
+ }
43
+ //# sourceMappingURL=signInToTenant.js.map
@@ -0,0 +1,24 @@
1
+ import * as azureEnv from '@azure/ms-rest-azure-env';
2
+ import * as vscode from 'vscode';
3
+ /**
4
+ * Gets the configured Azure environment.
5
+ *
6
+ * @returns The configured Azure environment from the settings in the built-in authentication provider extension
7
+ */
8
+ export declare function getConfiguredAzureEnv(): azureEnv.Environment & {
9
+ isCustomCloud: boolean;
10
+ };
11
+ /**
12
+ * Sets the configured Azure cloud.
13
+ *
14
+ * @param cloud Use `'AzureCloud'` or `undefined` for public Azure cloud, `'ChinaCloud'` for Azure China, or `'USGovernment'` for Azure US Government.
15
+ * These are the same values as the cloud names in `@azure/ms-rest-azure-env`. For a custom cloud, use an instance of the `@azure/ms-rest-azure-env` {@link azureEnv.EnvironmentParameters}.
16
+ *
17
+ * @param target (Optional) The configuration target to use, by default {@link vscode.ConfigurationTarget.Global}.
18
+ */
19
+ export declare function setConfiguredAzureEnv(cloud: 'AzureCloud' | 'ChinaCloud' | 'USGovernment' | undefined | azureEnv.EnvironmentParameters, target?: vscode.ConfigurationTarget): Promise<void>;
20
+ /**
21
+ * Gets the ID of the authentication provider configured to be used
22
+ * @returns The provider ID to use, either `'microsoft'` or `'microsoft-sovereign-cloud'`
23
+ */
24
+ export declare function getConfiguredAuthProviderId(): string;
@@ -0,0 +1,90 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import * as azureEnv from '@azure/ms-rest-azure-env'; // This package is so small that it's not worth lazy loading
6
+ import * as vscode from 'vscode';
7
+ // These strings come from https://github.com/microsoft/vscode/blob/eac16e9b63a11885b538db3e0b533a02a2fb8143/extensions/microsoft-authentication/package.json#L40-L99
8
+ const CustomCloudConfigurationSection = 'microsoft-sovereign-cloud';
9
+ const CloudEnvironmentSettingName = 'environment';
10
+ const CustomEnvironmentSettingName = 'customEnvironment';
11
+ var CloudEnvironmentSettingValue;
12
+ (function (CloudEnvironmentSettingValue) {
13
+ CloudEnvironmentSettingValue["ChinaCloud"] = "ChinaCloud";
14
+ CloudEnvironmentSettingValue["USGovernment"] = "USGovernment";
15
+ CloudEnvironmentSettingValue["Custom"] = "custom";
16
+ })(CloudEnvironmentSettingValue || (CloudEnvironmentSettingValue = {}));
17
+ /**
18
+ * Gets the configured Azure environment.
19
+ *
20
+ * @returns The configured Azure environment from the settings in the built-in authentication provider extension
21
+ */
22
+ export function getConfiguredAzureEnv() {
23
+ const authProviderConfig = vscode.workspace.getConfiguration(CustomCloudConfigurationSection);
24
+ const environmentSettingValue = authProviderConfig.get(CloudEnvironmentSettingName);
25
+ if (environmentSettingValue === CloudEnvironmentSettingValue.ChinaCloud) {
26
+ return {
27
+ ...azureEnv.Environment.ChinaCloud,
28
+ isCustomCloud: false,
29
+ };
30
+ }
31
+ else if (environmentSettingValue === CloudEnvironmentSettingValue.USGovernment) {
32
+ return {
33
+ ...azureEnv.Environment.USGovernment,
34
+ isCustomCloud: false,
35
+ };
36
+ }
37
+ else if (environmentSettingValue === CloudEnvironmentSettingValue.Custom) {
38
+ const customCloud = authProviderConfig.get(CustomEnvironmentSettingName);
39
+ if (customCloud) {
40
+ return {
41
+ ...new azureEnv.Environment(customCloud),
42
+ isCustomCloud: true,
43
+ };
44
+ }
45
+ throw new Error(vscode.l10n.t('The custom cloud choice is not configured. Please configure the setting `{0}.{1}`.', CustomCloudConfigurationSection, CustomEnvironmentSettingName));
46
+ }
47
+ return {
48
+ ...azureEnv.Environment.get(azureEnv.Environment.AzureCloud.name),
49
+ isCustomCloud: false,
50
+ };
51
+ }
52
+ /**
53
+ * Sets the configured Azure cloud.
54
+ *
55
+ * @param cloud Use `'AzureCloud'` or `undefined` for public Azure cloud, `'ChinaCloud'` for Azure China, or `'USGovernment'` for Azure US Government.
56
+ * These are the same values as the cloud names in `@azure/ms-rest-azure-env`. For a custom cloud, use an instance of the `@azure/ms-rest-azure-env` {@link azureEnv.EnvironmentParameters}.
57
+ *
58
+ * @param target (Optional) The configuration target to use, by default {@link vscode.ConfigurationTarget.Global}.
59
+ */
60
+ export async function setConfiguredAzureEnv(cloud, target = vscode.ConfigurationTarget.Global) {
61
+ const authProviderConfig = vscode.workspace.getConfiguration(CustomCloudConfigurationSection);
62
+ if (typeof cloud === 'undefined' || !cloud) {
63
+ // Use public cloud implicitly--set `environment` setting to `undefined`
64
+ await authProviderConfig.update(CloudEnvironmentSettingName, undefined, target);
65
+ }
66
+ else if (typeof cloud === 'string' && cloud === 'AzureCloud') {
67
+ // Use public cloud explicitly--set `environment` setting to `undefined`
68
+ await authProviderConfig.update(CloudEnvironmentSettingName, undefined, target);
69
+ }
70
+ else if (typeof cloud === 'string') {
71
+ // Use a sovereign cloud--set the `environment` setting to the specified value
72
+ await authProviderConfig.update(CloudEnvironmentSettingName, cloud, target);
73
+ }
74
+ else if (typeof cloud === 'object') {
75
+ // use a custom cloud--set the `environment` setting to `custom` and the `customEnvironment` setting to the specified value
76
+ await authProviderConfig.update(CloudEnvironmentSettingName, CloudEnvironmentSettingValue.Custom, target);
77
+ await authProviderConfig.update(CustomEnvironmentSettingName, cloud, target);
78
+ }
79
+ else {
80
+ throw new Error(`Invalid cloud value: ${JSON.stringify(cloud)}`);
81
+ }
82
+ }
83
+ /**
84
+ * Gets the ID of the authentication provider configured to be used
85
+ * @returns The provider ID to use, either `'microsoft'` or `'microsoft-sovereign-cloud'`
86
+ */
87
+ export function getConfiguredAuthProviderId() {
88
+ return getConfiguredAzureEnv().name === azureEnv.Environment.AzureCloud.name ? 'microsoft' : 'microsoft-sovereign-cloud';
89
+ }
90
+ //# sourceMappingURL=configuredAzureEnv.js.map
@@ -0,0 +1,6 @@
1
+ import type { AzureSubscriptionProvider } from "../AzureSubscriptionProvider";
2
+ import type { AzureTenant } from "../AzureTenant";
3
+ /**
4
+ * @returns list of tenants that VS Code doesn't have sessions for
5
+ */
6
+ export declare function getUnauthenticatedTenants(subscriptionProvider: AzureSubscriptionProvider): Promise<AzureTenant[]>;
@@ -0,0 +1,18 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ /**
6
+ * @returns list of tenants that VS Code doesn't have sessions for
7
+ */
8
+ export async function getUnauthenticatedTenants(subscriptionProvider) {
9
+ const tenants = await subscriptionProvider.getTenants();
10
+ const unauthenticatedTenants = [];
11
+ for await (const tenant of tenants) {
12
+ if (!await subscriptionProvider.isSignedIn(tenant.tenantId, tenant.account)) {
13
+ unauthenticatedTenants.push(tenant);
14
+ }
15
+ }
16
+ return unauthenticatedTenants;
17
+ }
18
+ //# sourceMappingURL=getUnauthenticatedTenants.js.map