@azure/identity 4.3.0 → 4.3.1-alpha.20240619.4
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/index.js +357 -703
- package/dist/index.js.map +1 -1
- package/dist-esm/src/constants.js +1 -1
- package/dist-esm/src/constants.js.map +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredential.js +18 -21
- package/dist-esm/src/credentials/interactiveBrowserCredential.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/index.js +3 -284
- package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/legacyMsiProvider.js +302 -0
- package/dist-esm/src/credentials/managedIdentityCredential/legacyMsiProvider.js.map +1 -0
- package/dist-esm/src/credentials/onBehalfOfCredential.js +62 -6
- package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClient.js +102 -0
- package/dist-esm/src/msal/nodeFlows/msalClient.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalPlugins.js.map +1 -1
- package/package.json +3 -3
- package/types/identity.d.ts +11 -25
package/dist/index.js
CHANGED
|
@@ -14,11 +14,12 @@ var path = require('path');
|
|
|
14
14
|
var msalCommon = require('@azure/msal-node');
|
|
15
15
|
var fs$1 = require('node:fs');
|
|
16
16
|
var https = require('https');
|
|
17
|
+
var open = require('open');
|
|
17
18
|
var promises = require('fs/promises');
|
|
18
19
|
var child_process = require('child_process');
|
|
19
20
|
var crypto = require('crypto');
|
|
20
|
-
var
|
|
21
|
-
var
|
|
21
|
+
var promises$1 = require('node:fs/promises');
|
|
22
|
+
var node_crypto = require('node:crypto');
|
|
22
23
|
|
|
23
24
|
function _interopNamespaceDefault(e) {
|
|
24
25
|
var n = Object.create(null);
|
|
@@ -45,7 +46,7 @@ var child_process__namespace = /*#__PURE__*/_interopNamespaceDefault(child_proce
|
|
|
45
46
|
/**
|
|
46
47
|
* Current version of the `@azure/identity` package.
|
|
47
48
|
*/
|
|
48
|
-
const SDK_VERSION = `4.3.
|
|
49
|
+
const SDK_VERSION = `4.3.1`;
|
|
49
50
|
/**
|
|
50
51
|
* The default client ID for authentication
|
|
51
52
|
* @internal
|
|
@@ -128,9 +129,6 @@ const msalNodeFlowCacheControl = {
|
|
|
128
129
|
* @internal
|
|
129
130
|
*/
|
|
130
131
|
let nativeBrokerInfo = undefined;
|
|
131
|
-
function hasNativeBroker() {
|
|
132
|
-
return nativeBrokerInfo !== undefined;
|
|
133
|
-
}
|
|
134
132
|
/**
|
|
135
133
|
* An object that allows setting the native broker provider.
|
|
136
134
|
* @internal
|
|
@@ -1009,16 +1007,88 @@ function useIdentityPlugin(plugin) {
|
|
|
1009
1007
|
|
|
1010
1008
|
// Copyright (c) Microsoft Corporation.
|
|
1011
1009
|
// Licensed under the MIT license.
|
|
1012
|
-
const msiName$6 = "ManagedIdentityCredential -
|
|
1010
|
+
const msiName$6 = "ManagedIdentityCredential - CloudShellMSI";
|
|
1013
1011
|
const logger$o = credentialLogger(msiName$6);
|
|
1014
1012
|
/**
|
|
1015
1013
|
* Generates the options used on the request for an access token.
|
|
1016
1014
|
*/
|
|
1017
|
-
function prepareRequestOptions$5(scopes, clientId) {
|
|
1015
|
+
function prepareRequestOptions$5(scopes, clientId, resourceId) {
|
|
1018
1016
|
const resource = mapScopesToResource(scopes);
|
|
1019
1017
|
if (!resource) {
|
|
1020
1018
|
throw new Error(`${msiName$6}: Multiple scopes are not supported.`);
|
|
1021
1019
|
}
|
|
1020
|
+
const body = {
|
|
1021
|
+
resource,
|
|
1022
|
+
};
|
|
1023
|
+
if (clientId) {
|
|
1024
|
+
body.client_id = clientId;
|
|
1025
|
+
}
|
|
1026
|
+
if (resourceId) {
|
|
1027
|
+
body.msi_res_id = resourceId;
|
|
1028
|
+
}
|
|
1029
|
+
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
1030
|
+
if (!process.env.MSI_ENDPOINT) {
|
|
1031
|
+
throw new Error(`${msiName$6}: Missing environment variable: MSI_ENDPOINT`);
|
|
1032
|
+
}
|
|
1033
|
+
const params = new URLSearchParams(body);
|
|
1034
|
+
return {
|
|
1035
|
+
url: process.env.MSI_ENDPOINT,
|
|
1036
|
+
method: "POST",
|
|
1037
|
+
body: params.toString(),
|
|
1038
|
+
headers: coreRestPipeline.createHttpHeaders({
|
|
1039
|
+
Accept: "application/json",
|
|
1040
|
+
Metadata: "true",
|
|
1041
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1042
|
+
}),
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Defines how to determine whether the Azure Cloud Shell MSI is available, and also how to retrieve a token from the Azure Cloud Shell MSI.
|
|
1047
|
+
* Since Azure Managed Identities aren't available in the Azure Cloud Shell, we log a warning for users that try to access cloud shell using user assigned identity.
|
|
1048
|
+
*/
|
|
1049
|
+
const cloudShellMsi = {
|
|
1050
|
+
name: "cloudShellMsi",
|
|
1051
|
+
async isAvailable({ scopes }) {
|
|
1052
|
+
const resource = mapScopesToResource(scopes);
|
|
1053
|
+
if (!resource) {
|
|
1054
|
+
logger$o.info(`${msiName$6}: Unavailable. Multiple scopes are not supported.`);
|
|
1055
|
+
return false;
|
|
1056
|
+
}
|
|
1057
|
+
const result = Boolean(process.env.MSI_ENDPOINT);
|
|
1058
|
+
if (!result) {
|
|
1059
|
+
logger$o.info(`${msiName$6}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
|
|
1060
|
+
}
|
|
1061
|
+
return result;
|
|
1062
|
+
},
|
|
1063
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
1064
|
+
const { identityClient, scopes, clientId, resourceId } = configuration;
|
|
1065
|
+
if (clientId) {
|
|
1066
|
+
logger$o.warning(`${msiName$6}: user-assigned identities not supported. The argument clientId might be ignored by the service.`);
|
|
1067
|
+
}
|
|
1068
|
+
if (resourceId) {
|
|
1069
|
+
logger$o.warning(`${msiName$6}: user defined managed Identity by resource Id not supported. The argument resourceId might be ignored by the service.`);
|
|
1070
|
+
}
|
|
1071
|
+
logger$o.info(`${msiName$6}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
|
|
1072
|
+
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$5(scopes, clientId, resourceId)), {
|
|
1073
|
+
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
|
1074
|
+
allowInsecureConnection: true }));
|
|
1075
|
+
const tokenResponse = await identityClient.sendTokenRequest(request);
|
|
1076
|
+
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
1077
|
+
},
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
// Copyright (c) Microsoft Corporation.
|
|
1081
|
+
// Licensed under the MIT license.
|
|
1082
|
+
const msiName$5 = "ManagedIdentityCredential - AppServiceMSI 2017";
|
|
1083
|
+
const logger$n = credentialLogger(msiName$5);
|
|
1084
|
+
/**
|
|
1085
|
+
* Generates the options used on the request for an access token.
|
|
1086
|
+
*/
|
|
1087
|
+
function prepareRequestOptions$4(scopes, clientId) {
|
|
1088
|
+
const resource = mapScopesToResource(scopes);
|
|
1089
|
+
if (!resource) {
|
|
1090
|
+
throw new Error(`${msiName$5}: Multiple scopes are not supported.`);
|
|
1091
|
+
}
|
|
1022
1092
|
const queryParameters = {
|
|
1023
1093
|
resource,
|
|
1024
1094
|
"api-version": "2017-09-01",
|
|
@@ -1029,10 +1099,10 @@ function prepareRequestOptions$5(scopes, clientId) {
|
|
|
1029
1099
|
const query = new URLSearchParams(queryParameters);
|
|
1030
1100
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
1031
1101
|
if (!process.env.MSI_ENDPOINT) {
|
|
1032
|
-
throw new Error(`${msiName$
|
|
1102
|
+
throw new Error(`${msiName$5}: Missing environment variable: MSI_ENDPOINT`);
|
|
1033
1103
|
}
|
|
1034
1104
|
if (!process.env.MSI_SECRET) {
|
|
1035
|
-
throw new Error(`${msiName$
|
|
1105
|
+
throw new Error(`${msiName$5}: Missing environment variable: MSI_SECRET`);
|
|
1036
1106
|
}
|
|
1037
1107
|
return {
|
|
1038
1108
|
url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
|
|
@@ -1051,23 +1121,23 @@ const appServiceMsi2017 = {
|
|
|
1051
1121
|
async isAvailable({ scopes }) {
|
|
1052
1122
|
const resource = mapScopesToResource(scopes);
|
|
1053
1123
|
if (!resource) {
|
|
1054
|
-
logger$
|
|
1124
|
+
logger$n.info(`${msiName$5}: Unavailable. Multiple scopes are not supported.`);
|
|
1055
1125
|
return false;
|
|
1056
1126
|
}
|
|
1057
1127
|
const env = process.env;
|
|
1058
1128
|
const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
|
|
1059
1129
|
if (!result) {
|
|
1060
|
-
logger$
|
|
1130
|
+
logger$n.info(`${msiName$5}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
|
|
1061
1131
|
}
|
|
1062
1132
|
return result;
|
|
1063
1133
|
},
|
|
1064
1134
|
async getToken(configuration, getTokenOptions = {}) {
|
|
1065
1135
|
const { identityClient, scopes, clientId, resourceId } = configuration;
|
|
1066
1136
|
if (resourceId) {
|
|
1067
|
-
logger$
|
|
1137
|
+
logger$n.warning(`${msiName$5}: managed Identity by resource Id is not supported. Argument resourceId might be ignored by the service.`);
|
|
1068
1138
|
}
|
|
1069
|
-
logger$
|
|
1070
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$
|
|
1139
|
+
logger$n.info(`${msiName$5}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
|
|
1140
|
+
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$4(scopes, clientId)), {
|
|
1071
1141
|
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
|
1072
1142
|
allowInsecureConnection: true }));
|
|
1073
1143
|
const tokenResponse = await identityClient.sendTokenRequest(request);
|
|
@@ -1077,15 +1147,15 @@ const appServiceMsi2017 = {
|
|
|
1077
1147
|
|
|
1078
1148
|
// Copyright (c) Microsoft Corporation.
|
|
1079
1149
|
// Licensed under the MIT license.
|
|
1080
|
-
const msiName$
|
|
1081
|
-
const logger$
|
|
1150
|
+
const msiName$4 = "ManagedIdentityCredential - AppServiceMSI 2019";
|
|
1151
|
+
const logger$m = credentialLogger(msiName$4);
|
|
1082
1152
|
/**
|
|
1083
1153
|
* Generates the options used on the request for an access token.
|
|
1084
1154
|
*/
|
|
1085
|
-
function prepareRequestOptions$
|
|
1155
|
+
function prepareRequestOptions$3(scopes, clientId, resourceId) {
|
|
1086
1156
|
const resource = mapScopesToResource(scopes);
|
|
1087
1157
|
if (!resource) {
|
|
1088
|
-
throw new Error(`${msiName$
|
|
1158
|
+
throw new Error(`${msiName$4}: Multiple scopes are not supported.`);
|
|
1089
1159
|
}
|
|
1090
1160
|
const queryParameters = {
|
|
1091
1161
|
resource,
|
|
@@ -1100,10 +1170,10 @@ function prepareRequestOptions$4(scopes, clientId, resourceId) {
|
|
|
1100
1170
|
const query = new URLSearchParams(queryParameters);
|
|
1101
1171
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
1102
1172
|
if (!process.env.IDENTITY_ENDPOINT) {
|
|
1103
|
-
throw new Error(`${msiName$
|
|
1173
|
+
throw new Error(`${msiName$4}: Missing environment variable: IDENTITY_ENDPOINT`);
|
|
1104
1174
|
}
|
|
1105
1175
|
if (!process.env.IDENTITY_HEADER) {
|
|
1106
|
-
throw new Error(`${msiName$
|
|
1176
|
+
throw new Error(`${msiName$4}: Missing environment variable: IDENTITY_HEADER`);
|
|
1107
1177
|
}
|
|
1108
1178
|
return {
|
|
1109
1179
|
url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
|
|
@@ -1122,20 +1192,20 @@ const appServiceMsi2019 = {
|
|
|
1122
1192
|
async isAvailable({ scopes }) {
|
|
1123
1193
|
const resource = mapScopesToResource(scopes);
|
|
1124
1194
|
if (!resource) {
|
|
1125
|
-
logger$
|
|
1195
|
+
logger$m.info(`${msiName$4}: Unavailable. Multiple scopes are not supported.`);
|
|
1126
1196
|
return false;
|
|
1127
1197
|
}
|
|
1128
1198
|
const env = process.env;
|
|
1129
1199
|
const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER);
|
|
1130
1200
|
if (!result) {
|
|
1131
|
-
logger$
|
|
1201
|
+
logger$m.info(`${msiName$4}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT and IDENTITY_HEADER.`);
|
|
1132
1202
|
}
|
|
1133
1203
|
return result;
|
|
1134
1204
|
},
|
|
1135
1205
|
async getToken(configuration, getTokenOptions = {}) {
|
|
1136
1206
|
const { identityClient, scopes, clientId, resourceId } = configuration;
|
|
1137
|
-
logger$
|
|
1138
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$
|
|
1207
|
+
logger$m.info(`${msiName$4}: Using the endpoint and the secret coming form the environment variables: IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT} and IDENTITY_HEADER=[REDACTED].`);
|
|
1208
|
+
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$3(scopes, clientId, resourceId)), {
|
|
1139
1209
|
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
|
1140
1210
|
allowInsecureConnection: true }));
|
|
1141
1211
|
const tokenResponse = await identityClient.sendTokenRequest(request);
|
|
@@ -1145,15 +1215,15 @@ const appServiceMsi2019 = {
|
|
|
1145
1215
|
|
|
1146
1216
|
// Copyright (c) Microsoft Corporation.
|
|
1147
1217
|
// Licensed under the MIT license.
|
|
1148
|
-
const msiName$
|
|
1149
|
-
const logger$
|
|
1218
|
+
const msiName$3 = "ManagedIdentityCredential - Azure Arc MSI";
|
|
1219
|
+
const logger$l = credentialLogger(msiName$3);
|
|
1150
1220
|
/**
|
|
1151
1221
|
* Generates the options used on the request for an access token.
|
|
1152
1222
|
*/
|
|
1153
|
-
function prepareRequestOptions$
|
|
1223
|
+
function prepareRequestOptions$2(scopes, clientId, resourceId) {
|
|
1154
1224
|
const resource = mapScopesToResource(scopes);
|
|
1155
1225
|
if (!resource) {
|
|
1156
|
-
throw new Error(`${msiName$
|
|
1226
|
+
throw new Error(`${msiName$3}: Multiple scopes are not supported.`);
|
|
1157
1227
|
}
|
|
1158
1228
|
const queryParameters = {
|
|
1159
1229
|
resource,
|
|
@@ -1167,7 +1237,7 @@ function prepareRequestOptions$3(scopes, clientId, resourceId) {
|
|
|
1167
1237
|
}
|
|
1168
1238
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
1169
1239
|
if (!process.env.IDENTITY_ENDPOINT) {
|
|
1170
|
-
throw new Error(`${msiName$
|
|
1240
|
+
throw new Error(`${msiName$3}: Missing environment variable: IDENTITY_ENDPOINT`);
|
|
1171
1241
|
}
|
|
1172
1242
|
const query = new URLSearchParams(queryParameters);
|
|
1173
1243
|
return coreRestPipeline.createPipelineRequest({
|
|
@@ -1190,7 +1260,7 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
|
|
|
1190
1260
|
if (response.bodyAsText) {
|
|
1191
1261
|
message = ` Response: ${response.bodyAsText}`;
|
|
1192
1262
|
}
|
|
1193
|
-
throw new AuthenticationError(response.status, `${msiName$
|
|
1263
|
+
throw new AuthenticationError(response.status, `${msiName$3}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
|
|
1194
1264
|
}
|
|
1195
1265
|
const authHeader = response.headers.get("www-authenticate") || "";
|
|
1196
1266
|
try {
|
|
@@ -1204,13 +1274,13 @@ function platformToFilePath() {
|
|
|
1204
1274
|
switch (process.platform) {
|
|
1205
1275
|
case "win32":
|
|
1206
1276
|
if (!process.env.PROGRAMDATA) {
|
|
1207
|
-
throw new Error(`${msiName$
|
|
1277
|
+
throw new Error(`${msiName$3}: PROGRAMDATA environment variable has no value.`);
|
|
1208
1278
|
}
|
|
1209
1279
|
return `${process.env.PROGRAMDATA}\\AzureConnectedMachineAgent\\Tokens`;
|
|
1210
1280
|
case "linux":
|
|
1211
1281
|
return "/var/opt/azcmagent/tokens";
|
|
1212
1282
|
default:
|
|
1213
|
-
throw new Error(`${msiName$
|
|
1283
|
+
throw new Error(`${msiName$3}: Unsupported platform ${process.platform}.`);
|
|
1214
1284
|
}
|
|
1215
1285
|
}
|
|
1216
1286
|
/**
|
|
@@ -1223,18 +1293,18 @@ function platformToFilePath() {
|
|
|
1223
1293
|
*/
|
|
1224
1294
|
function validateKeyFile(filePath) {
|
|
1225
1295
|
if (!filePath) {
|
|
1226
|
-
throw new Error(`${msiName$
|
|
1296
|
+
throw new Error(`${msiName$3}: Failed to find the token file.`);
|
|
1227
1297
|
}
|
|
1228
1298
|
if (!filePath.endsWith(".key")) {
|
|
1229
|
-
throw new Error(`${msiName$
|
|
1299
|
+
throw new Error(`${msiName$3}: unexpected file path from HIMDS service: ${filePath}.`);
|
|
1230
1300
|
}
|
|
1231
1301
|
const expectedPath = platformToFilePath();
|
|
1232
1302
|
if (!filePath.startsWith(expectedPath)) {
|
|
1233
|
-
throw new Error(`${msiName$
|
|
1303
|
+
throw new Error(`${msiName$3}: unexpected file path from HIMDS service: ${filePath}.`);
|
|
1234
1304
|
}
|
|
1235
1305
|
const stats = fs$1.statSync(filePath);
|
|
1236
1306
|
if (stats.size > 4096) {
|
|
1237
|
-
throw new Error(`${msiName$
|
|
1307
|
+
throw new Error(`${msiName$3}: The file at ${filePath} is larger than expected at ${stats.size} bytes.`);
|
|
1238
1308
|
}
|
|
1239
1309
|
}
|
|
1240
1310
|
/**
|
|
@@ -1245,12 +1315,12 @@ const arcMsi = {
|
|
|
1245
1315
|
async isAvailable({ scopes }) {
|
|
1246
1316
|
const resource = mapScopesToResource(scopes);
|
|
1247
1317
|
if (!resource) {
|
|
1248
|
-
logger$
|
|
1318
|
+
logger$l.info(`${msiName$3}: Unavailable. Multiple scopes are not supported.`);
|
|
1249
1319
|
return false;
|
|
1250
1320
|
}
|
|
1251
1321
|
const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
|
|
1252
1322
|
if (!result) {
|
|
1253
|
-
logger$
|
|
1323
|
+
logger$l.info(`${msiName$3}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
|
|
1254
1324
|
}
|
|
1255
1325
|
return result;
|
|
1256
1326
|
},
|
|
@@ -1258,13 +1328,13 @@ const arcMsi = {
|
|
|
1258
1328
|
var _a;
|
|
1259
1329
|
const { identityClient, scopes, clientId, resourceId } = configuration;
|
|
1260
1330
|
if (clientId) {
|
|
1261
|
-
logger$
|
|
1331
|
+
logger$l.warning(`${msiName$3}: user-assigned identities not supported. The argument clientId might be ignored by the service.`);
|
|
1262
1332
|
}
|
|
1263
1333
|
if (resourceId) {
|
|
1264
|
-
logger$
|
|
1334
|
+
logger$l.warning(`${msiName$3}: user defined managed Identity by resource Id is not supported. Argument resourceId will be ignored.`);
|
|
1265
1335
|
}
|
|
1266
|
-
logger$
|
|
1267
|
-
const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$
|
|
1336
|
+
logger$l.info(`${msiName$3}: Authenticating.`);
|
|
1337
|
+
const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$2(scopes, clientId, resourceId)), { allowInsecureConnection: true });
|
|
1268
1338
|
const filePath = await filePathRequest(identityClient, requestOptions);
|
|
1269
1339
|
validateKeyFile(filePath);
|
|
1270
1340
|
const key = await fs$1.promises.readFile(filePath, { encoding: "utf-8" });
|
|
@@ -1277,78 +1347,6 @@ const arcMsi = {
|
|
|
1277
1347
|
},
|
|
1278
1348
|
};
|
|
1279
1349
|
|
|
1280
|
-
// Copyright (c) Microsoft Corporation.
|
|
1281
|
-
// Licensed under the MIT license.
|
|
1282
|
-
const msiName$3 = "ManagedIdentityCredential - CloudShellMSI";
|
|
1283
|
-
const logger$l = credentialLogger(msiName$3);
|
|
1284
|
-
/**
|
|
1285
|
-
* Generates the options used on the request for an access token.
|
|
1286
|
-
*/
|
|
1287
|
-
function prepareRequestOptions$2(scopes, clientId, resourceId) {
|
|
1288
|
-
const resource = mapScopesToResource(scopes);
|
|
1289
|
-
if (!resource) {
|
|
1290
|
-
throw new Error(`${msiName$3}: Multiple scopes are not supported.`);
|
|
1291
|
-
}
|
|
1292
|
-
const body = {
|
|
1293
|
-
resource,
|
|
1294
|
-
};
|
|
1295
|
-
if (clientId) {
|
|
1296
|
-
body.client_id = clientId;
|
|
1297
|
-
}
|
|
1298
|
-
if (resourceId) {
|
|
1299
|
-
body.msi_res_id = resourceId;
|
|
1300
|
-
}
|
|
1301
|
-
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
1302
|
-
if (!process.env.MSI_ENDPOINT) {
|
|
1303
|
-
throw new Error(`${msiName$3}: Missing environment variable: MSI_ENDPOINT`);
|
|
1304
|
-
}
|
|
1305
|
-
const params = new URLSearchParams(body);
|
|
1306
|
-
return {
|
|
1307
|
-
url: process.env.MSI_ENDPOINT,
|
|
1308
|
-
method: "POST",
|
|
1309
|
-
body: params.toString(),
|
|
1310
|
-
headers: coreRestPipeline.createHttpHeaders({
|
|
1311
|
-
Accept: "application/json",
|
|
1312
|
-
Metadata: "true",
|
|
1313
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
1314
|
-
}),
|
|
1315
|
-
};
|
|
1316
|
-
}
|
|
1317
|
-
/**
|
|
1318
|
-
* Defines how to determine whether the Azure Cloud Shell MSI is available, and also how to retrieve a token from the Azure Cloud Shell MSI.
|
|
1319
|
-
* Since Azure Managed Identities aren't available in the Azure Cloud Shell, we log a warning for users that try to access cloud shell using user assigned identity.
|
|
1320
|
-
*/
|
|
1321
|
-
const cloudShellMsi = {
|
|
1322
|
-
name: "cloudShellMsi",
|
|
1323
|
-
async isAvailable({ scopes }) {
|
|
1324
|
-
const resource = mapScopesToResource(scopes);
|
|
1325
|
-
if (!resource) {
|
|
1326
|
-
logger$l.info(`${msiName$3}: Unavailable. Multiple scopes are not supported.`);
|
|
1327
|
-
return false;
|
|
1328
|
-
}
|
|
1329
|
-
const result = Boolean(process.env.MSI_ENDPOINT);
|
|
1330
|
-
if (!result) {
|
|
1331
|
-
logger$l.info(`${msiName$3}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
|
|
1332
|
-
}
|
|
1333
|
-
return result;
|
|
1334
|
-
},
|
|
1335
|
-
async getToken(configuration, getTokenOptions = {}) {
|
|
1336
|
-
const { identityClient, scopes, clientId, resourceId } = configuration;
|
|
1337
|
-
if (clientId) {
|
|
1338
|
-
logger$l.warning(`${msiName$3}: user-assigned identities not supported. The argument clientId might be ignored by the service.`);
|
|
1339
|
-
}
|
|
1340
|
-
if (resourceId) {
|
|
1341
|
-
logger$l.warning(`${msiName$3}: user defined managed Identity by resource Id not supported. The argument resourceId might be ignored by the service.`);
|
|
1342
|
-
}
|
|
1343
|
-
logger$l.info(`${msiName$3}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
|
|
1344
|
-
const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$2(scopes, clientId, resourceId)), {
|
|
1345
|
-
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
|
1346
|
-
allowInsecureConnection: true }));
|
|
1347
|
-
const tokenResponse = await identityClient.sendTokenRequest(request);
|
|
1348
|
-
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
1349
|
-
},
|
|
1350
|
-
};
|
|
1351
|
-
|
|
1352
1350
|
// Copyright (c) Microsoft Corporation.
|
|
1353
1351
|
// Licensed under the MIT license.
|
|
1354
1352
|
// This MSI can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:
|
|
@@ -1546,16 +1544,6 @@ function getMSALLogLevel(logLevel) {
|
|
|
1546
1544
|
return msalCommon__namespace.LogLevel.Info;
|
|
1547
1545
|
}
|
|
1548
1546
|
}
|
|
1549
|
-
/**
|
|
1550
|
-
* Wraps core-util's randomUUID in order to allow for mocking in tests.
|
|
1551
|
-
* This prepares the library for the upcoming core-util update to ESM.
|
|
1552
|
-
*
|
|
1553
|
-
* @internal
|
|
1554
|
-
* @returns A string containing a random UUID
|
|
1555
|
-
*/
|
|
1556
|
-
function randomUUID() {
|
|
1557
|
-
return coreUtil.randomUUID();
|
|
1558
|
-
}
|
|
1559
1547
|
/**
|
|
1560
1548
|
* Handles MSAL errors.
|
|
1561
1549
|
*/
|
|
@@ -1928,6 +1916,16 @@ function calculateRegionalAuthority(regionalAuthority) {
|
|
|
1928
1916
|
return azureRegion;
|
|
1929
1917
|
}
|
|
1930
1918
|
|
|
1919
|
+
// Copyright (c) Microsoft Corporation.
|
|
1920
|
+
// Licensed under the MIT license.
|
|
1921
|
+
/**
|
|
1922
|
+
* A call to open(), but mockable
|
|
1923
|
+
* @internal
|
|
1924
|
+
*/
|
|
1925
|
+
const interactiveBrowserMockable = {
|
|
1926
|
+
open,
|
|
1927
|
+
};
|
|
1928
|
+
|
|
1931
1929
|
// Copyright (c) Microsoft Corporation.
|
|
1932
1930
|
// Licensed under the MIT license.
|
|
1933
1931
|
/**
|
|
@@ -2234,6 +2232,105 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
|
|
|
2234
2232
|
});
|
|
2235
2233
|
});
|
|
2236
2234
|
}
|
|
2235
|
+
async function getTokenOnBehalfOf(scopes, userAssertionToken, clientSecretOrCertificate, options = {}) {
|
|
2236
|
+
msalLogger.getToken.info(`Attempting to acquire token on behalf of another user`);
|
|
2237
|
+
if (typeof clientSecretOrCertificate === "string") {
|
|
2238
|
+
// Client secret
|
|
2239
|
+
msalLogger.getToken.info(`Using client secret for on behalf of flow`);
|
|
2240
|
+
state.msalConfig.auth.clientSecret = clientSecretOrCertificate;
|
|
2241
|
+
}
|
|
2242
|
+
else {
|
|
2243
|
+
// Client certificate
|
|
2244
|
+
msalLogger.getToken.info(`Using client certificate for on behalf of flow`);
|
|
2245
|
+
state.msalConfig.auth.clientCertificate = clientSecretOrCertificate;
|
|
2246
|
+
}
|
|
2247
|
+
const msalApp = await getConfidentialApp(options);
|
|
2248
|
+
try {
|
|
2249
|
+
const response = await msalApp.acquireTokenOnBehalfOf({
|
|
2250
|
+
scopes,
|
|
2251
|
+
authority: state.msalConfig.auth.authority,
|
|
2252
|
+
claims: options.claims,
|
|
2253
|
+
oboAssertion: userAssertionToken,
|
|
2254
|
+
});
|
|
2255
|
+
ensureValidMsalToken(scopes, response, options);
|
|
2256
|
+
msalLogger.getToken.info(formatSuccess(scopes));
|
|
2257
|
+
return {
|
|
2258
|
+
token: response.accessToken,
|
|
2259
|
+
expiresOnTimestamp: response.expiresOn.getTime(),
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
catch (err) {
|
|
2263
|
+
throw handleMsalError(scopes, err, options);
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
async function getTokenByInteractiveRequest(scopes, options = {}) {
|
|
2267
|
+
msalLogger.getToken.info(`Attempting to acquire token interactively`);
|
|
2268
|
+
const app = await getPublicApp(options);
|
|
2269
|
+
/**
|
|
2270
|
+
* A helper function that supports brokered authentication through the MSAL's public application.
|
|
2271
|
+
*
|
|
2272
|
+
* When options.useDefaultBrokerAccount is true, the method will attempt to authenticate using the default broker account.
|
|
2273
|
+
* If the default broker account is not available, the method will fall back to interactive authentication.
|
|
2274
|
+
*/
|
|
2275
|
+
async function getBrokeredToken(useDefaultBrokerAccount) {
|
|
2276
|
+
var _a;
|
|
2277
|
+
msalLogger.verbose("Authentication will resume through the broker");
|
|
2278
|
+
const interactiveRequest = createBaseInteractiveRequest();
|
|
2279
|
+
if (state.pluginConfiguration.broker.parentWindowHandle) {
|
|
2280
|
+
interactiveRequest.windowHandle = Buffer.from(state.pluginConfiguration.broker.parentWindowHandle);
|
|
2281
|
+
}
|
|
2282
|
+
else {
|
|
2283
|
+
// this is a bug, as the pluginConfiguration handler should validate this case.
|
|
2284
|
+
msalLogger.warning("Parent window handle is not specified for the broker. This may cause unexpected behavior. Please provide the parentWindowHandle.");
|
|
2285
|
+
}
|
|
2286
|
+
if (state.pluginConfiguration.broker.enableMsaPassthrough) {
|
|
2287
|
+
((_a = interactiveRequest.tokenQueryParameters) !== null && _a !== void 0 ? _a : (interactiveRequest.tokenQueryParameters = {}))["msal_request_type"] =
|
|
2288
|
+
"consumer_passthrough";
|
|
2289
|
+
}
|
|
2290
|
+
if (useDefaultBrokerAccount) {
|
|
2291
|
+
interactiveRequest.prompt = "none";
|
|
2292
|
+
msalLogger.verbose("Attempting broker authentication using the default broker account");
|
|
2293
|
+
}
|
|
2294
|
+
else {
|
|
2295
|
+
msalLogger.verbose("Attempting broker authentication without the default broker account");
|
|
2296
|
+
}
|
|
2297
|
+
try {
|
|
2298
|
+
return await app.acquireTokenInteractive(interactiveRequest);
|
|
2299
|
+
}
|
|
2300
|
+
catch (e) {
|
|
2301
|
+
msalLogger.verbose(`Failed to authenticate through the broker: ${e.message}`);
|
|
2302
|
+
// If we tried to use the default broker account and failed, fall back to interactive authentication
|
|
2303
|
+
if (useDefaultBrokerAccount) {
|
|
2304
|
+
return getBrokeredToken(/* useDefaultBrokerAccount: */ false);
|
|
2305
|
+
}
|
|
2306
|
+
else {
|
|
2307
|
+
throw e;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
function createBaseInteractiveRequest() {
|
|
2312
|
+
var _a, _b;
|
|
2313
|
+
return {
|
|
2314
|
+
openBrowser: async (url) => {
|
|
2315
|
+
await interactiveBrowserMockable.open(url, { wait: true, newInstance: true });
|
|
2316
|
+
},
|
|
2317
|
+
scopes,
|
|
2318
|
+
authority: state.msalConfig.auth.authority,
|
|
2319
|
+
claims: options === null || options === void 0 ? void 0 : options.claims,
|
|
2320
|
+
loginHint: options === null || options === void 0 ? void 0 : options.loginHint,
|
|
2321
|
+
errorTemplate: (_a = options === null || options === void 0 ? void 0 : options.browserCustomizationOptions) === null || _a === void 0 ? void 0 : _a.errorMessage,
|
|
2322
|
+
successTemplate: (_b = options === null || options === void 0 ? void 0 : options.browserCustomizationOptions) === null || _b === void 0 ? void 0 : _b.successMessage,
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2325
|
+
return withSilentAuthentication(app, scopes, options, async () => {
|
|
2326
|
+
var _a;
|
|
2327
|
+
const interactiveRequest = createBaseInteractiveRequest();
|
|
2328
|
+
if (state.pluginConfiguration.broker.isEnabled) {
|
|
2329
|
+
return getBrokeredToken((_a = state.pluginConfiguration.broker.useDefaultBrokerAccount) !== null && _a !== void 0 ? _a : false);
|
|
2330
|
+
}
|
|
2331
|
+
return app.acquireTokenInteractive(interactiveRequest);
|
|
2332
|
+
});
|
|
2333
|
+
}
|
|
2237
2334
|
return {
|
|
2238
2335
|
getActiveAccount,
|
|
2239
2336
|
getTokenByClientSecret,
|
|
@@ -2242,6 +2339,8 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
|
|
|
2242
2339
|
getTokenByDeviceCode,
|
|
2243
2340
|
getTokenByUsernamePassword,
|
|
2244
2341
|
getTokenByAuthorizationCode,
|
|
2342
|
+
getTokenOnBehalfOf,
|
|
2343
|
+
getTokenByInteractiveRequest,
|
|
2245
2344
|
};
|
|
2246
2345
|
}
|
|
2247
2346
|
|
|
@@ -2422,19 +2521,7 @@ function tokenExchangeMsi() {
|
|
|
2422
2521
|
// Copyright (c) Microsoft Corporation.
|
|
2423
2522
|
// Licensed under the MIT license.
|
|
2424
2523
|
const logger$e = credentialLogger("ManagedIdentityCredential");
|
|
2425
|
-
|
|
2426
|
-
* Attempts authentication using a managed identity available at the deployment environment.
|
|
2427
|
-
* This authentication type works in Azure VMs, App Service instances, Azure Functions applications,
|
|
2428
|
-
* Azure Kubernetes Services, Azure Service Fabric instances and inside of the Azure Cloud Shell.
|
|
2429
|
-
*
|
|
2430
|
-
* More information about configuring managed identities can be found here:
|
|
2431
|
-
* https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
|
|
2432
|
-
*/
|
|
2433
|
-
class ManagedIdentityCredential {
|
|
2434
|
-
/**
|
|
2435
|
-
* @internal
|
|
2436
|
-
* @hidden
|
|
2437
|
-
*/
|
|
2524
|
+
class LegacyMsiProvider {
|
|
2438
2525
|
constructor(clientIdOrOptions, options) {
|
|
2439
2526
|
var _a, _b;
|
|
2440
2527
|
this.isEndpointUnavailable = null;
|
|
@@ -2456,7 +2543,7 @@ class ManagedIdentityCredential {
|
|
|
2456
2543
|
this.resourceId = _options === null || _options === void 0 ? void 0 : _options.resourceId;
|
|
2457
2544
|
// For JavaScript users.
|
|
2458
2545
|
if (this.clientId && this.resourceId) {
|
|
2459
|
-
throw new Error(
|
|
2546
|
+
throw new Error(`ManagedIdentityCredential - Client Id and Resource Id can't be provided at the same time.`);
|
|
2460
2547
|
}
|
|
2461
2548
|
if (((_a = _options === null || _options === void 0 ? void 0 : _options.retryOptions) === null || _a === void 0 ? void 0 : _a.maxRetries) !== undefined) {
|
|
2462
2549
|
this.msiRetryConfig.maxRetries = _options.retryOptions.maxRetries;
|
|
@@ -2509,10 +2596,10 @@ class ManagedIdentityCredential {
|
|
|
2509
2596
|
return msi;
|
|
2510
2597
|
}
|
|
2511
2598
|
}
|
|
2512
|
-
throw new CredentialUnavailableError(
|
|
2599
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential - No MSI credential available`);
|
|
2513
2600
|
}
|
|
2514
2601
|
async authenticateManagedIdentity(scopes, getTokenOptions) {
|
|
2515
|
-
const { span, updatedOptions } = tracingClient.startSpan(
|
|
2602
|
+
const { span, updatedOptions } = tracingClient.startSpan(`ManagedIdentityCredential.authenticateManagedIdentity`, getTokenOptions);
|
|
2516
2603
|
try {
|
|
2517
2604
|
// Determining the available MSI, and avoiding checking for other MSIs while the program is running.
|
|
2518
2605
|
const availableMSI = await this.cachedAvailableMSI(scopes, updatedOptions);
|
|
@@ -2546,7 +2633,7 @@ class ManagedIdentityCredential {
|
|
|
2546
2633
|
*/
|
|
2547
2634
|
async getToken(scopes, options) {
|
|
2548
2635
|
let result = null;
|
|
2549
|
-
const { span, updatedOptions } = tracingClient.startSpan(
|
|
2636
|
+
const { span, updatedOptions } = tracingClient.startSpan(`ManagedIdentityCredential.getToken`, options);
|
|
2550
2637
|
try {
|
|
2551
2638
|
// isEndpointAvailable can be true, false, or null,
|
|
2552
2639
|
// If it's null, it means we don't yet know whether
|
|
@@ -2612,27 +2699,27 @@ class ManagedIdentityCredential {
|
|
|
2612
2699
|
// If either the network is unreachable,
|
|
2613
2700
|
// we can safely assume the credential is unavailable.
|
|
2614
2701
|
if (err.code === "ENETUNREACH") {
|
|
2615
|
-
const error = new CredentialUnavailableError(
|
|
2702
|
+
const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. Network unreachable. Message: ${err.message}`);
|
|
2616
2703
|
logger$e.getToken.info(formatError(scopes, error));
|
|
2617
2704
|
throw error;
|
|
2618
2705
|
}
|
|
2619
2706
|
// If either the host was unreachable,
|
|
2620
2707
|
// we can safely assume the credential is unavailable.
|
|
2621
2708
|
if (err.code === "EHOSTUNREACH") {
|
|
2622
|
-
const error = new CredentialUnavailableError(
|
|
2709
|
+
const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. No managed identity endpoint found. Message: ${err.message}`);
|
|
2623
2710
|
logger$e.getToken.info(formatError(scopes, error));
|
|
2624
2711
|
throw error;
|
|
2625
2712
|
}
|
|
2626
2713
|
// If err.statusCode has a value of 400, it comes from sendTokenRequest,
|
|
2627
2714
|
// and it means that the endpoint is working, but that no identity is available.
|
|
2628
2715
|
if (err.statusCode === 400) {
|
|
2629
|
-
throw new CredentialUnavailableError(
|
|
2716
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
|
|
2630
2717
|
}
|
|
2631
2718
|
// This is a special case for Docker Desktop which responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network" or "A socket operation was attempted to an unreachable host"
|
|
2632
2719
|
// rather than just timing out, as expected.
|
|
2633
2720
|
if (err.statusCode === 403 || err.code === 403) {
|
|
2634
2721
|
if (err.message.includes("unreachable")) {
|
|
2635
|
-
const error = new CredentialUnavailableError(
|
|
2722
|
+
const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. Network unreachable. Message: ${err.message}`);
|
|
2636
2723
|
logger$e.getToken.info(formatError(scopes, error));
|
|
2637
2724
|
throw error;
|
|
2638
2725
|
}
|
|
@@ -2640,11 +2727,11 @@ class ManagedIdentityCredential {
|
|
|
2640
2727
|
// If the error has no status code, we can assume there was no available identity.
|
|
2641
2728
|
// This will throw silently during any ChainedTokenCredential.
|
|
2642
2729
|
if (err.statusCode === undefined) {
|
|
2643
|
-
throw new CredentialUnavailableError(
|
|
2730
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`);
|
|
2644
2731
|
}
|
|
2645
2732
|
// Any other error should break the chain.
|
|
2646
2733
|
throw new AuthenticationError(err.statusCode, {
|
|
2647
|
-
error:
|
|
2734
|
+
error: `ManagedIdentityCredential authentication failed.`,
|
|
2648
2735
|
error_description: err.message,
|
|
2649
2736
|
});
|
|
2650
2737
|
}
|
|
@@ -2721,24 +2808,56 @@ class ManagedIdentityCredential {
|
|
|
2721
2808
|
// Copyright (c) Microsoft Corporation.
|
|
2722
2809
|
// Licensed under the MIT license.
|
|
2723
2810
|
/**
|
|
2724
|
-
*
|
|
2725
|
-
*
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
/**
|
|
2731
|
-
* Throws if the received scope is not valid.
|
|
2732
|
-
* @internal
|
|
2811
|
+
* Attempts authentication using a managed identity available at the deployment environment.
|
|
2812
|
+
* This authentication type works in Azure VMs, App Service instances, Azure Functions applications,
|
|
2813
|
+
* Azure Kubernetes Services, Azure Service Fabric instances and inside of the Azure Cloud Shell.
|
|
2814
|
+
*
|
|
2815
|
+
* More information about configuring managed identities can be found here:
|
|
2816
|
+
* https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
|
|
2733
2817
|
*/
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2818
|
+
class ManagedIdentityCredential {
|
|
2819
|
+
/**
|
|
2820
|
+
* @internal
|
|
2821
|
+
* @hidden
|
|
2822
|
+
*/
|
|
2823
|
+
constructor(clientIdOrOptions, options) {
|
|
2824
|
+
this.implProvider = new LegacyMsiProvider(clientIdOrOptions, options);
|
|
2825
|
+
}
|
|
2826
|
+
/**
|
|
2827
|
+
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
|
2828
|
+
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
|
|
2829
|
+
* If an unexpected error occurs, an {@link AuthenticationError} will be thrown with the details of the failure.
|
|
2830
|
+
*
|
|
2831
|
+
* @param scopes - The list of scopes for which the token will have access.
|
|
2832
|
+
* @param options - The options used to configure any requests this
|
|
2833
|
+
* TokenCredential implementation might make.
|
|
2834
|
+
*/
|
|
2835
|
+
async getToken(scopes, options) {
|
|
2836
|
+
return this.implProvider.getToken(scopes, options);
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
// Copyright (c) Microsoft Corporation.
|
|
2841
|
+
// Licensed under the MIT license.
|
|
2842
|
+
/**
|
|
2843
|
+
* Ensures the scopes value is an array.
|
|
2844
|
+
* @internal
|
|
2845
|
+
*/
|
|
2846
|
+
function ensureScopes(scopes) {
|
|
2847
|
+
return Array.isArray(scopes) ? scopes : [scopes];
|
|
2848
|
+
}
|
|
2849
|
+
/**
|
|
2850
|
+
* Throws if the received scope is not valid.
|
|
2851
|
+
* @internal
|
|
2852
|
+
*/
|
|
2853
|
+
function ensureValidScopeForDevTimeCreds(scope, logger) {
|
|
2854
|
+
if (!scope.match(/^[0-9a-zA-Z-_.:/]+$/)) {
|
|
2855
|
+
const error = new Error("Invalid scope was specified by the user or calling client");
|
|
2856
|
+
logger.getToken.info(formatError(scope, error));
|
|
2857
|
+
throw error;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
/**
|
|
2742
2861
|
* Returns the resource out of a scope.
|
|
2743
2862
|
* @internal
|
|
2744
2863
|
*/
|
|
@@ -3826,425 +3945,6 @@ class DefaultAzureCredential extends ChainedTokenCredential {
|
|
|
3826
3945
|
}
|
|
3827
3946
|
}
|
|
3828
3947
|
|
|
3829
|
-
// Copyright (c) Microsoft Corporation.
|
|
3830
|
-
// Licensed under the MIT license.
|
|
3831
|
-
/**
|
|
3832
|
-
* MSAL partial base client for Node.js.
|
|
3833
|
-
*
|
|
3834
|
-
* It completes the input configuration with some default values.
|
|
3835
|
-
* It also provides with utility protected methods that can be used from any of the clients,
|
|
3836
|
-
* which includes handlers for successful responses and errors.
|
|
3837
|
-
*
|
|
3838
|
-
* @internal
|
|
3839
|
-
*/
|
|
3840
|
-
class MsalNode {
|
|
3841
|
-
constructor(options) {
|
|
3842
|
-
var _a, _b, _c, _d, _e, _f;
|
|
3843
|
-
this.app = {};
|
|
3844
|
-
this.caeApp = {};
|
|
3845
|
-
this.requiresConfidential = false;
|
|
3846
|
-
this.logger = options.logger;
|
|
3847
|
-
this.msalConfig = this.defaultNodeMsalConfig(options);
|
|
3848
|
-
this.tenantId = resolveTenantId(options.logger, options.tenantId, options.clientId);
|
|
3849
|
-
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds((_a = options === null || options === void 0 ? void 0 : options.tokenCredentialOptions) === null || _a === void 0 ? void 0 : _a.additionallyAllowedTenants);
|
|
3850
|
-
this.clientId = this.msalConfig.auth.clientId;
|
|
3851
|
-
if (options === null || options === void 0 ? void 0 : options.getAssertion) {
|
|
3852
|
-
this.getAssertion = options.getAssertion;
|
|
3853
|
-
}
|
|
3854
|
-
this.enableBroker = (_b = options === null || options === void 0 ? void 0 : options.brokerOptions) === null || _b === void 0 ? void 0 : _b.enabled;
|
|
3855
|
-
this.enableMsaPassthrough = (_c = options === null || options === void 0 ? void 0 : options.brokerOptions) === null || _c === void 0 ? void 0 : _c.legacyEnableMsaPassthrough;
|
|
3856
|
-
this.parentWindowHandle = (_d = options.brokerOptions) === null || _d === void 0 ? void 0 : _d.parentWindowHandle;
|
|
3857
|
-
// If persistence has been configured
|
|
3858
|
-
if (persistenceProvider !== undefined && ((_e = options.tokenCachePersistenceOptions) === null || _e === void 0 ? void 0 : _e.enabled)) {
|
|
3859
|
-
const cacheBaseName = options.tokenCachePersistenceOptions.name || DEFAULT_TOKEN_CACHE_NAME;
|
|
3860
|
-
const nonCaeOptions = Object.assign({ name: `${cacheBaseName}.${CACHE_NON_CAE_SUFFIX}` }, options.tokenCachePersistenceOptions);
|
|
3861
|
-
const caeOptions = Object.assign({ name: `${cacheBaseName}.${CACHE_CAE_SUFFIX}` }, options.tokenCachePersistenceOptions);
|
|
3862
|
-
this.createCachePlugin = () => persistenceProvider(nonCaeOptions);
|
|
3863
|
-
this.createCachePluginCae = () => persistenceProvider(caeOptions);
|
|
3864
|
-
}
|
|
3865
|
-
else if ((_f = options.tokenCachePersistenceOptions) === null || _f === void 0 ? void 0 : _f.enabled) {
|
|
3866
|
-
throw new Error([
|
|
3867
|
-
"Persistent token caching was requested, but no persistence provider was configured.",
|
|
3868
|
-
"You must install the identity-cache-persistence plugin package (`npm install --save @azure/identity-cache-persistence`)",
|
|
3869
|
-
"and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling",
|
|
3870
|
-
"`useIdentityPlugin(cachePersistencePlugin)` before using `tokenCachePersistenceOptions`.",
|
|
3871
|
-
].join(" "));
|
|
3872
|
-
}
|
|
3873
|
-
// If broker has not been configured
|
|
3874
|
-
if (!hasNativeBroker() && this.enableBroker) {
|
|
3875
|
-
throw new Error([
|
|
3876
|
-
"Broker for WAM was requested to be enabled, but no native broker was configured.",
|
|
3877
|
-
"You must install the identity-broker plugin package (`npm install --save @azure/identity-broker`)",
|
|
3878
|
-
"and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling",
|
|
3879
|
-
"`useIdentityPlugin(createNativeBrokerPlugin())` before using `enableBroker`.",
|
|
3880
|
-
].join(" "));
|
|
3881
|
-
}
|
|
3882
|
-
this.azureRegion = calculateRegionalAuthority(options.regionalAuthority);
|
|
3883
|
-
}
|
|
3884
|
-
/**
|
|
3885
|
-
* Generates a MSAL configuration that generally works for Node.js
|
|
3886
|
-
*/
|
|
3887
|
-
defaultNodeMsalConfig(options) {
|
|
3888
|
-
var _a;
|
|
3889
|
-
const clientId = options.clientId || DeveloperSignOnClientId;
|
|
3890
|
-
const tenantId = resolveTenantId(options.logger, options.tenantId, options.clientId);
|
|
3891
|
-
this.authorityHost = options.authorityHost || process.env.AZURE_AUTHORITY_HOST;
|
|
3892
|
-
const authority = getAuthority(tenantId, this.authorityHost);
|
|
3893
|
-
this.identityClient = new IdentityClient(Object.assign(Object.assign({}, options.tokenCredentialOptions), { authorityHost: authority, loggingOptions: options.loggingOptions }));
|
|
3894
|
-
const clientCapabilities = [];
|
|
3895
|
-
return {
|
|
3896
|
-
auth: {
|
|
3897
|
-
clientId,
|
|
3898
|
-
authority,
|
|
3899
|
-
knownAuthorities: getKnownAuthorities(tenantId, authority, options.disableInstanceDiscovery),
|
|
3900
|
-
clientCapabilities,
|
|
3901
|
-
},
|
|
3902
|
-
// Cache is defined in this.prepare();
|
|
3903
|
-
system: {
|
|
3904
|
-
networkClient: this.identityClient,
|
|
3905
|
-
loggerOptions: {
|
|
3906
|
-
loggerCallback: defaultLoggerCallback(options.logger),
|
|
3907
|
-
logLevel: getMSALLogLevel(logger$r.getLogLevel()),
|
|
3908
|
-
piiLoggingEnabled: (_a = options.loggingOptions) === null || _a === void 0 ? void 0 : _a.enableUnsafeSupportLogging,
|
|
3909
|
-
},
|
|
3910
|
-
},
|
|
3911
|
-
};
|
|
3912
|
-
}
|
|
3913
|
-
getApp(appType, enableCae) {
|
|
3914
|
-
const app = enableCae ? this.caeApp : this.app;
|
|
3915
|
-
if (appType === "publicFirst") {
|
|
3916
|
-
return (app.public || app.confidential);
|
|
3917
|
-
}
|
|
3918
|
-
else if (appType === "confidentialFirst") {
|
|
3919
|
-
return (app.confidential || app.public);
|
|
3920
|
-
}
|
|
3921
|
-
else if (appType === "confidential") {
|
|
3922
|
-
return app.confidential;
|
|
3923
|
-
}
|
|
3924
|
-
else {
|
|
3925
|
-
return app.public;
|
|
3926
|
-
}
|
|
3927
|
-
}
|
|
3928
|
-
/**
|
|
3929
|
-
* Prepares the MSAL applications.
|
|
3930
|
-
*/
|
|
3931
|
-
async init(options) {
|
|
3932
|
-
if (options === null || options === void 0 ? void 0 : options.abortSignal) {
|
|
3933
|
-
options.abortSignal.addEventListener("abort", () => {
|
|
3934
|
-
// This will abort any pending request in the IdentityClient,
|
|
3935
|
-
// based on the received or generated correlationId
|
|
3936
|
-
this.identityClient.abortRequests(options.correlationId);
|
|
3937
|
-
});
|
|
3938
|
-
}
|
|
3939
|
-
const app = (options === null || options === void 0 ? void 0 : options.enableCae) ? this.caeApp : this.app;
|
|
3940
|
-
if (options === null || options === void 0 ? void 0 : options.enableCae) {
|
|
3941
|
-
this.msalConfig.auth.clientCapabilities = ["cp1"];
|
|
3942
|
-
}
|
|
3943
|
-
if (app.public || app.confidential) {
|
|
3944
|
-
return;
|
|
3945
|
-
}
|
|
3946
|
-
if ((options === null || options === void 0 ? void 0 : options.enableCae) && this.createCachePluginCae !== undefined) {
|
|
3947
|
-
this.msalConfig.cache = {
|
|
3948
|
-
cachePlugin: await this.createCachePluginCae(),
|
|
3949
|
-
};
|
|
3950
|
-
}
|
|
3951
|
-
if (this.createCachePlugin !== undefined) {
|
|
3952
|
-
this.msalConfig.cache = {
|
|
3953
|
-
cachePlugin: await this.createCachePlugin(),
|
|
3954
|
-
};
|
|
3955
|
-
}
|
|
3956
|
-
if (hasNativeBroker() && this.enableBroker) {
|
|
3957
|
-
this.msalConfig.broker = {
|
|
3958
|
-
nativeBrokerPlugin: nativeBrokerInfo.broker,
|
|
3959
|
-
};
|
|
3960
|
-
if (!this.parentWindowHandle) {
|
|
3961
|
-
// error should have been thrown from within the constructor of InteractiveBrowserCredential
|
|
3962
|
-
this.logger.warning("Parent window handle is not specified for the broker. This may cause unexpected behavior. Please provide the parentWindowHandle.");
|
|
3963
|
-
}
|
|
3964
|
-
}
|
|
3965
|
-
if (options === null || options === void 0 ? void 0 : options.enableCae) {
|
|
3966
|
-
this.caeApp.public = new msalCommon__namespace.PublicClientApplication(this.msalConfig);
|
|
3967
|
-
}
|
|
3968
|
-
else {
|
|
3969
|
-
this.app.public = new msalCommon__namespace.PublicClientApplication(this.msalConfig);
|
|
3970
|
-
}
|
|
3971
|
-
if (this.getAssertion) {
|
|
3972
|
-
this.msalConfig.auth.clientAssertion = await this.getAssertion();
|
|
3973
|
-
}
|
|
3974
|
-
// The confidential client requires either a secret, assertion or certificate.
|
|
3975
|
-
if (this.msalConfig.auth.clientSecret ||
|
|
3976
|
-
this.msalConfig.auth.clientAssertion ||
|
|
3977
|
-
this.msalConfig.auth.clientCertificate) {
|
|
3978
|
-
if (options === null || options === void 0 ? void 0 : options.enableCae) {
|
|
3979
|
-
this.caeApp.confidential = new msalCommon__namespace.ConfidentialClientApplication(this.msalConfig);
|
|
3980
|
-
}
|
|
3981
|
-
else {
|
|
3982
|
-
this.app.confidential = new msalCommon__namespace.ConfidentialClientApplication(this.msalConfig);
|
|
3983
|
-
}
|
|
3984
|
-
}
|
|
3985
|
-
else {
|
|
3986
|
-
if (this.requiresConfidential) {
|
|
3987
|
-
throw new Error("Unable to generate the MSAL confidential client. Missing either the client's secret, certificate or assertion.");
|
|
3988
|
-
}
|
|
3989
|
-
}
|
|
3990
|
-
}
|
|
3991
|
-
/**
|
|
3992
|
-
* Allows the cancellation of a MSAL request.
|
|
3993
|
-
*/
|
|
3994
|
-
withCancellation(promise, abortSignal, onCancel) {
|
|
3995
|
-
return new Promise((resolve, reject) => {
|
|
3996
|
-
promise
|
|
3997
|
-
.then((msalToken) => {
|
|
3998
|
-
return resolve(msalToken);
|
|
3999
|
-
})
|
|
4000
|
-
.catch(reject);
|
|
4001
|
-
if (abortSignal) {
|
|
4002
|
-
abortSignal.addEventListener("abort", () => {
|
|
4003
|
-
onCancel === null || onCancel === void 0 ? void 0 : onCancel();
|
|
4004
|
-
});
|
|
4005
|
-
}
|
|
4006
|
-
});
|
|
4007
|
-
}
|
|
4008
|
-
/**
|
|
4009
|
-
* Returns the existing account, attempts to load the account from MSAL.
|
|
4010
|
-
*/
|
|
4011
|
-
async getActiveAccount(enableCae = false) {
|
|
4012
|
-
if (this.account) {
|
|
4013
|
-
return this.account;
|
|
4014
|
-
}
|
|
4015
|
-
const cache = this.getApp("confidentialFirst", enableCae).getTokenCache();
|
|
4016
|
-
const accountsByTenant = await (cache === null || cache === void 0 ? void 0 : cache.getAllAccounts());
|
|
4017
|
-
if (!accountsByTenant) {
|
|
4018
|
-
return;
|
|
4019
|
-
}
|
|
4020
|
-
if (accountsByTenant.length === 1) {
|
|
4021
|
-
this.account = msalToPublic(this.clientId, accountsByTenant[0]);
|
|
4022
|
-
}
|
|
4023
|
-
else {
|
|
4024
|
-
this.logger
|
|
4025
|
-
.info(`More than one account was found authenticated for this Client ID and Tenant ID.
|
|
4026
|
-
However, no "authenticationRecord" has been provided for this credential,
|
|
4027
|
-
therefore we're unable to pick between these accounts.
|
|
4028
|
-
A new login attempt will be requested, to ensure the correct account is picked.
|
|
4029
|
-
To work with multiple accounts for the same Client ID and Tenant ID, please provide an "authenticationRecord" when initializing a credential to prevent this from happening.`);
|
|
4030
|
-
return;
|
|
4031
|
-
}
|
|
4032
|
-
return this.account;
|
|
4033
|
-
}
|
|
4034
|
-
/**
|
|
4035
|
-
* Attempts to retrieve a token from cache.
|
|
4036
|
-
*/
|
|
4037
|
-
async getTokenSilent(scopes, options) {
|
|
4038
|
-
var _a, _b, _c;
|
|
4039
|
-
await this.getActiveAccount(options === null || options === void 0 ? void 0 : options.enableCae);
|
|
4040
|
-
if (!this.account) {
|
|
4041
|
-
throw new AuthenticationRequiredError({
|
|
4042
|
-
scopes,
|
|
4043
|
-
getTokenOptions: options,
|
|
4044
|
-
message: "Silent authentication failed. We couldn't retrieve an active account from the cache.",
|
|
4045
|
-
});
|
|
4046
|
-
}
|
|
4047
|
-
const silentRequest = {
|
|
4048
|
-
// To be able to re-use the account, the Token Cache must also have been provided.
|
|
4049
|
-
account: publicToMsal(this.account),
|
|
4050
|
-
correlationId: options === null || options === void 0 ? void 0 : options.correlationId,
|
|
4051
|
-
scopes,
|
|
4052
|
-
authority: options === null || options === void 0 ? void 0 : options.authority,
|
|
4053
|
-
claims: options === null || options === void 0 ? void 0 : options.claims,
|
|
4054
|
-
};
|
|
4055
|
-
if (hasNativeBroker() && this.enableBroker) {
|
|
4056
|
-
if (!silentRequest.tokenQueryParameters) {
|
|
4057
|
-
silentRequest.tokenQueryParameters = {};
|
|
4058
|
-
}
|
|
4059
|
-
if (!this.parentWindowHandle) {
|
|
4060
|
-
// error should have been thrown from within the constructor of InteractiveBrowserCredential
|
|
4061
|
-
this.logger.warning("Parent window handle is not specified for the broker. This may cause unexpected behavior. Please provide the parentWindowHandle.");
|
|
4062
|
-
}
|
|
4063
|
-
if (this.enableMsaPassthrough) {
|
|
4064
|
-
silentRequest.tokenQueryParameters["msal_request_type"] = "consumer_passthrough";
|
|
4065
|
-
}
|
|
4066
|
-
}
|
|
4067
|
-
try {
|
|
4068
|
-
this.logger.info("Attempting to acquire token silently");
|
|
4069
|
-
/**
|
|
4070
|
-
* The following code to retrieve all accounts is done as a workaround in an attempt to force the
|
|
4071
|
-
* refresh of the token cache with the token and the account passed in through the
|
|
4072
|
-
* `authenticationRecord` parameter. See issue - https://github.com/Azure/azure-sdk-for-js/issues/24349#issuecomment-1496715651
|
|
4073
|
-
* This workaround serves as a workaround for silent authentication not happening when authenticationRecord is passed.
|
|
4074
|
-
*/
|
|
4075
|
-
await ((_a = this.getApp("publicFirst", options === null || options === void 0 ? void 0 : options.enableCae)) === null || _a === void 0 ? void 0 : _a.getTokenCache().getAllAccounts());
|
|
4076
|
-
const response = (_c = (await ((_b = this.getApp("confidential", options === null || options === void 0 ? void 0 : options.enableCae)) === null || _b === void 0 ? void 0 : _b.acquireTokenSilent(silentRequest)))) !== null && _c !== void 0 ? _c : (await this.getApp("public", options === null || options === void 0 ? void 0 : options.enableCae).acquireTokenSilent(silentRequest));
|
|
4077
|
-
return this.handleResult(scopes, response || undefined);
|
|
4078
|
-
}
|
|
4079
|
-
catch (err) {
|
|
4080
|
-
throw handleMsalError(scopes, err, options);
|
|
4081
|
-
}
|
|
4082
|
-
}
|
|
4083
|
-
/**
|
|
4084
|
-
* Wrapper around each MSAL flow get token operation: doGetToken.
|
|
4085
|
-
* If disableAutomaticAuthentication is sent through the constructor, it will prevent MSAL from requesting the user input.
|
|
4086
|
-
*/
|
|
4087
|
-
async getToken(scopes, options = {}) {
|
|
4088
|
-
const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds) ||
|
|
4089
|
-
this.tenantId;
|
|
4090
|
-
options.authority = getAuthority(tenantId, this.authorityHost);
|
|
4091
|
-
options.correlationId = (options === null || options === void 0 ? void 0 : options.correlationId) || randomUUID();
|
|
4092
|
-
await this.init(options);
|
|
4093
|
-
try {
|
|
4094
|
-
// MSAL now caches tokens based on their claims,
|
|
4095
|
-
// so now one has to keep track fo claims in order to retrieve the newer tokens from acquireTokenSilent
|
|
4096
|
-
// This update happened on PR: https://github.com/AzureAD/microsoft-authentication-library-for-js/pull/4533
|
|
4097
|
-
const optionsClaims = options.claims;
|
|
4098
|
-
if (optionsClaims) {
|
|
4099
|
-
this.cachedClaims = optionsClaims;
|
|
4100
|
-
}
|
|
4101
|
-
if (this.cachedClaims && !optionsClaims) {
|
|
4102
|
-
options.claims = this.cachedClaims;
|
|
4103
|
-
}
|
|
4104
|
-
// We don't return the promise since we want to catch errors right here.
|
|
4105
|
-
return await this.getTokenSilent(scopes, options);
|
|
4106
|
-
}
|
|
4107
|
-
catch (err) {
|
|
4108
|
-
if (err.name !== "AuthenticationRequiredError") {
|
|
4109
|
-
throw err;
|
|
4110
|
-
}
|
|
4111
|
-
if (options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication) {
|
|
4112
|
-
throw new AuthenticationRequiredError({
|
|
4113
|
-
scopes,
|
|
4114
|
-
getTokenOptions: options,
|
|
4115
|
-
message: "Automatic authentication has been disabled. You may call the authentication() method.",
|
|
4116
|
-
});
|
|
4117
|
-
}
|
|
4118
|
-
this.logger.info(`Silent authentication failed, falling back to interactive method.`);
|
|
4119
|
-
return this.doGetToken(scopes, options);
|
|
4120
|
-
}
|
|
4121
|
-
}
|
|
4122
|
-
/**
|
|
4123
|
-
* Handles the MSAL authentication result.
|
|
4124
|
-
* If the result has an account, we update the local account reference.
|
|
4125
|
-
* If the token received is invalid, an error will be thrown depending on what's missing.
|
|
4126
|
-
*/
|
|
4127
|
-
handleResult(scopes, result, getTokenOptions) {
|
|
4128
|
-
if (result === null || result === void 0 ? void 0 : result.account) {
|
|
4129
|
-
this.account = msalToPublic(this.clientId, result.account);
|
|
4130
|
-
}
|
|
4131
|
-
ensureValidMsalToken(scopes, result, getTokenOptions);
|
|
4132
|
-
this.logger.getToken.info(formatSuccess(scopes));
|
|
4133
|
-
return {
|
|
4134
|
-
token: result.accessToken,
|
|
4135
|
-
expiresOnTimestamp: result.expiresOn.getTime(),
|
|
4136
|
-
};
|
|
4137
|
-
}
|
|
4138
|
-
}
|
|
4139
|
-
|
|
4140
|
-
// Copyright (c) Microsoft Corporation.
|
|
4141
|
-
// Licensed under the MIT license.
|
|
4142
|
-
/**
|
|
4143
|
-
* A call to open(), but mockable
|
|
4144
|
-
* @internal
|
|
4145
|
-
*/
|
|
4146
|
-
const interactiveBrowserMockable = {
|
|
4147
|
-
open,
|
|
4148
|
-
};
|
|
4149
|
-
/**
|
|
4150
|
-
* This MSAL client sets up a web server to listen for redirect callbacks, then calls to the MSAL's public application's `acquireTokenByDeviceCode` during `doGetToken`
|
|
4151
|
-
* to trigger the authentication flow, and then respond based on the values obtained from the redirect callback
|
|
4152
|
-
* @internal
|
|
4153
|
-
*/
|
|
4154
|
-
class MsalOpenBrowser extends MsalNode {
|
|
4155
|
-
constructor(options) {
|
|
4156
|
-
var _a, _b, _c, _d;
|
|
4157
|
-
super(options);
|
|
4158
|
-
this.loginHint = options.loginHint;
|
|
4159
|
-
this.errorTemplate = (_a = options.browserCustomizationOptions) === null || _a === void 0 ? void 0 : _a.errorMessage;
|
|
4160
|
-
this.successTemplate = (_b = options.browserCustomizationOptions) === null || _b === void 0 ? void 0 : _b.successMessage;
|
|
4161
|
-
this.logger = credentialLogger("Node.js MSAL Open Browser");
|
|
4162
|
-
this.useDefaultBrokerAccount =
|
|
4163
|
-
((_c = options.brokerOptions) === null || _c === void 0 ? void 0 : _c.enabled) && ((_d = options.brokerOptions) === null || _d === void 0 ? void 0 : _d.useDefaultBrokerAccount);
|
|
4164
|
-
}
|
|
4165
|
-
async doGetToken(scopes, options = {}) {
|
|
4166
|
-
try {
|
|
4167
|
-
const interactiveRequest = {
|
|
4168
|
-
openBrowser: async (url) => {
|
|
4169
|
-
await interactiveBrowserMockable.open(url, { wait: true, newInstance: true });
|
|
4170
|
-
},
|
|
4171
|
-
scopes,
|
|
4172
|
-
authority: options === null || options === void 0 ? void 0 : options.authority,
|
|
4173
|
-
claims: options === null || options === void 0 ? void 0 : options.claims,
|
|
4174
|
-
correlationId: options === null || options === void 0 ? void 0 : options.correlationId,
|
|
4175
|
-
loginHint: this.loginHint,
|
|
4176
|
-
errorTemplate: this.errorTemplate,
|
|
4177
|
-
successTemplate: this.successTemplate,
|
|
4178
|
-
};
|
|
4179
|
-
if (hasNativeBroker() && this.enableBroker) {
|
|
4180
|
-
return this.doGetBrokeredToken(scopes, interactiveRequest, {
|
|
4181
|
-
enableCae: options.enableCae,
|
|
4182
|
-
useDefaultBrokerAccount: this.useDefaultBrokerAccount,
|
|
4183
|
-
});
|
|
4184
|
-
}
|
|
4185
|
-
// If the broker is not enabled, we will fall back to interactive authentication
|
|
4186
|
-
if (hasNativeBroker() && !this.enableBroker) {
|
|
4187
|
-
this.logger.verbose("Authentication will resume normally without the broker, since it's not enabled");
|
|
4188
|
-
}
|
|
4189
|
-
const result = await this.getApp("public", options === null || options === void 0 ? void 0 : options.enableCae).acquireTokenInteractive(interactiveRequest);
|
|
4190
|
-
return this.handleResult(scopes, result || undefined);
|
|
4191
|
-
}
|
|
4192
|
-
catch (err) {
|
|
4193
|
-
throw handleMsalError(scopes, err, options);
|
|
4194
|
-
}
|
|
4195
|
-
}
|
|
4196
|
-
/**
|
|
4197
|
-
* A helper function that supports brokered authentication through the MSAL's public application.
|
|
4198
|
-
*
|
|
4199
|
-
* When options.useDefaultBrokerAccount is true, the method will attempt to authenticate using the default broker account.
|
|
4200
|
-
* If the default broker account is not available, the method will fall back to interactive authentication.
|
|
4201
|
-
*/
|
|
4202
|
-
async doGetBrokeredToken(scopes, interactiveRequest, options) {
|
|
4203
|
-
var _a;
|
|
4204
|
-
this.logger.verbose("Authentication will resume through the broker");
|
|
4205
|
-
if (this.parentWindowHandle) {
|
|
4206
|
-
interactiveRequest.windowHandle = Buffer.from(this.parentWindowHandle);
|
|
4207
|
-
}
|
|
4208
|
-
else {
|
|
4209
|
-
// error should have been thrown from within the constructor of InteractiveBrowserCredential
|
|
4210
|
-
this.logger.warning("Parent window handle is not specified for the broker. This may cause unexpected behavior. Please provide the parentWindowHandle.");
|
|
4211
|
-
}
|
|
4212
|
-
if (this.enableMsaPassthrough) {
|
|
4213
|
-
((_a = interactiveRequest.tokenQueryParameters) !== null && _a !== void 0 ? _a : (interactiveRequest.tokenQueryParameters = {}))["msal_request_type"] =
|
|
4214
|
-
"consumer_passthrough";
|
|
4215
|
-
}
|
|
4216
|
-
if (options.useDefaultBrokerAccount) {
|
|
4217
|
-
interactiveRequest.prompt = "none";
|
|
4218
|
-
this.logger.verbose("Attempting broker authentication using the default broker account");
|
|
4219
|
-
}
|
|
4220
|
-
else {
|
|
4221
|
-
interactiveRequest.prompt = undefined;
|
|
4222
|
-
this.logger.verbose("Attempting broker authentication without the default broker account");
|
|
4223
|
-
}
|
|
4224
|
-
try {
|
|
4225
|
-
const result = await this.getApp("public", options === null || options === void 0 ? void 0 : options.enableCae).acquireTokenInteractive(interactiveRequest);
|
|
4226
|
-
if (result.fromNativeBroker) {
|
|
4227
|
-
this.logger.verbose(`This result is returned from native broker`);
|
|
4228
|
-
}
|
|
4229
|
-
return this.handleResult(scopes, result || undefined);
|
|
4230
|
-
}
|
|
4231
|
-
catch (e) {
|
|
4232
|
-
this.logger.verbose(`Failed to authenticate through the broker: ${e.message}`);
|
|
4233
|
-
// If we tried to use the default broker account and failed, fall back to interactive authentication
|
|
4234
|
-
if (options.useDefaultBrokerAccount) {
|
|
4235
|
-
return this.doGetBrokeredToken(scopes, interactiveRequest, {
|
|
4236
|
-
enableCae: options.enableCae,
|
|
4237
|
-
useDefaultBrokerAccount: false,
|
|
4238
|
-
});
|
|
4239
|
-
}
|
|
4240
|
-
else {
|
|
4241
|
-
// If we're not using the default broker account, throw the error
|
|
4242
|
-
throw handleMsalError(scopes, e);
|
|
4243
|
-
}
|
|
4244
|
-
}
|
|
4245
|
-
}
|
|
4246
|
-
}
|
|
4247
|
-
|
|
4248
3948
|
// Copyright (c) Microsoft Corporation.
|
|
4249
3949
|
// Licensed under the MIT license.
|
|
4250
3950
|
const logger$4 = credentialLogger("InteractiveBrowserCredential");
|
|
@@ -4266,31 +3966,27 @@ class InteractiveBrowserCredential {
|
|
|
4266
3966
|
* @param options - Options for configuring the client which makes the authentication requests.
|
|
4267
3967
|
*/
|
|
4268
3968
|
constructor(options) {
|
|
4269
|
-
var _a, _b, _c, _d;
|
|
4270
|
-
|
|
4271
|
-
? options.redirectUri()
|
|
4272
|
-
: options.redirectUri || "http://localhost";
|
|
4273
|
-
this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
|
|
3969
|
+
var _a, _b, _c, _d, _e;
|
|
3970
|
+
this.tenantId = resolveTenantId(logger$4, options.tenantId, options.clientId);
|
|
4274
3971
|
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
|
|
3972
|
+
const msalClientOptions = Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$4 });
|
|
4275
3973
|
const ibcNodeOptions = options;
|
|
3974
|
+
this.browserCustomizationOptions = ibcNodeOptions.browserCustomizationOptions;
|
|
3975
|
+
this.loginHint = ibcNodeOptions.loginHint;
|
|
4276
3976
|
if ((_a = ibcNodeOptions === null || ibcNodeOptions === void 0 ? void 0 : ibcNodeOptions.brokerOptions) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
4277
3977
|
if (!((_b = ibcNodeOptions === null || ibcNodeOptions === void 0 ? void 0 : ibcNodeOptions.brokerOptions) === null || _b === void 0 ? void 0 : _b.parentWindowHandle)) {
|
|
4278
3978
|
throw new Error("In order to do WAM authentication, `parentWindowHandle` under `brokerOptions` is a required parameter");
|
|
4279
3979
|
}
|
|
4280
3980
|
else {
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
} }));
|
|
3981
|
+
msalClientOptions.brokerOptions = {
|
|
3982
|
+
enabled: true,
|
|
3983
|
+
parentWindowHandle: ibcNodeOptions.brokerOptions.parentWindowHandle,
|
|
3984
|
+
legacyEnableMsaPassthrough: (_c = ibcNodeOptions.brokerOptions) === null || _c === void 0 ? void 0 : _c.legacyEnableMsaPassthrough,
|
|
3985
|
+
useDefaultBrokerAccount: (_d = ibcNodeOptions.brokerOptions) === null || _d === void 0 ? void 0 : _d.useDefaultBrokerAccount,
|
|
3986
|
+
};
|
|
4288
3987
|
}
|
|
4289
3988
|
}
|
|
4290
|
-
|
|
4291
|
-
this.msalFlow = new MsalOpenBrowser(Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$4,
|
|
4292
|
-
redirectUri, browserCustomizationOptions: ibcNodeOptions === null || ibcNodeOptions === void 0 ? void 0 : ibcNodeOptions.browserCustomizationOptions }));
|
|
4293
|
-
}
|
|
3989
|
+
this.msalClient = createMsalClient((_e = options.clientId) !== null && _e !== void 0 ? _e : DeveloperSignOnClientId, this.tenantId, msalClientOptions);
|
|
4294
3990
|
this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
|
|
4295
3991
|
}
|
|
4296
3992
|
/**
|
|
@@ -4309,7 +4005,7 @@ class InteractiveBrowserCredential {
|
|
|
4309
4005
|
return tracingClient.withSpan(`${this.constructor.name}.getToken`, options, async (newOptions) => {
|
|
4310
4006
|
newOptions.tenantId = processMultiTenantRequest(this.tenantId, newOptions, this.additionallyAllowedTenantIds, logger$4);
|
|
4311
4007
|
const arrayScopes = ensureScopes(scopes);
|
|
4312
|
-
return this.
|
|
4008
|
+
return this.msalClient.getTokenByInteractiveRequest(arrayScopes, Object.assign(Object.assign({}, newOptions), { disableAutomaticAuthentication: this.disableAutomaticAuthentication, browserCustomizationOptions: this.browserCustomizationOptions, loginHint: this.loginHint }));
|
|
4313
4009
|
});
|
|
4314
4010
|
}
|
|
4315
4011
|
/**
|
|
@@ -4328,8 +4024,8 @@ class InteractiveBrowserCredential {
|
|
|
4328
4024
|
async authenticate(scopes, options = {}) {
|
|
4329
4025
|
return tracingClient.withSpan(`${this.constructor.name}.authenticate`, options, async (newOptions) => {
|
|
4330
4026
|
const arrayScopes = ensureScopes(scopes);
|
|
4331
|
-
await this.
|
|
4332
|
-
return this.
|
|
4027
|
+
await this.msalClient.getTokenByInteractiveRequest(arrayScopes, Object.assign(Object.assign({}, newOptions), { disableAutomaticAuthentication: false, browserCustomizationOptions: this.browserCustomizationOptions, loginHint: this.loginHint }));
|
|
4028
|
+
return this.msalClient.getActiveAccount();
|
|
4333
4029
|
});
|
|
4334
4030
|
}
|
|
4335
4031
|
}
|
|
@@ -4571,102 +4267,6 @@ class AuthorizationCodeCredential {
|
|
|
4571
4267
|
}
|
|
4572
4268
|
}
|
|
4573
4269
|
|
|
4574
|
-
// Copyright (c) Microsoft Corporation.
|
|
4575
|
-
// Licensed under the MIT license.
|
|
4576
|
-
const readFileAsync = util.promisify(fs.readFile);
|
|
4577
|
-
/**
|
|
4578
|
-
* Tries to asynchronously load a certificate from the given path.
|
|
4579
|
-
*
|
|
4580
|
-
* @param configuration - Either the PEM value or the path to the certificate.
|
|
4581
|
-
* @param sendCertificateChain - Option to include x5c header for SubjectName and Issuer name authorization.
|
|
4582
|
-
* @returns - The certificate parts, or `undefined` if the certificate could not be loaded.
|
|
4583
|
-
* @internal
|
|
4584
|
-
*/
|
|
4585
|
-
async function parseCertificate(configuration, sendCertificateChain) {
|
|
4586
|
-
const certificateParts = {};
|
|
4587
|
-
const certificate = configuration
|
|
4588
|
-
.certificate;
|
|
4589
|
-
const certificatePath = configuration
|
|
4590
|
-
.certificatePath;
|
|
4591
|
-
certificateParts.certificateContents =
|
|
4592
|
-
certificate || (await readFileAsync(certificatePath, "utf8"));
|
|
4593
|
-
if (sendCertificateChain) {
|
|
4594
|
-
certificateParts.x5c = certificateParts.certificateContents;
|
|
4595
|
-
}
|
|
4596
|
-
const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
|
|
4597
|
-
const publicKeys = [];
|
|
4598
|
-
// Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
|
|
4599
|
-
let match;
|
|
4600
|
-
do {
|
|
4601
|
-
match = certificatePattern.exec(certificateParts.certificateContents);
|
|
4602
|
-
if (match) {
|
|
4603
|
-
publicKeys.push(match[3]);
|
|
4604
|
-
}
|
|
4605
|
-
} while (match);
|
|
4606
|
-
if (publicKeys.length === 0) {
|
|
4607
|
-
throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
|
|
4608
|
-
}
|
|
4609
|
-
certificateParts.thumbprint = crypto.createHash("sha1")
|
|
4610
|
-
.update(Buffer.from(publicKeys[0], "base64"))
|
|
4611
|
-
.digest("hex")
|
|
4612
|
-
.toUpperCase();
|
|
4613
|
-
return certificateParts;
|
|
4614
|
-
}
|
|
4615
|
-
|
|
4616
|
-
// Copyright (c) Microsoft Corporation.
|
|
4617
|
-
// Licensed under the MIT license.
|
|
4618
|
-
/**
|
|
4619
|
-
* MSAL on behalf of flow. Calls to MSAL's confidential application's `acquireTokenOnBehalfOf` during `doGetToken`.
|
|
4620
|
-
* @internal
|
|
4621
|
-
*/
|
|
4622
|
-
class MsalOnBehalfOf extends MsalNode {
|
|
4623
|
-
constructor(options) {
|
|
4624
|
-
super(options);
|
|
4625
|
-
this.logger.info("Initialized MSAL's On-Behalf-Of flow");
|
|
4626
|
-
this.requiresConfidential = true;
|
|
4627
|
-
this.userAssertionToken = options.userAssertionToken;
|
|
4628
|
-
this.certificatePath = options.certificatePath;
|
|
4629
|
-
this.sendCertificateChain = options.sendCertificateChain;
|
|
4630
|
-
this.clientSecret = options.clientSecret;
|
|
4631
|
-
}
|
|
4632
|
-
// Changing the MSAL configuration asynchronously
|
|
4633
|
-
async init(options) {
|
|
4634
|
-
if (this.certificatePath) {
|
|
4635
|
-
try {
|
|
4636
|
-
const parts = await parseCertificate({ certificatePath: this.certificatePath }, this.sendCertificateChain);
|
|
4637
|
-
this.msalConfig.auth.clientCertificate = {
|
|
4638
|
-
thumbprint: parts.thumbprint,
|
|
4639
|
-
privateKey: parts.certificateContents,
|
|
4640
|
-
x5c: parts.x5c,
|
|
4641
|
-
};
|
|
4642
|
-
}
|
|
4643
|
-
catch (error) {
|
|
4644
|
-
this.logger.info(formatError("", error));
|
|
4645
|
-
throw error;
|
|
4646
|
-
}
|
|
4647
|
-
}
|
|
4648
|
-
else {
|
|
4649
|
-
this.msalConfig.auth.clientSecret = this.clientSecret;
|
|
4650
|
-
}
|
|
4651
|
-
return super.init(options);
|
|
4652
|
-
}
|
|
4653
|
-
async doGetToken(scopes, options = {}) {
|
|
4654
|
-
try {
|
|
4655
|
-
const result = await this.getApp("confidential", options.enableCae).acquireTokenOnBehalfOf({
|
|
4656
|
-
scopes,
|
|
4657
|
-
correlationId: options.correlationId,
|
|
4658
|
-
authority: options.authority,
|
|
4659
|
-
claims: options.claims,
|
|
4660
|
-
oboAssertion: this.userAssertionToken,
|
|
4661
|
-
});
|
|
4662
|
-
return this.handleResult(scopes, result || undefined);
|
|
4663
|
-
}
|
|
4664
|
-
catch (err) {
|
|
4665
|
-
throw handleMsalError(scopes, err, options);
|
|
4666
|
-
}
|
|
4667
|
-
}
|
|
4668
|
-
}
|
|
4669
|
-
|
|
4670
4270
|
// Copyright (c) Microsoft Corporation.
|
|
4671
4271
|
// Licensed under the MIT license.
|
|
4672
4272
|
const credentialName = "OnBehalfOfCredential";
|
|
@@ -4676,16 +4276,19 @@ const logger = credentialLogger(credentialName);
|
|
|
4676
4276
|
*/
|
|
4677
4277
|
class OnBehalfOfCredential {
|
|
4678
4278
|
constructor(options) {
|
|
4679
|
-
this.options = options;
|
|
4680
4279
|
const { clientSecret } = options;
|
|
4681
|
-
const { certificatePath } = options;
|
|
4280
|
+
const { certificatePath, sendCertificateChain } = options;
|
|
4682
4281
|
const { tenantId, clientId, userAssertionToken, additionallyAllowedTenants: additionallyAllowedTenantIds, } = options;
|
|
4683
4282
|
if (!tenantId || !clientId || !(clientSecret || certificatePath) || !userAssertionToken) {
|
|
4684
4283
|
throw new Error(`${credentialName}: tenantId, clientId, clientSecret (or certificatePath) and userAssertionToken are required parameters.`);
|
|
4685
4284
|
}
|
|
4285
|
+
this.certificatePath = certificatePath;
|
|
4286
|
+
this.clientSecret = clientSecret;
|
|
4287
|
+
this.userAssertionToken = userAssertionToken;
|
|
4288
|
+
this.sendCertificateChain = sendCertificateChain;
|
|
4686
4289
|
this.tenantId = tenantId;
|
|
4687
4290
|
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(additionallyAllowedTenantIds);
|
|
4688
|
-
this.
|
|
4291
|
+
this.msalClient = createMsalClient(clientId, this.tenantId, Object.assign(Object.assign({}, options), { logger, tokenCredentialOptions: options }));
|
|
4689
4292
|
}
|
|
4690
4293
|
/**
|
|
4691
4294
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
|
@@ -4698,9 +4301,60 @@ class OnBehalfOfCredential {
|
|
|
4698
4301
|
return tracingClient.withSpan(`${credentialName}.getToken`, options, async (newOptions) => {
|
|
4699
4302
|
newOptions.tenantId = processMultiTenantRequest(this.tenantId, newOptions, this.additionallyAllowedTenantIds, logger);
|
|
4700
4303
|
const arrayScopes = ensureScopes(scopes);
|
|
4701
|
-
|
|
4304
|
+
if (this.certificatePath) {
|
|
4305
|
+
const clientCertificate = await this.buildClientCertificate(this.certificatePath);
|
|
4306
|
+
return this.msalClient.getTokenOnBehalfOf(arrayScopes, this.userAssertionToken, clientCertificate, newOptions);
|
|
4307
|
+
}
|
|
4308
|
+
else if (this.clientSecret) {
|
|
4309
|
+
return this.msalClient.getTokenOnBehalfOf(arrayScopes, this.userAssertionToken, this.clientSecret, options);
|
|
4310
|
+
}
|
|
4311
|
+
else {
|
|
4312
|
+
// this is a bug, as the constructor should have thrown an error if neither clientSecret nor certificatePath were provided
|
|
4313
|
+
throw new Error("Expected either clientSecret or certificatePath to be defined.");
|
|
4314
|
+
}
|
|
4702
4315
|
});
|
|
4703
4316
|
}
|
|
4317
|
+
async buildClientCertificate(certificatePath) {
|
|
4318
|
+
try {
|
|
4319
|
+
const parts = await this.parseCertificate({ certificatePath }, this.sendCertificateChain);
|
|
4320
|
+
return {
|
|
4321
|
+
thumbprint: parts.thumbprint,
|
|
4322
|
+
privateKey: parts.certificateContents,
|
|
4323
|
+
x5c: parts.x5c,
|
|
4324
|
+
};
|
|
4325
|
+
}
|
|
4326
|
+
catch (error) {
|
|
4327
|
+
logger.info(formatError("", error));
|
|
4328
|
+
throw error;
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
async parseCertificate(configuration, sendCertificateChain) {
|
|
4332
|
+
const certificatePath = configuration.certificatePath;
|
|
4333
|
+
const certificateContents = await promises$1.readFile(certificatePath, "utf8");
|
|
4334
|
+
const x5c = sendCertificateChain ? certificateContents : undefined;
|
|
4335
|
+
const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
|
|
4336
|
+
const publicKeys = [];
|
|
4337
|
+
// Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
|
|
4338
|
+
let match;
|
|
4339
|
+
do {
|
|
4340
|
+
match = certificatePattern.exec(certificateContents);
|
|
4341
|
+
if (match) {
|
|
4342
|
+
publicKeys.push(match[3]);
|
|
4343
|
+
}
|
|
4344
|
+
} while (match);
|
|
4345
|
+
if (publicKeys.length === 0) {
|
|
4346
|
+
throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
|
|
4347
|
+
}
|
|
4348
|
+
const thumbprint = node_crypto.createHash("sha1")
|
|
4349
|
+
.update(Buffer.from(publicKeys[0], "base64"))
|
|
4350
|
+
.digest("hex")
|
|
4351
|
+
.toUpperCase();
|
|
4352
|
+
return {
|
|
4353
|
+
certificateContents,
|
|
4354
|
+
thumbprint,
|
|
4355
|
+
x5c,
|
|
4356
|
+
};
|
|
4357
|
+
}
|
|
4704
4358
|
}
|
|
4705
4359
|
|
|
4706
4360
|
// Copyright (c) Microsoft Corporation.
|