@azure/identity 4.3.1-alpha.20240618.4 → 4.3.1-alpha.20240619.4

Sign up to get free protection for your applications and to get access to all the features.
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 open = require('open');
21
- var util = require('util');
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);
@@ -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 - AppServiceMSI 2017";
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$6}: Missing environment variable: MSI_ENDPOINT`);
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$6}: Missing environment variable: MSI_SECRET`);
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$o.info(`${msiName$6}: Unavailable. Multiple scopes are not supported.`);
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$o.info(`${msiName$6}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
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$o.warning(`${msiName$6}: managed Identity by resource Id is not supported. Argument resourceId might be ignored by the service.`);
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$o.info(`${msiName$6}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
1070
- const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$5(scopes, clientId)), {
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$5 = "ManagedIdentityCredential - AppServiceMSI 2019";
1081
- const logger$n = credentialLogger(msiName$5);
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$4(scopes, clientId, resourceId) {
1155
+ function prepareRequestOptions$3(scopes, clientId, resourceId) {
1086
1156
  const resource = mapScopesToResource(scopes);
1087
1157
  if (!resource) {
1088
- throw new Error(`${msiName$5}: Multiple scopes are not supported.`);
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$5}: Missing environment variable: IDENTITY_ENDPOINT`);
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$5}: Missing environment variable: IDENTITY_HEADER`);
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$n.info(`${msiName$5}: Unavailable. Multiple scopes are not supported.`);
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$n.info(`${msiName$5}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT and IDENTITY_HEADER.`);
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$n.info(`${msiName$5}: Using the endpoint and the secret coming form the environment variables: IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT} and IDENTITY_HEADER=[REDACTED].`);
1138
- const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$4(scopes, clientId, resourceId)), {
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$4 = "ManagedIdentityCredential - Azure Arc MSI";
1149
- const logger$m = credentialLogger(msiName$4);
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$3(scopes, clientId, resourceId) {
1223
+ function prepareRequestOptions$2(scopes, clientId, resourceId) {
1154
1224
  const resource = mapScopesToResource(scopes);
1155
1225
  if (!resource) {
1156
- throw new Error(`${msiName$4}: Multiple scopes are not supported.`);
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$4}: Missing environment variable: IDENTITY_ENDPOINT`);
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$4}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
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$4}: PROGRAMDATA environment variable has no value.`);
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$4}: Unsupported platform ${process.platform}.`);
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$4}: Failed to find the token file.`);
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$4}: unexpected file path from HIMDS service: ${filePath}.`);
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$4}: unexpected file path from HIMDS service: ${filePath}.`);
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$4}: The file at ${filePath} is larger than expected at ${stats.size} bytes.`);
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$m.info(`${msiName$4}: Unavailable. Multiple scopes are not supported.`);
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$m.info(`${msiName$4}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
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$m.warning(`${msiName$4}: user-assigned identities not supported. The argument clientId might be ignored by the service.`);
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$m.warning(`${msiName$4}: user defined managed Identity by resource Id is not supported. Argument resourceId will be ignored.`);
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$m.info(`${msiName$4}: Authenticating.`);
1267
- const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$3(scopes, clientId, resourceId)), { allowInsecureConnection: true });
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(`${ManagedIdentityCredential.name} - Client Id and Resource Id can't be provided at the same time.`);
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(`${ManagedIdentityCredential.name} - No MSI credential available`);
2599
+ throw new CredentialUnavailableError(`ManagedIdentityCredential - No MSI credential available`);
2513
2600
  }
2514
2601
  async authenticateManagedIdentity(scopes, getTokenOptions) {
2515
- const { span, updatedOptions } = tracingClient.startSpan(`${ManagedIdentityCredential.name}.authenticateManagedIdentity`, getTokenOptions);
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(`${ManagedIdentityCredential.name}.getToken`, options);
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(`${ManagedIdentityCredential.name}: Unavailable. Network unreachable. Message: ${err.message}`);
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(`${ManagedIdentityCredential.name}: Unavailable. No managed identity endpoint found. Message: ${err.message}`);
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(`${ManagedIdentityCredential.name}: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
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(`${ManagedIdentityCredential.name}: Unavailable. Network unreachable. Message: ${err.message}`);
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(`${ManagedIdentityCredential.name}: Authentication failed. Message ${err.message}`);
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: `${ManagedIdentityCredential.name} authentication failed.`,
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
- * Ensures the scopes value is an array.
2725
- * @internal
2726
- */
2727
- function ensureScopes(scopes) {
2728
- return Array.isArray(scopes) ? scopes : [scopes];
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
- function ensureValidScopeForDevTimeCreds(scope, logger) {
2735
- if (!scope.match(/^[0-9a-zA-Z-_.:/]+$/)) {
2736
- const error = new Error("Invalid scope was specified by the user or calling client");
2737
- logger.getToken.info(formatError(scope, error));
2738
- throw error;
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
- const redirectUri = typeof options.redirectUri === "function"
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
- this.msalFlow = new MsalOpenBrowser(Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$4,
4282
- redirectUri, browserCustomizationOptions: ibcNodeOptions === null || ibcNodeOptions === void 0 ? void 0 : ibcNodeOptions.browserCustomizationOptions, brokerOptions: {
4283
- enabled: true,
4284
- parentWindowHandle: ibcNodeOptions.brokerOptions.parentWindowHandle,
4285
- legacyEnableMsaPassthrough: (_c = ibcNodeOptions.brokerOptions) === null || _c === void 0 ? void 0 : _c.legacyEnableMsaPassthrough,
4286
- useDefaultBrokerAccount: (_d = ibcNodeOptions.brokerOptions) === null || _d === void 0 ? void 0 : _d.useDefaultBrokerAccount,
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
- else {
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.msalFlow.getToken(arrayScopes, Object.assign(Object.assign({}, newOptions), { disableAutomaticAuthentication: this.disableAutomaticAuthentication }));
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.msalFlow.getToken(arrayScopes, newOptions);
4332
- return this.msalFlow.getActiveAccount();
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.msalFlow = new MsalOnBehalfOf(Object.assign(Object.assign({}, this.options), { logger, tokenCredentialOptions: this.options }));
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
- return this.msalFlow.getToken(arrayScopes, newOptions);
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.