Files
sap-erp/node_modules/@azure/identity/dist-esm/src/credentials/managedIdentityCredential/index.js
T
John 69b4e68baf
SAP-ERP Portal CI/CD / build (push) Failing after 5m20s
first commit
2026-09-23 17:31:02 +05:30

194 lines
9.4 KiB
JavaScript

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { IdentityClient } from "../../client/identityClient";
import { AuthenticationError, CredentialUnavailableError } from "../../errors";
import { credentialLogger, formatError, formatSuccess } from "../../util/logging";
import { appServiceMsi2017 } from "./appServiceMsi2017";
import { tracingClient } from "../../util/tracing";
import { cloudShellMsi } from "./cloudShellMsi";
import { imdsMsi } from "./imdsMsi";
import { arcMsi } from "./arcMsi";
import { tokenExchangeMsi } from "./tokenExchangeMsi";
import { fabricMsi } from "./fabricMsi";
import { appServiceMsi2019 } from "./appServiceMsi2019";
const logger = credentialLogger("ManagedIdentityCredential");
/**
* Attempts authentication using a managed identity available at the deployment environment.
* This authentication type works in Azure VMs, App Service instances, Azure Functions applications,
* Azure Kubernetes Services, Azure Service Fabric instances and inside of the Azure Cloud Shell.
*
* More information about configuring managed identities can be found here:
* https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
*/
export class ManagedIdentityCredential {
/**
* @internal
* @hidden
*/
constructor(clientIdOrOptions, options) {
this.isEndpointUnavailable = null;
let _options;
if (typeof clientIdOrOptions === "string") {
this.clientId = clientIdOrOptions;
_options = options;
}
else {
this.clientId = clientIdOrOptions === null || clientIdOrOptions === void 0 ? void 0 : clientIdOrOptions.clientId;
_options = clientIdOrOptions;
}
this.resourceId = _options === null || _options === void 0 ? void 0 : _options.resourceId;
// For JavaScript users.
if (this.clientId && this.resourceId) {
throw new Error(`${ManagedIdentityCredential.name} - Client Id and Resource Id can't be provided at the same time.`);
}
this.identityClient = new IdentityClient(_options);
this.isAvailableIdentityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { retryOptions: {
maxRetries: 0,
} }));
}
async cachedAvailableMSI(scopes, getTokenOptions) {
if (this.cachedMSI) {
return this.cachedMSI;
}
const MSIs = [
arcMsi,
fabricMsi,
appServiceMsi2019,
appServiceMsi2017,
cloudShellMsi,
tokenExchangeMsi(),
imdsMsi,
];
for (const msi of MSIs) {
if (await msi.isAvailable({
scopes,
identityClient: this.isAvailableIdentityClient,
clientId: this.clientId,
resourceId: this.resourceId,
getTokenOptions,
})) {
this.cachedMSI = msi;
return msi;
}
}
throw new CredentialUnavailableError(`${ManagedIdentityCredential.name} - No MSI credential available`);
}
async authenticateManagedIdentity(scopes, getTokenOptions) {
const { span, updatedOptions } = tracingClient.startSpan(`${ManagedIdentityCredential.name}.authenticateManagedIdentity`, getTokenOptions);
try {
// Determining the available MSI, and avoiding checking for other MSIs while the program is running.
const availableMSI = await this.cachedAvailableMSI(scopes, updatedOptions);
return availableMSI.getToken({
identityClient: this.identityClient,
scopes,
clientId: this.clientId,
resourceId: this.resourceId,
}, updatedOptions);
}
catch (err) {
span.setStatus({
status: "error",
error: err,
});
throw err;
}
finally {
span.end();
}
}
/**
* Authenticates with Azure Active Directory 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) {
let result = null;
const { span, updatedOptions } = tracingClient.startSpan(`${ManagedIdentityCredential.name}.getToken`, options);
try {
// isEndpointAvailable can be true, false, or null,
// If it's null, it means we don't yet know whether
// the endpoint is available and need to check for it.
if (this.isEndpointUnavailable !== true) {
result = await this.authenticateManagedIdentity(scopes, updatedOptions);
if (result === null) {
// If authenticateManagedIdentity returns null,
// it means no MSI endpoints are available.
// If so, we avoid trying to reach to them in future requests.
this.isEndpointUnavailable = true;
// It also means that the endpoint answered with either 200 or 201 (see the sendTokenRequest method),
// yet we had no access token. For this reason, we'll throw once with a specific message:
const error = new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
logger.getToken.info(formatError(scopes, error));
throw error;
}
// Since `authenticateManagedIdentity` didn't throw, and the result was not null,
// We will assume that this endpoint is reachable from this point forward,
// and avoid pinging again to it.
this.isEndpointUnavailable = false;
}
else {
// We've previously determined that the endpoint was unavailable,
// either because it was unreachable or permanently unable to authenticate.
const error = new CredentialUnavailableError("The managed identity endpoint is not currently available");
logger.getToken.info(formatError(scopes, error));
throw error;
}
logger.getToken.info(formatSuccess(scopes));
return result;
}
catch (err) {
// CredentialUnavailable errors are expected to reach here.
// We intend them to bubble up, so that DefaultAzureCredential can catch them.
if (err.name === "AuthenticationRequiredError") {
throw err;
}
// Expected errors to reach this point:
// - Errors coming from a method unexpectedly breaking.
// - When identityClient.sendTokenRequest throws, in which case
// if the status code was 400, it means that the endpoint is working,
// but no identity is available.
span.setStatus({
status: "error",
error: err,
});
// If either the network is unreachable,
// we can safely assume the credential is unavailable.
if (err.code === "ENETUNREACH") {
const error = new CredentialUnavailableError(`${ManagedIdentityCredential.name}: Unavailable. Network unreachable. Message: ${err.message}`);
logger.getToken.info(formatError(scopes, error));
throw error;
}
// If either the host was unreachable,
// we can safely assume the credential is unavailable.
if (err.code === "EHOSTUNREACH") {
const error = new CredentialUnavailableError(`${ManagedIdentityCredential.name}: Unavailable. No managed identity endpoint found. Message: ${err.message}`);
logger.getToken.info(formatError(scopes, error));
throw error;
}
// If err.statusCode has a value of 400, it comes from sendTokenRequest,
// and it means that the endpoint is working, but that no identity is available.
if (err.statusCode === 400) {
throw new CredentialUnavailableError(`${ManagedIdentityCredential.name}: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
}
// If the error has no status code, we can assume there was no available identity.
// This will throw silently during any ChainedTokenCredential.
if (err.statusCode === undefined) {
throw new CredentialUnavailableError(`${ManagedIdentityCredential.name}: Authentication failed. Message ${err.message}`);
}
// Any other error should break the chain.
throw new AuthenticationError(err.statusCode, {
error: `${ManagedIdentityCredential.name} authentication failed.`,
error_description: err.message,
});
}
finally {
// Finally is always called, both if we return and if we throw in the above try/catch.
span.end();
}
}
}
//# sourceMappingURL=index.js.map