UNPKG

@azure/identity

Version:

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

239 lines (238 loc) • 9.69 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 azureCliCredential_exports = {}; __export(azureCliCredential_exports, { AzureCliCredential: () => AzureCliCredential, azureCliPublicErrorMessages: () => azureCliPublicErrorMessages, cliCredentialInternals: () => cliCredentialInternals }); module.exports = __toCommonJS(azureCliCredential_exports); var import_tenantIdUtils = require("../util/tenantIdUtils.js"); var import_logging = require("../util/logging.js"); var import_scopeUtils = require("../util/scopeUtils.js"); var import_errors = require("../errors.js"); var import_tracing = require("../util/tracing.js"); var import_subscriptionUtils = require("../util/subscriptionUtils.js"); var import_processUtils = require("../util/processUtils.js"); var import_core_process = require("@azure/core-process"); const logger = (0, import_logging.credentialLogger)("AzureCliCredential"); const azureCliPublicErrorMessages = { claim: "This credential doesn't support claims challenges. To authenticate with the required claims, please run the following command:", notInstalled: "Azure CLI could not be found. Please visit https://aka.ms/azure-cli for installation instructions and then, once installed, authenticate to your Azure account using 'az login'.", login: "Please run 'az login' from a command prompt to authenticate before using this credential.", unknown: "Unknown error while trying to retrieve the access token", unexpectedResponse: 'Unexpected response from Azure CLI when getting token. Expected "expiresOn" to be a RFC3339 date string. Got:' }; const cliCredentialInternals = { /** * @internal */ getSafeWorkingDir() { if (process.platform === "win32") { let systemRoot = process.env.SystemRoot || process.env["SYSTEMROOT"]; if (!systemRoot) { logger.getToken.warning( "The SystemRoot environment variable is not set. This may cause issues when using the Azure CLI credential." ); systemRoot = "C:\\Windows"; } return systemRoot; } else { return "/bin"; } }, /** * Gets the access token from Azure CLI * @param resource - The resource to use when getting the token * @internal */ async getAzureCliAccessToken(resource, tenantId, subscription, timeout) { let tenantSection = []; let subscriptionSection = []; if (tenantId) { tenantSection = ["--tenant", tenantId]; } if (subscription) { subscriptionSection = ["--subscription", subscription]; } const args = [ "account", "get-access-token", "--output", "json", "--resource", resource, ...tenantSection, ...subscriptionSection ]; return import_processUtils.processUtils.execFileWithResult("az", args, { allowWindowsBatchFiles: true, cwd: cliCredentialInternals.getSafeWorkingDir(), encoding: "utf8", timeout }); } }; class AzureCliCredential { tenantId; additionallyAllowedTenantIds; timeout; subscription; /** * Creates an instance of the {@link AzureCliCredential}. * * To use this credential, ensure that you have already logged * in via the 'az' tool using the command "az login" from the commandline. * * @param options - Options, to optionally allow multi-tenant requests. */ constructor(options) { if (options?.tenantId) { (0, import_tenantIdUtils.checkTenantId)(logger, options?.tenantId); this.tenantId = options?.tenantId; } if (options?.subscription) { (0, import_subscriptionUtils.checkSubscription)(logger, options?.subscription); this.subscription = options?.subscription; } this.additionallyAllowedTenantIds = (0, import_tenantIdUtils.resolveAdditionallyAllowedTenantIds)( options?.additionallyAllowedTenants ); this.timeout = options?.processTimeoutInMs; } /** * 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. * * @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 = {}) { const scope = typeof scopes === "string" ? scopes : scopes[0]; const claimsValue = options.claims; if (claimsValue && claimsValue.trim()) { const encodedClaims = btoa(claimsValue); let loginCmd = `az login --claims-challenge ${encodedClaims} --scope ${scope}`; const tenantIdFromOptions = options.tenantId; if (tenantIdFromOptions) { loginCmd += ` --tenant ${tenantIdFromOptions}`; } const error = new import_errors.CredentialUnavailableError( `${azureCliPublicErrorMessages.claim} ${loginCmd}` ); logger.getToken.info((0, import_logging.formatError)(scope, error)); throw error; } const tenantId = (0, import_tenantIdUtils.processMultiTenantRequest)( this.tenantId, options, this.additionallyAllowedTenantIds ); if (tenantId) { (0, import_tenantIdUtils.checkTenantId)(logger, tenantId); } if (this.subscription) { (0, import_subscriptionUtils.checkSubscription)(logger, this.subscription); } logger.getToken.info(`Using the scope ${scope}`); return import_tracing.tracingClient.withSpan(`${this.constructor.name}.getToken`, options, async () => { try { (0, import_scopeUtils.ensureValidScopeForDevTimeCreds)(scope, logger); const resource = (0, import_scopeUtils.getScopeResource)(scope); const obj = await cliCredentialInternals.getAzureCliAccessToken( resource, tenantId, this.subscription, this.timeout ); const specificScope = obj.stderr?.match("(.*)az login --scope(.*)"); const isLoginError = obj.stderr?.match("(.*)az login(.*)") && !specificScope; const isNotInstallError = obj.stderr?.match("az:(.*)not found") || obj.stderr?.startsWith("'az' is not recognized") || obj.error && (0, import_core_process.isProcessError)(obj.error) && obj.error.code === "ENOENT"; if (isNotInstallError) { const error = new import_errors.CredentialUnavailableError(azureCliPublicErrorMessages.notInstalled); logger.getToken.info((0, import_logging.formatError)(scopes, error)); throw error; } if (isLoginError) { const error = new import_errors.CredentialUnavailableError(azureCliPublicErrorMessages.login); logger.getToken.info((0, import_logging.formatError)(scopes, error)); throw error; } try { const responseData = obj.stdout; const response = this.parseRawResponse(responseData); logger.getToken.info((0, import_logging.formatSuccess)(scopes)); return response; } catch (e) { if (obj.stderr) { throw new import_errors.CredentialUnavailableError(obj.stderr); } throw e; } } catch (err) { const error = err.name === "CredentialUnavailableError" ? err : new import_errors.CredentialUnavailableError( err.message || azureCliPublicErrorMessages.unknown ); logger.getToken.info((0, import_logging.formatError)(scopes, error)); throw error; } }); } /** * Parses the raw JSON response from the Azure CLI into a usable AccessToken object * * @param rawResponse - The raw JSON response from the Azure CLI * @returns An access token with the expiry time parsed from the raw response * * The expiryTime of the credential's access token, in milliseconds, is calculated as follows: * * When available, expires_on (introduced in Azure CLI v2.54.0) will be preferred. Otherwise falls back to expiresOn. */ parseRawResponse(rawResponse) { const response = JSON.parse(rawResponse); const token = response.accessToken; let expiresOnTimestamp = Number.parseInt(response.expires_on, 10) * 1e3; if (!isNaN(expiresOnTimestamp)) { logger.getToken.info("expires_on is available and is valid, using it"); return { token, expiresOnTimestamp, tokenType: "Bearer" }; } expiresOnTimestamp = new Date(response.expiresOn).getTime(); if (isNaN(expiresOnTimestamp)) { throw new import_errors.CredentialUnavailableError( `${azureCliPublicErrorMessages.unexpectedResponse} "${response.expiresOn}"` ); } return { token, expiresOnTimestamp, tokenType: "Bearer" }; } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { AzureCliCredential, azureCliPublicErrorMessages, cliCredentialInternals }); //# sourceMappingURL=azureCliCredential.js.map