UNPKG

@azure/msal-browser

Version:
269 lines (252 loc) 10.6 kB
/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { ICrypto, INetworkModule, Logger, AccountInfo, UrlString, ServerTelemetryManager, ServerTelemetryRequest, createClientConfigurationError, ClientConfigurationErrorCodes, Authority, AuthorityOptions, AuthorityFactory, IPerformanceClient, AzureCloudOptions, invokeAsync, StringDict, } from "@azure/msal-common/browser"; import * as BrowserPerformanceEvents from "../telemetry/BrowserPerformanceEvents.js"; import { BrowserConfiguration } from "../config/Configuration.js"; import { BrowserCacheManager } from "../cache/BrowserCacheManager.js"; import { EventHandler } from "../event/EventHandler.js"; import { EndSessionRequest } from "../request/EndSessionRequest.js"; import { RedirectRequest } from "../request/RedirectRequest.js"; import { PopupRequest } from "../request/PopupRequest.js"; import { SsoSilentRequest } from "../request/SsoSilentRequest.js"; import { version } from "../packageMetadata.js"; import { BrowserConstants } from "../utils/BrowserConstants.js"; import * as BrowserUtils from "../utils/BrowserUtils.js"; import { INavigationClient } from "../navigation/INavigationClient.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { ClearCacheRequest } from "../request/ClearCacheRequest.js"; import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; export abstract class BaseInteractionClient { protected config: BrowserConfiguration; protected browserStorage: BrowserCacheManager; protected browserCrypto: ICrypto; protected networkClient: INetworkModule; protected logger: Logger; protected eventHandler: EventHandler; protected navigationClient: INavigationClient; protected platformAuthProvider: IPlatformAuthHandler | undefined; protected correlationId: string; protected performanceClient: IPerformanceClient; constructor( config: BrowserConfiguration, storageImpl: BrowserCacheManager, browserCrypto: ICrypto, logger: Logger, eventHandler: EventHandler, navigationClient: INavigationClient, performanceClient: IPerformanceClient, correlationId: string, platformAuthProvider?: IPlatformAuthHandler ) { this.config = config; this.browserStorage = storageImpl; this.browserCrypto = browserCrypto; this.networkClient = this.config.system.networkClient; this.eventHandler = eventHandler; this.navigationClient = navigationClient; this.platformAuthProvider = platformAuthProvider; this.correlationId = correlationId; this.logger = logger.clone(BrowserConstants.MSAL_SKU, version); this.performanceClient = performanceClient; } abstract acquireToken( request: RedirectRequest | PopupRequest | SsoSilentRequest ): Promise<AuthenticationResult | void>; abstract logout( request: EndSessionRequest | ClearCacheRequest | undefined ): Promise<void>; } /** * Use to get the redirect URI configured in MSAL or construct one from the current page. * @param requestRedirectUri - Redirect URI from the request or undefined if not configured * @param clientConfigRedirectUri - Redirect URI from the client configuration or undefined if not configured * @param logger - Logger instance from the calling client * @param correlationId * @returns Absolute redirect URL constructed from the provided URI, config, or current page */ export function getRedirectUri( requestRedirectUri: string | undefined, clientConfigRedirectUri: string | undefined, logger: Logger, correlationId: string ): string { logger.verbose("getRedirectUri called", correlationId); const redirectUri = requestRedirectUri || clientConfigRedirectUri || ""; return UrlString.getAbsoluteUrl(redirectUri, BrowserUtils.getCurrentUri()); } /** * Initializes and returns a ServerTelemetryManager with the provided telemetry configuration. * @param apiId - The API identifier for telemetry tracking * @param clientId - The client application identifier * @param correlationId - Unique identifier for correlating requests * @param browserStorage - Browser cache manager instance for storing telemetry data * @param logger - Optional logger instance for verbose logging * @param forceRefresh - Optional flag to force refresh of telemetry data * @returns Configured ServerTelemetryManager instance */ export function initializeServerTelemetryManager( apiId: number, clientId: string, correlationId: string, browserStorage: BrowserCacheManager, logger: Logger, forceRefresh?: boolean ): ServerTelemetryManager { logger.verbose("initializeServerTelemetryManager called", correlationId); const telemetryPayload: ServerTelemetryRequest = { clientId: clientId, correlationId: correlationId, apiId: apiId, forceRefresh: forceRefresh || false, wrapperSKU: browserStorage.getWrapperMetadata()[0], wrapperVer: browserStorage.getWrapperMetadata()[1], }; return new ServerTelemetryManager(telemetryPayload, browserStorage); } /** * Used to get a discovered version of the default authority. * @param params - Configuration object containing authority and cloud options * @param params.requestAuthority - Optional specific authority URL to use * @param params.requestAzureCloudOptions - Optional Azure cloud configuration options * @param params.requestExtraQueryParameters - Optional additional query parameters * @param params.account - Optional account info for instance-aware scenarios * @param config - Browser configuration containing auth settings * @param correlationId - Unique identifier for correlating requests * @param performanceClient - Performance monitoring client instance * @param browserStorage - Browser cache manager instance * @param logger - Logger instance for tracking operations * @returns Promise that resolves to a discovered Authority instance */ export async function getDiscoveredAuthority( config: BrowserConfiguration, correlationId: string, performanceClient: IPerformanceClient, browserStorage: BrowserCacheManager, logger: Logger, requestAuthority?: string, requestAzureCloudOptions?: AzureCloudOptions, requestExtraQueryParameters?: StringDict, account?: AccountInfo ): Promise<Authority> { const instanceAwareEQ = requestExtraQueryParameters && requestExtraQueryParameters.hasOwnProperty("instance_aware") ? requestExtraQueryParameters["instance_aware"] : undefined; const authorityOptions: AuthorityOptions = { protocolMode: config.system.protocolMode, OIDCOptions: config.auth.OIDCOptions, knownAuthorities: config.auth.knownAuthorities, cloudDiscoveryMetadata: config.auth.cloudDiscoveryMetadata, authorityMetadata: config.auth.authorityMetadata, }; // build authority string based on auth params, precedence - azureCloudInstance + tenant >> authority const resolvedAuthority = requestAuthority || config.auth.authority; const resolvedInstanceAware = instanceAwareEQ?.length ? instanceAwareEQ === "true" : config.auth.instanceAware; const userAuthority = account && resolvedInstanceAware ? config.auth.authority.replace( UrlString.getDomainFromUrl(resolvedAuthority), account.environment ) : resolvedAuthority; // fall back to the authority from config const builtAuthority = Authority.generateAuthority( userAuthority, requestAzureCloudOptions || config.auth.azureCloudOptions ); const discoveredAuthority = await invokeAsync( AuthorityFactory.createDiscoveredInstance, BrowserPerformanceEvents.AuthorityFactoryCreateDiscoveredInstance, logger, performanceClient, correlationId )( builtAuthority, config.system.networkClient, browserStorage, authorityOptions, logger, correlationId, performanceClient ); if (account && !discoveredAuthority.isAlias(account.environment)) { throw createClientConfigurationError( ClientConfigurationErrorCodes.authorityMismatch ); } return discoveredAuthority; } /** * Clears cache and account information during logout. * * If an account is provided, removes the account from cache and, if it is the active account, sets the active account to null. * If no account is provided, clears all accounts and tokens from cache. * * @param browserStorage - The browser cache manager instance used to manage cache. * @param browserCrypto - The crypto interface for cache operations. * @param logger - Logger instance for logging operations. * @param correlationId - Correlation ID for the logout operation. * @param account - (Optional) The account to clear from cache. If not provided, all accounts are cleared. * @returns A promise that resolves when the cache has been cleared. */ export async function clearCacheOnLogout( browserStorage: BrowserCacheManager, browserCrypto: ICrypto, logger: Logger, correlationId: string, account?: AccountInfo | null ): Promise<void> { if (account) { // Clear given account. try { browserStorage.removeAccount(account, correlationId); logger.verbose( "Cleared cache items belonging to the account provided in the logout request.", correlationId ); } catch (error) { logger.error( "Account provided in logout request was not found. Local cache unchanged.", correlationId ); } } else { try { logger.verbose( "No account provided in logout request, clearing all cache items.", correlationId ); // Clear all accounts and tokens browserStorage.clear(correlationId); // Clear any stray keys from IndexedDB await browserCrypto.clearKeystore(correlationId); } catch (e) { logger.error( "Attempted to clear all MSAL cache items and failed. Local cache unchanged.", correlationId ); } } }