@microsoft/vscode-azext-azureauth 5.1.1 → 6.0.0-alpha.2
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 +8 -0
- package/README.md +9 -79
- package/dist/cjs/src/contracts/AzureAccount.js +7 -0
- package/dist/cjs/src/contracts/AzureSubscriptionProviderRequestOptions.js +48 -0
- package/dist/cjs/src/index.js +13 -10
- package/dist/cjs/src/providers/AzureDevOpsSubscriptionProvider.js +178 -0
- package/dist/cjs/src/providers/AzureSubscriptionProviderBase.js +393 -0
- package/dist/cjs/src/providers/VSCodeAzureSubscriptionProvider.js +269 -0
- package/dist/cjs/src/utils/Limiter.js +41 -0
- package/dist/cjs/src/{NotSignedInError.js → utils/NotSignedInError.js} +3 -2
- package/dist/cjs/src/utils/configuredAzureEnv.js +14 -16
- package/dist/cjs/src/utils/dedupeSubscriptions.js +27 -0
- package/dist/cjs/src/utils/getMetricsForTelemetry.js +47 -0
- package/dist/cjs/src/{getSessionFromVSCode.js → utils/getSessionFromVSCode.js} +5 -2
- package/dist/cjs/src/utils/getSignalForToken.js +29 -0
- package/dist/cjs/src/utils/map/CaselessMap.js +71 -0
- package/dist/cjs/src/utils/map/TwoKeyCaselessMap.js +194 -0
- package/dist/cjs/src/utils/screen.js +62 -0
- package/dist/cjs/src/{signInToTenant.js → utils/signInToTenant.js} +15 -13
- package/dist/cjs/src/utils/tryGetTokenExpiration.js +25 -0
- package/dist/esm/src/contracts/AzureAccount.d.ts +5 -0
- package/dist/esm/src/contracts/AzureAccount.js +6 -0
- package/dist/esm/src/{AzureAuthentication.d.ts → contracts/AzureAuthentication.d.ts} +1 -1
- package/dist/esm/src/{AzureSubscription.d.ts → contracts/AzureSubscription.d.ts} +4 -4
- package/dist/esm/src/contracts/AzureSubscriptionProvider.d.ts +112 -0
- package/dist/esm/src/contracts/AzureSubscriptionProviderRequestOptions.d.ts +103 -0
- package/dist/esm/src/contracts/AzureSubscriptionProviderRequestOptions.js +44 -0
- package/dist/esm/src/contracts/AzureTenant.d.ts +15 -0
- package/dist/esm/src/index.d.ts +13 -10
- package/dist/esm/src/index.js +13 -10
- package/dist/esm/src/providers/AzureDevOpsSubscriptionProvider.d.ts +68 -0
- package/dist/esm/src/providers/AzureDevOpsSubscriptionProvider.js +140 -0
- package/dist/esm/src/providers/AzureSubscriptionProviderBase.d.ts +74 -0
- package/dist/esm/src/providers/AzureSubscriptionProviderBase.js +356 -0
- package/dist/esm/src/providers/VSCodeAzureSubscriptionProvider.d.ts +70 -0
- package/dist/esm/src/providers/VSCodeAzureSubscriptionProvider.js +232 -0
- package/dist/esm/src/utils/Limiter.d.ts +9 -0
- package/dist/esm/src/utils/Limiter.js +37 -0
- package/dist/esm/src/{NotSignedInError.d.ts → utils/NotSignedInError.d.ts} +2 -2
- package/dist/esm/src/{NotSignedInError.js → utils/NotSignedInError.js} +3 -2
- package/dist/esm/src/utils/configuredAzureEnv.d.ts +7 -4
- package/dist/esm/src/utils/configuredAzureEnv.js +14 -16
- package/dist/esm/src/utils/dedupeSubscriptions.d.ts +14 -0
- package/dist/esm/src/utils/dedupeSubscriptions.js +24 -0
- package/dist/esm/src/utils/getMetricsForTelemetry.d.ts +32 -0
- package/dist/esm/src/utils/getMetricsForTelemetry.js +44 -0
- package/dist/esm/src/{getSessionFromVSCode.js → utils/getSessionFromVSCode.js} +5 -2
- package/dist/esm/src/utils/getSignalForToken.d.ts +7 -0
- package/dist/esm/src/utils/getSignalForToken.js +26 -0
- package/dist/esm/src/utils/map/CaselessMap.d.ts +28 -0
- package/dist/esm/src/utils/map/CaselessMap.js +67 -0
- package/dist/esm/src/utils/map/TwoKeyCaselessMap.d.ts +49 -0
- package/dist/esm/src/utils/map/TwoKeyCaselessMap.js +190 -0
- package/dist/esm/src/utils/screen.d.ts +9 -0
- package/dist/esm/src/utils/screen.js +59 -0
- package/dist/esm/src/utils/signInToTenant.d.ts +7 -0
- package/dist/esm/src/{signInToTenant.js → utils/signInToTenant.js} +16 -14
- package/dist/esm/src/utils/tryGetTokenExpiration.d.ts +2 -0
- package/dist/esm/src/utils/tryGetTokenExpiration.js +22 -0
- package/package.json +33 -23
- package/AzureFederatedCredentialsGuide.md +0 -174
- package/dist/cjs/src/AzureDevOpsSubscriptionProvider.js +0 -215
- package/dist/cjs/src/VSCodeAzureSubscriptionProvider.js +0 -395
- package/dist/cjs/src/utils/getUnauthenticatedTenants.js +0 -23
- package/dist/cjs/src/utils/isGetSubscriptionsFilter.js +0 -27
- package/dist/esm/src/AzureDevOpsSubscriptionProvider.d.ts +0 -68
- package/dist/esm/src/AzureDevOpsSubscriptionProvider.js +0 -210
- package/dist/esm/src/AzureSubscriptionProvider.d.ts +0 -82
- package/dist/esm/src/AzureTenant.d.ts +0 -5
- package/dist/esm/src/VSCodeAzureSubscriptionProvider.d.ts +0 -116
- package/dist/esm/src/VSCodeAzureSubscriptionProvider.js +0 -358
- package/dist/esm/src/signInToTenant.d.ts +0 -6
- package/dist/esm/src/utils/getUnauthenticatedTenants.d.ts +0 -9
- package/dist/esm/src/utils/getUnauthenticatedTenants.js +0 -20
- package/dist/esm/src/utils/isGetSubscriptionsFilter.d.ts +0 -14
- package/dist/esm/src/utils/isGetSubscriptionsFilter.js +0 -23
- /package/dist/cjs/src/{AzureAuthentication.js → contracts/AzureAuthentication.js} +0 -0
- /package/dist/cjs/src/{AzureSubscription.js → contracts/AzureSubscription.js} +0 -0
- /package/dist/cjs/src/{AzureSubscriptionProvider.js → contracts/AzureSubscriptionProvider.js} +0 -0
- /package/dist/cjs/src/{AzureTenant.js → contracts/AzureTenant.js} +0 -0
- /package/dist/esm/src/{AzureAuthentication.js → contracts/AzureAuthentication.js} +0 -0
- /package/dist/esm/src/{AzureSubscription.js → contracts/AzureSubscription.js} +0 -0
- /package/dist/esm/src/{AzureSubscriptionProvider.js → contracts/AzureSubscriptionProvider.js} +0 -0
- /package/dist/esm/src/{AzureTenant.js → contracts/AzureTenant.js} +0 -0
- /package/dist/esm/src/{getSessionFromVSCode.d.ts → utils/getSessionFromVSCode.d.ts} +0 -0
|
@@ -0,0 +1,393 @@
|
|
|
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
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.AzureSubscriptionProviderBase = void 0;
|
|
41
|
+
const vscode = __importStar(require("vscode"));
|
|
42
|
+
const AzureSubscriptionProviderRequestOptions_1 = require("../contracts/AzureSubscriptionProviderRequestOptions");
|
|
43
|
+
const configuredAzureEnv_1 = require("../utils/configuredAzureEnv");
|
|
44
|
+
const dedupeSubscriptions_1 = require("../utils/dedupeSubscriptions");
|
|
45
|
+
const getSessionFromVSCode_1 = require("../utils/getSessionFromVSCode");
|
|
46
|
+
const getSignalForToken_1 = require("../utils/getSignalForToken");
|
|
47
|
+
const isAuthenticationWwwAuthenticateRequest_1 = require("../utils/isAuthenticationWwwAuthenticateRequest");
|
|
48
|
+
const Limiter_1 = require("../utils/Limiter");
|
|
49
|
+
const NotSignedInError_1 = require("../utils/NotSignedInError");
|
|
50
|
+
const screen_1 = require("../utils/screen");
|
|
51
|
+
const tryGetTokenExpiration_1 = require("../utils/tryGetTokenExpiration");
|
|
52
|
+
const EventDebounce = 5 * 1000; // 5 seconds minimum between `onRefreshSuggested` events
|
|
53
|
+
const EventSilenceTime = 5 * 1000; // 5 seconds after sign-in to silence `onRefreshSuggested` events
|
|
54
|
+
const TenantListConcurrency = 3; // We will try to list tenants for at most 3 accounts in parallel
|
|
55
|
+
const SubscriptionListConcurrency = 5; // We will try to list subscriptions for at most 5 account+tenants in parallel
|
|
56
|
+
let armSubs;
|
|
57
|
+
/**
|
|
58
|
+
* Base class for Azure subscription providers that use VS Code authentication.
|
|
59
|
+
* Handles actual communication with Azure via the Azure SDK, as well as
|
|
60
|
+
* controlling the firing of `onRefreshSuggested` events.
|
|
61
|
+
*/
|
|
62
|
+
class AzureSubscriptionProviderBase {
|
|
63
|
+
logger;
|
|
64
|
+
sessionChangeListener;
|
|
65
|
+
refreshSuggestedEmitter = new vscode.EventEmitter();
|
|
66
|
+
lastRefreshSuggestedTime = 0;
|
|
67
|
+
suppressRefreshSuggestedEvents = false;
|
|
68
|
+
/**
|
|
69
|
+
* Constructs a new {@link AzureSubscriptionProviderBase}.
|
|
70
|
+
* @param logger (Optional) A logger to record information to
|
|
71
|
+
*/
|
|
72
|
+
constructor(logger) {
|
|
73
|
+
this.logger = logger;
|
|
74
|
+
}
|
|
75
|
+
dispose() {
|
|
76
|
+
if (this.timeout) {
|
|
77
|
+
clearTimeout(this.timeout);
|
|
78
|
+
this.timeout = undefined;
|
|
79
|
+
}
|
|
80
|
+
this.sessionChangeListener?.dispose();
|
|
81
|
+
this.refreshSuggestedEmitter.dispose();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* @inheritdoc
|
|
85
|
+
*/
|
|
86
|
+
onRefreshSuggested(callback, thisArg, disposables) {
|
|
87
|
+
this.sessionChangeListener ??= vscode.authentication.onDidChangeSessions(evt => {
|
|
88
|
+
if (evt.provider.id === (0, configuredAzureEnv_1.getConfiguredAuthProviderId)()) {
|
|
89
|
+
this.fireRefreshSuggestedIfNeeded({ reason: 'sessionChange' });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return this.refreshSuggestedEmitter.event(callback, thisArg, disposables);
|
|
93
|
+
}
|
|
94
|
+
fireRefreshSuggestedIfNeeded(evtArgs) {
|
|
95
|
+
if (this.suppressRefreshSuggestedEvents || Date.now() < this.lastRefreshSuggestedTime + EventDebounce) {
|
|
96
|
+
// Suppress and/or debounce events to avoid flooding
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
this.log(`Firing onRefreshSuggested event due to reason: ${evtArgs.reason}`);
|
|
100
|
+
this.lastRefreshSuggestedTime = Date.now();
|
|
101
|
+
this.refreshSuggestedEmitter.fire(evtArgs);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* @inheritdoc
|
|
106
|
+
*/
|
|
107
|
+
async signIn(tenant, options = AzureSubscriptionProviderRequestOptions_1.DefaultSignInOptions) {
|
|
108
|
+
const prompt = options.promptIfNeeded ?? AzureSubscriptionProviderRequestOptions_1.DefaultSignInOptions.promptIfNeeded;
|
|
109
|
+
if (prompt) {
|
|
110
|
+
// If interactive, suppress without timeout until sign in is done (it can take a while when done interactively)
|
|
111
|
+
this.suppressRefreshSuggestedEvents = true;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// If silent, suppress with normal timeout
|
|
115
|
+
this.silenceRefreshEvents();
|
|
116
|
+
}
|
|
117
|
+
const session = await (0, getSessionFromVSCode_1.getSessionFromVSCode)(undefined, tenant?.tenantId, {
|
|
118
|
+
account: tenant?.account,
|
|
119
|
+
clearSessionPreference: options.clearSessionPreference ?? AzureSubscriptionProviderRequestOptions_1.DefaultSignInOptions.clearSessionPreference,
|
|
120
|
+
createIfNone: prompt,
|
|
121
|
+
silent: !prompt,
|
|
122
|
+
});
|
|
123
|
+
if (prompt) {
|
|
124
|
+
// Interactive sign in can take a while, so silence events for a bit longer
|
|
125
|
+
this.silenceRefreshEvents();
|
|
126
|
+
}
|
|
127
|
+
return !!session;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* @inheritdoc
|
|
131
|
+
*/
|
|
132
|
+
async getAvailableSubscriptions(options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
133
|
+
try {
|
|
134
|
+
const availableSubscriptions = [];
|
|
135
|
+
const tenantListLimiter = new Limiter_1.Limiter(TenantListConcurrency);
|
|
136
|
+
const tenantListPromises = [];
|
|
137
|
+
const subscriptionListLimiter = new Limiter_1.Limiter(SubscriptionListConcurrency);
|
|
138
|
+
const subscriptionListPromisesFlat = [];
|
|
139
|
+
let tenantsProcessed = 0;
|
|
140
|
+
const maximumTenants = options.maximumTenants ?? AzureSubscriptionProviderRequestOptions_1.DefaultOptions.maximumTenants;
|
|
141
|
+
const accounts = await this.getAccounts(options);
|
|
142
|
+
for (const account of accounts) {
|
|
143
|
+
this.throwIfCancelled(options.token);
|
|
144
|
+
tenantListPromises.push(tenantListLimiter.queue(async () => {
|
|
145
|
+
try {
|
|
146
|
+
if (tenantsProcessed >= maximumTenants) {
|
|
147
|
+
this.logForAccount(account, `Skipping account because maximum tenants of ${maximumTenants} has been reached`);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const tenants = await this.getTenantsForAccount(account, options);
|
|
151
|
+
for (const tenant of tenants) {
|
|
152
|
+
this.throwIfCancelled(options.token);
|
|
153
|
+
if (tenantsProcessed >= maximumTenants) {
|
|
154
|
+
this.logForAccount(account, `Skipping remaining tenants because maximum tenants of ${maximumTenants} has been reached`);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
tenantsProcessed++;
|
|
158
|
+
subscriptionListPromisesFlat.push(subscriptionListLimiter.queue(async () => {
|
|
159
|
+
try {
|
|
160
|
+
const subscriptions = await this.getSubscriptionsForTenant(tenant, options);
|
|
161
|
+
availableSubscriptions.push(...subscriptions);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
if ((0, NotSignedInError_1.isNotSignedInError)(err)) {
|
|
165
|
+
this.logForTenant(tenant, 'Skipping account+tenant because it is not signed in');
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
if ((0, NotSignedInError_1.isNotSignedInError)(err)) {
|
|
175
|
+
this.logForAccount(account, 'Skipping account because it is not signed in');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
await Promise.all(tenantListPromises);
|
|
182
|
+
await Promise.all(subscriptionListPromisesFlat);
|
|
183
|
+
return (0, dedupeSubscriptions_1.dedupeSubscriptions)(availableSubscriptions);
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
// Intentionally not eating NotSignedInError here, if it is thrown by getAccounts()
|
|
187
|
+
this.remapLogRethrow(err, options.token);
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
this.throwIfCancelled(options.token);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* @inheritdoc
|
|
195
|
+
*/
|
|
196
|
+
async getAccounts(options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
197
|
+
try {
|
|
198
|
+
const startTime = Date.now();
|
|
199
|
+
this.log('Fetching accounts...');
|
|
200
|
+
this.silenceRefreshEvents();
|
|
201
|
+
const results = await vscode.authentication.getAccounts((0, configuredAzureEnv_1.getConfiguredAuthProviderId)());
|
|
202
|
+
if (results.length === 0) {
|
|
203
|
+
this.log('No accounts found');
|
|
204
|
+
throw new NotSignedInError_1.NotSignedInError();
|
|
205
|
+
}
|
|
206
|
+
this.log(`Fetched ${results.length} accounts (before filter) in ${Date.now() - startTime}ms`);
|
|
207
|
+
return Array.from(results);
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
// Cancellation is not actually supported by vscode.authentication.getAccounts, but just in case it is added in the future...
|
|
211
|
+
this.remapLogRethrow(err, options.token);
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
this.throwIfCancelled(options.token);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* @inheritdoc
|
|
219
|
+
*/
|
|
220
|
+
async getUnauthenticatedTenantsForAccount(account, options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
221
|
+
try {
|
|
222
|
+
const startTime = Date.now();
|
|
223
|
+
const tenantListLimiter = new Limiter_1.Limiter(TenantListConcurrency);
|
|
224
|
+
const tenantListPromises = [];
|
|
225
|
+
const allTenants = await this.getTenantsForAccount(account, { ...options, filter: false });
|
|
226
|
+
const unauthenticatedTenants = [];
|
|
227
|
+
for (const tenant of allTenants) {
|
|
228
|
+
tenantListPromises.push(tenantListLimiter.queue(async () => {
|
|
229
|
+
this.throwIfCancelled(options.token);
|
|
230
|
+
this.silenceRefreshEvents();
|
|
231
|
+
const session = await (0, getSessionFromVSCode_1.getSessionFromVSCode)(undefined, tenant.tenantId, {
|
|
232
|
+
account: account,
|
|
233
|
+
createIfNone: false,
|
|
234
|
+
silent: true,
|
|
235
|
+
});
|
|
236
|
+
if (!session) {
|
|
237
|
+
unauthenticatedTenants.push(tenant);
|
|
238
|
+
}
|
|
239
|
+
}));
|
|
240
|
+
}
|
|
241
|
+
await Promise.all(tenantListPromises);
|
|
242
|
+
this.logForAccount(account, `Found ${unauthenticatedTenants.length} unauthenticated tenants in ${Date.now() - startTime}ms`);
|
|
243
|
+
return unauthenticatedTenants;
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
this.throwIfCancelled(options.token);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* @inheritdoc
|
|
251
|
+
*/
|
|
252
|
+
async getTenantsForAccount(account, options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
253
|
+
try {
|
|
254
|
+
const startTime = Date.now();
|
|
255
|
+
this.logForAccount(account, 'Fetching tenants for account...');
|
|
256
|
+
const { client } = await this.getSubscriptionClient({ account: account, tenantId: undefined });
|
|
257
|
+
const allTenants = [];
|
|
258
|
+
for await (const tenant of client.tenants.list({ abortSignal: (0, getSignalForToken_1.getSignalForToken)(options.token) })) {
|
|
259
|
+
allTenants.push({
|
|
260
|
+
...tenant,
|
|
261
|
+
tenantId: tenant.tenantId, // eslint-disable-line @typescript-eslint/no-non-null-assertion -- This is never null in practice
|
|
262
|
+
account: account,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
this.logForAccount(account, `Fetched ${allTenants.length} tenants (before filter) in ${Date.now() - startTime}ms`);
|
|
266
|
+
return allTenants;
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
this.remapLogRethrow(err, options.token);
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
this.throwIfCancelled(options.token);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* @inheritdoc
|
|
277
|
+
*/
|
|
278
|
+
async getSubscriptionsForTenant(tenant, options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
279
|
+
try {
|
|
280
|
+
const startTime = Date.now();
|
|
281
|
+
this.logForTenant(tenant, 'Fetching subscriptions for account+tenant...');
|
|
282
|
+
const { client, credential, authentication } = await this.getSubscriptionClient(tenant);
|
|
283
|
+
const environment = (0, configuredAzureEnv_1.getConfiguredAzureEnv)();
|
|
284
|
+
const allSubs = [];
|
|
285
|
+
for await (const subscription of client.subscriptions.list({ abortSignal: (0, getSignalForToken_1.getSignalForToken)(options.token) })) {
|
|
286
|
+
allSubs.push({
|
|
287
|
+
authentication: authentication,
|
|
288
|
+
environment: environment,
|
|
289
|
+
credential: credential,
|
|
290
|
+
isCustomCloud: environment.isCustomCloud,
|
|
291
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
292
|
+
name: subscription.displayName,
|
|
293
|
+
subscriptionId: subscription.subscriptionId,
|
|
294
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
295
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
296
|
+
tenantId: subscription.tenantId || tenant.tenantId, // In rare cases, a subscription may be listed but come from a different tenant
|
|
297
|
+
account: tenant.account,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
this.logForTenant(tenant, `Fetched ${allSubs.length} subscriptions (before filter) in ${Date.now() - startTime}ms`);
|
|
301
|
+
return allSubs;
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
this.remapLogRethrow(err, options.token);
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
this.throwIfCancelled(options.token);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Gets a {@link SubscriptionClient} plus extras for the given account+tenant.
|
|
312
|
+
* @param tenant (Optional) The account+tenant to get a subscription client for. If not specified, the default account and home tenant
|
|
313
|
+
* will be used.
|
|
314
|
+
* @returns A {@link SubscriptionClient}, {@link TokenCredential}, and {@link AzureAuthentication} for the given account+tenant.
|
|
315
|
+
*/
|
|
316
|
+
async getSubscriptionClient(tenant) {
|
|
317
|
+
const credential = {
|
|
318
|
+
getToken: async (scopes, options) => {
|
|
319
|
+
this.silenceRefreshEvents();
|
|
320
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
321
|
+
const session = await (0, getSessionFromVSCode_1.getSessionFromVSCode)(scopes, options?.tenantId || tenant.tenantId, { createIfNone: false, silent: true, account: tenant.account });
|
|
322
|
+
if (!session) {
|
|
323
|
+
throw new NotSignedInError_1.NotSignedInError();
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
token: session.accessToken,
|
|
327
|
+
expiresOnTimestamp: (0, tryGetTokenExpiration_1.tryGetTokenExpiration)(session),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
armSubs ??= await import('@azure/arm-resources-subscriptions');
|
|
332
|
+
return {
|
|
333
|
+
client: new armSubs.SubscriptionClient(credential, { endpoint: (0, configuredAzureEnv_1.getConfiguredAzureEnv)().resourceManagerEndpointUrl }),
|
|
334
|
+
credential: credential,
|
|
335
|
+
authentication: {
|
|
336
|
+
getSession: async () => {
|
|
337
|
+
this.silenceRefreshEvents();
|
|
338
|
+
const session = await (0, getSessionFromVSCode_1.getSessionFromVSCode)(undefined, tenant.tenantId, { createIfNone: false, silent: true, account: tenant.account });
|
|
339
|
+
if (!session) {
|
|
340
|
+
throw new NotSignedInError_1.NotSignedInError();
|
|
341
|
+
}
|
|
342
|
+
return session;
|
|
343
|
+
},
|
|
344
|
+
getSessionWithScopes: async (scopeListOrRequest) => {
|
|
345
|
+
this.silenceRefreshEvents();
|
|
346
|
+
// in order to handle a challenge, we must enable createIfNone so
|
|
347
|
+
// that we can prompt the user to step-up their session with MFA
|
|
348
|
+
// otherwise, never prompt the user
|
|
349
|
+
const session = await (0, getSessionFromVSCode_1.getSessionFromVSCode)(scopeListOrRequest, tenant.tenantId, { ...((0, isAuthenticationWwwAuthenticateRequest_1.isAuthenticationWwwAuthenticateRequest)(scopeListOrRequest) ? { createIfNone: true } : { silent: true }), account: tenant.account });
|
|
350
|
+
if (!session) {
|
|
351
|
+
throw new NotSignedInError_1.NotSignedInError();
|
|
352
|
+
}
|
|
353
|
+
return session;
|
|
354
|
+
},
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
log(message) {
|
|
359
|
+
this.logger?.debug(`[auth] ${message}`);
|
|
360
|
+
}
|
|
361
|
+
logForAccount(account, message) {
|
|
362
|
+
this.logger?.debug(`[auth] [account: ${(0, screen_1.screen)(account)}] ${message}`);
|
|
363
|
+
}
|
|
364
|
+
logForTenant(tenant, message) {
|
|
365
|
+
this.logger?.debug(`[auth] [account: ${(0, screen_1.screen)(tenant.account)}] [tenant: ${(0, screen_1.screen)(tenant)}] ${message}`);
|
|
366
|
+
}
|
|
367
|
+
throwIfCancelled(token) {
|
|
368
|
+
if (token?.isCancellationRequested) {
|
|
369
|
+
throw new vscode.CancellationError();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
timeout;
|
|
373
|
+
silenceRefreshEvents() {
|
|
374
|
+
this.suppressRefreshSuggestedEvents = true;
|
|
375
|
+
if (this.timeout) {
|
|
376
|
+
clearTimeout(this.timeout);
|
|
377
|
+
this.timeout = undefined;
|
|
378
|
+
}
|
|
379
|
+
this.timeout = setTimeout(() => {
|
|
380
|
+
clearTimeout(this.timeout);
|
|
381
|
+
this.timeout = undefined;
|
|
382
|
+
this.suppressRefreshSuggestedEvents = false;
|
|
383
|
+
}, EventSilenceTime);
|
|
384
|
+
}
|
|
385
|
+
remapLogRethrow(err, token) {
|
|
386
|
+
this.throwIfCancelled(token);
|
|
387
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
388
|
+
this.logger?.error(`[auth] Error occurred: ${err}`);
|
|
389
|
+
throw err;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
exports.AzureSubscriptionProviderBase = AzureSubscriptionProviderBase;
|
|
393
|
+
//# sourceMappingURL=AzureSubscriptionProviderBase.js.map
|
|
@@ -0,0 +1,269 @@
|
|
|
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
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.VSCodeAzureSubscriptionProvider = void 0;
|
|
41
|
+
const vscode = __importStar(require("vscode"));
|
|
42
|
+
const AzureSubscriptionProviderRequestOptions_1 = require("../contracts/AzureSubscriptionProviderRequestOptions"); // eslint-disable-line @typescript-eslint/no-unused-vars -- It is used in the doc comments
|
|
43
|
+
const dedupeSubscriptions_1 = require("../utils/dedupeSubscriptions");
|
|
44
|
+
const CaselessMap_1 = require("../utils/map/CaselessMap");
|
|
45
|
+
const TwoKeyCaselessMap_1 = require("../utils/map/TwoKeyCaselessMap");
|
|
46
|
+
const AzureSubscriptionProviderBase_1 = require("./AzureSubscriptionProviderBase");
|
|
47
|
+
const ConfigPrefix = 'azureResourceGroups';
|
|
48
|
+
const SelectedSubscriptionsConfigKey = 'selectedSubscriptions';
|
|
49
|
+
/**
|
|
50
|
+
* Extension of {@link AzureSubscriptionProviderBase} that adds caching of accounts, tenants, and subscriptions,
|
|
51
|
+
* as well as filtering and deduplication according to configured settings. Additionally, promise
|
|
52
|
+
* coalescence is added for {@link getAvailableSubscriptions}.
|
|
53
|
+
*
|
|
54
|
+
* @note See important notes about caching on {@link BaseOptions.noCache}
|
|
55
|
+
*/
|
|
56
|
+
class VSCodeAzureSubscriptionProvider extends AzureSubscriptionProviderBase_1.AzureSubscriptionProviderBase {
|
|
57
|
+
accountCache = new CaselessMap_1.CaselessMap(); // Key is the account ID
|
|
58
|
+
tenantCache = new CaselessMap_1.CaselessMap(); // Key is the account ID
|
|
59
|
+
subscriptionCache = new TwoKeyCaselessMap_1.TwoKeyCaselessMap(); // Keys are account ID and tenant ID
|
|
60
|
+
availableSubscriptionsPromises = new Map(); // Key is from getOptionsCoalescenceKey
|
|
61
|
+
configChangeListener;
|
|
62
|
+
dispose() {
|
|
63
|
+
this.configChangeListener?.dispose();
|
|
64
|
+
super.dispose();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* @inheritdoc
|
|
68
|
+
*/
|
|
69
|
+
onRefreshSuggested(callback, thisArg, disposables) {
|
|
70
|
+
this.configChangeListener ??= vscode.workspace.onDidChangeConfiguration(e => {
|
|
71
|
+
if (e.affectsConfiguration(`${ConfigPrefix}.${SelectedSubscriptionsConfigKey}`)) {
|
|
72
|
+
this.fireRefreshSuggestedIfNeeded({ reason: 'subscriptionFilterChange' });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return super.onRefreshSuggested(callback, thisArg, disposables);
|
|
76
|
+
}
|
|
77
|
+
fireRefreshSuggestedIfNeeded(evtArgs) {
|
|
78
|
+
const actuallyFired = super.fireRefreshSuggestedIfNeeded(evtArgs);
|
|
79
|
+
if (actuallyFired && evtArgs.reason === 'sessionChange') {
|
|
80
|
+
// Clear just the account cache--tenants and subscriptions are probably still valid,
|
|
81
|
+
// but the session change event may been have fired due to account sign out
|
|
82
|
+
this.accountCache.clear();
|
|
83
|
+
}
|
|
84
|
+
return actuallyFired;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* @inheritdoc
|
|
88
|
+
*/
|
|
89
|
+
async getAvailableSubscriptions(options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
90
|
+
try {
|
|
91
|
+
const key = (0, AzureSubscriptionProviderRequestOptions_1.getCoalescenceKey)(options);
|
|
92
|
+
if (key && this.availableSubscriptionsPromises.has(key)) {
|
|
93
|
+
return await this.availableSubscriptionsPromises.get(key); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- We just checked it has the key
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
try {
|
|
97
|
+
const promise = super.getAvailableSubscriptions(options);
|
|
98
|
+
if (key) {
|
|
99
|
+
this.availableSubscriptionsPromises.set(key, promise);
|
|
100
|
+
}
|
|
101
|
+
return await promise;
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
if (key) {
|
|
105
|
+
this.availableSubscriptionsPromises.delete(key);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
this.throwIfCancelled(options.token);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @inheritdoc
|
|
116
|
+
*/
|
|
117
|
+
async getAccounts(options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
118
|
+
try {
|
|
119
|
+
if (options.noCache ?? AzureSubscriptionProviderRequestOptions_1.DefaultOptions.noCache) {
|
|
120
|
+
this.accountCache.clear();
|
|
121
|
+
}
|
|
122
|
+
// If needed, refill the cache
|
|
123
|
+
if (this.accountCache.size === 0) {
|
|
124
|
+
const accounts = await super.getAccounts(options);
|
|
125
|
+
accounts.forEach(account => this.accountCache.set(account.id, account));
|
|
126
|
+
this.log(`Cached ${accounts.length} accounts`);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.log('Using cached accounts');
|
|
130
|
+
}
|
|
131
|
+
let results = Array.from(this.accountCache.values());
|
|
132
|
+
// If needed, filter according to configured filters
|
|
133
|
+
if (options.filter ?? AzureSubscriptionProviderRequestOptions_1.DefaultOptions.filter) {
|
|
134
|
+
const accountFilters = await this.getAccountFilters();
|
|
135
|
+
if (accountFilters.length > 0) {
|
|
136
|
+
this.log(`Filtering accounts to ${accountFilters.length} configured accounts`);
|
|
137
|
+
results = results.filter(account => accountFilters.includes(account.id.toLowerCase()));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
this.log(`Returning ${results.length} accounts.`);
|
|
141
|
+
return results.sort((a, b) => a.label.localeCompare(b.label));
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
this.throwIfCancelled(options.token);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* @inheritdoc
|
|
149
|
+
*/
|
|
150
|
+
async getTenantsForAccount(account, options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
151
|
+
try {
|
|
152
|
+
// If needed, delete the cache for this account
|
|
153
|
+
if (options.noCache ?? AzureSubscriptionProviderRequestOptions_1.DefaultOptions.noCache) {
|
|
154
|
+
this.tenantCache.delete(account.id);
|
|
155
|
+
}
|
|
156
|
+
// If needed, refill the cache
|
|
157
|
+
if (!this.tenantCache.has(account.id)) {
|
|
158
|
+
const tenants = await super.getTenantsForAccount(account, options);
|
|
159
|
+
this.tenantCache.set(account.id, tenants);
|
|
160
|
+
this.logForAccount(account, `Cached ${tenants.length} tenants for account`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this.logForAccount(account, 'Using cached tenants for account');
|
|
164
|
+
}
|
|
165
|
+
let results = this.tenantCache.get(account.id); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- We just filled it
|
|
166
|
+
// If needed, filter according to configured filters
|
|
167
|
+
if (options.filter ?? AzureSubscriptionProviderRequestOptions_1.DefaultOptions.filter) {
|
|
168
|
+
const tenantFilters = await this.getTenantFilters();
|
|
169
|
+
if (tenantFilters.length > 0) {
|
|
170
|
+
this.logForAccount(account, `Filtering tenants for account to ${tenantFilters.length} configured tenants`);
|
|
171
|
+
results = results.filter(tenant => tenantFilters.includes(tenant.tenantId.toLowerCase()));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
this.logForAccount(account, `Returning ${results.length} tenants for account`);
|
|
175
|
+
// Finally, sort
|
|
176
|
+
return results.sort((a, b) => {
|
|
177
|
+
if (a.displayName && b.displayName) {
|
|
178
|
+
return a.displayName.localeCompare(b.displayName);
|
|
179
|
+
}
|
|
180
|
+
return a.tenantId.localeCompare(b.tenantId);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
this.throwIfCancelled(options.token);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* @inheritdoc
|
|
189
|
+
*/
|
|
190
|
+
async getSubscriptionsForTenant(tenant, options = AzureSubscriptionProviderRequestOptions_1.DefaultOptions) {
|
|
191
|
+
try {
|
|
192
|
+
// If needed, delete the cache for this account+tenant
|
|
193
|
+
if (options.noCache ?? AzureSubscriptionProviderRequestOptions_1.DefaultOptions.noCache) {
|
|
194
|
+
this.subscriptionCache.delete(tenant.account.id, tenant.tenantId);
|
|
195
|
+
}
|
|
196
|
+
// If needed, refill the cache
|
|
197
|
+
if (!this.subscriptionCache.has(tenant.account.id, tenant.tenantId)) {
|
|
198
|
+
const subscriptions = await super.getSubscriptionsForTenant(tenant, options);
|
|
199
|
+
this.subscriptionCache.set(tenant.account.id, tenant.tenantId, subscriptions);
|
|
200
|
+
this.logForTenant(tenant, `Cached ${subscriptions.length} subscriptions for account+tenant`);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
this.logForTenant(tenant, 'Using cached subscriptions for account+tenant');
|
|
204
|
+
}
|
|
205
|
+
let results = this.subscriptionCache.get(tenant.account.id, tenant.tenantId); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- We just filled it
|
|
206
|
+
// If needed, filter according to configured filters
|
|
207
|
+
if (options.filter ?? AzureSubscriptionProviderRequestOptions_1.DefaultOptions.filter) {
|
|
208
|
+
const subscriptionFilters = await this.getSubscriptionFilters();
|
|
209
|
+
if (subscriptionFilters.length > 0) {
|
|
210
|
+
this.logForTenant(tenant, `Filtering subscriptions for account+tenant to ${subscriptionFilters.length} configured subscriptions`);
|
|
211
|
+
results = results.filter(sub => subscriptionFilters.includes(sub.subscriptionId.toLowerCase()));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// If needed, dedupe according to options
|
|
215
|
+
if (options.dedupe ?? AzureSubscriptionProviderRequestOptions_1.DefaultOptions.dedupe) {
|
|
216
|
+
this.logForTenant(tenant, 'Deduping subscriptions for account+tenant');
|
|
217
|
+
results = (0, dedupeSubscriptions_1.dedupeSubscriptions)(results);
|
|
218
|
+
}
|
|
219
|
+
this.logForTenant(tenant, `Returning ${results.length} subscriptions for account+tenant`);
|
|
220
|
+
// Finally, sort
|
|
221
|
+
return results.sort((a, b) => a.name.localeCompare(b.name));
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
this.throwIfCancelled(options.token);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Gets the account filters that are configured in `azureResourceGroups.selectedSubscriptions`. To
|
|
229
|
+
* override the settings with a custom filter, implement a child class with filter methods overridden.
|
|
230
|
+
*
|
|
231
|
+
* If no values are returned by `getAccountFilters()`, then all accounts will be scanned for subscriptions.
|
|
232
|
+
*
|
|
233
|
+
* @returns A list of account IDs that are configured in `azureResourceGroups.selectedSubscriptions`.
|
|
234
|
+
*/
|
|
235
|
+
getAccountFilters() {
|
|
236
|
+
// TODO: implement account filtering based on configuration if needed
|
|
237
|
+
return Promise.resolve([]);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Gets the tenant filters that are configured in `azureResourceGroups.selectedSubscriptions`. To
|
|
241
|
+
* override the settings with a custom filter, implement a child class with filter methods overridden.
|
|
242
|
+
*
|
|
243
|
+
* If no values are returned by `getTenantFilters()`, then all tenants will be scanned for subscriptions.
|
|
244
|
+
*
|
|
245
|
+
* @returns A list of unique tenant IDs that are configured in `azureResourceGroups.selectedSubscriptions`.
|
|
246
|
+
*/
|
|
247
|
+
getTenantFilters() {
|
|
248
|
+
const config = vscode.workspace.getConfiguration(ConfigPrefix);
|
|
249
|
+
const fullSubscriptionIds = config.get(SelectedSubscriptionsConfigKey, []);
|
|
250
|
+
const tenantIds = fullSubscriptionIds.map(id => id.split('/')[0].toLowerCase());
|
|
251
|
+
return Promise.resolve(Array.from(new Set(tenantIds)));
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Gets the subscription filters that are configured in `azureResourceGroups.selectedSubscriptions`. To
|
|
255
|
+
* override the settings with a custom filter, implement a child class with filter methods overridden.
|
|
256
|
+
*
|
|
257
|
+
* If no values are returned by `getSubscriptionFilters()`, then all subscriptions will be scanned.
|
|
258
|
+
*
|
|
259
|
+
* @returns A list of unique subscription IDs that are configured in `azureResourceGroups.selectedSubscriptions`.
|
|
260
|
+
*/
|
|
261
|
+
getSubscriptionFilters() {
|
|
262
|
+
const config = vscode.workspace.getConfiguration(ConfigPrefix);
|
|
263
|
+
const fullSubscriptionIds = config.get(SelectedSubscriptionsConfigKey, []);
|
|
264
|
+
const subscriptionIds = fullSubscriptionIds.map(id => id.split('/')[1].toLowerCase());
|
|
265
|
+
return Promise.resolve(Array.from(new Set(subscriptionIds)));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
exports.VSCodeAzureSubscriptionProvider = VSCodeAzureSubscriptionProvider;
|
|
269
|
+
//# sourceMappingURL=VSCodeAzureSubscriptionProvider.js.map
|