UNPKG

@azure/identity

Version:

Provides credential implementations for Azure SDK libraries that can authenticate with Microsoft Entra ID

272 lines (271 loc) • 10.8 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var managedIdentityCredential_exports = {}; __export(managedIdentityCredential_exports, { ManagedIdentityCredential: () => ManagedIdentityCredential }); module.exports = __toCommonJS(managedIdentityCredential_exports); var import_logger = require("@azure/logger"); var import_msal_node = require("@azure/msal-node"); var import_identityClient = require("../../client/identityClient.js"); var import_errors = require("../../errors.js"); var import_utils = require("../../msal/utils.js"); var import_imdsRetryPolicy = require("./imdsRetryPolicy.js"); var import_logging = require("../../util/logging.js"); var import_tracing = require("../../util/tracing.js"); var import_imdsMsi = require("./imdsMsi.js"); var import_tokenExchangeMsi = require("./tokenExchangeMsi.js"); var import_utils2 = require("./utils.js"); const logger = (0, import_logging.credentialLogger)("ManagedIdentityCredential"); class ManagedIdentityCredential { managedIdentityApp; identityClient; clientId; resourceId; objectId; msiRetryConfig = { maxRetries: 5, startDelayInMs: 800, intervalIncrement: 2 }; isAvailableIdentityClient; sendProbeRequest; /** * @internal * @hidden */ constructor(clientIdOrOptions, options) { let _options; if (typeof clientIdOrOptions === "string") { this.clientId = clientIdOrOptions; _options = options ?? {}; } else { this.clientId = clientIdOrOptions?.clientId; _options = clientIdOrOptions ?? {}; } this.resourceId = _options?.resourceId; this.objectId = _options?.objectId; this.sendProbeRequest = _options?.sendProbeRequest ?? false; const providedIds = [ { key: "clientId", value: this.clientId }, { key: "resourceId", value: this.resourceId }, { key: "objectId", value: this.objectId } ].filter((id) => id.value); if (providedIds.length > 1) { throw new Error( `ManagedIdentityCredential: only one of 'clientId', 'resourceId', or 'objectId' can be provided. Received values: ${JSON.stringify( { clientId: this.clientId, resourceId: this.resourceId, objectId: this.objectId } )}` ); } _options.allowInsecureConnection = true; if (_options.retryOptions?.maxRetries !== void 0) { this.msiRetryConfig.maxRetries = _options.retryOptions.maxRetries; } this.identityClient = new import_identityClient.IdentityClient({ ..._options, additionalPolicies: [{ policy: (0, import_imdsRetryPolicy.imdsRetryPolicy)(this.msiRetryConfig), position: "perCall" }] }); this.managedIdentityApp = new import_msal_node.ManagedIdentityApplication({ managedIdentityIdParams: { userAssignedClientId: this.clientId, userAssignedResourceId: this.resourceId, userAssignedObjectId: this.objectId }, system: { disableInternalRetries: true, networkClient: this.identityClient, loggerOptions: { logLevel: (0, import_utils.getMSALLogLevel)((0, import_logger.getLogLevel)()), piiLoggingEnabled: _options.loggingOptions?.enableUnsafeSupportLogging, loggerCallback: (0, import_utils.defaultLoggerCallback)(logger) } } }); this.isAvailableIdentityClient = new import_identityClient.IdentityClient({ ..._options, retryOptions: { maxRetries: 0 } }); const managedIdentitySource = this.managedIdentityApp.getManagedIdentitySource(); if (managedIdentitySource === "CloudShell") { if (this.clientId || this.resourceId || this.objectId) { logger.warning( `CloudShell MSI detected with user-provided IDs - throwing. Received values: ${JSON.stringify( { clientId: this.clientId, resourceId: this.resourceId, objectId: this.objectId } )}.` ); throw new import_errors.CredentialUnavailableError( "ManagedIdentityCredential: Specifying a user-assigned managed identity is not supported for CloudShell at runtime. When using Managed Identity in CloudShell, omit the clientId, resourceId, and objectId parameters." ); } } if (managedIdentitySource === "ServiceFabric") { if (this.clientId || this.resourceId || this.objectId) { logger.warning( `Service Fabric detected with user-provided IDs - throwing. Received values: ${JSON.stringify( { clientId: this.clientId, resourceId: this.resourceId, objectId: this.objectId } )}.` ); throw new import_errors.CredentialUnavailableError( `ManagedIdentityCredential: ${import_utils2.serviceFabricErrorMessage}` ); } } logger.info(`Using ${managedIdentitySource} managed identity.`); if (providedIds.length === 1) { const { key, value } = providedIds[0]; logger.info(`${managedIdentitySource} with ${key}: ${value}`); } } /** * Authenticates with Microsoft Entra ID and returns an access token if successful. * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure. * If an unexpected error occurs, an {@link AuthenticationError} will be thrown with the details of the failure. * * @param scopes - The list of scopes for which the token will have access. * @param options - The options used to configure any requests this * TokenCredential implementation might make. */ async getToken(scopes, options = {}) { logger.getToken.info("Using the MSAL provider for Managed Identity."); const resource = (0, import_utils2.mapScopesToResource)(scopes); if (!resource) { throw new import_errors.CredentialUnavailableError( `ManagedIdentityCredential: Multiple scopes are not supported. Scopes: ${JSON.stringify( scopes )}` ); } return import_tracing.tracingClient.withSpan("ManagedIdentityCredential.getToken", options, async () => { try { const isTokenExchangeMsi = await import_tokenExchangeMsi.tokenExchangeMsi.isAvailable(this.clientId); const identitySource = this.managedIdentityApp.getManagedIdentitySource(); const isImdsMsi = identitySource === "DefaultToImds" || identitySource === "Imds"; logger.getToken.info(`MSAL Identity source: ${identitySource}`); if (isTokenExchangeMsi) { logger.getToken.info("Using the token exchange managed identity."); const result = await import_tokenExchangeMsi.tokenExchangeMsi.getToken({ scopes, clientId: this.clientId, identityClient: this.identityClient, retryConfig: this.msiRetryConfig, resourceId: this.resourceId }); if (result === null) { throw new import_errors.CredentialUnavailableError( "Attempted to use the token exchange managed identity, but received a null response." ); } return result; } else if (isImdsMsi && this.sendProbeRequest) { logger.getToken.info("Using the IMDS endpoint to probe for availability."); const isAvailable = await import_imdsMsi.imdsMsi.isAvailable({ scopes, clientId: this.clientId, getTokenOptions: options, identityClient: this.isAvailableIdentityClient, resourceId: this.resourceId }); if (!isAvailable) { throw new import_errors.CredentialUnavailableError( `Attempted to use the IMDS endpoint, but it is not available.` ); } } logger.getToken.info("Calling into MSAL for managed identity token."); const token = await this.managedIdentityApp.acquireToken({ resource }); this.ensureValidMsalToken(scopes, token, options); logger.getToken.info((0, import_logging.formatSuccess)(scopes)); return { expiresOnTimestamp: token.expiresOn.getTime(), token: token.accessToken, refreshAfterTimestamp: token.refreshOn?.getTime(), tokenType: "Bearer" }; } catch (err) { logger.getToken.error((0, import_logging.formatError)(scopes, err)); if (err.name === "AuthenticationRequiredError") { throw err; } if (isNetworkError(err)) { throw new import_errors.CredentialUnavailableError( `ManagedIdentityCredential: Network unreachable. Message: ${err.message}`, { cause: err } ); } throw new import_errors.CredentialUnavailableError( `ManagedIdentityCredential: Authentication failed. Message ${err.message}`, { cause: err } ); } }); } /** * Ensures the validity of the MSAL token */ ensureValidMsalToken(scopes, msalToken, getTokenOptions) { const createError = (message) => { logger.getToken.info(message); return new import_errors.AuthenticationRequiredError({ scopes: Array.isArray(scopes) ? scopes : [scopes], getTokenOptions, message }); }; if (!msalToken) { throw createError("No response."); } if (!msalToken.expiresOn) { throw createError(`Response had no "expiresOn" property.`); } if (!msalToken.accessToken) { throw createError(`Response had no "accessToken" property.`); } } } function isNetworkError(err) { if (err.errorCode === "network_error") { return true; } if (err.code === "ENETUNREACH" || err.code === "EHOSTUNREACH") { return true; } if (err.statusCode === 403 || err.code === 403) { if (err.message.includes("unreachable")) { return true; } } return false; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ManagedIdentityCredential }); //# sourceMappingURL=index.js.map