wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
{"version":3,"file":"azureCliCredential.js","sourceRoot":"","sources":["../../../src/credentials/azureCliCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport {\n  checkTenantId,\n  processMultiTenantRequest,\n  resolveAdditionallyAllowedTenantIds,\n} from \"../util/tenantIdUtils.js\";\nimport { credentialLogger, formatError, formatSuccess } from \"../util/logging.js\";\nimport { ensureValidScopeForDevTimeCreds, getScopeResource } from \"../util/scopeUtils.js\";\n\nimport type { AzureCliCredentialOptions } from \"./azureCliCredentialOptions.js\";\nimport { CredentialUnavailableError } from \"../errors.js\";\nimport child_process from \"child_process\";\nimport { tracingClient } from \"../util/tracing.js\";\nimport { checkSubscription } from \"../util/subscriptionUtils.js\";\n\nconst logger = credentialLogger(\"AzureCliCredential\");\n\n/**\n * Messages to use when throwing in this credential.\n * @internal\n */\nexport const azureCliPublicErrorMessages = {\n  claim:\n    \"This credential doesn't support claims challenges. To authenticate with the required claims, please run the following command:\",\n  notInstalled:\n    \"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'.\",\n  login:\n    \"Please run 'az login' from a command prompt to authenticate before using this credential.\",\n  unknown: \"Unknown error while trying to retrieve the access token\",\n  unexpectedResponse:\n    'Unexpected response from Azure CLI when getting token. Expected \"expiresOn\" to be a RFC3339 date string. Got:',\n};\n\n/**\n * Mockable reference to the CLI credential cliCredentialFunctions\n * @internal\n */\nexport const cliCredentialInternals = {\n  /**\n   * @internal\n   */\n  getSafeWorkingDir(): string {\n    if (process.platform === \"win32\") {\n      let systemRoot = process.env.SystemRoot || process.env[\"SYSTEMROOT\"];\n      if (!systemRoot) {\n        logger.getToken.warning(\n          \"The SystemRoot environment variable is not set. This may cause issues when using the Azure CLI credential.\",\n        );\n\n        systemRoot = \"C:\\\\Windows\";\n      }\n      return systemRoot;\n    } else {\n      return \"/bin\";\n    }\n  },\n\n  /**\n   * Gets the access token from Azure CLI\n   * @param resource - The resource to use when getting the token\n   * @internal\n   */\n  async getAzureCliAccessToken(\n    resource: string,\n    tenantId?: string,\n    subscription?: string,\n    timeout?: number,\n  ): Promise<{ stdout: string; stderr: string; error: Error | null }> {\n    let tenantSection: string[] = [];\n    let subscriptionSection: string[] = [];\n    if (tenantId) {\n      tenantSection = [\"--tenant\", tenantId];\n    }\n    if (subscription) {\n      // Add quotes around the subscription to handle subscriptions with spaces\n      subscriptionSection = [\"--subscription\", `\"${subscription}\"`];\n    }\n    return new Promise((resolve, reject) => {\n      try {\n        const args = [\n          \"account\",\n          \"get-access-token\",\n          \"--output\",\n          \"json\",\n          \"--resource\",\n          resource,\n          ...tenantSection,\n          ...subscriptionSection,\n        ];\n        const command = [\"az\", ...args].join(\" \");\n        child_process.exec(\n          command,\n          { cwd: cliCredentialInternals.getSafeWorkingDir(), timeout },\n          (error, stdout, stderr) => {\n            resolve({ stdout: stdout, stderr: stderr, error });\n          },\n        );\n      } catch (err: any) {\n        reject(err);\n      }\n    });\n  },\n};\n\n/**\n * This credential will use the currently logged-in user login information\n * via the Azure CLI ('az') commandline tool.\n * To do so, it will read the user access token and expire time\n * with Azure CLI command \"az account get-access-token\".\n */\nexport class AzureCliCredential implements TokenCredential {\n  private tenantId?: string;\n  private additionallyAllowedTenantIds: string[];\n  private timeout?: number;\n  private subscription?: string;\n\n  /**\n   * Creates an instance of the {@link AzureCliCredential}.\n   *\n   * To use this credential, ensure that you have already logged\n   * in via the 'az' tool using the command \"az login\" from the commandline.\n   *\n   * @param options - Options, to optionally allow multi-tenant requests.\n   */\n  constructor(options?: AzureCliCredentialOptions) {\n    if (options?.tenantId) {\n      checkTenantId(logger, options?.tenantId);\n      this.tenantId = options?.tenantId;\n    }\n    if (options?.subscription) {\n      checkSubscription(logger, options?.subscription);\n      this.subscription = options?.subscription;\n    }\n    this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(\n      options?.additionallyAllowedTenants,\n    );\n    this.timeout = options?.processTimeoutInMs;\n  }\n\n  /**\n   * Authenticates with Microsoft Entra ID and returns an access token if successful.\n   * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.\n   *\n   * @param scopes - The list of scopes for which the token will have access.\n   * @param options - The options used to configure any requests this\n   *                TokenCredential implementation might make.\n   */\n  public async getToken(\n    scopes: string | string[],\n    options: GetTokenOptions = {},\n  ): Promise<AccessToken> {\n    const scope = typeof scopes === \"string\" ? scopes : scopes[0];\n    const claimsValue = options.claims;\n    if (claimsValue && claimsValue.trim()) {\n      const encodedClaims = btoa(claimsValue);\n      let loginCmd = `az login --claims-challenge ${encodedClaims} --scope ${scope}`;\n\n      const tenantIdFromOptions = options.tenantId;\n      if (tenantIdFromOptions) {\n        loginCmd += ` --tenant ${tenantIdFromOptions}`;\n      }\n\n      const error = new CredentialUnavailableError(\n        `${azureCliPublicErrorMessages.claim} ${loginCmd}`,\n      );\n      logger.getToken.info(formatError(scope, error));\n      throw error;\n    }\n\n    const tenantId = processMultiTenantRequest(\n      this.tenantId,\n      options,\n      this.additionallyAllowedTenantIds,\n    );\n    if (tenantId) {\n      checkTenantId(logger, tenantId);\n    }\n    if (this.subscription) {\n      checkSubscription(logger, this.subscription);\n    }\n    logger.getToken.info(`Using the scope ${scope}`);\n\n    return tracingClient.withSpan(`${this.constructor.name}.getToken`, options, async () => {\n      try {\n        ensureValidScopeForDevTimeCreds(scope, logger);\n        const resource = getScopeResource(scope);\n        const obj = await cliCredentialInternals.getAzureCliAccessToken(\n          resource,\n          tenantId,\n          this.subscription,\n          this.timeout,\n        );\n        const specificScope = obj.stderr?.match(\"(.*)az login --scope(.*)\");\n        const isLoginError = obj.stderr?.match(\"(.*)az login(.*)\") && !specificScope;\n        const isNotInstallError =\n          obj.stderr?.match(\"az:(.*)not found\") || obj.stderr?.startsWith(\"'az' is not recognized\");\n\n        if (isNotInstallError) {\n          const error = new CredentialUnavailableError(azureCliPublicErrorMessages.notInstalled);\n          logger.getToken.info(formatError(scopes, error));\n          throw error;\n        }\n        if (isLoginError) {\n          const error = new CredentialUnavailableError(azureCliPublicErrorMessages.login);\n          logger.getToken.info(formatError(scopes, error));\n          throw error;\n        }\n        try {\n          const responseData = obj.stdout;\n          const response: AccessToken = this.parseRawResponse(responseData);\n          logger.getToken.info(formatSuccess(scopes));\n          return response;\n        } catch (e: any) {\n          if (obj.stderr) {\n            throw new CredentialUnavailableError(obj.stderr);\n          }\n          throw e;\n        }\n      } catch (err: any) {\n        const error =\n          err.name === \"CredentialUnavailableError\"\n            ? err\n            : new CredentialUnavailableError(\n                (err as Error).message || azureCliPublicErrorMessages.unknown,\n              );\n        logger.getToken.info(formatError(scopes, error));\n        throw error;\n      }\n    });\n  }\n\n  /**\n   * Parses the raw JSON response from the Azure CLI into a usable AccessToken object\n   *\n   * @param rawResponse - The raw JSON response from the Azure CLI\n   * @returns An access token with the expiry time parsed from the raw response\n   *\n   * The expiryTime of the credential's access token, in milliseconds, is calculated as follows:\n   *\n   * When available, expires_on (introduced in Azure CLI v2.54.0) will be preferred. Otherwise falls back to expiresOn.\n   */\n  private parseRawResponse(rawResponse: string): AccessToken {\n    const response: any = JSON.parse(rawResponse);\n    const token = response.accessToken;\n    // if available, expires_on will be a number representing seconds since epoch.\n    // ensure it's a number or NaN\n    let expiresOnTimestamp = Number.parseInt(response.expires_on, 10) * 1000;\n    if (!isNaN(expiresOnTimestamp)) {\n      logger.getToken.info(\"expires_on is available and is valid, using it\");\n      return {\n        token,\n        expiresOnTimestamp,\n        tokenType: \"Bearer\",\n      };\n    }\n\n    // fallback to the older expiresOn - an RFC3339 date string\n    expiresOnTimestamp = new Date(response.expiresOn).getTime();\n\n    // ensure expiresOn is well-formatted\n    if (isNaN(expiresOnTimestamp)) {\n      throw new CredentialUnavailableError(\n        `${azureCliPublicErrorMessages.unexpectedResponse} \"${response.expiresOn}\"`,\n      );\n    }\n\n    return {\n      token,\n      expiresOnTimestamp,\n      tokenType: \"Bearer\",\n    };\n  }\n}\n"]}