Estructura inicial del proyecto

This commit is contained in:
2026-06-02 16:57:08 +00:00
commit 8b306b9afc
9864 changed files with 1435687 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { Authority, formatAuthorityUri } from "./Authority.js";
import { INetworkModule } from "../network/INetworkModule.js";
import {
createClientAuthError,
ClientAuthErrorCodes,
} from "../error/ClientAuthError.js";
import { ICacheManager } from "../cache/interface/ICacheManager.js";
import { AuthorityOptions } from "./AuthorityOptions.js";
import { Logger } from "../logger/Logger.js";
import { IPerformanceClient } from "../telemetry/performance/IPerformanceClient.js";
import * as PerformanceEvents from "../telemetry/performance/PerformanceEvents.js";
import { invokeAsync } from "../utils/FunctionWrappers.js";
/**
* Create an authority object of the correct type based on the url
* Performs basic authority validation - checks to see if the authority is of a valid type (i.e. aad, b2c, adfs)
*
* Also performs endpoint discovery.
*
* @param authorityUri
* @param networkClient
* @param cacheManager
* @param authorityOptions
* @param logger
* @param correlationId
* @param performanceClient
* @internal
*/
export async function createDiscoveredInstance(
authorityUri: string,
networkClient: INetworkModule,
cacheManager: ICacheManager,
authorityOptions: AuthorityOptions,
logger: Logger,
correlationId: string,
performanceClient: IPerformanceClient
): Promise<Authority> {
const authorityUriFinal = Authority.transformCIAMAuthority(
formatAuthorityUri(authorityUri)
);
// Initialize authority and perform discovery endpoint check.
const acquireTokenAuthority: Authority = new Authority(
authorityUriFinal,
networkClient,
cacheManager,
authorityOptions,
logger,
correlationId,
performanceClient
);
try {
await invokeAsync(
acquireTokenAuthority.resolveEndpointsAsync.bind(
acquireTokenAuthority
),
PerformanceEvents.AuthorityResolveEndpointsAsync,
logger,
performanceClient,
correlationId
)();
return acquireTokenAuthority;
} catch (e) {
throw createClientAuthError(
ClientAuthErrorCodes.endpointResolutionError
);
}
}

View File

@ -0,0 +1,242 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { Logger } from "../logger/Logger.js";
import { UrlString } from "../url/UrlString.js";
import { AuthorityMetadataSource } from "../utils/Constants.js";
import { StaticAuthorityOptions } from "./AuthorityOptions.js";
import { CloudDiscoveryMetadata } from "./CloudDiscoveryMetadata.js";
import { CloudInstanceDiscoveryResponse } from "./CloudInstanceDiscoveryResponse.js";
import { OpenIdConfigResponse } from "./OpenIdConfigResponse.js";
type RawMetadata = {
endpointMetadata: { [key: string]: OpenIdConfigResponse };
instanceDiscoveryMetadata: CloudInstanceDiscoveryResponse;
};
// Build endpoint metadata dynamically to avoid string duplication
const endpointHosts: Array<{ host: string; issuerHost?: string }> = [
{ host: "login.microsoftonline.com" },
{
host: "login.chinacloudapi.cn",
issuerHost: "login.partner.microsoftonline.cn", // Issuer differs
},
{ host: "login.microsoftonline.us" },
{ host: "login.sovcloud-identity.fr" },
{ host: "login.sovcloud-identity.de" },
{ host: "login.sovcloud-identity.sg" },
];
function buildOpenIdConfig(
host: string,
issuerHost: string
): OpenIdConfigResponse {
return {
token_endpoint: `https://${host}/{tenantid}/oauth2/v2.0/token`,
jwks_uri: `https://${host}/{tenantid}/discovery/v2.0/keys`,
issuer: `https://${issuerHost}/{tenantid}/v2.0`,
authorization_endpoint: `https://${host}/{tenantid}/oauth2/v2.0/authorize`,
end_session_endpoint: `https://${host}/{tenantid}/oauth2/v2.0/logout`,
};
}
const dynamicEndpointMetadata: RawMetadata["endpointMetadata"] =
endpointHosts.reduce((acc, { host, issuerHost }) => {
acc[host] = buildOpenIdConfig(host, issuerHost || host);
return acc;
}, {} as Record<string, OpenIdConfigResponse>);
export const rawMetdataJSON: RawMetadata = {
endpointMetadata: dynamicEndpointMetadata,
instanceDiscoveryMetadata: {
tenant_discovery_endpoint:
"https://{canonicalAuthority}/v2.0/.well-known/openid-configuration",
metadata: [
{
preferred_network: "login.microsoftonline.com",
preferred_cache: "login.windows.net",
aliases: [
"login.microsoftonline.com",
"login.windows.net",
"login.microsoft.com",
"sts.windows.net",
],
},
{
preferred_network: "login.partner.microsoftonline.cn",
preferred_cache: "login.partner.microsoftonline.cn",
aliases: [
"login.partner.microsoftonline.cn",
"login.chinacloudapi.cn",
],
},
{
preferred_network: "login.microsoftonline.de",
preferred_cache: "login.microsoftonline.de",
aliases: ["login.microsoftonline.de"],
},
{
preferred_network: "login.microsoftonline.us",
preferred_cache: "login.microsoftonline.us",
aliases: [
"login.microsoftonline.us",
"login.usgovcloudapi.net",
],
},
{
preferred_network: "login-us.microsoftonline.com",
preferred_cache: "login-us.microsoftonline.com",
aliases: ["login-us.microsoftonline.com"],
},
{
preferred_network: "login.sovcloud-identity.fr",
preferred_cache: "login.sovcloud-identity.fr",
aliases: ["login.sovcloud-identity.fr"],
},
{
preferred_network: "login.sovcloud-identity.de",
preferred_cache: "login.sovcloud-identity.de",
aliases: ["login.sovcloud-identity.de"],
},
{
preferred_network: "login.sovcloud-identity.sg",
preferred_cache: "login.sovcloud-identity.sg",
aliases: ["login.sovcloud-identity.sg"],
},
{
preferred_network: "login.windows-ppe.net",
preferred_cache: "login.windows-ppe.net",
aliases: [
"login.windows-ppe.net",
"sts.windows-ppe.net",
"login.microsoft-ppe.com",
],
},
],
},
};
export const EndpointMetadata = rawMetdataJSON.endpointMetadata;
export const InstanceDiscoveryMetadata =
rawMetdataJSON.instanceDiscoveryMetadata;
export const InstanceDiscoveryMetadataAliases: Set<String> = new Set();
InstanceDiscoveryMetadata.metadata.forEach(
(metadataEntry: CloudDiscoveryMetadata) => {
metadataEntry.aliases.forEach((alias: string) => {
InstanceDiscoveryMetadataAliases.add(alias);
});
}
);
/**
* Attempts to get an aliases array from the static authority metadata sources based on the canonical authority host
* @param staticAuthorityOptions
* @param logger
* @returns
*/
export function getAliasesFromStaticSources(
staticAuthorityOptions: StaticAuthorityOptions,
logger: Logger,
correlationId: string
): string[] {
let staticAliases: string[] | undefined;
const canonicalAuthority = staticAuthorityOptions.canonicalAuthority;
if (canonicalAuthority) {
const authorityHost = new UrlString(
canonicalAuthority
).getUrlComponents().HostNameAndPort;
staticAliases =
getAliasesFromMetadata(
logger,
correlationId,
authorityHost,
staticAuthorityOptions.cloudDiscoveryMetadata?.metadata,
AuthorityMetadataSource.CONFIG
) ||
getAliasesFromMetadata(
logger,
correlationId,
authorityHost,
InstanceDiscoveryMetadata.metadata,
AuthorityMetadataSource.HARDCODED_VALUES
) ||
staticAuthorityOptions.knownAuthorities;
}
return staticAliases || [];
}
/**
* Returns aliases for from the raw cloud discovery metadata passed in
* @param authorityHost
* @param rawCloudDiscoveryMetadata
* @returns
*/
export function getAliasesFromMetadata(
logger: Logger,
correlationId: string,
authorityHost?: string,
cloudDiscoveryMetadata?: CloudDiscoveryMetadata[],
source?: AuthorityMetadataSource
): string[] | null {
logger.trace(
`getAliasesFromMetadata called with source: '${source}'`,
correlationId
);
if (authorityHost && cloudDiscoveryMetadata) {
const metadata = getCloudDiscoveryMetadataFromNetworkResponse(
cloudDiscoveryMetadata,
authorityHost
);
if (metadata) {
logger.trace(
`getAliasesFromMetadata: found cloud discovery metadata in '${source}', returning aliases`,
correlationId
);
return metadata.aliases;
} else {
logger.trace(
`getAliasesFromMetadata: did not find cloud discovery metadata in '${source}'`,
correlationId
);
}
}
return null;
}
/**
* Get cloud discovery metadata for common authorities
*/
export function getCloudDiscoveryMetadataFromHardcodedValues(
authorityHost: string
): CloudDiscoveryMetadata | null {
const metadata = getCloudDiscoveryMetadataFromNetworkResponse(
InstanceDiscoveryMetadata.metadata,
authorityHost
);
return metadata;
}
/**
* Searches instance discovery network response for the entry that contains the host in the aliases list
* @param response
* @param authority
*/
export function getCloudDiscoveryMetadataFromNetworkResponse(
response: CloudDiscoveryMetadata[],
authorityHost: string
): CloudDiscoveryMetadata | null {
for (let i = 0; i < response.length; i++) {
const metadata = response[i];
if (metadata.aliases.includes(authorityHost)) {
return metadata;
}
}
return null;
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { ProtocolMode } from "./ProtocolMode.js";
import { OIDCOptions } from "./OIDCOptions.js";
import { AzureRegionConfiguration } from "./AzureRegionConfiguration.js";
import { CloudInstanceDiscoveryResponse } from "./CloudInstanceDiscoveryResponse.js";
export type AuthorityOptions = {
protocolMode: ProtocolMode;
OIDCOptions?: OIDCOptions | null;
knownAuthorities: Array<string>;
cloudDiscoveryMetadata: string;
authorityMetadata: string;
azureRegionConfiguration?: AzureRegionConfiguration;
authority?: string;
};
export type StaticAuthorityOptions = Partial<
Pick<AuthorityOptions, "knownAuthorities">
> & {
canonicalAuthority?: string;
cloudDiscoveryMetadata?: CloudInstanceDiscoveryResponse;
};
export const AzureCloudInstance = {
// AzureCloudInstance is not specified.
None: "none",
// Microsoft Azure public cloud
AzurePublic: "https://login.microsoftonline.com",
// Microsoft PPE
AzurePpe: "https://login.windows-ppe.net",
// Microsoft Chinese national/regional cloud
AzureChina: "https://login.chinacloudapi.cn",
// Microsoft German national/regional cloud ("Black Forest")
AzureGermany: "https://login.microsoftonline.de",
// US Government cloud
AzureUsGovernment: "https://login.microsoftonline.us",
} as const;
export type AzureCloudInstance =
(typeof AzureCloudInstance)[keyof typeof AzureCloudInstance];

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* Authority types supported by MSAL.
*/
export const AuthorityType = {
Default: 0,
Adfs: 1,
Dsts: 2,
Ciam: 3,
} as const;
export type AuthorityType = (typeof AuthorityType)[keyof typeof AuthorityType];

View File

@ -0,0 +1,7 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
// The type here is a string instead of enum as the list of regional end points supported is not final yet.
export type AzureRegion = string;

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { AzureRegion } from "./AzureRegion.js";
/*
* AzureRegionConfiguration
* - preferredAzureRegion - Preferred azure region from the user
* - environmentRegionFunc - Environment specific way of fetching the region from the environment
*/
export type AzureRegionConfiguration = {
azureRegion?: AzureRegion;
environmentRegion: string | undefined;
};

View File

@ -0,0 +1,10 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
export type CloudDiscoveryMetadata = {
preferred_network: string;
preferred_cache: string;
aliases: Array<string>;
};

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* The OpenID Configuration Endpoint Response type. Used by the authority class to get relevant OAuth endpoints.
*/
export type CloudInstanceDiscoveryErrorResponse = {
error: String;
error_description: String;
error_codes?: Array<Number>;
timestamp?: String;
trace_id?: String;
correlation_id?: String;
error_uri?: String;
};
export function isCloudInstanceDiscoveryErrorResponse(
response: object
): boolean {
return (
response.hasOwnProperty("error") &&
response.hasOwnProperty("error_description")
);
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { CloudDiscoveryMetadata } from "./CloudDiscoveryMetadata.js";
/**
* The OpenID Configuration Endpoint Response type. Used by the authority class to get relevant OAuth endpoints.
*/
export type CloudInstanceDiscoveryResponse = {
tenant_discovery_endpoint: string;
metadata: Array<CloudDiscoveryMetadata>;
};
export function isCloudInstanceDiscoveryResponse(response: object): boolean {
return (
response.hasOwnProperty("tenant_discovery_endpoint") &&
response.hasOwnProperty("metadata")
);
}

View File

@ -0,0 +1,10 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
export type ImdsOptions = {
headers?: {
Metadata: string;
};
};

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { ResponseMode } from "../utils/Constants.js";
/**
* Options for the OIDC protocol mode.
*/
export type OIDCOptions = {
responseMode?: ResponseMode;
defaultScopes?: Array<string>;
};

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* Tenant Discovery Response which contains the relevant OAuth endpoints and data needed for authentication and authorization.
*/
export type OpenIdConfigResponse = {
authorization_endpoint: string;
token_endpoint: string;
end_session_endpoint?: string;
issuer: string;
jwks_uri: string;
};
export function isOpenIdConfigResponse(response: object): boolean {
return (
response.hasOwnProperty("authorization_endpoint") &&
response.hasOwnProperty("token_endpoint") &&
response.hasOwnProperty("issuer") &&
response.hasOwnProperty("jwks_uri")
);
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* Protocol modes supported by MSAL.
*/
export const ProtocolMode = {
/**
* Auth Code + PKCE with Entra ID (formerly AAD) specific optimizations and features
*/
AAD: "AAD",
/**
* Auth Code + PKCE without Entra ID specific optimizations and features. For use only with non-Microsoft owned authorities.
* Support is limited for this mode.
*/
OIDC: "OIDC",
/**
* Encrypted Authorize Response (EAR) with Entra ID specific optimizations and features
*/
EAR: "EAR",
} as const;
export type ProtocolMode = (typeof ProtocolMode)[keyof typeof ProtocolMode];

View File

@ -0,0 +1,178 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { INetworkModule } from "../network/INetworkModule.js";
import { NetworkResponse } from "../network/NetworkResponse.js";
import { IMDSBadResponse } from "../response/IMDSBadResponse.js";
import * as Constants from "../utils/Constants.js";
import { RegionDiscoveryMetadata } from "./RegionDiscoveryMetadata.js";
import { ImdsOptions } from "./ImdsOptions.js";
import { IPerformanceClient } from "../telemetry/performance/IPerformanceClient.js";
import * as PerformanceEvents from "../telemetry/performance/PerformanceEvents.js";
import { invokeAsync } from "../utils/FunctionWrappers.js";
import { Logger } from "../logger/Logger.js";
export class RegionDiscovery {
// Network interface to make requests with.
protected networkInterface: INetworkModule;
// Logger
private logger: Logger;
// Performance client
protected performanceClient: IPerformanceClient;
// CorrelationId
protected correlationId: string;
// Options for the IMDS endpoint request
protected static IMDS_OPTIONS: ImdsOptions = {
headers: {
Metadata: "true",
},
};
constructor(
networkInterface: INetworkModule,
logger: Logger,
performanceClient: IPerformanceClient,
correlationId: string
) {
this.networkInterface = networkInterface;
this.logger = logger;
this.performanceClient = performanceClient;
this.correlationId = correlationId;
}
/**
* Detect the region from the application's environment.
*
* @returns Promise<string | null>
*/
public async detectRegion(
environmentRegion: string | undefined,
regionDiscoveryMetadata: RegionDiscoveryMetadata
): Promise<string | null> {
// Initialize auto detected region with the region from the envrionment
let autodetectedRegionName = environmentRegion;
// Check if a region was detected from the environment, if not, attempt to get the region from IMDS
if (!autodetectedRegionName) {
const options = RegionDiscovery.IMDS_OPTIONS;
try {
const localIMDSVersionResponse = await invokeAsync(
this.getRegionFromIMDS.bind(this),
PerformanceEvents.RegionDiscoveryGetRegionFromIMDS,
this.logger,
this.performanceClient,
this.correlationId
)(Constants.IMDS_VERSION, options);
if (
localIMDSVersionResponse.status === Constants.HTTP_SUCCESS
) {
autodetectedRegionName = localIMDSVersionResponse.body;
regionDiscoveryMetadata.region_source =
Constants.RegionDiscoverySources.IMDS;
}
// If the response using the local IMDS version failed, try to fetch the current version of IMDS and retry.
if (
localIMDSVersionResponse.status ===
Constants.HTTP_BAD_REQUEST
) {
const currentIMDSVersion = await invokeAsync(
this.getCurrentVersion.bind(this),
PerformanceEvents.RegionDiscoveryGetCurrentVersion,
this.logger,
this.performanceClient,
this.correlationId
)(options);
if (!currentIMDSVersion) {
regionDiscoveryMetadata.region_source =
Constants.RegionDiscoverySources.FAILED_AUTO_DETECTION;
return null;
}
const currentIMDSVersionResponse = await invokeAsync(
this.getRegionFromIMDS.bind(this),
PerformanceEvents.RegionDiscoveryGetRegionFromIMDS,
this.logger,
this.performanceClient,
this.correlationId
)(currentIMDSVersion, options);
if (
currentIMDSVersionResponse.status ===
Constants.HTTP_SUCCESS
) {
autodetectedRegionName =
currentIMDSVersionResponse.body;
regionDiscoveryMetadata.region_source =
Constants.RegionDiscoverySources.IMDS;
}
}
} catch (e) {
regionDiscoveryMetadata.region_source =
Constants.RegionDiscoverySources.FAILED_AUTO_DETECTION;
return null;
}
} else {
regionDiscoveryMetadata.region_source =
Constants.RegionDiscoverySources.ENVIRONMENT_VARIABLE;
}
// If no region was auto detected from the environment or from the IMDS endpoint, mark the attempt as a FAILED_AUTO_DETECTION
if (!autodetectedRegionName) {
regionDiscoveryMetadata.region_source =
Constants.RegionDiscoverySources.FAILED_AUTO_DETECTION;
}
return autodetectedRegionName || null;
}
/**
* Make the call to the IMDS endpoint
*
* @param imdsEndpointUrl
* @returns Promise<NetworkResponse<string>>
*/
private async getRegionFromIMDS(
version: string,
options: ImdsOptions
): Promise<NetworkResponse<string>> {
return this.networkInterface.sendGetRequestAsync<string>(
`${Constants.IMDS_ENDPOINT}?api-version=${version}&format=text`,
options,
Constants.IMDS_TIMEOUT
);
}
/**
* Get the most recent version of the IMDS endpoint available
*
* @returns Promise<string | null>
*/
private async getCurrentVersion(
options: ImdsOptions
): Promise<string | null> {
try {
const response =
await this.networkInterface.sendGetRequestAsync<IMDSBadResponse>(
`${Constants.IMDS_ENDPOINT}?format=json`,
options
);
// When IMDS endpoint is called without the api version query param, bad request response comes back with latest version.
if (
response.status === Constants.HTTP_BAD_REQUEST &&
response.body &&
response.body["newest-versions"] &&
response.body["newest-versions"].length > 0
) {
return response.body["newest-versions"][0];
}
return null;
} catch (e) {
return null;
}
}
}

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import {
RegionDiscoveryOutcomes,
RegionDiscoverySources,
} from "../utils/Constants.js";
export type RegionDiscoveryMetadata = {
region_used?: string;
region_source?: RegionDiscoverySources;
region_outcome?: RegionDiscoveryOutcomes;
};