wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
{"version":3,"file":"azurePipelinesCredential.js","sourceRoot":"","sources":["../../../src/credentials/azurePipelinesCredential.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 { AuthenticationError, CredentialUnavailableError } from \"../errors.js\";\nimport { createHttpHeaders, createPipelineRequest } from \"@azure/core-rest-pipeline\";\n\nimport type { AzurePipelinesCredentialOptions } from \"./azurePipelinesCredentialOptions.js\";\nimport { ClientAssertionCredential } from \"./clientAssertionCredential.js\";\nimport { IdentityClient } from \"../client/identityClient.js\";\nimport type { PipelineResponse } from \"@azure/core-rest-pipeline\";\nimport { checkTenantId } from \"../util/tenantIdUtils.js\";\nimport { credentialLogger } from \"../util/logging.js\";\n\nconst credentialName = \"AzurePipelinesCredential\";\nconst logger = credentialLogger(credentialName);\nconst OIDC_API_VERSION = \"7.1\";\n\n/**\n * This credential is designed to be used in Azure Pipelines with service connections\n * as a setup for workload identity federation.\n */\nexport class AzurePipelinesCredential implements TokenCredential {\n  private clientAssertionCredential: ClientAssertionCredential | undefined;\n  private identityClient: IdentityClient;\n\n  /**\n   * AzurePipelinesCredential supports Federated Identity on Azure Pipelines through Service Connections.\n   * @param tenantId - tenantId associated with the service connection\n   * @param clientId - clientId associated with the service connection\n   * @param serviceConnectionId - Unique ID for the service connection, as found in the querystring's resourceId key\n   * @param systemAccessToken - The pipeline's <see href=\"https://learn.microsoft.com/azure/devops/pipelines/build/variables?view=azure-devops%26tabs=yaml#systemaccesstoken\">System.AccessToken</see> value.\n   * @param options - The identity client options to use for authentication.\n   */\n  constructor(\n    tenantId: string,\n    clientId: string,\n    serviceConnectionId: string,\n    systemAccessToken: string,\n    options: AzurePipelinesCredentialOptions = {},\n  ) {\n    if (!clientId) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. clientId is a required parameter.`,\n      );\n    }\n    if (!tenantId) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. tenantId is a required parameter.`,\n      );\n    }\n    if (!serviceConnectionId) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. serviceConnectionId is a required parameter.`,\n      );\n    }\n    if (!systemAccessToken) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. systemAccessToken is a required parameter.`,\n      );\n    }\n\n    // Allow these headers to be logged for troubleshooting by AzurePipelines.\n    options.loggingOptions = {\n      ...options?.loggingOptions,\n      additionalAllowedHeaderNames: [\n        ...(options.loggingOptions?.additionalAllowedHeaderNames ?? []),\n        \"x-vss-e2eid\",\n        \"x-msedge-ref\",\n      ],\n    };\n\n    this.identityClient = new IdentityClient(options);\n    checkTenantId(logger, tenantId);\n    logger.info(\n      `Invoking AzurePipelinesCredential with tenant ID: ${tenantId}, client ID: ${clientId}, and service connection ID: ${serviceConnectionId}`,\n    );\n    if (!process.env.SYSTEM_OIDCREQUESTURI) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. Ensure that you're running this task in an Azure Pipeline, so that following missing system variable(s) can be defined- \"SYSTEM_OIDCREQUESTURI\"`,\n      );\n    }\n\n    const oidcRequestUrl = `${process.env.SYSTEM_OIDCREQUESTURI}?api-version=${OIDC_API_VERSION}&serviceConnectionId=${serviceConnectionId}`;\n    logger.info(\n      `Invoking ClientAssertionCredential with tenant ID: ${tenantId}, client ID: ${clientId} and service connection ID: ${serviceConnectionId}`,\n    );\n    this.clientAssertionCredential = new ClientAssertionCredential(\n      tenantId,\n      clientId,\n      this.requestOidcToken.bind(this, oidcRequestUrl, systemAccessToken),\n      options,\n    );\n  }\n\n  /**\n   * Authenticates with Microsoft Entra ID and returns an access token if successful.\n   * If authentication fails, a {@link CredentialUnavailableError} or {@link AuthenticationError} 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    if (!this.clientAssertionCredential) {\n      const errorMessage = `${credentialName}: is unavailable. To use Federation Identity in Azure Pipelines, the following parameters are required - \n      tenantId,\n      clientId,\n      serviceConnectionId,\n      systemAccessToken,\n      \"SYSTEM_OIDCREQUESTURI\".      \n      See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`;\n      logger.error(errorMessage);\n      throw new CredentialUnavailableError(errorMessage);\n    }\n    logger.info(\"Invoking getToken() of Client Assertion Credential\");\n    return this.clientAssertionCredential.getToken(scopes, options);\n  }\n\n  /**\n   *\n   * @param oidcRequestUrl - oidc request url\n   * @param systemAccessToken - system access token\n   * @returns OIDC token from Azure Pipelines\n   */\n  private async requestOidcToken(\n    oidcRequestUrl: string,\n    systemAccessToken: string,\n  ): Promise<string> {\n    logger.info(\"Requesting OIDC token from Azure Pipelines...\");\n    logger.info(oidcRequestUrl);\n    const request = createPipelineRequest({\n      url: oidcRequestUrl,\n      method: \"POST\",\n      headers: createHttpHeaders({\n        \"Content-Type\": \"application/json\",\n        Authorization: `Bearer ${systemAccessToken}`,\n        // Prevents the service from responding with a redirect HTTP status code (useful for automation).\n        \"X-TFS-FedAuthRedirect\": \"Suppress\",\n      }),\n    });\n    const response = await this.identityClient.sendRequest(request);\n    return handleOidcResponse(response);\n  }\n}\n\nexport function handleOidcResponse(response: PipelineResponse): string {\n  // OIDC token is present in `bodyAsText` field\n  const text = response.bodyAsText;\n  if (!text) {\n    logger.error(\n      `${credentialName}: Authentication Failed. Received null token from OIDC request. Response status- ${\n        response.status\n      }. Complete response - ${JSON.stringify(response)}`,\n    );\n    throw new AuthenticationError(response.status, {\n      error: `${credentialName}: Authentication Failed. Received null token from OIDC request.`,\n      error_description: `${JSON.stringify(\n        response,\n      )}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,\n    });\n  }\n  try {\n    const result = JSON.parse(text);\n    if (result?.oidcToken) {\n      return result.oidcToken;\n    } else {\n      const errorMessage = `${credentialName}: Authentication Failed. oidcToken field not detected in the response.`;\n      let errorDescription = ``;\n      if (response.status !== 200) {\n        errorDescription = `Response body = ${text}. Response Headers [\"x-vss-e2eid\"] = ${response.headers.get(\"x-vss-e2eid\")} and [\"x-msedge-ref\"] = ${response.headers.get(\"x-msedge-ref\")}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`;\n      }\n      logger.error(errorMessage);\n      logger.error(errorDescription);\n      throw new AuthenticationError(response.status, {\n        error: errorMessage,\n        error_description: errorDescription,\n      });\n    }\n  } catch (e: any) {\n    const errorDetails = `${credentialName}: Authentication Failed. oidcToken field not detected in the response.`;\n    logger.error(\n      `Response from service = ${text}, Response Headers [\"x-vss-e2eid\"] = ${response.headers.get(\"x-vss-e2eid\")} \n      and [\"x-msedge-ref\"] = ${response.headers.get(\"x-msedge-ref\")}, error message = ${e.message}`,\n    );\n    logger.error(errorDetails);\n    throw new AuthenticationError(response.status, {\n      error: errorDetails,\n      error_description: `Response = ${text}. Response headers [\"x-vss-e2eid\"] = ${response.headers.get(\"x-vss-e2eid\")} and [\"x-msedge-ref\"] =  ${response.headers.get(\"x-msedge-ref\")}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,\n    });\n  }\n}\n"]}