@azure/identity 4.3.0-alpha.20240520.1 → 4.3.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ var fs = require('fs');
12
12
  var os = require('os');
13
13
  var path = require('path');
14
14
  var msalCommon = require('@azure/msal-node');
15
+ var fs$1 = require('node:fs');
15
16
  var https = require('https');
16
17
  var promises = require('fs/promises');
17
18
  var child_process = require('child_process');
@@ -44,7 +45,7 @@ var child_process__namespace = /*#__PURE__*/_interopNamespaceDefault(child_proce
44
45
  /**
45
46
  * Current version of the `@azure/identity` package.
46
47
  */
47
- const SDK_VERSION = `4.3.0-beta.1`;
48
+ const SDK_VERSION = `4.3.0-beta.2`;
48
49
  /**
49
50
  * The default client ID for authentication
50
51
  * @internal
@@ -1179,18 +1180,6 @@ function prepareRequestOptions$3(scopes, clientId, resourceId) {
1179
1180
  }),
1180
1181
  });
1181
1182
  }
1182
- /**
1183
- * Retrieves the file contents at the given path using promises.
1184
- * Useful since `fs`'s readFileSync locks the thread, and to avoid extra dependencies.
1185
- */
1186
- function readFileAsync$1(path, options) {
1187
- return new Promise((resolve, reject) => fs.readFile(path, options, (err, data) => {
1188
- if (err) {
1189
- reject(err);
1190
- }
1191
- resolve(data);
1192
- }));
1193
- }
1194
1183
  /**
1195
1184
  * Does a request to the authentication provider that results in a file path.
1196
1185
  */
@@ -1211,6 +1200,43 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
1211
1200
  throw Error(`Invalid www-authenticate header format: ${authHeader}`);
1212
1201
  }
1213
1202
  }
1203
+ function platformToFilePath() {
1204
+ switch (process.platform) {
1205
+ case "win32":
1206
+ if (!process.env.PROGRAMDATA) {
1207
+ throw new Error(`${msiName$4}: PROGRAMDATA environment variable has no value.`);
1208
+ }
1209
+ return `${process.env.PROGRAMDATA}\\AzureConnectedMachineAgent\\Tokens`;
1210
+ case "linux":
1211
+ return "/var/opt/azcmagent/tokens";
1212
+ default:
1213
+ throw new Error(`${msiName$4}: Unsupported platform ${process.platform}.`);
1214
+ }
1215
+ }
1216
+ /**
1217
+ * Validates that a given Azure Arc MSI file path is valid for use.
1218
+ *
1219
+ * A valid file will:
1220
+ * 1. Be in the expected path for the current platform.
1221
+ * 2. Have a `.key` extension.
1222
+ * 3. Be at most 4096 bytes in size.
1223
+ */
1224
+ function validateKeyFile(filePath) {
1225
+ if (!filePath) {
1226
+ throw new Error(`${msiName$4}: Failed to find the token file.`);
1227
+ }
1228
+ if (!filePath.endsWith(".key")) {
1229
+ throw new Error(`${msiName$4}: unexpected file path from HIMDS service: ${filePath}.`);
1230
+ }
1231
+ const expectedPath = platformToFilePath();
1232
+ if (!filePath.startsWith(expectedPath)) {
1233
+ throw new Error(`${msiName$4}: unexpected file path from HIMDS service: ${filePath}.`);
1234
+ }
1235
+ const stats = fs$1.statSync(filePath);
1236
+ if (stats.size > 4096) {
1237
+ throw new Error(`${msiName$4}: The file at ${filePath} is larger than expected at ${stats.size} bytes.`);
1238
+ }
1239
+ }
1214
1240
  /**
1215
1241
  * Defines how to determine whether the Azure Arc MSI is available, and also how to retrieve a token from the Azure Arc MSI.
1216
1242
  */
@@ -1240,10 +1266,8 @@ const arcMsi = {
1240
1266
  logger$m.info(`${msiName$4}: Authenticating.`);
1241
1267
  const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$3(scopes, clientId, resourceId)), { allowInsecureConnection: true });
1242
1268
  const filePath = await filePathRequest(identityClient, requestOptions);
1243
- if (!filePath) {
1244
- throw new Error(`${msiName$4}: Failed to find the token file.`);
1245
- }
1246
- const key = await readFileAsync$1(filePath, { encoding: "utf-8" });
1269
+ validateKeyFile(filePath);
1270
+ const key = await fs$1.promises.readFile(filePath, { encoding: "utf-8" });
1247
1271
  (_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
1248
1272
  const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({}, requestOptions), {
1249
1273
  // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
@@ -2185,6 +2209,28 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
2185
2209
  }
2186
2210
  return msalToPublic(clientId, state.cachedAccount);
2187
2211
  }
2212
+ async function getTokenByAuthorizationCode(scopes, redirectUri, authorizationCode, clientSecret, options = {}) {
2213
+ msalLogger.getToken.info(`Attempting to acquire token using authorization code`);
2214
+ let msalApp;
2215
+ if (clientSecret) {
2216
+ // If a client secret is provided, we need to use a confidential client application
2217
+ // See https://learn.microsoft.com/entra/identity-platform/v2-oauth2-auth-code-flow#request-an-access-token-with-a-client_secret
2218
+ state.msalConfig.auth.clientSecret = clientSecret;
2219
+ msalApp = await getConfidentialApp(options);
2220
+ }
2221
+ else {
2222
+ msalApp = await getPublicApp(options);
2223
+ }
2224
+ return withSilentAuthentication(msalApp, scopes, options, () => {
2225
+ return msalApp.acquireTokenByCode({
2226
+ scopes,
2227
+ redirectUri,
2228
+ code: authorizationCode,
2229
+ authority: state.msalConfig.auth.authority,
2230
+ claims: options === null || options === void 0 ? void 0 : options.claims,
2231
+ });
2232
+ });
2233
+ }
2188
2234
  return {
2189
2235
  getActiveAccount,
2190
2236
  getTokenByClientSecret,
@@ -2192,6 +2238,7 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
2192
2238
  getTokenByClientCertificate,
2193
2239
  getTokenByDeviceCode,
2194
2240
  getTokenByUsernamePassword,
2241
+ getTokenByAuthorizationCode,
2195
2242
  };
2196
2243
  }
2197
2244
 
@@ -4326,7 +4373,7 @@ class DeviceCodeCredential {
4326
4373
  const clientId = (_a = options === null || options === void 0 ? void 0 : options.clientId) !== null && _a !== void 0 ? _a : DeveloperSignOnClientId;
4327
4374
  const tenantId = resolveTenantId(logger$3, options === null || options === void 0 ? void 0 : options.tenantId, clientId);
4328
4375
  this.userPromptCallback = (_b = options === null || options === void 0 ? void 0 : options.userPromptCallback) !== null && _b !== void 0 ? _b : defaultDeviceCodePromptCallback;
4329
- this.msalClient = createMsalClient(clientId, tenantId, Object.assign(Object.assign({}, options), { tokenCredentialOptions: options || {} }));
4376
+ this.msalClient = createMsalClient(clientId, tenantId, Object.assign(Object.assign({}, options), { logger: logger$3, tokenCredentialOptions: options || {} }));
4330
4377
  this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
4331
4378
  }
4332
4379
  /**
@@ -4492,50 +4539,6 @@ class AzurePipelinesCredential {
4492
4539
  }
4493
4540
  }
4494
4541
 
4495
- // Copyright (c) Microsoft Corporation.
4496
- // Licensed under the MIT license.
4497
- /**
4498
- * 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`
4499
- * to trigger the authentication flow, and then respond based on the values obtained from the redirect callback
4500
- * @internal
4501
- */
4502
- class MsalAuthorizationCode extends MsalNode {
4503
- constructor(options) {
4504
- super(options);
4505
- this.logger = credentialLogger("Node.js MSAL Authorization Code");
4506
- this.redirectUri = options.redirectUri;
4507
- this.authorizationCode = options.authorizationCode;
4508
- if (options.clientSecret) {
4509
- this.msalConfig.auth.clientSecret = options.clientSecret;
4510
- }
4511
- }
4512
- async getAuthCodeUrl(options) {
4513
- await this.init();
4514
- return this.getApp("confidentialFirst", options.enableCae).getAuthCodeUrl({
4515
- scopes: options.scopes,
4516
- redirectUri: options.redirectUri,
4517
- });
4518
- }
4519
- async doGetToken(scopes, options) {
4520
- try {
4521
- const result = await this.getApp("confidentialFirst", options === null || options === void 0 ? void 0 : options.enableCae).acquireTokenByCode({
4522
- scopes,
4523
- redirectUri: this.redirectUri,
4524
- code: this.authorizationCode,
4525
- correlationId: options === null || options === void 0 ? void 0 : options.correlationId,
4526
- authority: options === null || options === void 0 ? void 0 : options.authority,
4527
- claims: options === null || options === void 0 ? void 0 : options.claims,
4528
- });
4529
- // The Client Credential flow does not return an account,
4530
- // so each time getToken gets called, we will have to acquire a new token through the service.
4531
- return this.handleResult(scopes, result || undefined);
4532
- }
4533
- catch (err) {
4534
- throw handleMsalError(scopes, err, options);
4535
- }
4536
- }
4537
- }
4538
-
4539
4542
  // Copyright (c) Microsoft Corporation.
4540
4543
  // Licensed under the MIT license.
4541
4544
  const logger$1 = credentialLogger("AuthorizationCodeCredential");
@@ -4553,7 +4556,7 @@ class AuthorizationCodeCredential {
4553
4556
  */
4554
4557
  constructor(tenantId, clientId, clientSecretOrAuthorizationCode, authorizationCodeOrRedirectUri, redirectUriOrOptions, options) {
4555
4558
  checkTenantId(logger$1, tenantId);
4556
- let clientSecret = clientSecretOrAuthorizationCode;
4559
+ this.clientSecret = clientSecretOrAuthorizationCode;
4557
4560
  if (typeof redirectUriOrOptions === "string") {
4558
4561
  // the clientId+clientSecret constructor
4559
4562
  this.authorizationCode = authorizationCodeOrRedirectUri;
@@ -4564,15 +4567,13 @@ class AuthorizationCodeCredential {
4564
4567
  // clientId only
4565
4568
  this.authorizationCode = clientSecretOrAuthorizationCode;
4566
4569
  this.redirectUri = authorizationCodeOrRedirectUri;
4567
- clientSecret = undefined;
4570
+ this.clientSecret = undefined;
4568
4571
  options = redirectUriOrOptions;
4569
4572
  }
4570
4573
  // TODO: Validate tenant if provided
4571
4574
  this.tenantId = tenantId;
4572
4575
  this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
4573
- this.msalFlow = new MsalAuthorizationCode(Object.assign(Object.assign({}, options), { clientSecret,
4574
- clientId,
4575
- tenantId, tokenCredentialOptions: options || {}, logger: logger$1, redirectUri: this.redirectUri, authorizationCode: this.authorizationCode }));
4576
+ this.msalClient = createMsalClient(clientId, tenantId, Object.assign(Object.assign({}, options), { logger: logger$1, tokenCredentialOptions: options !== null && options !== void 0 ? options : {} }));
4576
4577
  }
4577
4578
  /**
4578
4579
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -4587,7 +4588,7 @@ class AuthorizationCodeCredential {
4587
4588
  const tenantId = processMultiTenantRequest(this.tenantId, newOptions, this.additionallyAllowedTenantIds);
4588
4589
  newOptions.tenantId = tenantId;
4589
4590
  const arrayScopes = ensureScopes(scopes);
4590
- return this.msalFlow.getToken(arrayScopes, Object.assign(Object.assign({}, newOptions), { disableAutomaticAuthentication: this.disableAutomaticAuthentication }));
4591
+ return this.msalClient.getTokenByAuthorizationCode(arrayScopes, this.redirectUri, this.authorizationCode, this.clientSecret, Object.assign(Object.assign({}, newOptions), { disableAutomaticAuthentication: this.disableAutomaticAuthentication }));
4591
4592
  });
4592
4593
  }
4593
4594
  }