@microsoft/vscode-azext-azureauth 6.0.0-alpha.4 → 6.0.0-alpha.6
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/dist/cjs/src/index.js +1 -0
- package/dist/cjs/src/providers/AzureSubscriptionProviderBase.js +48 -10
- package/dist/cjs/src/utils/BearerChallengePolicy.js +41 -0
- package/dist/esm/src/index.d.ts +1 -0
- package/dist/esm/src/index.js +1 -0
- package/dist/esm/src/providers/AzureSubscriptionProviderBase.js +48 -10
- package/dist/esm/src/utils/BearerChallengePolicy.d.ts +10 -0
- package/dist/esm/src/utils/BearerChallengePolicy.js +36 -0
- package/package.json +2 -1
package/dist/cjs/src/index.js
CHANGED
|
@@ -26,6 +26,7 @@ __exportStar(require("./contracts/AzureTenant"), exports);
|
|
|
26
26
|
// The `AzureDevOpsSubscriptionProvider` is intentionally not exported, it must be imported from `'@microsoft/vscode-azext-azureauth/azdo'`
|
|
27
27
|
__exportStar(require("./providers/AzureSubscriptionProviderBase"), exports);
|
|
28
28
|
__exportStar(require("./providers/VSCodeAzureSubscriptionProvider"), exports);
|
|
29
|
+
__exportStar(require("./utils/BearerChallengePolicy"), exports);
|
|
29
30
|
__exportStar(require("./utils/configuredAzureEnv"), exports);
|
|
30
31
|
__exportStar(require("./utils/dedupeSubscriptions"), exports);
|
|
31
32
|
__exportStar(require("./utils/getMetricsForTelemetry"), exports);
|
|
@@ -38,6 +38,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
})();
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.AzureSubscriptionProviderBase = void 0;
|
|
41
|
+
const BearerChallengePolicy_1 = require("../utils/BearerChallengePolicy");
|
|
41
42
|
const util_1 = require("util");
|
|
42
43
|
const vscode = __importStar(require("vscode"));
|
|
43
44
|
const AzureSubscriptionProviderRequestOptions_1 = require("../contracts/AzureSubscriptionProviderRequestOptions");
|
|
@@ -115,12 +116,18 @@ class AzureSubscriptionProviderBase {
|
|
|
115
116
|
// If silent, suppress with normal timeout
|
|
116
117
|
this.silenceRefreshEvents();
|
|
117
118
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
let session;
|
|
120
|
+
try {
|
|
121
|
+
session = await (0, getSessionFromVSCode_1.getSessionFromVSCode)(undefined, tenant?.tenantId, {
|
|
122
|
+
account: tenant?.account,
|
|
123
|
+
clearSessionPreference: options.clearSessionPreference ?? AzureSubscriptionProviderRequestOptions_1.DefaultSignInOptions.clearSessionPreference,
|
|
124
|
+
createIfNone: prompt,
|
|
125
|
+
silent: !prompt,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
throw maybeImproveSignInError(err, tenant?.tenantId);
|
|
130
|
+
}
|
|
124
131
|
if (prompt) {
|
|
125
132
|
// Interactive sign in can take a while, so silence events for a bit longer
|
|
126
133
|
this.silenceRefreshEvents();
|
|
@@ -341,8 +348,15 @@ class AzureSubscriptionProviderBase {
|
|
|
341
348
|
}
|
|
342
349
|
};
|
|
343
350
|
armSubs ??= await import('@azure/arm-resources-subscriptions');
|
|
351
|
+
const endpoint = (0, configuredAzureEnv_1.getConfiguredAzureEnv)().resourceManagerEndpointUrl;
|
|
352
|
+
const client = new armSubs.SubscriptionClient(credential, { endpoint });
|
|
353
|
+
client.pipeline.addPolicy(new BearerChallengePolicy_1.BearerChallengePolicy(async (challenge) => {
|
|
354
|
+
this.silenceRefreshEvents();
|
|
355
|
+
const session = await (0, getSessionFromVSCode_1.getSessionFromVSCode)(challenge, tenant.tenantId, { createIfNone: true, account: tenant.account });
|
|
356
|
+
return session?.accessToken;
|
|
357
|
+
}, endpoint), { phase: 'Sign', afterPolicies: ['bearerTokenAuthenticationPolicy'] });
|
|
344
358
|
return {
|
|
345
|
-
client
|
|
359
|
+
client,
|
|
346
360
|
credential: credential,
|
|
347
361
|
authentication: {
|
|
348
362
|
getSession: async () => {
|
|
@@ -368,13 +382,13 @@ class AzureSubscriptionProviderBase {
|
|
|
368
382
|
};
|
|
369
383
|
}
|
|
370
384
|
log(message) {
|
|
371
|
-
this.logger?.
|
|
385
|
+
this.logger?.info(`[auth] ${message}`);
|
|
372
386
|
}
|
|
373
387
|
logForAccount(account, message) {
|
|
374
|
-
this.logger?.
|
|
388
|
+
this.logger?.info(`[auth] [account: ${(0, screen_1.screen)(account)}] ${message}`);
|
|
375
389
|
}
|
|
376
390
|
logForTenant(tenant, message) {
|
|
377
|
-
this.logger?.
|
|
391
|
+
this.logger?.info(`[auth] [account: ${(0, screen_1.screen)(tenant.account)}] [tenant: ${(0, screen_1.screen)(tenant)}] ${message}`);
|
|
378
392
|
}
|
|
379
393
|
warnForAccount(account, message) {
|
|
380
394
|
this.logger?.warn(`[auth] [account: ${(0, screen_1.screen)(account)}] ${message}`);
|
|
@@ -426,4 +440,28 @@ class AzureSubscriptionProviderBase {
|
|
|
426
440
|
}
|
|
427
441
|
}
|
|
428
442
|
exports.AzureSubscriptionProviderBase = AzureSubscriptionProviderBase;
|
|
443
|
+
/**
|
|
444
|
+
* Inspects an error thrown during sign-in and returns a more user-friendly
|
|
445
|
+
* error when possible (e.g. native broker errors), otherwise returns the
|
|
446
|
+
* original error unchanged.
|
|
447
|
+
*/
|
|
448
|
+
function maybeImproveSignInError(err, tenantId) {
|
|
449
|
+
if (!(err instanceof Error)) {
|
|
450
|
+
return err;
|
|
451
|
+
}
|
|
452
|
+
const message = err.message;
|
|
453
|
+
// The native MSAL broker surfaces opaque "platform_broker_error" messages
|
|
454
|
+
// that don't tell the user what went wrong. Re-wrap with actionable text.
|
|
455
|
+
if (message.includes('platform_broker_error')) {
|
|
456
|
+
const tenantHint = tenantId
|
|
457
|
+
? vscode.l10n.t(' for tenant "{0}"', tenantId)
|
|
458
|
+
: '';
|
|
459
|
+
const improved = new Error(vscode.l10n.t('Sign-in failed{0}. The tenant may have expired or is no longer valid. Please verify the tenant is still active and try again.', tenantHint), { cause: err });
|
|
460
|
+
if (err.stack && improved.stack) {
|
|
461
|
+
improved.stack += `\nCaused by: ${err.stack}`;
|
|
462
|
+
}
|
|
463
|
+
return improved;
|
|
464
|
+
}
|
|
465
|
+
return err;
|
|
466
|
+
}
|
|
429
467
|
//# sourceMappingURL=AzureSubscriptionProviderBase.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
exports.BearerChallengePolicy = void 0;
|
|
8
|
+
exports.getDefaultScopeFromEndpoint = getDefaultScopeFromEndpoint;
|
|
9
|
+
function getDefaultScopeFromEndpoint(endpoint) {
|
|
10
|
+
let base = endpoint ?? 'https://management.azure.com/';
|
|
11
|
+
base = base.replace(/\/+$/, '');
|
|
12
|
+
return `${base}/.default`;
|
|
13
|
+
}
|
|
14
|
+
const challengeRetriedRequests = new WeakSet();
|
|
15
|
+
class BearerChallengePolicy {
|
|
16
|
+
getTokenForChallenge;
|
|
17
|
+
endpoint;
|
|
18
|
+
name = 'BearerChallengePolicy';
|
|
19
|
+
constructor(getTokenForChallenge, endpoint) {
|
|
20
|
+
this.getTokenForChallenge = getTokenForChallenge;
|
|
21
|
+
this.endpoint = endpoint;
|
|
22
|
+
}
|
|
23
|
+
async sendRequest(request, next) {
|
|
24
|
+
const initial = await next(request);
|
|
25
|
+
if (initial.status === 401 && !challengeRetriedRequests.has(request)) {
|
|
26
|
+
const header = initial.headers.get('WWW-Authenticate') || initial.headers.get('www-authenticate');
|
|
27
|
+
if (header) {
|
|
28
|
+
const scopes = [getDefaultScopeFromEndpoint(this.endpoint)];
|
|
29
|
+
challengeRetriedRequests.add(request);
|
|
30
|
+
const token = await this.getTokenForChallenge({ wwwAuthenticate: header, fallbackScopes: scopes });
|
|
31
|
+
if (token) {
|
|
32
|
+
request.headers.set('Authorization', `Bearer ${token}`);
|
|
33
|
+
return await next(request);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return initial;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.BearerChallengePolicy = BearerChallengePolicy;
|
|
41
|
+
//# sourceMappingURL=BearerChallengePolicy.js.map
|
package/dist/esm/src/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export type * from './contracts/AzureSubscriptionProviderRequestOptions';
|
|
|
6
6
|
export * from './contracts/AzureTenant';
|
|
7
7
|
export * from './providers/AzureSubscriptionProviderBase';
|
|
8
8
|
export * from './providers/VSCodeAzureSubscriptionProvider';
|
|
9
|
+
export * from './utils/BearerChallengePolicy';
|
|
9
10
|
export * from './utils/configuredAzureEnv';
|
|
10
11
|
export * from './utils/dedupeSubscriptions';
|
|
11
12
|
export * from './utils/getMetricsForTelemetry';
|
package/dist/esm/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export * from './contracts/AzureTenant';
|
|
|
10
10
|
// The `AzureDevOpsSubscriptionProvider` is intentionally not exported, it must be imported from `'@microsoft/vscode-azext-azureauth/azdo'`
|
|
11
11
|
export * from './providers/AzureSubscriptionProviderBase';
|
|
12
12
|
export * from './providers/VSCodeAzureSubscriptionProvider';
|
|
13
|
+
export * from './utils/BearerChallengePolicy';
|
|
13
14
|
export * from './utils/configuredAzureEnv';
|
|
14
15
|
export * from './utils/dedupeSubscriptions';
|
|
15
16
|
export * from './utils/getMetricsForTelemetry';
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import { BearerChallengePolicy } from '../utils/BearerChallengePolicy';
|
|
5
6
|
import { inspect } from 'util';
|
|
6
7
|
import * as vscode from 'vscode';
|
|
7
8
|
import { DefaultOptions, DefaultSignInOptions } from '../contracts/AzureSubscriptionProviderRequestOptions';
|
|
@@ -79,12 +80,18 @@ export class AzureSubscriptionProviderBase {
|
|
|
79
80
|
// If silent, suppress with normal timeout
|
|
80
81
|
this.silenceRefreshEvents();
|
|
81
82
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
let session;
|
|
84
|
+
try {
|
|
85
|
+
session = await getSessionFromVSCode(undefined, tenant?.tenantId, {
|
|
86
|
+
account: tenant?.account,
|
|
87
|
+
clearSessionPreference: options.clearSessionPreference ?? DefaultSignInOptions.clearSessionPreference,
|
|
88
|
+
createIfNone: prompt,
|
|
89
|
+
silent: !prompt,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
throw maybeImproveSignInError(err, tenant?.tenantId);
|
|
94
|
+
}
|
|
88
95
|
if (prompt) {
|
|
89
96
|
// Interactive sign in can take a while, so silence events for a bit longer
|
|
90
97
|
this.silenceRefreshEvents();
|
|
@@ -305,8 +312,15 @@ export class AzureSubscriptionProviderBase {
|
|
|
305
312
|
}
|
|
306
313
|
};
|
|
307
314
|
armSubs ??= await import('@azure/arm-resources-subscriptions');
|
|
315
|
+
const endpoint = getConfiguredAzureEnv().resourceManagerEndpointUrl;
|
|
316
|
+
const client = new armSubs.SubscriptionClient(credential, { endpoint });
|
|
317
|
+
client.pipeline.addPolicy(new BearerChallengePolicy(async (challenge) => {
|
|
318
|
+
this.silenceRefreshEvents();
|
|
319
|
+
const session = await getSessionFromVSCode(challenge, tenant.tenantId, { createIfNone: true, account: tenant.account });
|
|
320
|
+
return session?.accessToken;
|
|
321
|
+
}, endpoint), { phase: 'Sign', afterPolicies: ['bearerTokenAuthenticationPolicy'] });
|
|
308
322
|
return {
|
|
309
|
-
client
|
|
323
|
+
client,
|
|
310
324
|
credential: credential,
|
|
311
325
|
authentication: {
|
|
312
326
|
getSession: async () => {
|
|
@@ -332,13 +346,13 @@ export class AzureSubscriptionProviderBase {
|
|
|
332
346
|
};
|
|
333
347
|
}
|
|
334
348
|
log(message) {
|
|
335
|
-
this.logger?.
|
|
349
|
+
this.logger?.info(`[auth] ${message}`);
|
|
336
350
|
}
|
|
337
351
|
logForAccount(account, message) {
|
|
338
|
-
this.logger?.
|
|
352
|
+
this.logger?.info(`[auth] [account: ${screen(account)}] ${message}`);
|
|
339
353
|
}
|
|
340
354
|
logForTenant(tenant, message) {
|
|
341
|
-
this.logger?.
|
|
355
|
+
this.logger?.info(`[auth] [account: ${screen(tenant.account)}] [tenant: ${screen(tenant)}] ${message}`);
|
|
342
356
|
}
|
|
343
357
|
warnForAccount(account, message) {
|
|
344
358
|
this.logger?.warn(`[auth] [account: ${screen(account)}] ${message}`);
|
|
@@ -389,4 +403,28 @@ export class AzureSubscriptionProviderBase {
|
|
|
389
403
|
throw err;
|
|
390
404
|
}
|
|
391
405
|
}
|
|
406
|
+
/**
|
|
407
|
+
* Inspects an error thrown during sign-in and returns a more user-friendly
|
|
408
|
+
* error when possible (e.g. native broker errors), otherwise returns the
|
|
409
|
+
* original error unchanged.
|
|
410
|
+
*/
|
|
411
|
+
function maybeImproveSignInError(err, tenantId) {
|
|
412
|
+
if (!(err instanceof Error)) {
|
|
413
|
+
return err;
|
|
414
|
+
}
|
|
415
|
+
const message = err.message;
|
|
416
|
+
// The native MSAL broker surfaces opaque "platform_broker_error" messages
|
|
417
|
+
// that don't tell the user what went wrong. Re-wrap with actionable text.
|
|
418
|
+
if (message.includes('platform_broker_error')) {
|
|
419
|
+
const tenantHint = tenantId
|
|
420
|
+
? vscode.l10n.t(' for tenant "{0}"', tenantId)
|
|
421
|
+
: '';
|
|
422
|
+
const improved = new Error(vscode.l10n.t('Sign-in failed{0}. The tenant may have expired or is no longer valid. Please verify the tenant is still active and try again.', tenantHint), { cause: err });
|
|
423
|
+
if (err.stack && improved.stack) {
|
|
424
|
+
improved.stack += `\nCaused by: ${err.stack}`;
|
|
425
|
+
}
|
|
426
|
+
return improved;
|
|
427
|
+
}
|
|
428
|
+
return err;
|
|
429
|
+
}
|
|
392
430
|
//# sourceMappingURL=AzureSubscriptionProviderBase.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PipelinePolicy, PipelineRequest, PipelineResponse, SendRequest } from '@azure/core-rest-pipeline';
|
|
2
|
+
import type * as vscode from 'vscode';
|
|
3
|
+
export declare function getDefaultScopeFromEndpoint(endpoint?: string): string;
|
|
4
|
+
export declare class BearerChallengePolicy implements PipelinePolicy {
|
|
5
|
+
private readonly getTokenForChallenge;
|
|
6
|
+
private readonly endpoint?;
|
|
7
|
+
readonly name = "BearerChallengePolicy";
|
|
8
|
+
constructor(getTokenForChallenge: (request: vscode.AuthenticationWwwAuthenticateRequest) => Promise<string | undefined>, endpoint?: string | undefined);
|
|
9
|
+
sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
export function getDefaultScopeFromEndpoint(endpoint) {
|
|
6
|
+
let base = endpoint ?? 'https://management.azure.com/';
|
|
7
|
+
base = base.replace(/\/+$/, '');
|
|
8
|
+
return `${base}/.default`;
|
|
9
|
+
}
|
|
10
|
+
const challengeRetriedRequests = new WeakSet();
|
|
11
|
+
export class BearerChallengePolicy {
|
|
12
|
+
getTokenForChallenge;
|
|
13
|
+
endpoint;
|
|
14
|
+
name = 'BearerChallengePolicy';
|
|
15
|
+
constructor(getTokenForChallenge, endpoint) {
|
|
16
|
+
this.getTokenForChallenge = getTokenForChallenge;
|
|
17
|
+
this.endpoint = endpoint;
|
|
18
|
+
}
|
|
19
|
+
async sendRequest(request, next) {
|
|
20
|
+
const initial = await next(request);
|
|
21
|
+
if (initial.status === 401 && !challengeRetriedRequests.has(request)) {
|
|
22
|
+
const header = initial.headers.get('WWW-Authenticate') || initial.headers.get('www-authenticate');
|
|
23
|
+
if (header) {
|
|
24
|
+
const scopes = [getDefaultScopeFromEndpoint(this.endpoint)];
|
|
25
|
+
challengeRetriedRequests.add(request);
|
|
26
|
+
const token = await this.getTokenForChallenge({ wwwAuthenticate: header, fallbackScopes: scopes });
|
|
27
|
+
if (token) {
|
|
28
|
+
request.headers.set('Authorization', `Bearer ${token}`);
|
|
29
|
+
return await next(request);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return initial;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=BearerChallengePolicy.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/vscode-azext-azureauth",
|
|
3
3
|
"author": "Microsoft Corporation",
|
|
4
|
-
"version": "6.0.0-alpha.
|
|
4
|
+
"version": "6.0.0-alpha.6",
|
|
5
5
|
"description": "Azure authentication helpers for Visual Studio Code",
|
|
6
6
|
"tags": [
|
|
7
7
|
"azure",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@azure/arm-resources-subscriptions": "^2.1.0",
|
|
58
|
+
"@azure/core-rest-pipeline": "^1.22.2",
|
|
58
59
|
"@azure/identity": "^4.13.0",
|
|
59
60
|
"@azure/ms-rest-azure-env": "^2.0.0"
|
|
60
61
|
},
|