mirror of
https://github.com/tvytlx/ai-agent-deep-dive.git
synced 2026-04-08 10:04:48 +08:00
Add extracted source directory and README navigation
This commit is contained in:
99
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/imdsMsi.js
generated
vendored
Normal file
99
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/imdsMsi.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
||||
import { isError } from "@azure/core-util";
|
||||
import { credentialLogger } from "../../util/logging.js";
|
||||
import { mapScopesToResource } from "./utils.js";
|
||||
import { tracingClient } from "../../util/tracing.js";
|
||||
const msiName = "ManagedIdentityCredential - IMDS";
|
||||
const logger = credentialLogger(msiName);
|
||||
const imdsHost = "http://169.254.169.254";
|
||||
const imdsEndpointPath = "/metadata/identity/oauth2/token";
|
||||
/**
|
||||
* Generates an invalid request options to get a response quickly from IMDS endpoint.
|
||||
* The response indicates the availability of IMSD service; otherwise the request would time out.
|
||||
*/
|
||||
function prepareInvalidRequestOptions(scopes) {
|
||||
var _a;
|
||||
const resource = mapScopesToResource(scopes);
|
||||
if (!resource) {
|
||||
throw new Error(`${msiName}: Multiple scopes are not supported.`);
|
||||
}
|
||||
// Pod Identity will try to process this request even if the Metadata header is missing.
|
||||
// We can exclude the request query to ensure no IMDS endpoint tries to process the ping request.
|
||||
const url = new URL(imdsEndpointPath, (_a = process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : imdsHost);
|
||||
const rawHeaders = {
|
||||
Accept: "application/json",
|
||||
// intentionally leave out the Metadata header to invoke an error from IMDS endpoint.
|
||||
};
|
||||
return {
|
||||
// intentionally not including any query
|
||||
url: `${url}`,
|
||||
method: "GET",
|
||||
headers: createHttpHeaders(rawHeaders),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Defines how to determine whether the Azure IMDS MSI is available.
|
||||
*
|
||||
* Actually getting the token once we determine IMDS is available is handled by MSAL.
|
||||
*/
|
||||
export const imdsMsi = {
|
||||
name: "imdsMsi",
|
||||
async isAvailable(options) {
|
||||
const { scopes, identityClient, getTokenOptions } = options;
|
||||
const resource = mapScopesToResource(scopes);
|
||||
if (!resource) {
|
||||
logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
|
||||
return false;
|
||||
}
|
||||
// if the PodIdentityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
|
||||
if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
|
||||
return true;
|
||||
}
|
||||
if (!identityClient) {
|
||||
throw new Error("Missing IdentityClient");
|
||||
}
|
||||
const requestOptions = prepareInvalidRequestOptions(resource);
|
||||
return tracingClient.withSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions !== null && getTokenOptions !== void 0 ? getTokenOptions : {}, async (updatedOptions) => {
|
||||
var _a, _b;
|
||||
requestOptions.tracingOptions = updatedOptions.tracingOptions;
|
||||
// Create a request with a timeout since we expect that
|
||||
// not having a "Metadata" header should cause an error to be
|
||||
// returned quickly from the endpoint, proving its availability.
|
||||
const request = createPipelineRequest(requestOptions);
|
||||
// Default to 1000 if the default of 0 is used.
|
||||
// Negative values can still be used to disable the timeout.
|
||||
request.timeout = ((_a = updatedOptions.requestOptions) === null || _a === void 0 ? void 0 : _a.timeout) || 1000;
|
||||
// This MSI uses the imdsEndpoint to get the token, which only uses http://
|
||||
request.allowInsecureConnection = true;
|
||||
let response;
|
||||
try {
|
||||
logger.info(`${msiName}: Pinging the Azure IMDS endpoint`);
|
||||
response = await identityClient.sendRequest(request);
|
||||
}
|
||||
catch (err) {
|
||||
// If the request failed, or Node.js was unable to establish a connection,
|
||||
// or the host was down, we'll assume the IMDS endpoint isn't available.
|
||||
if (isError(err)) {
|
||||
logger.verbose(`${msiName}: Caught error ${err.name}: ${err.message}`);
|
||||
}
|
||||
// This is a special case for Docker Desktop which responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network" or "A socket operation was attempted to an unreachable host"
|
||||
// rather than just timing out, as expected.
|
||||
logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);
|
||||
return false;
|
||||
}
|
||||
if (response.status === 403) {
|
||||
if ((_b = response.bodyAsText) === null || _b === void 0 ? void 0 : _b.includes("unreachable")) {
|
||||
logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);
|
||||
logger.info(`${msiName}: ${response.bodyAsText}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If we received any response, the endpoint is available
|
||||
logger.info(`${msiName}: The Azure IMDS endpoint is available`);
|
||||
return true;
|
||||
});
|
||||
},
|
||||
};
|
||||
//# sourceMappingURL=imdsMsi.js.map
|
||||
33
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/imdsRetryPolicy.js
generated
vendored
Normal file
33
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/imdsRetryPolicy.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
import { retryPolicy } from "@azure/core-rest-pipeline";
|
||||
import { calculateRetryDelay } from "@azure/core-util";
|
||||
// Matches the default retry configuration in expontentialRetryStrategy.ts
|
||||
const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 64;
|
||||
/**
|
||||
* An additional policy that retries on 404 errors. The default retry policy does not retry on
|
||||
* 404s, but the IMDS endpoint can return 404s when the token is not yet available. This policy
|
||||
* will retry on 404s with an exponential backoff.
|
||||
*
|
||||
* @param msiRetryConfig - The retry configuration for the MSI credential.
|
||||
* @returns - The policy that will retry on 404s.
|
||||
*/
|
||||
export function imdsRetryPolicy(msiRetryConfig) {
|
||||
return retryPolicy([
|
||||
{
|
||||
name: "imdsRetryPolicy",
|
||||
retry: ({ retryCount, response }) => {
|
||||
if ((response === null || response === void 0 ? void 0 : response.status) !== 404) {
|
||||
return { skipStrategy: true };
|
||||
}
|
||||
return calculateRetryDelay(retryCount, {
|
||||
retryDelayInMs: msiRetryConfig.startDelayInMs,
|
||||
maxRetryDelayInMs: DEFAULT_CLIENT_MAX_RETRY_INTERVAL,
|
||||
});
|
||||
},
|
||||
},
|
||||
], {
|
||||
maxRetries: msiRetryConfig.maxRetries,
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=imdsRetryPolicy.js.map
|
||||
239
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/index.js
generated
vendored
Normal file
239
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/index.js
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
import { getLogLevel } from "@azure/logger";
|
||||
import { ManagedIdentityApplication } from "@azure/msal-node";
|
||||
import { IdentityClient } from "../../client/identityClient.js";
|
||||
import { AuthenticationRequiredError, CredentialUnavailableError } from "../../errors.js";
|
||||
import { getMSALLogLevel, defaultLoggerCallback } from "../../msal/utils.js";
|
||||
import { imdsRetryPolicy } from "./imdsRetryPolicy.js";
|
||||
import { formatSuccess, formatError, credentialLogger } from "../../util/logging.js";
|
||||
import { tracingClient } from "../../util/tracing.js";
|
||||
import { imdsMsi } from "./imdsMsi.js";
|
||||
import { tokenExchangeMsi } from "./tokenExchangeMsi.js";
|
||||
import { mapScopesToResource, serviceFabricErrorMessage } from "./utils.js";
|
||||
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://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview
|
||||
*/
|
||||
export class ManagedIdentityCredential {
|
||||
/**
|
||||
* @internal
|
||||
* @hidden
|
||||
*/
|
||||
constructor(clientIdOrOptions, options) {
|
||||
var _a, _b;
|
||||
this.msiRetryConfig = {
|
||||
maxRetries: 5,
|
||||
startDelayInMs: 800,
|
||||
intervalIncrement: 2,
|
||||
};
|
||||
let _options;
|
||||
if (typeof clientIdOrOptions === "string") {
|
||||
this.clientId = clientIdOrOptions;
|
||||
_options = options !== null && options !== void 0 ? options : {};
|
||||
}
|
||||
else {
|
||||
this.clientId = clientIdOrOptions === null || clientIdOrOptions === void 0 ? void 0 : clientIdOrOptions.clientId;
|
||||
_options = clientIdOrOptions !== null && clientIdOrOptions !== void 0 ? clientIdOrOptions : {};
|
||||
}
|
||||
this.resourceId = _options === null || _options === void 0 ? void 0 : _options.resourceId;
|
||||
this.objectId = _options === null || _options === void 0 ? void 0 : _options.objectId;
|
||||
// For JavaScript users.
|
||||
const providedIds = [
|
||||
{ key: "clientId", value: this.clientId },
|
||||
{ key: "resourceId", value: this.resourceId },
|
||||
{ key: "objectId", value: this.objectId },
|
||||
].filter((id) => id.value);
|
||||
if (providedIds.length > 1) {
|
||||
throw new Error(`ManagedIdentityCredential: only one of 'clientId', 'resourceId', or 'objectId' can be provided. Received values: ${JSON.stringify({ clientId: this.clientId, resourceId: this.resourceId, objectId: this.objectId })}`);
|
||||
}
|
||||
// ManagedIdentity uses http for local requests
|
||||
_options.allowInsecureConnection = true;
|
||||
if (((_a = _options.retryOptions) === null || _a === void 0 ? void 0 : _a.maxRetries) !== undefined) {
|
||||
this.msiRetryConfig.maxRetries = _options.retryOptions.maxRetries;
|
||||
}
|
||||
this.identityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { additionalPolicies: [{ policy: imdsRetryPolicy(this.msiRetryConfig), position: "perCall" }] }));
|
||||
this.managedIdentityApp = new ManagedIdentityApplication({
|
||||
managedIdentityIdParams: {
|
||||
userAssignedClientId: this.clientId,
|
||||
userAssignedResourceId: this.resourceId,
|
||||
userAssignedObjectId: this.objectId,
|
||||
},
|
||||
system: {
|
||||
disableInternalRetries: true,
|
||||
networkClient: this.identityClient,
|
||||
loggerOptions: {
|
||||
logLevel: getMSALLogLevel(getLogLevel()),
|
||||
piiLoggingEnabled: (_b = _options.loggingOptions) === null || _b === void 0 ? void 0 : _b.enableUnsafeSupportLogging,
|
||||
loggerCallback: defaultLoggerCallback(logger),
|
||||
},
|
||||
},
|
||||
});
|
||||
this.isAvailableIdentityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { retryOptions: {
|
||||
maxRetries: 0,
|
||||
} }));
|
||||
const managedIdentitySource = this.managedIdentityApp.getManagedIdentitySource();
|
||||
// CloudShell MSI will ignore any user-assigned identity passed as parameters. To avoid confusion, we prevent this from happening as early as possible.
|
||||
if (managedIdentitySource === "CloudShell") {
|
||||
if (this.clientId || this.resourceId || this.objectId) {
|
||||
logger.warning(`CloudShell MSI detected with user-provided IDs - throwing. Received values: ${JSON.stringify({
|
||||
clientId: this.clientId,
|
||||
resourceId: this.resourceId,
|
||||
objectId: this.objectId,
|
||||
})}.`);
|
||||
throw new CredentialUnavailableError("ManagedIdentityCredential: Specifying a user-assigned managed identity is not supported for CloudShell at runtime. When using Managed Identity in CloudShell, omit the clientId, resourceId, and objectId parameters.");
|
||||
}
|
||||
}
|
||||
// ServiceFabric does not support specifying user-assigned managed identity by client ID or resource ID. The managed identity selected is based on the resource configuration.
|
||||
if (managedIdentitySource === "ServiceFabric") {
|
||||
if (this.clientId || this.resourceId || this.objectId) {
|
||||
logger.warning(`Service Fabric detected with user-provided IDs - throwing. Received values: ${JSON.stringify({
|
||||
clientId: this.clientId,
|
||||
resourceId: this.resourceId,
|
||||
objectId: this.objectId,
|
||||
})}.`);
|
||||
throw new CredentialUnavailableError(`ManagedIdentityCredential: ${serviceFabricErrorMessage}`);
|
||||
}
|
||||
}
|
||||
logger.info(`Using ${managedIdentitySource} managed identity.`);
|
||||
// Check if either clientId, resourceId or objectId was provided and log the value used
|
||||
if (providedIds.length === 1) {
|
||||
const { key, value } = providedIds[0];
|
||||
logger.info(`${managedIdentitySource} with ${key}: ${value}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
* 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 = {}) {
|
||||
logger.getToken.info("Using the MSAL provider for Managed Identity.");
|
||||
const resource = mapScopesToResource(scopes);
|
||||
if (!resource) {
|
||||
throw new CredentialUnavailableError(`ManagedIdentityCredential: Multiple scopes are not supported. Scopes: ${JSON.stringify(scopes)}`);
|
||||
}
|
||||
return tracingClient.withSpan("ManagedIdentityCredential.getToken", options, async () => {
|
||||
var _a;
|
||||
try {
|
||||
const isTokenExchangeMsi = await tokenExchangeMsi.isAvailable(this.clientId);
|
||||
// Most scenarios are handled by MSAL except for two:
|
||||
// AKS pod identity - MSAL does not implement the token exchange flow.
|
||||
// IMDS Endpoint probing - MSAL does not do any probing before trying to get a token.
|
||||
// As a DefaultAzureCredential optimization we probe the IMDS endpoint with a short timeout and no retries before actually trying to get a token
|
||||
// We will continue to implement these features in the Identity library.
|
||||
const identitySource = this.managedIdentityApp.getManagedIdentitySource();
|
||||
const isImdsMsi = identitySource === "DefaultToImds" || identitySource === "Imds"; // Neither actually checks that IMDS endpoint is available, just that it's the source the MSAL _would_ try to use.
|
||||
logger.getToken.info(`MSAL Identity source: ${identitySource}`);
|
||||
if (isTokenExchangeMsi) {
|
||||
// In the AKS scenario we will use the existing tokenExchangeMsi indefinitely.
|
||||
logger.getToken.info("Using the token exchange managed identity.");
|
||||
const result = await tokenExchangeMsi.getToken({
|
||||
scopes,
|
||||
clientId: this.clientId,
|
||||
identityClient: this.identityClient,
|
||||
retryConfig: this.msiRetryConfig,
|
||||
resourceId: this.resourceId,
|
||||
});
|
||||
if (result === null) {
|
||||
throw new CredentialUnavailableError("Attempted to use the token exchange managed identity, but received a null response.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if (isImdsMsi) {
|
||||
// In the IMDS scenario we will probe the IMDS endpoint to ensure it's available before trying to get a token.
|
||||
// If the IMDS endpoint is not available and this is the source that MSAL will use, we will fail-fast with an error that tells DAC to move to the next credential.
|
||||
logger.getToken.info("Using the IMDS endpoint to probe for availability.");
|
||||
const isAvailable = await imdsMsi.isAvailable({
|
||||
scopes,
|
||||
clientId: this.clientId,
|
||||
getTokenOptions: options,
|
||||
identityClient: this.isAvailableIdentityClient,
|
||||
resourceId: this.resourceId,
|
||||
});
|
||||
if (!isAvailable) {
|
||||
throw new CredentialUnavailableError(`Attempted to use the IMDS endpoint, but it is not available.`);
|
||||
}
|
||||
}
|
||||
// If we got this far, it means:
|
||||
// - This is not a tokenExchangeMsi,
|
||||
// - We already probed for IMDS endpoint availability and failed-fast if it's unreachable.
|
||||
// We can proceed normally by calling MSAL for a token.
|
||||
logger.getToken.info("Calling into MSAL for managed identity token.");
|
||||
const token = await this.managedIdentityApp.acquireToken({
|
||||
resource,
|
||||
});
|
||||
this.ensureValidMsalToken(scopes, token, options);
|
||||
logger.getToken.info(formatSuccess(scopes));
|
||||
return {
|
||||
expiresOnTimestamp: token.expiresOn.getTime(),
|
||||
token: token.accessToken,
|
||||
refreshAfterTimestamp: (_a = token.refreshOn) === null || _a === void 0 ? void 0 : _a.getTime(),
|
||||
tokenType: "Bearer",
|
||||
};
|
||||
}
|
||||
catch (err) {
|
||||
logger.getToken.error(formatError(scopes, err));
|
||||
// AuthenticationRequiredError described as Error to enforce authentication after trying to retrieve a token silently.
|
||||
// TODO: why would this _ever_ happen considering we're not trying the silent request in this flow?
|
||||
if (err.name === "AuthenticationRequiredError") {
|
||||
throw err;
|
||||
}
|
||||
if (isNetworkError(err)) {
|
||||
throw new CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}`, { cause: err });
|
||||
}
|
||||
throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`, { cause: err });
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Ensures the validity of the MSAL token
|
||||
*/
|
||||
ensureValidMsalToken(scopes, msalToken, getTokenOptions) {
|
||||
const createError = (message) => {
|
||||
logger.getToken.info(message);
|
||||
return new AuthenticationRequiredError({
|
||||
scopes: Array.isArray(scopes) ? scopes : [scopes],
|
||||
getTokenOptions,
|
||||
message,
|
||||
});
|
||||
};
|
||||
if (!msalToken) {
|
||||
throw createError("No response.");
|
||||
}
|
||||
if (!msalToken.expiresOn) {
|
||||
throw createError(`Response had no "expiresOn" property.`);
|
||||
}
|
||||
if (!msalToken.accessToken) {
|
||||
throw createError(`Response had no "accessToken" property.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
function isNetworkError(err) {
|
||||
// MSAL error
|
||||
if (err.errorCode === "network_error") {
|
||||
return true;
|
||||
}
|
||||
// Probe errors
|
||||
if (err.code === "ENETUNREACH" || err.code === "EHOSTUNREACH") {
|
||||
return true;
|
||||
}
|
||||
// This is a special case for Docker Desktop which responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network" or "A socket operation was attempted to an unreachable host"
|
||||
// rather than just timing out, as expected.
|
||||
if (err.statusCode === 403 || err.code === 403) {
|
||||
if (err.message.includes("unreachable")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
32
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/tokenExchangeMsi.js
generated
vendored
Normal file
32
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/tokenExchangeMsi.js
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
import { WorkloadIdentityCredential } from "../workloadIdentityCredential.js";
|
||||
import { credentialLogger } from "../../util/logging.js";
|
||||
const msiName = "ManagedIdentityCredential - Token Exchange";
|
||||
const logger = credentialLogger(msiName);
|
||||
/**
|
||||
* Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI.
|
||||
*
|
||||
* Token exchange MSI (used by AKS) is the only MSI implementation handled entirely by Azure Identity.
|
||||
* The rest have been migrated to MSAL.
|
||||
*/
|
||||
export const tokenExchangeMsi = {
|
||||
name: "tokenExchangeMsi",
|
||||
async isAvailable(clientId) {
|
||||
const env = process.env;
|
||||
const result = Boolean((clientId || env.AZURE_CLIENT_ID) &&
|
||||
env.AZURE_TENANT_ID &&
|
||||
process.env.AZURE_FEDERATED_TOKEN_FILE);
|
||||
if (!result) {
|
||||
logger.info(`${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`);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
async getToken(configuration, getTokenOptions = {}) {
|
||||
const { scopes, clientId } = configuration;
|
||||
const identityClientTokenCredentialOptions = {};
|
||||
const workloadIdentityCredential = new WorkloadIdentityCredential(Object.assign(Object.assign({ clientId, tenantId: process.env.AZURE_TENANT_ID, tokenFilePath: process.env.AZURE_FEDERATED_TOKEN_FILE }, identityClientTokenCredentialOptions), { disableInstanceDiscovery: true }));
|
||||
return workloadIdentityCredential.getToken(scopes, getTokenOptions);
|
||||
},
|
||||
};
|
||||
//# sourceMappingURL=tokenExchangeMsi.js.map
|
||||
81
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/utils.js
generated
vendored
Normal file
81
extracted-source/node_modules/@azure/identity/dist/esm/credentials/managedIdentityCredential/utils.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
const DefaultScopeSuffix = "/.default";
|
||||
/**
|
||||
* Error message for Service Fabric Managed Identity environment.
|
||||
*/
|
||||
export const serviceFabricErrorMessage = "Specifying a `clientId` or `resourceId` is not supported by the Service Fabric managed identity environment. The managed identity configuration is determined by the Service Fabric cluster resource configuration. See https://aka.ms/servicefabricmi for more information";
|
||||
/**
|
||||
* Most MSIs send requests to the IMDS endpoint, or a similar endpoint.
|
||||
* These are GET requests that require sending a `resource` parameter on the query.
|
||||
* This resource can be derived from the scopes received through the getToken call, as long as only one scope is received.
|
||||
* Multiple scopes assume that the resulting token will have access to multiple resources, which won't be the case.
|
||||
*
|
||||
* For that reason, when we encounter multiple scopes, we return undefined.
|
||||
* It's up to the individual MSI implementations to throw the errors (which helps us provide less generic errors).
|
||||
*/
|
||||
export function mapScopesToResource(scopes) {
|
||||
let scope = "";
|
||||
if (Array.isArray(scopes)) {
|
||||
if (scopes.length !== 1) {
|
||||
return;
|
||||
}
|
||||
scope = scopes[0];
|
||||
}
|
||||
else if (typeof scopes === "string") {
|
||||
scope = scopes;
|
||||
}
|
||||
if (!scope.endsWith(DefaultScopeSuffix)) {
|
||||
return scope;
|
||||
}
|
||||
return scope.substr(0, scope.lastIndexOf(DefaultScopeSuffix));
|
||||
}
|
||||
/**
|
||||
* Given a token response, return the expiration timestamp as the number of milliseconds from the Unix epoch.
|
||||
* @param body - A parsed response body from the authentication endpoint.
|
||||
*/
|
||||
export function parseExpirationTimestamp(body) {
|
||||
if (typeof body.expires_on === "number") {
|
||||
return body.expires_on * 1000;
|
||||
}
|
||||
if (typeof body.expires_on === "string") {
|
||||
const asNumber = +body.expires_on;
|
||||
if (!isNaN(asNumber)) {
|
||||
return asNumber * 1000;
|
||||
}
|
||||
const asDate = Date.parse(body.expires_on);
|
||||
if (!isNaN(asDate)) {
|
||||
return asDate;
|
||||
}
|
||||
}
|
||||
if (typeof body.expires_in === "number") {
|
||||
return Date.now() + body.expires_in * 1000;
|
||||
}
|
||||
throw new Error(`Failed to parse token expiration from body. expires_in="${body.expires_in}", expires_on="${body.expires_on}"`);
|
||||
}
|
||||
/**
|
||||
* Given a token response, return the expiration timestamp as the number of milliseconds from the Unix epoch.
|
||||
* @param body - A parsed response body from the authentication endpoint.
|
||||
*/
|
||||
export function parseRefreshTimestamp(body) {
|
||||
if (body.refresh_on) {
|
||||
if (typeof body.refresh_on === "number") {
|
||||
return body.refresh_on * 1000;
|
||||
}
|
||||
if (typeof body.refresh_on === "string") {
|
||||
const asNumber = +body.refresh_on;
|
||||
if (!isNaN(asNumber)) {
|
||||
return asNumber * 1000;
|
||||
}
|
||||
const asDate = Date.parse(body.refresh_on);
|
||||
if (!isNaN(asDate)) {
|
||||
return asDate;
|
||||
}
|
||||
}
|
||||
throw new Error(`Failed to parse refresh_on from body. refresh_on="${body.refresh_on}"`);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=utils.js.map
|
||||
Reference in New Issue
Block a user