{"version":3,"file":"tokenExchangeMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/tokenExchangeMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport fs from \"fs\";\nimport {\n PipelineRequestOptions,\n createHttpHeaders,\n createPipelineRequest,\n} from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { promisify } from \"util\";\nimport { DefaultAuthorityHost } from \"../../constants\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { MSI, MSIConfiguration } from \"./models\";\n\nconst msiName = \"ManagedIdentityCredential - Token Exchange\";\nconst logger = credentialLogger(msiName);\n\nconst readFileAsync = promisify(fs.readFile);\n\n/**\n * Generates the options used on the request for an access token.\n */\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientAssertion: string,\n clientId: string\n): PipelineRequestOptions {\n const bodyParams: Record = {\n scope: Array.isArray(scopes) ? scopes.join(\" \") : scopes,\n client_assertion: clientAssertion,\n client_assertion_type: \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\",\n client_id: clientId,\n grant_type: \"client_credentials\",\n };\n\n const urlParams = new URLSearchParams(bodyParams);\n const url = new URL(\n `${process.env.AZURE_TENANT_ID}/oauth2/v2.0/token`,\n process.env.AZURE_AUTHORITY_HOST ?? DefaultAuthorityHost\n );\n\n return {\n url: url.toString(),\n method: \"POST\",\n body: urlParams.toString(),\n headers: createHttpHeaders({\n Accept: \"application/json\",\n }),\n };\n}\n\n/**\n * Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI.\n */\nexport function tokenExchangeMsi(): MSI {\n const azureFederatedTokenFilePath = process.env.AZURE_FEDERATED_TOKEN_FILE;\n let azureFederatedTokenFileContent: string | undefined = undefined;\n let cacheDate: number | undefined = undefined;\n\n // Only reads from the assertion file once every 5 minutes\n async function readAssertion(): Promise {\n // Cached assertions expire after 5 minutes\n if (cacheDate !== undefined && Date.now() - cacheDate >= 1000 * 60 * 5) {\n azureFederatedTokenFileContent = undefined;\n }\n if (!azureFederatedTokenFileContent) {\n const file = await readFileAsync(azureFederatedTokenFilePath!, \"utf8\");\n const value = file.trim();\n if (!value) {\n throw new Error(\n `No content on the file ${azureFederatedTokenFilePath}, indicated by the environment variable AZURE_FEDERATED_TOKEN_FILE`\n );\n } else {\n azureFederatedTokenFileContent = value;\n cacheDate = Date.now();\n }\n }\n return azureFederatedTokenFileContent;\n }\n\n return {\n async isAvailable({ clientId }): Promise {\n const env = process.env;\n const result = Boolean(\n (clientId || env.AZURE_CLIENT_ID) && env.AZURE_TENANT_ID && azureFederatedTokenFilePath\n );\n if (!result) {\n logger.info(\n `${msiName}: Unavailable. The environment variables needed are: AZURE_CLIENT_ID (or the client ID sent through the parameters), AZURE_TENANT_ID and AZURE_FEDERATED_TOKEN_FILE`\n );\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(`${msiName}: Using the client assertion coming from environment variables.`);\n\n let assertion: string;\n\n try {\n assertion = await readAssertion();\n } catch (err: any) {\n throw new Error(\n `${msiName}: Failed to read ${azureFederatedTokenFilePath}, indicated by the environment variable AZURE_FEDERATED_TOKEN_FILE`\n );\n }\n\n const request = createPipelineRequest({\n abortSignal: getTokenOptions.abortSignal,\n ...prepareRequestOptions(scopes, assertion, clientId || process.env.AZURE_CLIENT_ID!),\n // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).\n allowInsecureConnection: true,\n });\n const tokenResponse = await identityClient.sendTokenRequest(request);\n return (tokenResponse && tokenResponse.accessToken) || null;\n },\n };\n}\n"]}