Estructura inicial del proyecto
This commit is contained in:
215
backend/node_modules/@azure/msal-browser/src/app/IPublicClientApplication.ts
generated
vendored
Normal file
215
backend/node_modules/@azure/msal-browser/src/app/IPublicClientApplication.ts
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AccountFilter,
|
||||
AccountInfo,
|
||||
Logger,
|
||||
PerformanceCallbackFunction,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { RedirectRequest } from "../request/RedirectRequest.js";
|
||||
import { PopupRequest } from "../request/PopupRequest.js";
|
||||
import { SilentRequest } from "../request/SilentRequest.js";
|
||||
import { SsoSilentRequest } from "../request/SsoSilentRequest.js";
|
||||
import { EndSessionRequest } from "../request/EndSessionRequest.js";
|
||||
import {
|
||||
BrowserConfigurationAuthErrorCodes,
|
||||
createBrowserConfigurationAuthError,
|
||||
} from "../error/BrowserConfigurationAuthError.js";
|
||||
import { WrapperSKU } from "../utils/BrowserConstants.js";
|
||||
import { INavigationClient } from "../navigation/INavigationClient.js";
|
||||
import { EndSessionPopupRequest } from "../request/EndSessionPopupRequest.js";
|
||||
import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js";
|
||||
import { BrowserConfiguration } from "../config/Configuration.js";
|
||||
import { AuthenticationResult } from "../response/AuthenticationResult.js";
|
||||
import { EventCallbackFunction } from "../event/EventMessage.js";
|
||||
import { ClearCacheRequest } from "../request/ClearCacheRequest.js";
|
||||
import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js";
|
||||
import { EventType } from "../event/EventType.js";
|
||||
import { HandleRedirectPromiseOptions } from "../request/HandleRedirectPromiseOptions.js";
|
||||
|
||||
export interface IPublicClientApplication {
|
||||
// TODO: Make request mandatory in the next major version?
|
||||
initialize(request?: InitializeApplicationRequest): Promise<void>;
|
||||
acquireTokenPopup(request: PopupRequest): Promise<AuthenticationResult>;
|
||||
acquireTokenRedirect(request: RedirectRequest): Promise<void>;
|
||||
acquireTokenSilent(
|
||||
silentRequest: SilentRequest
|
||||
): Promise<AuthenticationResult>;
|
||||
acquireTokenByCode(
|
||||
request: AuthorizationCodeRequest
|
||||
): Promise<AuthenticationResult>;
|
||||
addEventCallback(
|
||||
callback: EventCallbackFunction,
|
||||
eventTypes?: Array<EventType>
|
||||
): string | null;
|
||||
removeEventCallback(callbackId: string): void;
|
||||
addPerformanceCallback(callback: PerformanceCallbackFunction): string;
|
||||
removePerformanceCallback(callbackId: string): boolean;
|
||||
getAccount(accountFilter: AccountFilter): AccountInfo | null;
|
||||
getAllAccounts(accountFilter?: AccountFilter): AccountInfo[];
|
||||
handleRedirectPromise(
|
||||
options?: HandleRedirectPromiseOptions
|
||||
): Promise<AuthenticationResult | null>;
|
||||
loginPopup(request?: PopupRequest): Promise<AuthenticationResult>;
|
||||
loginRedirect(request?: RedirectRequest): Promise<void>;
|
||||
logoutRedirect(logoutRequest?: EndSessionRequest): Promise<void>;
|
||||
logoutPopup(logoutRequest?: EndSessionPopupRequest): Promise<void>;
|
||||
ssoSilent(request: SsoSilentRequest): Promise<AuthenticationResult>;
|
||||
getLogger(): Logger;
|
||||
setLogger(logger: Logger): void;
|
||||
setActiveAccount(account: AccountInfo | null): void;
|
||||
getActiveAccount(): AccountInfo | null;
|
||||
initializeWrapperLibrary(sku: WrapperSKU, version: string): void;
|
||||
setNavigationClient(navigationClient: INavigationClient): void;
|
||||
/** @internal */
|
||||
getConfiguration(): BrowserConfiguration;
|
||||
hydrateCache(
|
||||
result: AuthenticationResult,
|
||||
request:
|
||||
| SilentRequest
|
||||
| SsoSilentRequest
|
||||
| RedirectRequest
|
||||
| PopupRequest
|
||||
): Promise<void>;
|
||||
clearCache(logoutRequest?: ClearCacheRequest): Promise<void>;
|
||||
}
|
||||
|
||||
export const stubbedPublicClientApplication: IPublicClientApplication = {
|
||||
initialize: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
acquireTokenPopup: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
acquireTokenRedirect: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
acquireTokenSilent: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
acquireTokenByCode: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
getAllAccounts: () => {
|
||||
return [];
|
||||
},
|
||||
getAccount: () => {
|
||||
return null;
|
||||
},
|
||||
handleRedirectPromise: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
loginPopup: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
loginRedirect: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
logoutRedirect: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
logoutPopup: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
ssoSilent: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
addEventCallback: () => {
|
||||
return null;
|
||||
},
|
||||
removeEventCallback: () => {
|
||||
return;
|
||||
},
|
||||
addPerformanceCallback: () => {
|
||||
return "";
|
||||
},
|
||||
removePerformanceCallback: () => {
|
||||
return false;
|
||||
},
|
||||
getLogger: () => {
|
||||
throw createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
);
|
||||
},
|
||||
setLogger: () => {
|
||||
return;
|
||||
},
|
||||
setActiveAccount: () => {
|
||||
return;
|
||||
},
|
||||
getActiveAccount: () => {
|
||||
return null;
|
||||
},
|
||||
initializeWrapperLibrary: () => {
|
||||
return;
|
||||
},
|
||||
setNavigationClient: () => {
|
||||
return;
|
||||
},
|
||||
getConfiguration: () => {
|
||||
throw createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
);
|
||||
},
|
||||
hydrateCache: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
clearCache: () => {
|
||||
return Promise.reject(
|
||||
createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.stubbedPublicClientApplicationCalled
|
||||
)
|
||||
);
|
||||
},
|
||||
};
|
||||
398
backend/node_modules/@azure/msal-browser/src/app/PublicClientApplication.ts
generated
vendored
Normal file
398
backend/node_modules/@azure/msal-browser/src/app/PublicClientApplication.ts
generated
vendored
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { INavigationClient } from "../navigation/INavigationClient.js";
|
||||
import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js";
|
||||
import { PopupRequest } from "../request/PopupRequest.js";
|
||||
import { RedirectRequest } from "../request/RedirectRequest.js";
|
||||
import { SilentRequest } from "../request/SilentRequest.js";
|
||||
import { WrapperSKU } from "../utils/BrowserConstants.js";
|
||||
import { IPublicClientApplication } from "./IPublicClientApplication.js";
|
||||
import { IController } from "../controllers/IController.js";
|
||||
import {
|
||||
PerformanceCallbackFunction,
|
||||
AccountInfo,
|
||||
AccountFilter,
|
||||
Logger,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { EndSessionRequest } from "../request/EndSessionRequest.js";
|
||||
import { SsoSilentRequest } from "../request/SsoSilentRequest.js";
|
||||
import { StandardController } from "../controllers/StandardController.js";
|
||||
import {
|
||||
BrowserConfiguration,
|
||||
Configuration,
|
||||
} from "../config/Configuration.js";
|
||||
import { StandardOperatingContext } from "../operatingcontext/StandardOperatingContext.js";
|
||||
import { AuthenticationResult } from "../response/AuthenticationResult.js";
|
||||
import { EventCallbackFunction } from "../event/EventMessage.js";
|
||||
import { ClearCacheRequest } from "../request/ClearCacheRequest.js";
|
||||
import { EndSessionPopupRequest } from "../request/EndSessionPopupRequest.js";
|
||||
import { NestedAppAuthController } from "../controllers/NestedAppAuthController.js";
|
||||
import { NestedAppOperatingContext } from "../operatingcontext/NestedAppOperatingContext.js";
|
||||
import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js";
|
||||
import { EventType } from "../event/EventType.js";
|
||||
import { createNewGuid } from "../crypto/BrowserCrypto.js";
|
||||
import { HandleRedirectPromiseOptions } from "../request/HandleRedirectPromiseOptions.js";
|
||||
|
||||
/**
|
||||
* The PublicClientApplication class is the object exposed by the library to perform authentication and authorization functions in Single Page Applications
|
||||
* to obtain JWT tokens as described in the OAuth 2.0 Authorization Code Flow with PKCE specification.
|
||||
*/
|
||||
export class PublicClientApplication implements IPublicClientApplication {
|
||||
protected controller: IController;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* Constructor for the PublicClientApplication used to instantiate the PublicClientApplication object
|
||||
*
|
||||
* Important attributes in the Configuration object for auth are:
|
||||
* - clientID: the application ID of your application. You can obtain one by registering your application with our Application registration portal : https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview
|
||||
* - authority: the authority URL for your application.
|
||||
* - redirect_uri: the uri of your application registered in the portal.
|
||||
*
|
||||
* In Azure AD, authority is a URL indicating the Azure active directory that MSAL uses to obtain tokens.
|
||||
* It is of the form https://login.microsoftonline.com/{Enter_the_Tenant_Info_Here}
|
||||
* If your application supports Accounts in one organizational directory, replace "Enter_the_Tenant_Info_Here" value with the Tenant Id or Tenant name (for example, contoso.microsoft.com).
|
||||
* If your application supports Accounts in any organizational directory, replace "Enter_the_Tenant_Info_Here" value with organizations.
|
||||
* If your application supports Accounts in any organizational directory and personal Microsoft accounts, replace "Enter_the_Tenant_Info_Here" value with common.
|
||||
* To restrict support to Personal Microsoft accounts only, replace "Enter_the_Tenant_Info_Here" value with consumers.
|
||||
*
|
||||
* In Azure B2C, authority is of the form https://{instance}/tfp/{tenant}/{policyName}/
|
||||
* Full B2C functionality will be available in this library in future versions.
|
||||
*
|
||||
* @param configuration Object for the MSAL PublicClientApplication instance
|
||||
* @param IController Optional parameter to explictly set the controller. (Will be removed when we remove public constructor)
|
||||
*/
|
||||
public constructor(configuration: Configuration, controller?: IController) {
|
||||
this.controller =
|
||||
controller ||
|
||||
new StandardController(new StandardOperatingContext(configuration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializer function to perform async startup tasks such as connecting to WAM extension
|
||||
* @param request {?InitializeApplicationRequest}
|
||||
*/
|
||||
async initialize(request?: InitializeApplicationRequest): Promise<void> {
|
||||
return this.controller.initialize(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use when you want to obtain an access_token for your API via opening a popup window in the user's browser
|
||||
*
|
||||
* @param request
|
||||
*
|
||||
* @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised.
|
||||
*/
|
||||
async acquireTokenPopup(
|
||||
request: PopupRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
return this.controller.acquireTokenPopup(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use when you want to obtain an access_token for your API by redirecting the user's browser window to the authorization endpoint. This function redirects
|
||||
* the page, so any code that follows this function will not execute.
|
||||
*
|
||||
* IMPORTANT: It is NOT recommended to have code that is dependent on the resolution of the Promise. This function will navigate away from the current
|
||||
* browser window. It currently returns a Promise in order to reflect the asynchronous nature of the code running in this function.
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
acquireTokenRedirect(request: RedirectRequest): Promise<void> {
|
||||
return this.controller.acquireTokenRedirect(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Silently acquire an access token for a given set of scopes. Returns currently processing promise if parallel requests are made.
|
||||
*
|
||||
* @param {@link (SilentRequest:type)}
|
||||
* @returns {Promise.<AuthenticationResult>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthenticationResult} object
|
||||
*/
|
||||
acquireTokenSilent(
|
||||
silentRequest: SilentRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
return this.controller.acquireTokenSilent(silentRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function redeems an authorization code (passed as code) from the eSTS token endpoint.
|
||||
* This authorization code should be acquired server-side using a confidential client to acquire a spa_code.
|
||||
* This API is not indended for normal authorization code acquisition and redemption.
|
||||
*
|
||||
* Redemption of this authorization code will not require PKCE, as it was acquired by a confidential client.
|
||||
*
|
||||
* @param request {@link AuthorizationCodeRequest}
|
||||
* @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised.
|
||||
*/
|
||||
acquireTokenByCode(
|
||||
request: AuthorizationCodeRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
return this.controller.acquireTokenByCode(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds event callbacks to array
|
||||
* @param callback
|
||||
* @param eventTypes
|
||||
*/
|
||||
addEventCallback(
|
||||
callback: EventCallbackFunction,
|
||||
eventTypes?: Array<EventType>
|
||||
): string | null {
|
||||
return this.controller.addEventCallback(callback, eventTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes callback with provided id from callback array
|
||||
* @param callbackId
|
||||
*/
|
||||
removeEventCallback(callbackId: string): void {
|
||||
return this.controller.removeEventCallback(callbackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback to receive performance events.
|
||||
*
|
||||
* @param {PerformanceCallbackFunction} callback
|
||||
* @returns {string}
|
||||
*/
|
||||
addPerformanceCallback(callback: PerformanceCallbackFunction): string {
|
||||
return this.controller.addPerformanceCallback(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a callback registered with addPerformanceCallback.
|
||||
*
|
||||
* @param {string} callbackId
|
||||
* @returns {boolean}
|
||||
*/
|
||||
removePerformanceCallback(callbackId: string): boolean {
|
||||
return this.controller.removePerformanceCallback(callbackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first account found in the cache that matches the account filter passed in.
|
||||
* @param accountFilter
|
||||
* @returns The first account found in the cache matching the provided filter or null if no account could be found.
|
||||
*/
|
||||
getAccount(accountFilter: AccountFilter): AccountInfo | null {
|
||||
return this.controller.getAccount(accountFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the accounts in the cache that match the optional filter. If no filter is provided, all accounts are returned.
|
||||
* @param accountFilter - (Optional) filter to narrow down the accounts returned
|
||||
* @returns Array of AccountInfo objects in cache
|
||||
*/
|
||||
getAllAccounts(accountFilter?: AccountFilter): AccountInfo[] {
|
||||
return this.controller.getAllAccounts(accountFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler function which allows users to fire events after the PublicClientApplication object
|
||||
* has loaded during redirect flows. This should be invoked on all page loads involved in redirect
|
||||
* auth flows.
|
||||
* @param hash Hash to process. Defaults to the current value of window.location.hash. Only needs to be provided explicitly if the response to be handled is not contained in the current value.
|
||||
* @param options Object containing optional configuration for redirect promise handling.
|
||||
* @returns Token response or null. If the return value is null, then no auth redirect was detected.
|
||||
*/
|
||||
handleRedirectPromise(
|
||||
options?: HandleRedirectPromiseOptions
|
||||
): Promise<AuthenticationResult | null> {
|
||||
return this.controller.handleRedirectPromise(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use when initiating the login process via opening a popup window in the user's browser
|
||||
*
|
||||
* @param request
|
||||
*
|
||||
* @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised.
|
||||
*/
|
||||
loginPopup(
|
||||
request?: PopupRequest | undefined
|
||||
): Promise<AuthenticationResult> {
|
||||
return this.controller.loginPopup(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use when initiating the login process by redirecting the user's browser to the authorization endpoint. This function redirects the page, so
|
||||
* any code that follows this function will not execute.
|
||||
*
|
||||
* IMPORTANT: It is NOT recommended to have code that is dependent on the resolution of the Promise. This function will navigate away from the current
|
||||
* browser window. It currently returns a Promise in order to reflect the asynchronous nature of the code running in this function.
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
loginRedirect(request?: RedirectRequest | undefined): Promise<void> {
|
||||
return this.controller.loginRedirect(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to log out the current user, and redirect the user to the postLogoutRedirectUri.
|
||||
* Default behaviour is to redirect the user to `window.location.href`.
|
||||
* @param logoutRequest
|
||||
*/
|
||||
logoutRedirect(logoutRequest?: EndSessionRequest): Promise<void> {
|
||||
return this.controller.logoutRedirect(logoutRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears local cache for the current user then opens a popup window prompting the user to sign-out of the server
|
||||
* @param logoutRequest
|
||||
*/
|
||||
logoutPopup(logoutRequest?: EndSessionPopupRequest): Promise<void> {
|
||||
return this.controller.logoutPopup(logoutRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function uses a hidden iframe to fetch an authorization code from the eSTS. There are cases where this may not work:
|
||||
* - Any browser using a form of Intelligent Tracking Prevention
|
||||
* - If there is not an established session with the service
|
||||
*
|
||||
* In these cases, the request must be done inside a popup or full frame redirect.
|
||||
*
|
||||
* For the cases where interaction is required, you cannot send a request with prompt=none.
|
||||
*
|
||||
* If your refresh token has expired, you can use this function to fetch a new set of tokens silently as long as
|
||||
* you session on the server still exists.
|
||||
* @param request {@link SsoSilentRequest}
|
||||
*
|
||||
* @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised.
|
||||
*/
|
||||
ssoSilent(request: SsoSilentRequest): Promise<AuthenticationResult> {
|
||||
return this.controller.ssoSilent(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logger instance
|
||||
*/
|
||||
getLogger(): Logger {
|
||||
return this.controller.getLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the default logger set in configurations with new Logger with new configurations
|
||||
* @param logger Logger instance
|
||||
*/
|
||||
setLogger(logger: Logger): void {
|
||||
this.controller.setLogger(logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the account to use as the active account. If no account is passed to the acquireToken APIs, then MSAL will use this active account.
|
||||
* @param account
|
||||
*/
|
||||
setActiveAccount(account: AccountInfo | null): void {
|
||||
this.controller.setActiveAccount(account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently active account
|
||||
*/
|
||||
getActiveAccount(): AccountInfo | null {
|
||||
return this.controller.getActiveAccount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by wrapper libraries (Angular & React) to set SKU and Version passed down to telemetry, logger, etc.
|
||||
* @param sku
|
||||
* @param version
|
||||
*/
|
||||
initializeWrapperLibrary(sku: WrapperSKU, version: string): void {
|
||||
return this.controller.initializeWrapperLibrary(sku, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets navigation client
|
||||
* @param navigationClient
|
||||
*/
|
||||
setNavigationClient(navigationClient: INavigationClient): void {
|
||||
this.controller.setNavigationClient(navigationClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration object
|
||||
* @internal
|
||||
*/
|
||||
getConfiguration(): BrowserConfiguration {
|
||||
return this.controller.getConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates cache with the tokens and account in the AuthenticationResult object
|
||||
* @param result
|
||||
* @param request - The request object that was used to obtain the AuthenticationResult
|
||||
* @returns
|
||||
*/
|
||||
async hydrateCache(
|
||||
result: AuthenticationResult,
|
||||
request:
|
||||
| SilentRequest
|
||||
| SsoSilentRequest
|
||||
| RedirectRequest
|
||||
| PopupRequest
|
||||
): Promise<void> {
|
||||
return this.controller.hydrateCache(result, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears tokens and account from the browser cache.
|
||||
* @param logoutRequest
|
||||
*/
|
||||
clearCache(logoutRequest?: ClearCacheRequest): Promise<void> {
|
||||
return this.controller.clearCache(logoutRequest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* creates NestedAppAuthController and passes it to the PublicClientApplication,
|
||||
* falls back to StandardController if NestedAppAuthController is not available
|
||||
*
|
||||
* @param configuration
|
||||
* @param correlationId
|
||||
* @param pcaFactory
|
||||
* @returns IPublicClientApplication
|
||||
*
|
||||
*/
|
||||
export async function createNestablePublicClientApplication(
|
||||
configuration: Configuration,
|
||||
correlationId?: string,
|
||||
pcaFactory?: (
|
||||
configuration: Configuration,
|
||||
controller: IController
|
||||
) => IPublicClientApplication
|
||||
): Promise<IPublicClientApplication> {
|
||||
const nestedAppAuth = new NestedAppOperatingContext(configuration);
|
||||
await nestedAppAuth.initialize(correlationId);
|
||||
|
||||
if (nestedAppAuth.isAvailable()) {
|
||||
const cid = correlationId || createNewGuid();
|
||||
const controller = new NestedAppAuthController(nestedAppAuth);
|
||||
const nestablePCA = pcaFactory
|
||||
? pcaFactory(configuration, controller)
|
||||
: new PublicClientApplication(configuration, controller);
|
||||
await nestablePCA.initialize({ correlationId: cid });
|
||||
return nestablePCA;
|
||||
}
|
||||
|
||||
return createStandardPublicClientApplication(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates PublicClientApplication using StandardController
|
||||
*
|
||||
* @param configuration
|
||||
* @returns IPublicClientApplication
|
||||
*
|
||||
*/
|
||||
export async function createStandardPublicClientApplication(
|
||||
configuration: Configuration
|
||||
): Promise<IPublicClientApplication> {
|
||||
const pca = new PublicClientApplication(configuration);
|
||||
await pca.initialize();
|
||||
return pca;
|
||||
}
|
||||
17
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { PlatformAuthRequest } from "./PlatformAuthRequest.js";
|
||||
import { PlatformAuthResponse } from "./PlatformAuthResponse.js";
|
||||
|
||||
/**
|
||||
* Interface for the Platform Broker Handlers
|
||||
*/
|
||||
export interface IPlatformAuthHandler {
|
||||
getExtensionId(): string | undefined;
|
||||
getExtensionVersion(): string | undefined;
|
||||
getExtensionName(): string | undefined;
|
||||
sendMessage(request: PlatformAuthRequest): Promise<PlatformAuthResponse>;
|
||||
}
|
||||
14
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts
generated
vendored
Normal file
14
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
// Status Codes that can be thrown by WAM
|
||||
export const USER_INTERACTION_REQUIRED = "USER_INTERACTION_REQUIRED";
|
||||
export const USER_CANCEL = "USER_CANCEL";
|
||||
export const NO_NETWORK = "NO_NETWORK";
|
||||
export const TRANSIENT_ERROR = "TRANSIENT_ERROR";
|
||||
export const PERSISTENT_ERROR = "PERSISTENT_ERROR";
|
||||
export const DISABLED = "DISABLED";
|
||||
export const ACCOUNT_UNAVAILABLE = "ACCOUNT_UNAVAILABLE";
|
||||
export const UX_NOT_ALLOWED = "UX_NOT_ALLOWED";
|
||||
281
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts
generated
vendored
Normal file
281
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts
generated
vendored
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Logger,
|
||||
createAuthError,
|
||||
AuthErrorCodes,
|
||||
IPerformanceClient,
|
||||
StringDict,
|
||||
} from "@azure/msal-common/browser";
|
||||
import {
|
||||
DOMExtraParameters,
|
||||
PlatformAuthRequest,
|
||||
PlatformDOMTokenRequest,
|
||||
} from "./PlatformAuthRequest.js";
|
||||
import { PlatformAuthConstants } from "../../utils/BrowserConstants.js";
|
||||
import {
|
||||
PlatformAuthResponse,
|
||||
PlatformDOMTokenResponse,
|
||||
} from "./PlatformAuthResponse.js";
|
||||
import { createNativeAuthError } from "../../error/NativeAuthError.js";
|
||||
import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js";
|
||||
|
||||
export class PlatformAuthDOMHandler implements IPlatformAuthHandler {
|
||||
protected logger: Logger;
|
||||
protected performanceClient: IPerformanceClient;
|
||||
protected correlationId: string;
|
||||
platformAuthType: string;
|
||||
|
||||
constructor(
|
||||
logger: Logger,
|
||||
performanceClient: IPerformanceClient,
|
||||
correlationId: string
|
||||
) {
|
||||
this.logger = logger;
|
||||
this.performanceClient = performanceClient;
|
||||
this.correlationId = correlationId;
|
||||
this.platformAuthType = PlatformAuthConstants.PLATFORM_DOM_PROVIDER;
|
||||
}
|
||||
|
||||
static async createProvider(
|
||||
logger: Logger,
|
||||
performanceClient: IPerformanceClient,
|
||||
correlationId: string
|
||||
): Promise<PlatformAuthDOMHandler | undefined> {
|
||||
logger.trace(
|
||||
"PlatformAuthDOMHandler: createProvider called",
|
||||
correlationId
|
||||
);
|
||||
|
||||
// @ts-ignore
|
||||
if (window.navigator?.platformAuthentication) {
|
||||
const supportedContracts =
|
||||
// @ts-ignore
|
||||
await window.navigator.platformAuthentication.getSupportedContracts(
|
||||
PlatformAuthConstants.MICROSOFT_ENTRA_BROKERID
|
||||
);
|
||||
if (
|
||||
supportedContracts?.includes(
|
||||
PlatformAuthConstants.PLATFORM_DOM_APIS
|
||||
)
|
||||
) {
|
||||
logger.trace(
|
||||
"Platform auth api available in DOM",
|
||||
correlationId
|
||||
);
|
||||
return new PlatformAuthDOMHandler(
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id for the broker extension this handler is communicating with
|
||||
* @returns
|
||||
*/
|
||||
getExtensionId(): string {
|
||||
return PlatformAuthConstants.MICROSOFT_ENTRA_BROKERID;
|
||||
}
|
||||
|
||||
getExtensionVersion(): string | undefined {
|
||||
return "";
|
||||
}
|
||||
|
||||
getExtensionName(): string | undefined {
|
||||
return PlatformAuthConstants.DOM_API_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send token request to platform broker via browser DOM API
|
||||
* @param request
|
||||
* @returns
|
||||
*/
|
||||
async sendMessage(
|
||||
request: PlatformAuthRequest
|
||||
): Promise<PlatformAuthResponse> {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - Sending request to browser DOM API`,
|
||||
request.correlationId
|
||||
);
|
||||
|
||||
try {
|
||||
const platformDOMRequest: PlatformDOMTokenRequest =
|
||||
this.initializePlatformDOMRequest(request);
|
||||
const response: object =
|
||||
// @ts-ignore
|
||||
await window.navigator.platformAuthentication.executeGetToken(
|
||||
platformDOMRequest
|
||||
);
|
||||
return this.validatePlatformBrokerResponse(
|
||||
response,
|
||||
request.correlationId
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(
|
||||
`'${this.platformAuthType}' - executeGetToken DOM API error`,
|
||||
request.correlationId
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private initializePlatformDOMRequest(
|
||||
request: PlatformAuthRequest
|
||||
): PlatformDOMTokenRequest {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - initializeNativeDOMRequest called`,
|
||||
request.correlationId
|
||||
);
|
||||
|
||||
const {
|
||||
accountId,
|
||||
clientId,
|
||||
authority,
|
||||
scope,
|
||||
redirectUri,
|
||||
correlationId,
|
||||
state,
|
||||
storeInCache,
|
||||
embeddedClientId,
|
||||
extraParameters,
|
||||
...remainingProperties
|
||||
} = request;
|
||||
|
||||
const validExtraParameters: DOMExtraParameters = this.getDOMExtraParams(
|
||||
remainingProperties,
|
||||
correlationId
|
||||
);
|
||||
|
||||
const platformDOMRequest: PlatformDOMTokenRequest = {
|
||||
accountId: accountId,
|
||||
brokerId: this.getExtensionId(),
|
||||
authority: authority,
|
||||
clientId: clientId,
|
||||
correlationId: correlationId || this.correlationId,
|
||||
extraParameters: {
|
||||
...extraParameters,
|
||||
...validExtraParameters,
|
||||
},
|
||||
isSecurityTokenService: false,
|
||||
redirectUri: redirectUri,
|
||||
scope: scope,
|
||||
state: state,
|
||||
storeInCache: storeInCache,
|
||||
embeddedClientId: embeddedClientId,
|
||||
};
|
||||
|
||||
return platformDOMRequest;
|
||||
}
|
||||
|
||||
private validatePlatformBrokerResponse(
|
||||
response: object,
|
||||
correlationId: string
|
||||
): PlatformAuthResponse {
|
||||
if (response.hasOwnProperty("isSuccess")) {
|
||||
if (
|
||||
response.hasOwnProperty("accessToken") &&
|
||||
response.hasOwnProperty("idToken") &&
|
||||
response.hasOwnProperty("clientInfo") &&
|
||||
response.hasOwnProperty("account") &&
|
||||
response.hasOwnProperty("scopes") &&
|
||||
response.hasOwnProperty("expiresIn")
|
||||
) {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - platform broker returned successful and valid response`,
|
||||
correlationId
|
||||
);
|
||||
return this.convertToPlatformBrokerResponse(
|
||||
response as PlatformDOMTokenResponse,
|
||||
correlationId
|
||||
);
|
||||
} else if (response.hasOwnProperty("error")) {
|
||||
const errorResponse = response as PlatformDOMTokenResponse;
|
||||
if (
|
||||
errorResponse.isSuccess === false &&
|
||||
errorResponse.error &&
|
||||
errorResponse.error.code
|
||||
) {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - platform broker returned error response`,
|
||||
correlationId
|
||||
);
|
||||
throw createNativeAuthError(
|
||||
errorResponse.error.code,
|
||||
errorResponse.error.description,
|
||||
{
|
||||
error: parseInt(errorResponse.error.errorCode),
|
||||
protocol_error: errorResponse.error.protocolError,
|
||||
status: errorResponse.error.status,
|
||||
properties: errorResponse.error.properties,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw createAuthError(
|
||||
AuthErrorCodes.unexpectedError,
|
||||
"Response missing expected properties."
|
||||
);
|
||||
}
|
||||
|
||||
private convertToPlatformBrokerResponse(
|
||||
response: PlatformDOMTokenResponse,
|
||||
correlationId: string
|
||||
): PlatformAuthResponse {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - convertToNativeResponse called`,
|
||||
correlationId
|
||||
);
|
||||
const nativeResponse: PlatformAuthResponse = {
|
||||
access_token: response.accessToken,
|
||||
id_token: response.idToken,
|
||||
client_info: response.clientInfo,
|
||||
account: response.account,
|
||||
expires_in: response.expiresIn,
|
||||
scope: response.scopes,
|
||||
state: response.state || "",
|
||||
properties: response.properties || {},
|
||||
extendedLifetimeToken: response.extendedLifetimeToken ?? false,
|
||||
shr: response.proofOfPossessionPayload,
|
||||
};
|
||||
|
||||
return nativeResponse;
|
||||
}
|
||||
|
||||
private getDOMExtraParams(
|
||||
extraParameters: Record<string, unknown>,
|
||||
correlationId: string
|
||||
): DOMExtraParameters {
|
||||
try {
|
||||
const stringifiedProperties: StringDict = {};
|
||||
for (const [key, value] of Object.entries(extraParameters)) {
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
stringifiedProperties[key] = JSON.stringify(value);
|
||||
} else {
|
||||
stringifiedProperties[key] = String(value);
|
||||
}
|
||||
}
|
||||
return stringifiedProperties;
|
||||
} catch (e) {
|
||||
this.logger.error(
|
||||
`'${this.platformAuthType}' - Error stringifying extra parameters`,
|
||||
correlationId
|
||||
);
|
||||
this.logger.errorPii(
|
||||
`'${this.platformAuthType}' - Error stringifying extra parameters: '${e}'`,
|
||||
correlationId
|
||||
);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
452
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts
generated
vendored
Normal file
452
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts
generated
vendored
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
PlatformAuthConstants,
|
||||
NativeExtensionMethod,
|
||||
} from "../../utils/BrowserConstants.js";
|
||||
import {
|
||||
Logger,
|
||||
AuthError,
|
||||
createAuthError,
|
||||
AuthErrorCodes,
|
||||
InProgressPerformanceEvent,
|
||||
IPerformanceClient,
|
||||
} from "@azure/msal-common/browser";
|
||||
import * as BrowserPerformanceEvents from "../../telemetry/BrowserPerformanceEvents.js";
|
||||
import {
|
||||
NativeExtensionRequest,
|
||||
NativeExtensionRequestBody,
|
||||
PlatformAuthRequest,
|
||||
} from "./PlatformAuthRequest.js";
|
||||
import { createNativeAuthError } from "../../error/NativeAuthError.js";
|
||||
import {
|
||||
createBrowserAuthError,
|
||||
BrowserAuthErrorCodes,
|
||||
} from "../../error/BrowserAuthError.js";
|
||||
import { createNewGuid } from "../../crypto/BrowserCrypto.js";
|
||||
import { PlatformAuthResponse } from "./PlatformAuthResponse.js";
|
||||
import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js";
|
||||
import { createGuid } from "../../utils/BrowserUtils.js";
|
||||
|
||||
type ResponseResolvers<T> = {
|
||||
resolve: (value: T | PromiseLike<T>) => void;
|
||||
reject: (
|
||||
value: AuthError | Error | PromiseLike<Error> | PromiseLike<AuthError>
|
||||
) => void;
|
||||
};
|
||||
|
||||
export class PlatformAuthExtensionHandler implements IPlatformAuthHandler {
|
||||
private extensionId: string | undefined;
|
||||
private extensionVersion: string | undefined;
|
||||
private logger: Logger;
|
||||
private readonly handshakeTimeoutMs: number;
|
||||
private timeoutId: number | undefined;
|
||||
private resolvers: Map<string, ResponseResolvers<object>>;
|
||||
private handshakeResolvers: Map<string, ResponseResolvers<void>>;
|
||||
private messageChannel: MessageChannel;
|
||||
private readonly windowListener: (event: MessageEvent) => void;
|
||||
private readonly performanceClient: IPerformanceClient;
|
||||
private readonly handshakeEvent: InProgressPerformanceEvent;
|
||||
platformAuthType: string;
|
||||
|
||||
constructor(
|
||||
logger: Logger,
|
||||
handshakeTimeoutMs: number,
|
||||
performanceClient: IPerformanceClient,
|
||||
extensionId?: string
|
||||
) {
|
||||
this.logger = logger;
|
||||
this.handshakeTimeoutMs = handshakeTimeoutMs;
|
||||
this.extensionId = extensionId;
|
||||
this.resolvers = new Map(); // Used for non-handshake messages
|
||||
this.handshakeResolvers = new Map(); // Used for handshake messages
|
||||
this.messageChannel = new MessageChannel();
|
||||
this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound
|
||||
this.performanceClient = performanceClient;
|
||||
this.handshakeEvent = this.performanceClient.startMeasurement(
|
||||
BrowserPerformanceEvents.NativeMessageHandlerHandshake
|
||||
);
|
||||
this.platformAuthType =
|
||||
PlatformAuthConstants.PLATFORM_EXTENSION_PROVIDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a given message to the extension and resolves with the extension response
|
||||
* @param request
|
||||
*/
|
||||
async sendMessage(
|
||||
request: PlatformAuthRequest
|
||||
): Promise<PlatformAuthResponse> {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - sendMessage called.`,
|
||||
request.correlationId
|
||||
);
|
||||
|
||||
// fall back to native calls
|
||||
const messageBody: NativeExtensionRequestBody = {
|
||||
method: NativeExtensionMethod.GetToken,
|
||||
request: request,
|
||||
};
|
||||
|
||||
const req: NativeExtensionRequest = {
|
||||
channel: PlatformAuthConstants.CHANNEL_ID,
|
||||
extensionId: this.extensionId,
|
||||
responseId: createNewGuid(),
|
||||
body: messageBody,
|
||||
};
|
||||
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - Sending request to browser extension`,
|
||||
request.correlationId
|
||||
);
|
||||
this.logger.tracePii(
|
||||
`'${
|
||||
this.platformAuthType
|
||||
}' - Sending request to browser extension: '${JSON.stringify(
|
||||
req
|
||||
)}'`,
|
||||
request.correlationId
|
||||
);
|
||||
this.messageChannel.port1.postMessage(req);
|
||||
|
||||
const response: object = await new Promise((resolve, reject) => {
|
||||
this.resolvers.set(req.responseId, { resolve, reject });
|
||||
});
|
||||
|
||||
const validatedResponse: PlatformAuthResponse =
|
||||
this.validatePlatformBrokerResponse(response);
|
||||
|
||||
return validatedResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the MessageHandler that has successfully established a connection with an extension
|
||||
* @param {Logger} logger
|
||||
* @param {number} handshakeTimeoutMs
|
||||
* @param {IPerformanceClient} performanceClient
|
||||
* @param {ICrypto} crypto
|
||||
*/
|
||||
static async createProvider(
|
||||
logger: Logger,
|
||||
handshakeTimeoutMs: number,
|
||||
performanceClient: IPerformanceClient,
|
||||
correlationId: string
|
||||
): Promise<PlatformAuthExtensionHandler> {
|
||||
logger.trace(
|
||||
"PlatformAuthExtensionHandler - createProvider called.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
try {
|
||||
const preferredProvider = new PlatformAuthExtensionHandler(
|
||||
logger,
|
||||
handshakeTimeoutMs,
|
||||
performanceClient,
|
||||
PlatformAuthConstants.PREFERRED_EXTENSION_ID
|
||||
);
|
||||
await preferredProvider.sendHandshakeRequest(correlationId);
|
||||
return preferredProvider;
|
||||
} catch (e) {
|
||||
// If preferred extension fails for whatever reason, fallback to using any installed extension
|
||||
const backupProvider = new PlatformAuthExtensionHandler(
|
||||
logger,
|
||||
handshakeTimeoutMs,
|
||||
performanceClient
|
||||
);
|
||||
await backupProvider.sendHandshakeRequest(correlationId);
|
||||
return backupProvider;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send handshake request helper.
|
||||
*/
|
||||
private async sendHandshakeRequest(correlationId: string): Promise<void> {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - sendHandshakeRequest called.`,
|
||||
correlationId
|
||||
);
|
||||
// Register this event listener before sending handshake
|
||||
window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first
|
||||
|
||||
const req: NativeExtensionRequest = {
|
||||
channel: PlatformAuthConstants.CHANNEL_ID,
|
||||
extensionId: this.extensionId,
|
||||
responseId: createNewGuid(),
|
||||
body: {
|
||||
method: NativeExtensionMethod.HandshakeRequest,
|
||||
},
|
||||
};
|
||||
this.handshakeEvent.add({
|
||||
extensionId: this.extensionId,
|
||||
extensionHandshakeTimeoutMs: this.handshakeTimeoutMs,
|
||||
});
|
||||
|
||||
this.messageChannel.port1.onmessage = (event) => {
|
||||
this.onChannelMessage(event);
|
||||
};
|
||||
|
||||
window.postMessage(req, window.origin, [this.messageChannel.port2]);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.handshakeResolvers.set(req.responseId, { resolve, reject });
|
||||
this.timeoutId = window.setTimeout(() => {
|
||||
/*
|
||||
* Throw an error if neither HandshakeResponse nor original Handshake request are received in a reasonable timeframe.
|
||||
* This typically suggests an event handler stopped propagation of the Handshake request but did not respond to it on the MessageChannel port
|
||||
*/
|
||||
window.removeEventListener(
|
||||
"message",
|
||||
this.windowListener,
|
||||
false
|
||||
);
|
||||
this.messageChannel.port1.close();
|
||||
this.messageChannel.port2.close();
|
||||
this.handshakeEvent.end({
|
||||
extensionHandshakeTimedOut: true,
|
||||
success: false,
|
||||
});
|
||||
reject(
|
||||
createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.nativeHandshakeTimeout
|
||||
)
|
||||
);
|
||||
this.handshakeResolvers.delete(req.responseId);
|
||||
}, this.handshakeTimeoutMs); // Use a reasonable timeout in milliseconds here
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when a message is posted to the window. If a handshake request is received it means the extension is not installed.
|
||||
* @param event
|
||||
*/
|
||||
private onWindowMessage(event: MessageEvent): void {
|
||||
const correlationId = createGuid();
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - onWindowMessage called`,
|
||||
correlationId
|
||||
);
|
||||
// We only accept messages from ourselves
|
||||
if (event.source !== window) {
|
||||
return;
|
||||
}
|
||||
|
||||
const request = event.data;
|
||||
|
||||
if (
|
||||
!request.channel ||
|
||||
request.channel !== PlatformAuthConstants.CHANNEL_ID
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.extensionId && request.extensionId !== this.extensionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.body.method === NativeExtensionMethod.HandshakeRequest) {
|
||||
const handshakeResolver = this.handshakeResolvers.get(
|
||||
request.responseId
|
||||
);
|
||||
/*
|
||||
* Filter out responses with no matched resolvers sooner to keep channel ports open while waiting for
|
||||
* the proper response.
|
||||
*/
|
||||
if (!handshakeResolver) {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}'.onWindowMessage - resolver can't be found for request '${request.responseId}'`,
|
||||
correlationId
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we receive this message back it means no extension intercepted the request, meaning no extension supporting handshake protocol is installed
|
||||
this.logger.verbose(
|
||||
request.extensionId
|
||||
? `Extension with id: ${request.extensionId} not installed`
|
||||
: "No extension installed",
|
||||
correlationId
|
||||
);
|
||||
clearTimeout(this.timeoutId);
|
||||
this.messageChannel.port1.close();
|
||||
this.messageChannel.port2.close();
|
||||
window.removeEventListener("message", this.windowListener, false);
|
||||
this.handshakeEvent.end({
|
||||
success: false,
|
||||
extensionInstalled: false,
|
||||
});
|
||||
handshakeResolver.reject(
|
||||
createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.nativeExtensionNotInstalled
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when a message is received from the extension on the MessageChannel port
|
||||
* @param event
|
||||
*/
|
||||
private onChannelMessage(event: MessageEvent): void {
|
||||
const correlationId = createGuid();
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - onChannelMessage called.`,
|
||||
correlationId
|
||||
);
|
||||
const request = event.data;
|
||||
|
||||
const resolver = this.resolvers.get(request.responseId);
|
||||
const handshakeResolver = this.handshakeResolvers.get(
|
||||
request.responseId
|
||||
);
|
||||
|
||||
try {
|
||||
const method = request.body.method;
|
||||
|
||||
if (method === NativeExtensionMethod.Response) {
|
||||
if (!resolver) {
|
||||
return;
|
||||
}
|
||||
const response = request.body.response;
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}' - Received response from browser extension`,
|
||||
correlationId
|
||||
);
|
||||
this.logger.tracePii(
|
||||
`'${
|
||||
this.platformAuthType
|
||||
}' - Received response from browser extension: '${JSON.stringify(
|
||||
response
|
||||
)}'`,
|
||||
correlationId
|
||||
);
|
||||
if (response.status !== "Success") {
|
||||
resolver.reject(
|
||||
createNativeAuthError(
|
||||
response.code,
|
||||
response.description,
|
||||
response.ext
|
||||
)
|
||||
);
|
||||
} else if (response.result) {
|
||||
if (
|
||||
response.result["code"] &&
|
||||
response.result["description"]
|
||||
) {
|
||||
resolver.reject(
|
||||
createNativeAuthError(
|
||||
response.result["code"],
|
||||
response.result["description"],
|
||||
response.result["ext"]
|
||||
)
|
||||
);
|
||||
} else {
|
||||
resolver.resolve(response.result);
|
||||
}
|
||||
} else {
|
||||
throw createAuthError(
|
||||
AuthErrorCodes.unexpectedError,
|
||||
"Event does not contain result."
|
||||
);
|
||||
}
|
||||
this.resolvers.delete(request.responseId);
|
||||
} else if (method === NativeExtensionMethod.HandshakeResponse) {
|
||||
if (!handshakeResolver) {
|
||||
this.logger.trace(
|
||||
`'${this.platformAuthType}'.onChannelMessage - resolver can't be found for request '${request.responseId}'`,
|
||||
correlationId
|
||||
);
|
||||
return;
|
||||
}
|
||||
clearTimeout(this.timeoutId); // Clear setTimeout
|
||||
window.removeEventListener(
|
||||
"message",
|
||||
this.windowListener,
|
||||
false
|
||||
); // Remove 'No extension' listener
|
||||
this.extensionId = request.extensionId;
|
||||
this.extensionVersion = request.body.version;
|
||||
this.logger.verbose(
|
||||
`'${this.platformAuthType}' - Received HandshakeResponse from extension: '${this.extensionId}'`,
|
||||
correlationId
|
||||
);
|
||||
this.handshakeEvent.end({
|
||||
extensionInstalled: true,
|
||||
success: true,
|
||||
});
|
||||
|
||||
handshakeResolver.resolve();
|
||||
this.handshakeResolvers.delete(request.responseId);
|
||||
}
|
||||
// Do nothing if method is not Response or HandshakeResponse
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
"Error parsing response from WAM Extension",
|
||||
correlationId
|
||||
);
|
||||
this.logger.errorPii(
|
||||
`Error parsing response from WAM Extension: '${err as string}'`,
|
||||
correlationId
|
||||
);
|
||||
this.logger.errorPii(`Unable to parse '${event}'`, correlationId);
|
||||
|
||||
if (resolver) {
|
||||
resolver.reject(err as AuthError);
|
||||
} else if (handshakeResolver) {
|
||||
handshakeResolver.reject(err as AuthError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates native platform response before processing
|
||||
* @param response
|
||||
*/
|
||||
private validatePlatformBrokerResponse(
|
||||
response: object
|
||||
): PlatformAuthResponse {
|
||||
if (
|
||||
response.hasOwnProperty("access_token") &&
|
||||
response.hasOwnProperty("id_token") &&
|
||||
response.hasOwnProperty("client_info") &&
|
||||
response.hasOwnProperty("account") &&
|
||||
response.hasOwnProperty("scope") &&
|
||||
response.hasOwnProperty("expires_in")
|
||||
) {
|
||||
return response as PlatformAuthResponse;
|
||||
} else {
|
||||
throw createAuthError(
|
||||
AuthErrorCodes.unexpectedError,
|
||||
"Response missing expected properties."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id for the browser extension this handler is communicating with
|
||||
* @returns
|
||||
*/
|
||||
getExtensionId(): string | undefined {
|
||||
return this.extensionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version for the browser extension this handler is communicating with
|
||||
* @returns
|
||||
*/
|
||||
getExtensionVersion(): string | undefined {
|
||||
return this.extensionVersion;
|
||||
}
|
||||
|
||||
getExtensionName(): string | undefined {
|
||||
return this.getExtensionId() ===
|
||||
PlatformAuthConstants.PREFERRED_EXTENSION_ID
|
||||
? "chrome"
|
||||
: this.getExtensionId()?.length
|
||||
? "unknown"
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
171
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts
generated
vendored
Normal file
171
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
LoggerOptions,
|
||||
IPerformanceClient,
|
||||
Logger,
|
||||
Constants,
|
||||
StubPerformanceClient,
|
||||
createClientConfigurationError,
|
||||
ClientConfigurationErrorCodes,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { name, version } from "../../packageMetadata.js";
|
||||
import {
|
||||
BrowserConfiguration,
|
||||
DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS,
|
||||
} from "../../config/Configuration.js";
|
||||
import { PlatformAuthExtensionHandler } from "./PlatformAuthExtensionHandler.js";
|
||||
import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js";
|
||||
import { PlatformAuthDOMHandler } from "./PlatformAuthDOMHandler.js";
|
||||
import { createNewGuid } from "../../crypto/BrowserCrypto.js";
|
||||
|
||||
/**
|
||||
* Checks if the platform broker is available in the current environment.
|
||||
* @param domConfig - Whether to enable platform broker DOM API support (required)
|
||||
* @param loggerOptions - Optional logger options
|
||||
* @param perfClient - Optional performance client
|
||||
* @param correlationId - Optional correlation ID
|
||||
* @returns Promise<boolean> indicating if platform broker is available
|
||||
*/
|
||||
export async function isPlatformBrokerAvailable(
|
||||
domConfig: boolean,
|
||||
loggerOptions?: LoggerOptions,
|
||||
perfClient?: IPerformanceClient,
|
||||
correlationId?: string
|
||||
): Promise<boolean> {
|
||||
const logger = new Logger(loggerOptions || {}, name, version);
|
||||
|
||||
const performanceClient = perfClient || new StubPerformanceClient();
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
logger.trace(
|
||||
"Non-browser environment detected, returning false",
|
||||
correlationId || createNewGuid()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!(await getPlatformAuthProvider(
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId || createNewGuid(),
|
||||
undefined,
|
||||
domConfig
|
||||
));
|
||||
}
|
||||
|
||||
export async function getPlatformAuthProvider(
|
||||
logger: Logger,
|
||||
performanceClient: IPerformanceClient,
|
||||
correlationId: string,
|
||||
nativeBrokerHandshakeTimeout?: number,
|
||||
enablePlatformBrokerDOMSupport?: boolean
|
||||
): Promise<IPlatformAuthHandler | undefined> {
|
||||
logger.trace("getPlatformAuthProvider called", correlationId);
|
||||
|
||||
logger.trace(
|
||||
`Has client allowed platform auth via DOM API: '${enablePlatformBrokerDOMSupport}'`,
|
||||
correlationId
|
||||
);
|
||||
|
||||
let platformAuthProvider: IPlatformAuthHandler | undefined;
|
||||
try {
|
||||
if (enablePlatformBrokerDOMSupport) {
|
||||
// Check if DOM platform API is supported first
|
||||
platformAuthProvider = await PlatformAuthDOMHandler.createProvider(
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
if (!platformAuthProvider) {
|
||||
logger.trace(
|
||||
"Platform auth via DOM API not available, checking for extension",
|
||||
correlationId
|
||||
);
|
||||
/*
|
||||
* If DOM APIs are not available, check if browser extension is available.
|
||||
* Platform authentication via DOM APIs is preferred over extension APIs.
|
||||
*/
|
||||
platformAuthProvider =
|
||||
await PlatformAuthExtensionHandler.createProvider(
|
||||
logger,
|
||||
nativeBrokerHandshakeTimeout ||
|
||||
DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS,
|
||||
performanceClient,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.trace("Platform auth not available", e as string);
|
||||
}
|
||||
return platformAuthProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns boolean indicating whether or not the request should attempt to use platform broker
|
||||
* @param logger
|
||||
* @param config
|
||||
* @param correlationId
|
||||
* @param platformAuthProvider
|
||||
* @param authenticationScheme
|
||||
*/
|
||||
export function isPlatformAuthAllowed(
|
||||
config: BrowserConfiguration,
|
||||
logger: Logger,
|
||||
correlationId: string,
|
||||
platformAuthProvider?: IPlatformAuthHandler,
|
||||
authenticationScheme?: Constants.AuthenticationScheme
|
||||
): boolean {
|
||||
logger.trace("isPlatformAuthAllowed called", correlationId);
|
||||
|
||||
// throw an error if allowPlatformBroker is not enabled and allowPlatformBrokerWithDOM is enabled
|
||||
if (
|
||||
!config.system.allowPlatformBroker &&
|
||||
config.experimental.allowPlatformBrokerWithDOM
|
||||
) {
|
||||
throw createClientConfigurationError(
|
||||
ClientConfigurationErrorCodes.invalidPlatformBrokerConfiguration
|
||||
);
|
||||
}
|
||||
|
||||
if (!config.system.allowPlatformBroker) {
|
||||
logger.trace(
|
||||
"isPlatformAuthAllowed: allowPlatformBroker is not enabled, returning false",
|
||||
correlationId
|
||||
);
|
||||
// Developer disabled WAM
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!platformAuthProvider) {
|
||||
logger.trace(
|
||||
"isPlatformAuthAllowed: Platform auth provider is not initialized, returning false",
|
||||
correlationId
|
||||
);
|
||||
// Platform broker auth providers are not available
|
||||
return false;
|
||||
}
|
||||
|
||||
if (authenticationScheme) {
|
||||
switch (authenticationScheme) {
|
||||
case Constants.AuthenticationScheme.BEARER:
|
||||
case Constants.AuthenticationScheme.POP:
|
||||
logger.trace(
|
||||
"isPlatformAuthAllowed: authenticationScheme is supported, returning true",
|
||||
correlationId
|
||||
);
|
||||
return true;
|
||||
default:
|
||||
logger.trace(
|
||||
"isPlatformAuthAllowed: authenticationScheme is not supported, returning false",
|
||||
correlationId
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
94
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthRequest.ts
generated
vendored
Normal file
94
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthRequest.ts
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { NativeExtensionMethod } from "../../utils/BrowserConstants.js";
|
||||
import { StoreInCache, StringDict } from "@azure/msal-common/browser";
|
||||
|
||||
/**
|
||||
* Token request which native broker will use to acquire tokens
|
||||
*/
|
||||
export type PlatformAuthRequest = {
|
||||
accountId: string; // WAM specific account id used for identification of WAM account. This can be any broker-id eventually
|
||||
clientId: string;
|
||||
authority: string;
|
||||
redirectUri: string;
|
||||
scope: string;
|
||||
correlationId: string;
|
||||
windowTitleSubstring: string; // The name of the document title. This helps the native prompt properly "parent" to the window making the request
|
||||
prompt?: string;
|
||||
nonce?: string;
|
||||
claims?: string;
|
||||
state?: string;
|
||||
reqCnf?: string;
|
||||
keyId?: string;
|
||||
tokenType?: string;
|
||||
shrClaims?: string;
|
||||
shrNonce?: string;
|
||||
resourceRequestMethod?: string;
|
||||
resourceRequestUri?: string;
|
||||
extendedExpiryToken?: boolean;
|
||||
resource?: string;
|
||||
extraParameters?: StringDict;
|
||||
storeInCache?: StoreInCache; // Object of booleans indicating whether to store tokens in the cache or not (default is true)
|
||||
signPopToken?: boolean; // Set to true only if token request deos not contain a PoP keyId
|
||||
embeddedClientId?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request which will be forwarded to native broker by the browser extension
|
||||
*/
|
||||
export type NativeExtensionRequestBody = {
|
||||
method: NativeExtensionMethod;
|
||||
request?: PlatformAuthRequest;
|
||||
};
|
||||
|
||||
/**
|
||||
* Browser extension request
|
||||
*/
|
||||
export type NativeExtensionRequest = {
|
||||
channel: string;
|
||||
responseId: string;
|
||||
extensionId?: string;
|
||||
body: NativeExtensionRequestBody;
|
||||
};
|
||||
|
||||
export type PlatformDOMTokenRequest = {
|
||||
brokerId: string;
|
||||
accountId?: string;
|
||||
clientId: string;
|
||||
authority: string;
|
||||
scope: string;
|
||||
redirectUri: string;
|
||||
correlationId: string;
|
||||
isSecurityTokenService: boolean;
|
||||
state?: string;
|
||||
/*
|
||||
* Known optional parameters will go into extraQueryParameters.
|
||||
* List of known parameters is:
|
||||
* "prompt", "nonce", "claims", "loginHint", "instanceAware", "windowTitleSubstring", "extendedExpiryToken", "storeInCache",
|
||||
* ProofOfPossessionParams: "reqCnf", "keyId", "tokenType", "shrClaims", "shrNonce", "resourceRequestMethod", "resourceRequestUri", "signPopToken"
|
||||
*/
|
||||
extraParameters?: DOMExtraParameters;
|
||||
embeddedClientId?: string;
|
||||
storeInCache?: StoreInCache; // Object of booleans indicating whether to store tokens in the cache or not (default is true)
|
||||
};
|
||||
|
||||
export type DOMExtraParameters = StringDict & {
|
||||
prompt?: string;
|
||||
nonce?: string;
|
||||
claims?: string;
|
||||
loginHint?: string;
|
||||
instanceAware?: string;
|
||||
windowTitleSubstring?: string;
|
||||
extendedExpiryToken?: string;
|
||||
reqCnf?: string;
|
||||
keyId?: string;
|
||||
tokenType?: string;
|
||||
shrClaims?: string;
|
||||
shrNonce?: string;
|
||||
resourceRequestMethod?: string;
|
||||
resourceRequestUri?: string;
|
||||
signPopToken?: string; // Set to true only if token request deos not contain a PoP keyId
|
||||
};
|
||||
80
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthResponse.ts
generated
vendored
Normal file
80
backend/node_modules/@azure/msal-browser/src/broker/nativeBroker/PlatformAuthResponse.ts
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Account properties returned by Native Platform e.g. WAM
|
||||
*/
|
||||
export type NativeAccountInfo = {
|
||||
id: string;
|
||||
properties: object;
|
||||
userName: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Token response returned by Native Platform
|
||||
*/
|
||||
export type PlatformAuthResponse = {
|
||||
access_token: string;
|
||||
account: NativeAccountInfo;
|
||||
client_info: string;
|
||||
expires_in: number;
|
||||
id_token: string;
|
||||
properties: NativeResponseProperties;
|
||||
scope: string;
|
||||
state: string;
|
||||
shr?: string;
|
||||
extendedLifetimeToken?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Properties returned under "properties" of the NativeResponse
|
||||
*/
|
||||
export type NativeResponseProperties = {
|
||||
MATS?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The native token broker can optionally include additional information about operations it performs. If that data is returned, MSAL.js will include the following properties in the telemetry it collects.
|
||||
*/
|
||||
export type MATS = {
|
||||
is_cached?: number;
|
||||
broker_version?: string;
|
||||
account_join_on_start?: string;
|
||||
account_join_on_end?: string;
|
||||
device_join?: string;
|
||||
prompt_behavior?: string;
|
||||
api_error_code?: number;
|
||||
ui_visible?: boolean;
|
||||
silent_code?: number;
|
||||
silent_bi_sub_code?: number;
|
||||
silent_message?: string;
|
||||
silent_status?: number;
|
||||
http_status?: number;
|
||||
http_event_count?: number;
|
||||
};
|
||||
|
||||
export type PlatformDOMTokenResponse = {
|
||||
isSuccess: boolean;
|
||||
state?: string;
|
||||
accessToken: string;
|
||||
expiresIn: number;
|
||||
account: NativeAccountInfo;
|
||||
clientInfo: string;
|
||||
idToken: string;
|
||||
scopes: string;
|
||||
proofOfPossessionPayload?: string;
|
||||
extendedLifetimeToken?: boolean;
|
||||
error: ErrorResult;
|
||||
properties?: Record<string, string>;
|
||||
};
|
||||
|
||||
export type ErrorResult = {
|
||||
code: string;
|
||||
description?: string;
|
||||
errorCode: string;
|
||||
protocolError?: string;
|
||||
status: string;
|
||||
properties?: object;
|
||||
};
|
||||
79
backend/node_modules/@azure/msal-browser/src/cache/AccountManager.ts
generated
vendored
Normal file
79
backend/node_modules/@azure/msal-browser/src/cache/AccountManager.ts
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AccountInfo, AccountFilter, Logger } from "@azure/msal-common/browser";
|
||||
import { BrowserCacheManager } from "./BrowserCacheManager.js";
|
||||
|
||||
/**
|
||||
* Returns all the accounts in the cache that match the optional filter. If no filter is provided, all accounts are returned.
|
||||
* @param accountFilter - (Optional) filter to narrow down the accounts returned
|
||||
* @returns Array of AccountInfo objects in cache
|
||||
*/
|
||||
export function getAllAccounts(
|
||||
logger: Logger,
|
||||
browserStorage: BrowserCacheManager,
|
||||
isInBrowser: boolean,
|
||||
correlationId: string,
|
||||
accountFilter?: AccountFilter
|
||||
): AccountInfo[] {
|
||||
logger.verbose("getAllAccounts called", correlationId);
|
||||
return isInBrowser
|
||||
? browserStorage.getAllAccounts(accountFilter, correlationId)
|
||||
: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first account found in the cache that matches the account filter passed in.
|
||||
* @param accountFilter
|
||||
* @returns The first account found in the cache matching the provided filter or null if no account could be found.
|
||||
*/
|
||||
export function getAccount(
|
||||
accountFilter: AccountFilter,
|
||||
logger: Logger,
|
||||
browserStorage: BrowserCacheManager,
|
||||
correlationId: string
|
||||
): AccountInfo | null {
|
||||
logger.trace("getAccount called", correlationId);
|
||||
const account: AccountInfo | null = browserStorage.getAccountInfoFilteredBy(
|
||||
accountFilter,
|
||||
correlationId
|
||||
);
|
||||
|
||||
if (account) {
|
||||
logger.verbose(
|
||||
"getAccount: Account matching provided filter found, returning",
|
||||
correlationId
|
||||
);
|
||||
return account;
|
||||
} else {
|
||||
logger.verbose(
|
||||
"getAccount: No matching account found, returning null",
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the account to use as the active account. If no account is passed to the acquireToken APIs, then MSAL will use this active account.
|
||||
* @param account
|
||||
*/
|
||||
export function setActiveAccount(
|
||||
account: AccountInfo | null,
|
||||
browserStorage: BrowserCacheManager,
|
||||
correlationId: string
|
||||
): void {
|
||||
browserStorage.setActiveAccount(account, correlationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently active account
|
||||
*/
|
||||
export function getActiveAccount(
|
||||
browserStorage: BrowserCacheManager,
|
||||
correlationId: string
|
||||
): AccountInfo | null {
|
||||
return browserStorage.getActiveAccount(correlationId);
|
||||
}
|
||||
173
backend/node_modules/@azure/msal-browser/src/cache/AsyncMemoryStorage.ts
generated
vendored
Normal file
173
backend/node_modules/@azure/msal-browser/src/cache/AsyncMemoryStorage.ts
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { Logger } from "@azure/msal-common/browser";
|
||||
import {
|
||||
BrowserAuthError,
|
||||
BrowserAuthErrorCodes,
|
||||
} from "../error/BrowserAuthError.js";
|
||||
import { DatabaseStorage } from "./DatabaseStorage.js";
|
||||
import { IAsyncStorage } from "./IAsyncStorage.js";
|
||||
import { MemoryStorage } from "./MemoryStorage.js";
|
||||
|
||||
/**
|
||||
* This class allows MSAL to store artifacts asynchronously using the DatabaseStorage IndexedDB wrapper,
|
||||
* backed up with the more volatile MemoryStorage object for cases in which IndexedDB may be unavailable.
|
||||
*/
|
||||
export class AsyncMemoryStorage<T> implements IAsyncStorage<T> {
|
||||
private inMemoryCache: MemoryStorage<T>;
|
||||
private indexedDBCache: DatabaseStorage<T>;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(logger: Logger) {
|
||||
this.inMemoryCache = new MemoryStorage<T>();
|
||||
this.indexedDBCache = new DatabaseStorage<T>();
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
private handleDatabaseAccessError(
|
||||
error: unknown,
|
||||
correlationId: string
|
||||
): void {
|
||||
if (
|
||||
error instanceof BrowserAuthError &&
|
||||
error.errorCode === BrowserAuthErrorCodes.databaseUnavailable
|
||||
) {
|
||||
this.logger.error(
|
||||
"Could not access persistent storage. This may be caused by browser privacy features which block persistent storage in third-party contexts.",
|
||||
correlationId
|
||||
);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the item matching the given key. Tries in-memory cache first, then in the asynchronous
|
||||
* storage object if item isn't found in-memory.
|
||||
* @param key
|
||||
* @param correlationId
|
||||
*/
|
||||
async getItem(key: string, correlationId: string): Promise<T | null> {
|
||||
const item = this.inMemoryCache.getItem(key);
|
||||
if (!item) {
|
||||
try {
|
||||
this.logger.verbose(
|
||||
"Queried item not found in in-memory cache, now querying persistent storage.",
|
||||
correlationId
|
||||
);
|
||||
return await this.indexedDBCache.getItem(key);
|
||||
} catch (e) {
|
||||
this.handleDatabaseAccessError(e, correlationId);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item in the in-memory cache and then tries to set it in the asynchronous
|
||||
* storage object with the given key.
|
||||
* @param key
|
||||
* @param value
|
||||
* @param correlationId
|
||||
*/
|
||||
async setItem(key: string, value: T, correlationId: string): Promise<void> {
|
||||
this.inMemoryCache.setItem(key, value);
|
||||
try {
|
||||
await this.indexedDBCache.setItem(key, value);
|
||||
} catch (e) {
|
||||
this.handleDatabaseAccessError(e, correlationId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the item matching the key from the in-memory cache, then tries to remove it from the asynchronous storage object.
|
||||
* @param key
|
||||
* @param correlationId
|
||||
*/
|
||||
async removeItem(key: string, correlationId: string): Promise<void> {
|
||||
this.inMemoryCache.removeItem(key);
|
||||
try {
|
||||
await this.indexedDBCache.removeItem(key);
|
||||
} catch (e) {
|
||||
this.handleDatabaseAccessError(e, correlationId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the keys from the in-memory cache as an iterable array of strings. If no keys are found, query the keys in the
|
||||
* asynchronous storage object.
|
||||
* @param correlationId
|
||||
*/
|
||||
async getKeys(correlationId: string): Promise<string[]> {
|
||||
const cacheKeys = this.inMemoryCache.getKeys();
|
||||
if (cacheKeys.length === 0) {
|
||||
try {
|
||||
this.logger.verbose(
|
||||
"In-memory cache is empty, now querying persistent storage.",
|
||||
correlationId
|
||||
);
|
||||
return await this.indexedDBCache.getKeys();
|
||||
} catch (e) {
|
||||
this.handleDatabaseAccessError(e, correlationId);
|
||||
}
|
||||
}
|
||||
return cacheKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true or false if the given key is present in the cache.
|
||||
* @param key
|
||||
* @param correlationId
|
||||
*/
|
||||
async containsKey(key: string, correlationId: string): Promise<boolean> {
|
||||
const containsKey = this.inMemoryCache.containsKey(key);
|
||||
if (!containsKey) {
|
||||
try {
|
||||
this.logger.verbose(
|
||||
"Key not found in in-memory cache, now querying persistent storage.",
|
||||
correlationId
|
||||
);
|
||||
return await this.indexedDBCache.containsKey(key);
|
||||
} catch (e) {
|
||||
this.handleDatabaseAccessError(e, correlationId);
|
||||
}
|
||||
}
|
||||
return containsKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears in-memory Map
|
||||
* @param correlationId
|
||||
*/
|
||||
clearInMemory(correlationId: string): void {
|
||||
// InMemory cache is a Map instance, clear is straightforward
|
||||
this.logger.verbose(`Deleting in-memory keystore`, correlationId);
|
||||
this.inMemoryCache.clear();
|
||||
this.logger.verbose(`In-memory keystore deleted`, correlationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to delete the IndexedDB database
|
||||
* @param correlationId
|
||||
* @returns
|
||||
*/
|
||||
async clearPersistent(correlationId: string): Promise<boolean> {
|
||||
try {
|
||||
this.logger.verbose("Deleting persistent keystore", correlationId);
|
||||
const dbDeleted = await this.indexedDBCache.deleteDatabase();
|
||||
if (dbDeleted) {
|
||||
this.logger.verbose(
|
||||
"Persistent keystore deleted",
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
|
||||
return dbDeleted;
|
||||
} catch (e) {
|
||||
this.handleDatabaseAccessError(e, correlationId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
2419
backend/node_modules/@azure/msal-browser/src/cache/BrowserCacheManager.ts
generated
vendored
Normal file
2419
backend/node_modules/@azure/msal-browser/src/cache/BrowserCacheManager.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
60
backend/node_modules/@azure/msal-browser/src/cache/CacheHelpers.ts
generated
vendored
Normal file
60
backend/node_modules/@azure/msal-browser/src/cache/CacheHelpers.ts
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { TokenKeys } from "@azure/msal-common/browser";
|
||||
import { IWindowStorage } from "./IWindowStorage.js";
|
||||
import * as CacheKeys from "./CacheKeys.js";
|
||||
|
||||
/**
|
||||
* Returns a list of cache keys for all known accounts
|
||||
* @param storage
|
||||
* @returns
|
||||
*/
|
||||
export function getAccountKeys(
|
||||
storage: IWindowStorage<string>,
|
||||
schemaVersion?: number
|
||||
): Array<string> {
|
||||
const accountKeys = storage.getItem(
|
||||
CacheKeys.getAccountKeysCacheKey(schemaVersion)
|
||||
);
|
||||
if (accountKeys) {
|
||||
return JSON.parse(accountKeys);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of cache keys for all known tokens
|
||||
* @param clientId
|
||||
* @param storage
|
||||
* @returns
|
||||
*/
|
||||
export function getTokenKeys(
|
||||
clientId: string,
|
||||
storage: IWindowStorage<string>,
|
||||
schemaVersion?: number
|
||||
): TokenKeys {
|
||||
const item = storage.getItem(
|
||||
CacheKeys.getTokenKeysCacheKey(clientId, schemaVersion)
|
||||
);
|
||||
if (item) {
|
||||
const tokenKeys = JSON.parse(item);
|
||||
if (
|
||||
tokenKeys &&
|
||||
tokenKeys.hasOwnProperty("idToken") &&
|
||||
tokenKeys.hasOwnProperty("accessToken") &&
|
||||
tokenKeys.hasOwnProperty("refreshToken")
|
||||
) {
|
||||
return tokenKeys as TokenKeys;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
idToken: [],
|
||||
accessToken: [],
|
||||
refreshToken: [],
|
||||
};
|
||||
}
|
||||
40
backend/node_modules/@azure/msal-browser/src/cache/CacheKeys.ts
generated
vendored
Normal file
40
backend/node_modules/@azure/msal-browser/src/cache/CacheKeys.ts
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export const PREFIX = "msal";
|
||||
const BROWSER_PREFIX = "browser";
|
||||
export const CACHE_KEY_SEPARATOR = "|";
|
||||
export const CREDENTIAL_SCHEMA_VERSION = 3;
|
||||
export const ACCOUNT_SCHEMA_VERSION = 3;
|
||||
|
||||
export const LOG_LEVEL_CACHE_KEY = `${PREFIX}.${BROWSER_PREFIX}.log.level`;
|
||||
export const LOG_PII_CACHE_KEY = `${PREFIX}.${BROWSER_PREFIX}.log.pii`;
|
||||
export const BROWSER_PERF_ENABLED_KEY = `${PREFIX}.${BROWSER_PREFIX}.performance.enabled`;
|
||||
export const PLATFORM_AUTH_DOM_SUPPORT = `${PREFIX}.${BROWSER_PREFIX}.platform.auth.dom`;
|
||||
export const VERSION_CACHE_KEY = `${PREFIX}.version`;
|
||||
export const ACCOUNT_KEYS = "account.keys";
|
||||
export const TOKEN_KEYS = "token.keys";
|
||||
export const SSO_CAPABLE = `${PREFIX}.${BROWSER_PREFIX}.sso.capable`;
|
||||
|
||||
export function getAccountKeysCacheKey(
|
||||
schema: number = ACCOUNT_SCHEMA_VERSION
|
||||
): string {
|
||||
if (schema < 1) {
|
||||
return `${PREFIX}.${ACCOUNT_KEYS}`;
|
||||
}
|
||||
|
||||
return `${PREFIX}.${schema}.${ACCOUNT_KEYS}`;
|
||||
}
|
||||
|
||||
export function getTokenKeysCacheKey(
|
||||
clientId: string,
|
||||
schema: number = CREDENTIAL_SCHEMA_VERSION
|
||||
): string {
|
||||
if (schema < 1) {
|
||||
return `${PREFIX}.${TOKEN_KEYS}.${clientId}`;
|
||||
}
|
||||
|
||||
return `${PREFIX}.${schema}.${TOKEN_KEYS}.${clientId}`;
|
||||
}
|
||||
125
backend/node_modules/@azure/msal-browser/src/cache/CookieStorage.ts
generated
vendored
Normal file
125
backend/node_modules/@azure/msal-browser/src/cache/CookieStorage.ts
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ClientAuthErrorCodes,
|
||||
createClientAuthError,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { IWindowStorage } from "./IWindowStorage.js";
|
||||
|
||||
// Cookie life calculation (hours * minutes * seconds * ms)
|
||||
const COOKIE_LIFE_MULTIPLIER = 24 * 60 * 60 * 1000;
|
||||
|
||||
export const SameSiteOptions = {
|
||||
Lax: "Lax",
|
||||
None: "None",
|
||||
} as const;
|
||||
export type SameSiteOptions =
|
||||
(typeof SameSiteOptions)[keyof typeof SameSiteOptions];
|
||||
|
||||
export class CookieStorage implements IWindowStorage<string> {
|
||||
initialize(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
getItem(key: string): string | null {
|
||||
const name = encodeURIComponent(key);
|
||||
const cookieList = document.cookie.split(";");
|
||||
for (let i = 0; i < cookieList.length; i++) {
|
||||
const cookie = cookieList[i].trim();
|
||||
const eqIndex = cookie.indexOf("=");
|
||||
const rawKey =
|
||||
eqIndex === -1 ? cookie : cookie.substring(0, eqIndex);
|
||||
if (rawKey === name) {
|
||||
const rawValue =
|
||||
eqIndex === -1 ? "" : cookie.substring(eqIndex + 1);
|
||||
try {
|
||||
return decodeURIComponent(rawValue);
|
||||
} catch {
|
||||
return rawValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
getUserData(): string | null {
|
||||
throw createClientAuthError(ClientAuthErrorCodes.methodNotImplemented);
|
||||
}
|
||||
|
||||
setItem(
|
||||
key: string,
|
||||
value: string,
|
||||
cookieLifeDays?: number,
|
||||
secure: boolean = true,
|
||||
sameSite: SameSiteOptions = SameSiteOptions.Lax
|
||||
): void {
|
||||
let cookieStr = `${encodeURIComponent(key)}=${encodeURIComponent(
|
||||
value
|
||||
)};path=/;SameSite=${sameSite};`;
|
||||
|
||||
if (cookieLifeDays) {
|
||||
const expireTime = getCookieExpirationTime(cookieLifeDays);
|
||||
cookieStr += `expires=${expireTime};`;
|
||||
}
|
||||
|
||||
if (secure || sameSite === SameSiteOptions.None) {
|
||||
// SameSite None requires Secure flag
|
||||
cookieStr += "Secure;";
|
||||
}
|
||||
|
||||
document.cookie = cookieStr;
|
||||
}
|
||||
|
||||
async setUserData(): Promise<void> {
|
||||
return Promise.reject(
|
||||
createClientAuthError(ClientAuthErrorCodes.methodNotImplemented)
|
||||
);
|
||||
}
|
||||
|
||||
removeItem(key: string): void {
|
||||
// Setting expiration to -1 removes it
|
||||
this.setItem(key, "", -1);
|
||||
}
|
||||
|
||||
getKeys(): string[] {
|
||||
const cookieList = document.cookie.split(";");
|
||||
const keys: Array<string> = [];
|
||||
cookieList.forEach((cookie) => {
|
||||
const trimmed = cookie.trim();
|
||||
const eqIndex = trimmed.indexOf("=");
|
||||
const rawKey =
|
||||
eqIndex === -1 ? trimmed : trimmed.substring(0, eqIndex);
|
||||
try {
|
||||
keys.push(decodeURIComponent(rawKey));
|
||||
} catch {
|
||||
// Skip cookies with malformed percent-encoded sequences in the key
|
||||
}
|
||||
});
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
containsKey(key: string): boolean {
|
||||
return this.getKeys().includes(key);
|
||||
}
|
||||
|
||||
decryptData(): Promise<object | null> {
|
||||
// Cookie storage does not support encryption, so this method is a no-op
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cookie expiration time
|
||||
* @param cookieLifeDays
|
||||
*/
|
||||
export function getCookieExpirationTime(cookieLifeDays: number): string {
|
||||
const today = new Date();
|
||||
const expr = new Date(
|
||||
today.getTime() + cookieLifeDays * COOKIE_LIFE_MULTIPLIER
|
||||
);
|
||||
return expr.toUTCString();
|
||||
}
|
||||
301
backend/node_modules/@azure/msal-browser/src/cache/DatabaseStorage.ts
generated
vendored
Normal file
301
backend/node_modules/@azure/msal-browser/src/cache/DatabaseStorage.ts
generated
vendored
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
createBrowserAuthError,
|
||||
BrowserAuthErrorCodes,
|
||||
} from "../error/BrowserAuthError.js";
|
||||
import {
|
||||
DB_NAME,
|
||||
DB_TABLE_NAME,
|
||||
DB_VERSION,
|
||||
} from "../utils/BrowserConstants.js";
|
||||
import { IAsyncStorage } from "./IAsyncStorage.js";
|
||||
|
||||
interface IDBOpenDBRequestEvent extends Event {
|
||||
target: IDBOpenDBRequest & EventTarget;
|
||||
}
|
||||
|
||||
interface IDBOpenOnUpgradeNeededEvent extends IDBVersionChangeEvent {
|
||||
target: IDBOpenDBRequest & EventTarget;
|
||||
}
|
||||
|
||||
interface IDBRequestEvent extends Event {
|
||||
target: IDBRequest & EventTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage wrapper for IndexedDB storage in browsers: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
|
||||
*/
|
||||
export class DatabaseStorage<T> implements IAsyncStorage<T> {
|
||||
private db: IDBDatabase | undefined;
|
||||
private dbName: string;
|
||||
private tableName: string;
|
||||
private version: number;
|
||||
private dbOpen: boolean;
|
||||
|
||||
constructor() {
|
||||
this.dbName = DB_NAME;
|
||||
this.version = DB_VERSION;
|
||||
this.tableName = DB_TABLE_NAME;
|
||||
this.dbOpen = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens IndexedDB instance.
|
||||
*/
|
||||
async open(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const openDB = window.indexedDB.open(this.dbName, this.version);
|
||||
openDB.addEventListener(
|
||||
"upgradeneeded",
|
||||
(e: IDBVersionChangeEvent) => {
|
||||
const event = e as IDBOpenOnUpgradeNeededEvent;
|
||||
event.target.result.createObjectStore(this.tableName);
|
||||
}
|
||||
);
|
||||
openDB.addEventListener("success", (e: Event) => {
|
||||
const event = e as IDBOpenDBRequestEvent;
|
||||
this.db = event.target.result;
|
||||
this.dbOpen = true;
|
||||
resolve();
|
||||
});
|
||||
openDB.addEventListener("error", () =>
|
||||
reject(
|
||||
createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.databaseUnavailable
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the connection to IndexedDB database when all pending transactions
|
||||
* complete.
|
||||
*/
|
||||
closeConnection(): void {
|
||||
const db = this.db;
|
||||
if (db && this.dbOpen) {
|
||||
db.close();
|
||||
this.dbOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens database if it's not already open
|
||||
*/
|
||||
private async validateDbIsOpen(): Promise<void> {
|
||||
if (!this.dbOpen) {
|
||||
return this.open();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves item from IndexedDB instance.
|
||||
* @param key
|
||||
*/
|
||||
async getItem(key: string): Promise<T | null> {
|
||||
await this.validateDbIsOpen();
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
// TODO: Add timeouts?
|
||||
if (!this.db) {
|
||||
return reject(
|
||||
createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.databaseNotOpen
|
||||
)
|
||||
);
|
||||
}
|
||||
const transaction = this.db.transaction(
|
||||
[this.tableName],
|
||||
"readonly"
|
||||
);
|
||||
const objectStore = transaction.objectStore(this.tableName);
|
||||
const dbGet = objectStore.get(key);
|
||||
|
||||
dbGet.addEventListener("success", (e: Event) => {
|
||||
const event = e as IDBRequestEvent;
|
||||
this.closeConnection();
|
||||
resolve(event.target.result);
|
||||
});
|
||||
|
||||
dbGet.addEventListener("error", (e: Event) => {
|
||||
this.closeConnection();
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds item to IndexedDB under given key
|
||||
* @param key
|
||||
* @param payload
|
||||
*/
|
||||
async setItem(key: string, payload: T): Promise<void> {
|
||||
await this.validateDbIsOpen();
|
||||
return new Promise<void>((resolve: Function, reject: Function) => {
|
||||
// TODO: Add timeouts?
|
||||
if (!this.db) {
|
||||
return reject(
|
||||
createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.databaseNotOpen
|
||||
)
|
||||
);
|
||||
}
|
||||
const transaction = this.db.transaction(
|
||||
[this.tableName],
|
||||
"readwrite"
|
||||
);
|
||||
|
||||
const objectStore = transaction.objectStore(this.tableName);
|
||||
|
||||
const dbPut = objectStore.put(payload, key);
|
||||
|
||||
dbPut.addEventListener("success", () => {
|
||||
this.closeConnection();
|
||||
resolve();
|
||||
});
|
||||
|
||||
dbPut.addEventListener("error", (e) => {
|
||||
this.closeConnection();
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes item from IndexedDB under given key
|
||||
* @param key
|
||||
*/
|
||||
async removeItem(key: string): Promise<void> {
|
||||
await this.validateDbIsOpen();
|
||||
return new Promise<void>((resolve: Function, reject: Function) => {
|
||||
if (!this.db) {
|
||||
return reject(
|
||||
createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.databaseNotOpen
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const transaction = this.db.transaction(
|
||||
[this.tableName],
|
||||
"readwrite"
|
||||
);
|
||||
const objectStore = transaction.objectStore(this.tableName);
|
||||
const dbDelete = objectStore.delete(key);
|
||||
|
||||
dbDelete.addEventListener("success", () => {
|
||||
this.closeConnection();
|
||||
resolve();
|
||||
});
|
||||
|
||||
dbDelete.addEventListener("error", (e) => {
|
||||
this.closeConnection();
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the keys from the storage object as an iterable array of strings.
|
||||
*/
|
||||
async getKeys(): Promise<string[]> {
|
||||
await this.validateDbIsOpen();
|
||||
return new Promise<string[]>((resolve: Function, reject: Function) => {
|
||||
if (!this.db) {
|
||||
return reject(
|
||||
createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.databaseNotOpen
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const transaction = this.db.transaction(
|
||||
[this.tableName],
|
||||
"readonly"
|
||||
);
|
||||
const objectStore = transaction.objectStore(this.tableName);
|
||||
const dbGetKeys = objectStore.getAllKeys();
|
||||
|
||||
dbGetKeys.addEventListener("success", (e: Event) => {
|
||||
const event = e as IDBRequestEvent;
|
||||
this.closeConnection();
|
||||
resolve(event.target.result);
|
||||
});
|
||||
|
||||
dbGetKeys.addEventListener("error", (e: Event) => {
|
||||
this.closeConnection();
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Checks whether there is an object under the search key in the object store
|
||||
*/
|
||||
async containsKey(key: string): Promise<boolean> {
|
||||
await this.validateDbIsOpen();
|
||||
|
||||
return new Promise<boolean>((resolve: Function, reject: Function) => {
|
||||
if (!this.db) {
|
||||
return reject(
|
||||
createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.databaseNotOpen
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const transaction = this.db.transaction(
|
||||
[this.tableName],
|
||||
"readonly"
|
||||
);
|
||||
const objectStore = transaction.objectStore(this.tableName);
|
||||
const dbContainsKey = objectStore.count(key);
|
||||
|
||||
dbContainsKey.addEventListener("success", (e: Event) => {
|
||||
const event = e as IDBRequestEvent;
|
||||
this.closeConnection();
|
||||
resolve(event.target.result === 1);
|
||||
});
|
||||
|
||||
dbContainsKey.addEventListener("error", (e: Event) => {
|
||||
this.closeConnection();
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the MSAL database. The database is deleted rather than cleared to make it possible
|
||||
* for client applications to downgrade to a previous MSAL version without worrying about forward compatibility issues
|
||||
* with IndexedDB database versions.
|
||||
*/
|
||||
async deleteDatabase(): Promise<boolean> {
|
||||
// Check if database being deleted exists
|
||||
|
||||
if (this.db && this.dbOpen) {
|
||||
this.closeConnection();
|
||||
}
|
||||
|
||||
return new Promise<boolean>((resolve: Function, reject: Function) => {
|
||||
const deleteDbRequest = window.indexedDB.deleteDatabase(DB_NAME);
|
||||
const id = setTimeout(() => reject(false), 200); // Reject if events aren't raised within 200ms
|
||||
deleteDbRequest.addEventListener("success", () => {
|
||||
clearTimeout(id);
|
||||
return resolve(true);
|
||||
});
|
||||
deleteDbRequest.addEventListener("blocked", () => {
|
||||
clearTimeout(id);
|
||||
return resolve(true);
|
||||
});
|
||||
deleteDbRequest.addEventListener("error", () => {
|
||||
clearTimeout(id);
|
||||
return reject(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
19
backend/node_modules/@azure/msal-browser/src/cache/EncryptedData.ts
generated
vendored
Normal file
19
backend/node_modules/@azure/msal-browser/src/cache/EncryptedData.ts
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export type EncryptedData = {
|
||||
id: string;
|
||||
nonce: string;
|
||||
data: string;
|
||||
lastUpdatedAt: string;
|
||||
};
|
||||
|
||||
export function isEncrypted(data: object): data is EncryptedData {
|
||||
return (
|
||||
data.hasOwnProperty("id") &&
|
||||
data.hasOwnProperty("nonce") &&
|
||||
data.hasOwnProperty("data")
|
||||
);
|
||||
}
|
||||
41
backend/node_modules/@azure/msal-browser/src/cache/IAsyncStorage.ts
generated
vendored
Normal file
41
backend/node_modules/@azure/msal-browser/src/cache/IAsyncStorage.ts
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export interface IAsyncStorage<T> {
|
||||
/**
|
||||
* Get the item from the asynchronous storage object matching the given key.
|
||||
* @param key
|
||||
* @param correlationId
|
||||
*/
|
||||
getItem(key: string, correlationId: string): Promise<T | null>;
|
||||
|
||||
/**
|
||||
* Sets the item in the asynchronous storage object with the given key.
|
||||
* @param key
|
||||
* @param value
|
||||
* @param correlationId
|
||||
*/
|
||||
setItem(key: string, value: T, correlationId: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Removes the item in the asynchronous storage object matching the given key.
|
||||
* @param key
|
||||
* @param correlationId
|
||||
*/
|
||||
removeItem(key: string, correlationId: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Get all the keys from the asynchronous storage object as an iterable array of strings.
|
||||
* @param correlationId
|
||||
*/
|
||||
getKeys(correlationId: string): Promise<string[]>;
|
||||
|
||||
/**
|
||||
* Returns true or false if the given key is present in the cache.
|
||||
* @param key
|
||||
* @param correlationId
|
||||
*/
|
||||
containsKey(key: string, correlationId: string): Promise<boolean>;
|
||||
}
|
||||
64
backend/node_modules/@azure/msal-browser/src/cache/IWindowStorage.ts
generated
vendored
Normal file
64
backend/node_modules/@azure/msal-browser/src/cache/IWindowStorage.ts
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { EncryptedData } from "./EncryptedData.js";
|
||||
|
||||
export interface IWindowStorage<T> {
|
||||
/**
|
||||
* Async initializer
|
||||
*/
|
||||
initialize(correlationId: string): Promise<void>;
|
||||
/**
|
||||
* Get the item from the window storage object matching the given key.
|
||||
* @param key
|
||||
*/
|
||||
getItem(key: string): T | null;
|
||||
|
||||
/**
|
||||
* Getter for sensitive data that may contain PII.
|
||||
*/
|
||||
getUserData(key: string): T | null;
|
||||
|
||||
/**
|
||||
* Sets the item in the window storage object with the given key.
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
setItem(key: string, value: T): void;
|
||||
|
||||
/**
|
||||
* Setter for sensitive data that may contain PII.
|
||||
*/
|
||||
setUserData(
|
||||
key: string,
|
||||
value: T,
|
||||
correlationId: string,
|
||||
timestamp: string,
|
||||
kmsi: boolean
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Removes the item in the window storage object matching the given key.
|
||||
* @param key
|
||||
*/
|
||||
removeItem(key: string): void;
|
||||
|
||||
/**
|
||||
* Get all the keys from the window storage object as an iterable array of strings.
|
||||
*/
|
||||
getKeys(): string[];
|
||||
|
||||
/**
|
||||
* Returns true or false if the given key is present in the cache.
|
||||
* @param key
|
||||
*/
|
||||
containsKey(key: string): boolean;
|
||||
|
||||
decryptData(
|
||||
key: string,
|
||||
data: EncryptedData,
|
||||
correlationId: string
|
||||
): Promise<object | null>;
|
||||
}
|
||||
516
backend/node_modules/@azure/msal-browser/src/cache/LocalStorage.ts
generated
vendored
Normal file
516
backend/node_modules/@azure/msal-browser/src/cache/LocalStorage.ts
generated
vendored
Normal file
@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
TokenKeys,
|
||||
IPerformanceClient,
|
||||
invokeAsync,
|
||||
Logger,
|
||||
invoke,
|
||||
} from "@azure/msal-common/browser";
|
||||
import * as BrowserPerformanceEvents from "../telemetry/BrowserPerformanceEvents.js";
|
||||
import * as BrowserRootPerformanceEvents from "../telemetry/BrowserRootPerformanceEvents.js";
|
||||
import {
|
||||
createNewGuid,
|
||||
decrypt,
|
||||
encrypt,
|
||||
generateBaseKey,
|
||||
generateHKDF,
|
||||
} from "../crypto/BrowserCrypto.js";
|
||||
import { base64DecToArr } from "../encode/Base64Decode.js";
|
||||
import { urlEncodeArr } from "../encode/Base64Encode.js";
|
||||
import {
|
||||
BrowserAuthErrorCodes,
|
||||
createBrowserAuthError,
|
||||
} from "../error/BrowserAuthError.js";
|
||||
import {
|
||||
BrowserConfigurationAuthErrorCodes,
|
||||
createBrowserConfigurationAuthError,
|
||||
} from "../error/BrowserConfigurationAuthError.js";
|
||||
import { CookieStorage, SameSiteOptions } from "./CookieStorage.js";
|
||||
import { IWindowStorage } from "./IWindowStorage.js";
|
||||
import { MemoryStorage } from "./MemoryStorage.js";
|
||||
import { getAccountKeys, getTokenKeys } from "./CacheHelpers.js";
|
||||
import * as CacheKeys from "./CacheKeys.js";
|
||||
import { EncryptedData, isEncrypted } from "./EncryptedData.js";
|
||||
|
||||
const ENCRYPTION_KEY = "msal.cache.encryption";
|
||||
const BROADCAST_CHANNEL_NAME = "msal.broadcast.cache";
|
||||
|
||||
type EncryptionCookie = {
|
||||
id: string;
|
||||
key: CryptoKey;
|
||||
};
|
||||
|
||||
export class LocalStorage implements IWindowStorage<string> {
|
||||
private clientId: string;
|
||||
private initialized: boolean;
|
||||
private memoryStorage: MemoryStorage<string>;
|
||||
private performanceClient: IPerformanceClient;
|
||||
private logger: Logger;
|
||||
private encryptionCookie?: EncryptionCookie;
|
||||
private broadcast: BroadcastChannel;
|
||||
|
||||
constructor(
|
||||
clientId: string,
|
||||
logger: Logger,
|
||||
performanceClient: IPerformanceClient
|
||||
) {
|
||||
if (!window.localStorage) {
|
||||
throw createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.storageNotSupported
|
||||
);
|
||||
}
|
||||
this.memoryStorage = new MemoryStorage<string>();
|
||||
this.initialized = false;
|
||||
this.clientId = clientId;
|
||||
this.logger = logger;
|
||||
this.performanceClient = performanceClient;
|
||||
this.broadcast = new BroadcastChannel(BROADCAST_CHANNEL_NAME);
|
||||
}
|
||||
|
||||
async initialize(correlationId: string): Promise<void> {
|
||||
const cookies = new CookieStorage();
|
||||
const cookieString = cookies.getItem(ENCRYPTION_KEY);
|
||||
let parsedCookie = { key: "", id: "" };
|
||||
if (cookieString) {
|
||||
try {
|
||||
parsedCookie = JSON.parse(cookieString);
|
||||
} catch (e) {}
|
||||
}
|
||||
if (parsedCookie.key && parsedCookie.id) {
|
||||
// Encryption key already exists, import
|
||||
const baseKey = invoke(
|
||||
base64DecToArr,
|
||||
BrowserPerformanceEvents.Base64Decode,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)(parsedCookie.key);
|
||||
this.encryptionCookie = {
|
||||
id: parsedCookie.id,
|
||||
key: await invokeAsync(
|
||||
generateHKDF,
|
||||
BrowserPerformanceEvents.GenerateHKDF,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)(baseKey),
|
||||
};
|
||||
} else {
|
||||
// Encryption key doesn't exist or is invalid, generate a new one
|
||||
const id = createNewGuid();
|
||||
const baseKey = await invokeAsync(
|
||||
generateBaseKey,
|
||||
BrowserPerformanceEvents.GenerateBaseKey,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)();
|
||||
const keyStr = invoke(
|
||||
urlEncodeArr,
|
||||
BrowserPerformanceEvents.UrlEncodeArr,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)(new Uint8Array(baseKey));
|
||||
this.encryptionCookie = {
|
||||
id: id,
|
||||
key: await invokeAsync(
|
||||
generateHKDF,
|
||||
BrowserPerformanceEvents.GenerateHKDF,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)(baseKey),
|
||||
};
|
||||
|
||||
const cookieData = {
|
||||
id: id,
|
||||
key: keyStr,
|
||||
};
|
||||
|
||||
cookies.setItem(
|
||||
ENCRYPTION_KEY,
|
||||
JSON.stringify(cookieData),
|
||||
0, // Expiration - 0 means cookie will be cleared at the end of the browser session
|
||||
true, // Secure flag
|
||||
SameSiteOptions.None // SameSite must be None to support iframed apps
|
||||
);
|
||||
}
|
||||
|
||||
await invokeAsync(
|
||||
this.importExistingCache.bind(this),
|
||||
BrowserPerformanceEvents.ImportExistingCache,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)(correlationId);
|
||||
|
||||
// Register listener for cache updates in other tabs
|
||||
this.broadcast.addEventListener("message", (event: MessageEvent) => {
|
||||
this.updateCache(event, correlationId);
|
||||
});
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
getItem(key: string): string | null {
|
||||
return window.localStorage.getItem(key);
|
||||
}
|
||||
|
||||
getUserData(key: string): string | null {
|
||||
if (!this.initialized) {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.uninitializedPublicClientApplication
|
||||
);
|
||||
}
|
||||
return this.memoryStorage.getItem(key);
|
||||
}
|
||||
|
||||
async decryptData(
|
||||
key: string,
|
||||
data: EncryptedData,
|
||||
correlationId: string
|
||||
): Promise<object | null> {
|
||||
if (!this.initialized || !this.encryptionCookie) {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.uninitializedPublicClientApplication
|
||||
);
|
||||
}
|
||||
|
||||
if (data.id !== this.encryptionCookie.id) {
|
||||
// Data was encrypted with a different key. It must be removed because it is from a previous session.
|
||||
this.performanceClient.incrementFields(
|
||||
{ encryptedCacheExpiredCount: 1 },
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const decryptedData = await invokeAsync(
|
||||
decrypt,
|
||||
BrowserPerformanceEvents.Decrypt,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)(
|
||||
this.encryptionCookie.key,
|
||||
data.nonce,
|
||||
this.getContext(key),
|
||||
data.data
|
||||
);
|
||||
|
||||
if (!decryptedData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return {
|
||||
...JSON.parse(decryptedData),
|
||||
lastUpdatedAt: data.lastUpdatedAt,
|
||||
};
|
||||
} catch (e) {
|
||||
this.performanceClient.incrementFields(
|
||||
{ encryptedCacheCorruptionCount: 1 },
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
setItem(key: string, value: string): void {
|
||||
window.localStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
async setUserData(
|
||||
key: string,
|
||||
value: string,
|
||||
correlationId: string,
|
||||
timestamp: string,
|
||||
kmsi: boolean
|
||||
): Promise<void> {
|
||||
if (!this.initialized || !this.encryptionCookie) {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.uninitializedPublicClientApplication
|
||||
);
|
||||
}
|
||||
|
||||
if (kmsi) {
|
||||
this.setItem(key, value);
|
||||
} else {
|
||||
const { data, nonce } = await invokeAsync(
|
||||
encrypt,
|
||||
BrowserPerformanceEvents.Encrypt,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)(this.encryptionCookie.key, value, this.getContext(key));
|
||||
const encryptedData: EncryptedData = {
|
||||
id: this.encryptionCookie.id,
|
||||
nonce: nonce,
|
||||
data: data,
|
||||
lastUpdatedAt: timestamp,
|
||||
};
|
||||
this.setItem(key, JSON.stringify(encryptedData));
|
||||
}
|
||||
|
||||
this.memoryStorage.setItem(key, value);
|
||||
|
||||
// Notify other frames to update their in-memory cache
|
||||
this.broadcast.postMessage({
|
||||
key: key,
|
||||
value: value,
|
||||
context: this.getContext(key),
|
||||
});
|
||||
}
|
||||
|
||||
removeItem(key: string): void {
|
||||
if (this.memoryStorage.containsKey(key)) {
|
||||
this.memoryStorage.removeItem(key);
|
||||
this.broadcast.postMessage({
|
||||
key: key,
|
||||
value: null,
|
||||
context: this.getContext(key),
|
||||
});
|
||||
}
|
||||
window.localStorage.removeItem(key);
|
||||
}
|
||||
|
||||
getKeys(): string[] {
|
||||
return Object.keys(window.localStorage);
|
||||
}
|
||||
|
||||
containsKey(key: string): boolean {
|
||||
return window.localStorage.hasOwnProperty(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all known MSAL keys from the cache
|
||||
*/
|
||||
clear(): void {
|
||||
// Removes all remaining MSAL cache items
|
||||
this.memoryStorage.clear();
|
||||
|
||||
const accountKeys = getAccountKeys(this);
|
||||
accountKeys.forEach((key) => this.removeItem(key));
|
||||
const tokenKeys = getTokenKeys(this.clientId, this);
|
||||
tokenKeys.idToken.forEach((key) => this.removeItem(key));
|
||||
tokenKeys.accessToken.forEach((key) => this.removeItem(key));
|
||||
tokenKeys.refreshToken.forEach((key) => this.removeItem(key));
|
||||
|
||||
// Clean up anything left
|
||||
this.getKeys().forEach((cacheKey: string) => {
|
||||
if (
|
||||
cacheKey.startsWith(CacheKeys.PREFIX) ||
|
||||
cacheKey.indexOf(this.clientId) !== -1
|
||||
) {
|
||||
this.removeItem(cacheKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to decrypt all known MSAL keys in localStorage and save them to inMemory storage
|
||||
* @returns
|
||||
*/
|
||||
private async importExistingCache(correlationId: string): Promise<void> {
|
||||
if (!this.encryptionCookie) {
|
||||
return;
|
||||
}
|
||||
|
||||
let accountKeys = getAccountKeys(this);
|
||||
accountKeys = await this.importArray(accountKeys, correlationId);
|
||||
// Write valid account keys back to map
|
||||
if (accountKeys.length) {
|
||||
this.setItem(
|
||||
CacheKeys.getAccountKeysCacheKey(),
|
||||
JSON.stringify(accountKeys)
|
||||
);
|
||||
} else {
|
||||
this.removeItem(CacheKeys.getAccountKeysCacheKey());
|
||||
}
|
||||
|
||||
const tokenKeys: TokenKeys = getTokenKeys(this.clientId, this);
|
||||
tokenKeys.idToken = await this.importArray(
|
||||
tokenKeys.idToken,
|
||||
correlationId
|
||||
);
|
||||
tokenKeys.accessToken = await this.importArray(
|
||||
tokenKeys.accessToken,
|
||||
correlationId
|
||||
);
|
||||
tokenKeys.refreshToken = await this.importArray(
|
||||
tokenKeys.refreshToken,
|
||||
correlationId
|
||||
);
|
||||
// Write valid token keys back to map
|
||||
if (
|
||||
tokenKeys.idToken.length ||
|
||||
tokenKeys.accessToken.length ||
|
||||
tokenKeys.refreshToken.length
|
||||
) {
|
||||
this.setItem(
|
||||
CacheKeys.getTokenKeysCacheKey(this.clientId),
|
||||
JSON.stringify(tokenKeys)
|
||||
);
|
||||
} else {
|
||||
this.removeItem(CacheKeys.getTokenKeysCacheKey(this.clientId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to decrypt and save cache entries
|
||||
* @param key
|
||||
* @returns
|
||||
*/
|
||||
private async getItemFromEncryptedCache(
|
||||
key: string,
|
||||
correlationId: string
|
||||
): Promise<string | null> {
|
||||
if (!this.encryptionCookie) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rawCache = this.getItem(key);
|
||||
if (!rawCache) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let encObj: EncryptedData;
|
||||
try {
|
||||
encObj = JSON.parse(rawCache);
|
||||
} catch (e) {
|
||||
// Not a valid encrypted object, remove
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isEncrypted(encObj)) {
|
||||
// Data is not encrypted
|
||||
this.performanceClient.incrementFields(
|
||||
{ unencryptedCacheCount: 1 },
|
||||
correlationId
|
||||
);
|
||||
return rawCache;
|
||||
}
|
||||
|
||||
if (encObj.id !== this.encryptionCookie.id) {
|
||||
// Data was encrypted with a different key. It must be removed because it is from a previous session.
|
||||
this.performanceClient.incrementFields(
|
||||
{ encryptedCacheExpiredCount: 1 },
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
this.performanceClient.incrementFields(
|
||||
{ encryptedCacheCount: 1 },
|
||||
correlationId
|
||||
);
|
||||
|
||||
return invokeAsync(
|
||||
decrypt,
|
||||
BrowserPerformanceEvents.Decrypt,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
correlationId
|
||||
)(
|
||||
this.encryptionCookie.key,
|
||||
encObj.nonce,
|
||||
this.getContext(key),
|
||||
encObj.data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to decrypt and save an array of cache keys
|
||||
* @param arr
|
||||
* @returns Array of keys successfully imported
|
||||
*/
|
||||
private async importArray(
|
||||
arr: Array<string>,
|
||||
correlationId: string
|
||||
): Promise<Array<string>> {
|
||||
const importedArr: Array<string> = [];
|
||||
const promiseArr: Array<Promise<void>> = [];
|
||||
arr.forEach((key) => {
|
||||
const promise = this.getItemFromEncryptedCache(
|
||||
key,
|
||||
correlationId
|
||||
).then((value) => {
|
||||
if (value) {
|
||||
this.memoryStorage.setItem(key, value);
|
||||
importedArr.push(key);
|
||||
} else {
|
||||
// If value is empty, unencrypted or expired remove
|
||||
this.removeItem(key);
|
||||
}
|
||||
});
|
||||
promiseArr.push(promise);
|
||||
});
|
||||
|
||||
await Promise.all(promiseArr);
|
||||
return importedArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets encryption context for a given cache entry. This is clientId for app specific entries, empty string for shared entries
|
||||
* @param key
|
||||
* @returns
|
||||
*/
|
||||
private getContext(key: string): string {
|
||||
let context = "";
|
||||
if (key.includes(this.clientId)) {
|
||||
context = this.clientId; // Used to bind encryption key to this appId
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private updateCache(event: MessageEvent, correlationId: string): void {
|
||||
this.logger.trace(
|
||||
"Updating internal cache from broadcast event",
|
||||
correlationId
|
||||
);
|
||||
const perfMeasurement = this.performanceClient.startMeasurement(
|
||||
BrowserRootPerformanceEvents.LocalStorageUpdated
|
||||
);
|
||||
perfMeasurement.add({ isBackground: true });
|
||||
|
||||
const { key, value, context } = event.data;
|
||||
if (!key) {
|
||||
this.logger.error("Broadcast event missing key", correlationId);
|
||||
perfMeasurement.end({ success: false, errorCode: "noKey" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (context && context !== this.clientId) {
|
||||
this.logger.trace(
|
||||
`Ignoring broadcast event from clientId: '${context}'`,
|
||||
correlationId
|
||||
);
|
||||
perfMeasurement.end({
|
||||
success: false,
|
||||
errorCode: "contextMismatch",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
this.memoryStorage.removeItem(key);
|
||||
this.logger.verbose(
|
||||
"Removed item from internal cache",
|
||||
correlationId
|
||||
);
|
||||
} else {
|
||||
this.memoryStorage.setItem(key, value);
|
||||
this.logger.verbose(
|
||||
"Updated item in internal cache",
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
perfMeasurement.end({ success: true });
|
||||
}
|
||||
}
|
||||
59
backend/node_modules/@azure/msal-browser/src/cache/MemoryStorage.ts
generated
vendored
Normal file
59
backend/node_modules/@azure/msal-browser/src/cache/MemoryStorage.ts
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { IWindowStorage } from "./IWindowStorage.js";
|
||||
|
||||
export class MemoryStorage<T> implements IWindowStorage<T> {
|
||||
private cache: Map<string, T>;
|
||||
|
||||
constructor() {
|
||||
this.cache = new Map<string, T>();
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
// Memory storage does not require initialization
|
||||
}
|
||||
|
||||
getItem(key: string): T | null {
|
||||
return this.cache.get(key) || null;
|
||||
}
|
||||
|
||||
getUserData(key: string): T | null {
|
||||
return this.getItem(key);
|
||||
}
|
||||
|
||||
setItem(key: string, value: T): void {
|
||||
this.cache.set(key, value);
|
||||
}
|
||||
|
||||
async setUserData(key: string, value: T): Promise<void> {
|
||||
this.setItem(key, value);
|
||||
}
|
||||
|
||||
removeItem(key: string): void {
|
||||
this.cache.delete(key);
|
||||
}
|
||||
|
||||
getKeys(): string[] {
|
||||
const cacheKeys: string[] = [];
|
||||
this.cache.forEach((value: T, key: string) => {
|
||||
cacheKeys.push(key);
|
||||
});
|
||||
return cacheKeys;
|
||||
}
|
||||
|
||||
containsKey(key: string): boolean {
|
||||
return this.cache.has(key);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
decryptData(): Promise<object | null> {
|
||||
// Memory storage does not support encryption, so this method is a no-op
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
57
backend/node_modules/@azure/msal-browser/src/cache/SessionStorage.ts
generated
vendored
Normal file
57
backend/node_modules/@azure/msal-browser/src/cache/SessionStorage.ts
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
BrowserConfigurationAuthErrorCodes,
|
||||
createBrowserConfigurationAuthError,
|
||||
} from "../error/BrowserConfigurationAuthError.js";
|
||||
import { IWindowStorage } from "./IWindowStorage.js";
|
||||
|
||||
export class SessionStorage implements IWindowStorage<string> {
|
||||
constructor() {
|
||||
if (!window.sessionStorage) {
|
||||
throw createBrowserConfigurationAuthError(
|
||||
BrowserConfigurationAuthErrorCodes.storageNotSupported
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
// Session storage does not require initialization
|
||||
}
|
||||
|
||||
getItem(key: string): string | null {
|
||||
return window.sessionStorage.getItem(key);
|
||||
}
|
||||
|
||||
getUserData(key: string): string | null {
|
||||
return this.getItem(key);
|
||||
}
|
||||
|
||||
setItem(key: string, value: string): void {
|
||||
window.sessionStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
async setUserData(key: string, value: string): Promise<void> {
|
||||
this.setItem(key, value);
|
||||
}
|
||||
|
||||
removeItem(key: string): void {
|
||||
window.sessionStorage.removeItem(key);
|
||||
}
|
||||
|
||||
getKeys(): string[] {
|
||||
return Object.keys(window.sessionStorage);
|
||||
}
|
||||
|
||||
containsKey(key: string): boolean {
|
||||
return window.sessionStorage.hasOwnProperty(key);
|
||||
}
|
||||
|
||||
decryptData(): Promise<object | null> {
|
||||
// Session storage does not support encryption, so this method is a no-op
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
523
backend/node_modules/@azure/msal-browser/src/cache/TokenCache.ts
generated
vendored
Normal file
523
backend/node_modules/@azure/msal-browser/src/cache/TokenCache.ts
generated
vendored
Normal file
@ -0,0 +1,523 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AccessTokenEntity,
|
||||
AccountEntity,
|
||||
AccountEntityUtils,
|
||||
Authority,
|
||||
AuthorityFactory,
|
||||
AuthorityOptions,
|
||||
AuthToken,
|
||||
buildAccountToCache,
|
||||
buildStaticAuthorityOptions,
|
||||
CacheHelpers,
|
||||
CacheRecord,
|
||||
ExternalTokenResponse,
|
||||
ICrypto,
|
||||
IdTokenEntity,
|
||||
invokeAsync,
|
||||
IPerformanceClient,
|
||||
Logger,
|
||||
RefreshTokenEntity,
|
||||
ScopeSet,
|
||||
StubPerformanceClient,
|
||||
TimeUtils,
|
||||
TokenClaims,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { buildConfiguration, Configuration } from "../config/Configuration.js";
|
||||
import * as BrowserCrypto from "../crypto/BrowserCrypto.js";
|
||||
import { CryptoOps } from "../crypto/CryptoOps.js";
|
||||
import { base64Decode } from "../encode/Base64Decode.js";
|
||||
import {
|
||||
BrowserAuthErrorCodes,
|
||||
createBrowserAuthError,
|
||||
} from "../error/BrowserAuthError.js";
|
||||
import { EventHandler } from "../event/EventHandler.js";
|
||||
import type { SilentRequest } from "../request/SilentRequest.js";
|
||||
import type { AuthenticationResult } from "../response/AuthenticationResult.js";
|
||||
import * as BrowserPerformanceEvents from "../telemetry/BrowserPerformanceEvents.js";
|
||||
import * as BrowserRootPerformanceEvents from "../telemetry/BrowserRootPerformanceEvents.js";
|
||||
import { ApiId } from "../utils/BrowserConstants.js";
|
||||
import * as BrowserUtils from "../utils/BrowserUtils.js";
|
||||
import { BrowserCacheManager } from "./BrowserCacheManager.js";
|
||||
|
||||
export type LoadTokenOptions = {
|
||||
clientInfo?: string;
|
||||
expiresOn?: number;
|
||||
extendedExpiresOn?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* API to load tokens to msal-browser cache.
|
||||
* @param config - Object to configure the MSAL app.
|
||||
* @param request - Silent request containing authority, scopes, and account.
|
||||
* @param response - External token response to load into the cache.
|
||||
* @param options - Options controlling how tokens are loaded into the cache.
|
||||
* @param performanceClient - Optional performance client used for telemetry measurements.
|
||||
* @returns `AuthenticationResult` for the response that was loaded.
|
||||
*/
|
||||
export async function loadExternalTokens(
|
||||
config: Configuration,
|
||||
request: SilentRequest,
|
||||
response: ExternalTokenResponse,
|
||||
options: LoadTokenOptions,
|
||||
performanceClient: IPerformanceClient = new StubPerformanceClient()
|
||||
): Promise<AuthenticationResult> {
|
||||
BrowserUtils.blockNonBrowserEnvironment();
|
||||
|
||||
const browserConfig = buildConfiguration(config, true);
|
||||
|
||||
const correlationId =
|
||||
request.correlationId || BrowserCrypto.createNewGuid();
|
||||
|
||||
const rootMeasurement = performanceClient.startMeasurement(
|
||||
BrowserRootPerformanceEvents.LoadExternalTokens,
|
||||
correlationId
|
||||
);
|
||||
|
||||
try {
|
||||
const idTokenClaims = response.id_token
|
||||
? AuthToken.extractTokenClaims(response.id_token, base64Decode)
|
||||
: undefined;
|
||||
const kmsi = AuthToken.isKmsi(idTokenClaims || {});
|
||||
|
||||
const authorityOptions: AuthorityOptions = {
|
||||
protocolMode: browserConfig.system.protocolMode,
|
||||
knownAuthorities: browserConfig.auth.knownAuthorities,
|
||||
cloudDiscoveryMetadata: browserConfig.auth.cloudDiscoveryMetadata,
|
||||
authorityMetadata: browserConfig.auth.authorityMetadata,
|
||||
};
|
||||
|
||||
const logger = new Logger(browserConfig.system.loggerOptions || {});
|
||||
const cryptoOps = new CryptoOps(logger, browserConfig.telemetry.client);
|
||||
const storage = new BrowserCacheManager(
|
||||
browserConfig.auth.clientId,
|
||||
browserConfig.cache,
|
||||
cryptoOps,
|
||||
logger,
|
||||
browserConfig.telemetry.client,
|
||||
new EventHandler(logger),
|
||||
buildStaticAuthorityOptions(browserConfig.auth)
|
||||
);
|
||||
|
||||
const authorityString =
|
||||
request.authority || browserConfig.auth.authority;
|
||||
const authority = await AuthorityFactory.createDiscoveredInstance(
|
||||
Authority.generateAuthority(
|
||||
authorityString,
|
||||
request.azureCloudOptions
|
||||
),
|
||||
browserConfig.system.networkClient,
|
||||
storage,
|
||||
authorityOptions,
|
||||
logger,
|
||||
correlationId,
|
||||
performanceClient
|
||||
);
|
||||
|
||||
const cacheRecordAccount: AccountEntity = await invokeAsync(
|
||||
loadAccount,
|
||||
BrowserPerformanceEvents.LoadAccount,
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
)(
|
||||
request,
|
||||
options.clientInfo || response.client_info || "",
|
||||
correlationId,
|
||||
storage,
|
||||
logger,
|
||||
cryptoOps,
|
||||
authority,
|
||||
idTokenClaims,
|
||||
performanceClient
|
||||
);
|
||||
|
||||
const idToken = await invokeAsync(
|
||||
loadIdToken,
|
||||
BrowserPerformanceEvents.LoadIdToken,
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
)(
|
||||
response,
|
||||
cacheRecordAccount.homeAccountId,
|
||||
cacheRecordAccount.environment,
|
||||
cacheRecordAccount.realm,
|
||||
kmsi,
|
||||
correlationId,
|
||||
storage,
|
||||
logger,
|
||||
config.auth.clientId
|
||||
);
|
||||
|
||||
const accessToken = await invokeAsync(
|
||||
loadAccessToken,
|
||||
BrowserPerformanceEvents.LoadAccessToken,
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
)(
|
||||
request,
|
||||
response,
|
||||
cacheRecordAccount.homeAccountId,
|
||||
cacheRecordAccount.environment,
|
||||
cacheRecordAccount.realm,
|
||||
kmsi,
|
||||
options,
|
||||
correlationId,
|
||||
storage,
|
||||
logger,
|
||||
config.auth.clientId
|
||||
);
|
||||
|
||||
const refreshToken = await invokeAsync(
|
||||
loadRefreshToken,
|
||||
BrowserPerformanceEvents.LoadRefreshToken,
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
)(
|
||||
response,
|
||||
cacheRecordAccount.homeAccountId,
|
||||
cacheRecordAccount.environment,
|
||||
kmsi,
|
||||
correlationId,
|
||||
storage,
|
||||
logger,
|
||||
config.auth.clientId,
|
||||
performanceClient
|
||||
);
|
||||
|
||||
rootMeasurement.end(
|
||||
{ success: true },
|
||||
undefined,
|
||||
AccountEntityUtils.getAccountInfo(cacheRecordAccount)
|
||||
);
|
||||
|
||||
return generateAuthenticationResult(
|
||||
request,
|
||||
{
|
||||
account: cacheRecordAccount,
|
||||
idToken,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
},
|
||||
authority,
|
||||
idTokenClaims
|
||||
);
|
||||
} catch (error) {
|
||||
rootMeasurement.end({ success: false }, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to load account to msal-browser cache
|
||||
* @param idToken
|
||||
* @param environment
|
||||
* @param clientInfo
|
||||
* @param authorityType
|
||||
* @param requestHomeAccountId
|
||||
* @returns `AccountEntity`
|
||||
*/
|
||||
async function loadAccount(
|
||||
request: SilentRequest,
|
||||
clientInfo: string,
|
||||
correlationId: string,
|
||||
storage: BrowserCacheManager,
|
||||
logger: Logger,
|
||||
cryptoObj: ICrypto,
|
||||
authority: Authority,
|
||||
idTokenClaims?: TokenClaims,
|
||||
performanceClient?: IPerformanceClient
|
||||
): Promise<AccountEntity> {
|
||||
logger.verbose("TokenCache - loading account", correlationId);
|
||||
|
||||
if (request.account) {
|
||||
const accountEntity =
|
||||
AccountEntityUtils.createAccountEntityFromAccountInfo(
|
||||
request.account
|
||||
);
|
||||
await storage.setAccount(
|
||||
accountEntity,
|
||||
correlationId,
|
||||
AuthToken.isKmsi(idTokenClaims || {}),
|
||||
ApiId.loadExternalTokens
|
||||
);
|
||||
return accountEntity;
|
||||
} else if (!clientInfo && !idTokenClaims) {
|
||||
logger.error(
|
||||
"TokenCache - if an account is not provided on the request, clientInfo or idToken must be provided instead.",
|
||||
correlationId
|
||||
);
|
||||
throw createBrowserAuthError(BrowserAuthErrorCodes.unableToLoadToken);
|
||||
}
|
||||
|
||||
const homeAccountId = AccountEntityUtils.generateHomeAccountId(
|
||||
clientInfo,
|
||||
authority.authorityType,
|
||||
logger,
|
||||
cryptoObj,
|
||||
correlationId,
|
||||
idTokenClaims
|
||||
);
|
||||
|
||||
const claimsTenantId = idTokenClaims?.tid;
|
||||
|
||||
const cachedAccount = buildAccountToCache(
|
||||
storage,
|
||||
authority,
|
||||
homeAccountId,
|
||||
base64Decode,
|
||||
correlationId,
|
||||
idTokenClaims,
|
||||
clientInfo,
|
||||
authority.getPreferredCache(),
|
||||
claimsTenantId,
|
||||
undefined, // authCodePayload
|
||||
undefined, // nativeAccountId
|
||||
logger,
|
||||
performanceClient
|
||||
);
|
||||
|
||||
await storage.setAccount(
|
||||
cachedAccount,
|
||||
correlationId,
|
||||
AuthToken.isKmsi(idTokenClaims || {}),
|
||||
ApiId.loadExternalTokens
|
||||
);
|
||||
return cachedAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to load id tokens to msal-browser cache
|
||||
* @param idToken
|
||||
* @param homeAccountId
|
||||
* @param environment
|
||||
* @param tenantId
|
||||
* @returns `IdTokenEntity`
|
||||
*/
|
||||
async function loadIdToken(
|
||||
response: ExternalTokenResponse,
|
||||
homeAccountId: string,
|
||||
environment: string,
|
||||
tenantId: string,
|
||||
kmsi: boolean,
|
||||
correlationId: string,
|
||||
storage: BrowserCacheManager,
|
||||
logger: Logger,
|
||||
clientId: string
|
||||
): Promise<IdTokenEntity | null> {
|
||||
if (!response.id_token) {
|
||||
logger.verbose(
|
||||
"TokenCache - no id token found in response",
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.verbose("TokenCache - loading id token", correlationId);
|
||||
const idTokenEntity = CacheHelpers.createIdTokenEntity(
|
||||
homeAccountId,
|
||||
environment,
|
||||
response.id_token,
|
||||
clientId,
|
||||
tenantId
|
||||
);
|
||||
|
||||
await storage.setIdTokenCredential(idTokenEntity, correlationId, kmsi);
|
||||
return idTokenEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to load access tokens to msal-browser cache
|
||||
* @param request
|
||||
* @param response
|
||||
* @param homeAccountId
|
||||
* @param environment
|
||||
* @param tenantId
|
||||
* @returns `AccessTokenEntity`
|
||||
*/
|
||||
async function loadAccessToken(
|
||||
request: SilentRequest,
|
||||
response: ExternalTokenResponse,
|
||||
homeAccountId: string,
|
||||
environment: string,
|
||||
tenantId: string,
|
||||
kmsi: boolean,
|
||||
options: LoadTokenOptions,
|
||||
correlationId: string,
|
||||
storage: BrowserCacheManager,
|
||||
logger: Logger,
|
||||
clientId: string
|
||||
): Promise<AccessTokenEntity | null> {
|
||||
if (!response.access_token) {
|
||||
logger.verbose(
|
||||
"TokenCache - no access token found in response",
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
} else if (!response.expires_in) {
|
||||
logger.error(
|
||||
"TokenCache - no expiration set on the access token. Cannot add it to the cache.",
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
} else if (!response.scope && (!request.scopes || !request.scopes.length)) {
|
||||
logger.error(
|
||||
"TokenCache - scopes not specified in the request or response. Cannot add token to the cache.",
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.verbose("TokenCache - loading access token", correlationId);
|
||||
|
||||
const scopes = response.scope
|
||||
? ScopeSet.fromString(response.scope)
|
||||
: new ScopeSet(request.scopes);
|
||||
const expiresOn =
|
||||
options.expiresOn || response.expires_in + TimeUtils.nowSeconds();
|
||||
|
||||
const extendedExpiresOn =
|
||||
options.extendedExpiresOn ||
|
||||
(response.ext_expires_in || response.expires_in) +
|
||||
TimeUtils.nowSeconds();
|
||||
|
||||
const accessTokenEntity = CacheHelpers.createAccessTokenEntity(
|
||||
homeAccountId,
|
||||
environment,
|
||||
response.access_token,
|
||||
clientId,
|
||||
tenantId,
|
||||
scopes.printScopes(),
|
||||
expiresOn,
|
||||
extendedExpiresOn,
|
||||
base64Decode
|
||||
);
|
||||
|
||||
await storage.setAccessTokenCredential(
|
||||
accessTokenEntity,
|
||||
correlationId,
|
||||
kmsi
|
||||
);
|
||||
return accessTokenEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to load refresh tokens to msal-browser cache
|
||||
* @param request
|
||||
* @param response
|
||||
* @param homeAccountId
|
||||
* @param environment
|
||||
* @returns `RefreshTokenEntity`
|
||||
*/
|
||||
async function loadRefreshToken(
|
||||
response: ExternalTokenResponse,
|
||||
homeAccountId: string,
|
||||
environment: string,
|
||||
kmsi: boolean,
|
||||
correlationId: string,
|
||||
storage: BrowserCacheManager,
|
||||
logger: Logger,
|
||||
clientId: string,
|
||||
performanceClient: IPerformanceClient
|
||||
): Promise<RefreshTokenEntity | null> {
|
||||
if (!response.refresh_token) {
|
||||
logger.verbose(
|
||||
"TokenCache - no refresh token found in response",
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const expiresOn = response.refresh_token_expires_in
|
||||
? response.refresh_token_expires_in + TimeUtils.nowSeconds()
|
||||
: undefined;
|
||||
performanceClient.addFields(
|
||||
{
|
||||
extRtExpiresOnSeconds: expiresOn,
|
||||
},
|
||||
correlationId
|
||||
);
|
||||
|
||||
logger.verbose("TokenCache - loading refresh token", correlationId);
|
||||
const refreshTokenEntity = CacheHelpers.createRefreshTokenEntity(
|
||||
homeAccountId,
|
||||
environment,
|
||||
response.refresh_token,
|
||||
clientId,
|
||||
response.foci,
|
||||
undefined, // userAssertionHash
|
||||
expiresOn
|
||||
);
|
||||
|
||||
await storage.setRefreshTokenCredential(
|
||||
refreshTokenEntity,
|
||||
correlationId,
|
||||
kmsi
|
||||
);
|
||||
return refreshTokenEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to generate an `AuthenticationResult` for the result.
|
||||
* @param request
|
||||
* @param idTokenObj
|
||||
* @param cacheRecord
|
||||
* @param authority
|
||||
* @returns `AuthenticationResult`
|
||||
*/
|
||||
function generateAuthenticationResult(
|
||||
request: SilentRequest,
|
||||
cacheRecord: CacheRecord & { account: AccountEntity },
|
||||
authority: Authority,
|
||||
idTokenClaims?: TokenClaims
|
||||
): AuthenticationResult {
|
||||
let accessToken: string = "";
|
||||
let responseScopes: Array<string> = [];
|
||||
let expiresOn: Date | null = null;
|
||||
let extExpiresOn: Date | undefined;
|
||||
|
||||
if (cacheRecord?.accessToken) {
|
||||
accessToken = cacheRecord.accessToken.secret;
|
||||
responseScopes = ScopeSet.fromString(
|
||||
cacheRecord.accessToken.target
|
||||
).asArray();
|
||||
// Access token expiresOn stored in seconds, converting to Date for AuthenticationResult
|
||||
expiresOn = TimeUtils.toDateFromSeconds(
|
||||
cacheRecord.accessToken.expiresOn
|
||||
);
|
||||
extExpiresOn = TimeUtils.toDateFromSeconds(
|
||||
cacheRecord.accessToken.extendedExpiresOn
|
||||
);
|
||||
}
|
||||
|
||||
const accountEntity = cacheRecord.account;
|
||||
|
||||
return {
|
||||
authority: authority.canonicalAuthority,
|
||||
uniqueId: cacheRecord.account.localAccountId,
|
||||
tenantId: cacheRecord.account.realm,
|
||||
scopes: responseScopes,
|
||||
account: AccountEntityUtils.getAccountInfo(accountEntity),
|
||||
idToken: cacheRecord.idToken?.secret || "",
|
||||
idTokenClaims: idTokenClaims || {},
|
||||
accessToken: accessToken,
|
||||
fromCache: true,
|
||||
expiresOn: expiresOn,
|
||||
correlationId: request.correlationId || "",
|
||||
requestId: "",
|
||||
extExpiresOn: extExpiresOn,
|
||||
familyId: cacheRecord.refreshToken?.familyId || "",
|
||||
tokenType: cacheRecord?.accessToken?.tokenType || "",
|
||||
state: request.state || "",
|
||||
cloudGraphHostName: accountEntity.cloudGraphHostName || "",
|
||||
msGraphHost: accountEntity.msGraphHost || "",
|
||||
fromPlatformBroker: false,
|
||||
};
|
||||
}
|
||||
385
backend/node_modules/@azure/msal-browser/src/config/Configuration.ts
generated
vendored
Normal file
385
backend/node_modules/@azure/msal-browser/src/config/Configuration.ts
generated
vendored
Normal file
@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
SystemOptions,
|
||||
LoggerOptions,
|
||||
INetworkModule,
|
||||
DEFAULT_SYSTEM_OPTIONS,
|
||||
ProtocolMode,
|
||||
OIDCOptions,
|
||||
LogLevel,
|
||||
StubbedNetworkModule,
|
||||
AzureCloudInstance,
|
||||
AzureCloudOptions,
|
||||
ApplicationTelemetry,
|
||||
createClientConfigurationError,
|
||||
ClientConfigurationErrorCodes,
|
||||
IPerformanceClient,
|
||||
StubPerformanceClient,
|
||||
Logger,
|
||||
Constants,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { BrowserCacheLocation } from "../utils/BrowserConstants.js";
|
||||
import { INavigationClient } from "../navigation/INavigationClient.js";
|
||||
import { NavigationClient } from "../navigation/NavigationClient.js";
|
||||
import { FetchClient } from "../network/FetchClient.js";
|
||||
|
||||
// Default timeout for popup windows and iframes in milliseconds
|
||||
export const DEFAULT_POPUP_TIMEOUT_MS = 60000;
|
||||
export const DEFAULT_IFRAME_TIMEOUT_MS = 10000;
|
||||
export const DEFAULT_REDIRECT_TIMEOUT_MS = 30000;
|
||||
export const DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS = 2000;
|
||||
|
||||
/**
|
||||
* Use this to configure the auth options in the Configuration object
|
||||
*/
|
||||
export type BrowserAuthOptions = {
|
||||
/**
|
||||
* Client ID of your app registered with our Application registration portal : https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview in Microsoft Identity Platform
|
||||
*/
|
||||
clientId: string;
|
||||
/**
|
||||
* You can configure a specific authority, defaults to " " or "https://login.microsoftonline.com/common"
|
||||
*/
|
||||
authority?: string;
|
||||
/**
|
||||
* An array of URIs that are known to be valid. Used in B2C scenarios.
|
||||
*/
|
||||
knownAuthorities?: Array<string>;
|
||||
/**
|
||||
* A string containing the cloud discovery response. Used in AAD scenarios.
|
||||
*/
|
||||
cloudDiscoveryMetadata?: string;
|
||||
/**
|
||||
* A string containing the .well-known/openid-configuration endpoint response
|
||||
*/
|
||||
authorityMetadata?: string;
|
||||
/**
|
||||
* The redirect URI where authentication responses can be received by your application. It must exactly match one of the redirect URIs registered in the Azure portal.
|
||||
*/
|
||||
redirectUri?: string;
|
||||
/**
|
||||
* The redirect URI where the window navigates after a successful logout.
|
||||
*/
|
||||
postLogoutRedirectUri?: string | null;
|
||||
|
||||
/**
|
||||
* Array of capabilities which will be added to the claims.access_token.xms_cc request property on every network request.
|
||||
*/
|
||||
clientCapabilities?: Array<string>;
|
||||
/**
|
||||
* Enum that configures options for the OIDC protocol mode.
|
||||
*/
|
||||
OIDCOptions?: OIDCOptions;
|
||||
/**
|
||||
* Enum that represents the Azure Cloud to use.
|
||||
*/
|
||||
azureCloudOptions?: AzureCloudOptions;
|
||||
/**
|
||||
* Callback that will be passed the url that MSAL will navigate to in redirect flows. Returning false in the callback will stop navigation.
|
||||
*/
|
||||
onRedirectNavigate?: (url: string) => boolean | void;
|
||||
/**
|
||||
* Flag of whether the STS will send back additional parameters to specify where the tokens should be retrieved from.
|
||||
*/
|
||||
instanceAware?: boolean;
|
||||
/**
|
||||
* Flag on whether a resource parameter is required for token requests. Used for MCP flows.
|
||||
*/
|
||||
isMcp?: boolean;
|
||||
/**
|
||||
* If set to true, MSAL will make a background SSO verification call after successful interactive authentication.
|
||||
* This adds an extra network call, so it is recommended to leave this set to false unless your application has a specific need for it.
|
||||
* Additional network calls may occur after interactive authentication flows such as acquireTokenPopup and handleRedirectPromise.
|
||||
* This is a boolean flag and defaults to false if not specified.
|
||||
*/
|
||||
verifySSO?: boolean;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export type InternalAuthOptions = Omit<
|
||||
Required<BrowserAuthOptions>,
|
||||
"onRedirectNavigate"
|
||||
> & {
|
||||
OIDCOptions: Required<OIDCOptions>;
|
||||
onRedirectNavigate?: (url: string) => boolean | void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Use this to configure the below cache configuration options:
|
||||
*/
|
||||
export type CacheOptions = {
|
||||
/**
|
||||
* Used to specify the cacheLocation user wants to set. Valid values are "localStorage", "sessionStorage" and "memoryStorage".
|
||||
*/
|
||||
cacheLocation?: BrowserCacheLocation | string;
|
||||
/**
|
||||
* Used to specify the number of days cache entries written by previous versions of MSAL.js should be retained in the browser. Defaults to 5 days.
|
||||
*/
|
||||
cacheRetentionDays?: number;
|
||||
};
|
||||
|
||||
export type BrowserSystemOptions = SystemOptions & {
|
||||
/**
|
||||
* Used to initialize the Logger object (See ClientConfiguration.ts)
|
||||
*/
|
||||
loggerOptions?: LoggerOptions;
|
||||
/**
|
||||
* Network interface implementation
|
||||
*/
|
||||
networkClient?: INetworkModule;
|
||||
/**
|
||||
* Override the methods used to navigate to other webpages. Particularly useful if you are using a client-side router
|
||||
*/
|
||||
navigationClient?: INavigationClient;
|
||||
/**
|
||||
* Sets the timeout for waiting for response from a popup using BroadcastChannel
|
||||
*/
|
||||
popupBridgeTimeout?: number;
|
||||
/**
|
||||
* Sets the timeout for waiting for response from an iframe using BroadcastChannel
|
||||
*/
|
||||
iframeBridgeTimeout?: number;
|
||||
/**
|
||||
* Time to wait for redirection to occur before resolving promise
|
||||
*/
|
||||
redirectNavigationTimeout?: number;
|
||||
/**
|
||||
* Sets whether popups are opened and navigated to later. By default, this flag is set to true. When set to true, blank popups are opened and navigates to login domain. When set to false, popups are opened directly to the login domain.
|
||||
*/
|
||||
navigatePopups?: boolean;
|
||||
/**
|
||||
* Flag to enable redirect opertaions when the app is rendered in an iframe (to support scenarios such as embedded B2C login).
|
||||
*/
|
||||
allowRedirectInIframe?: boolean;
|
||||
/**
|
||||
* Flag to enable native broker support (e.g. acquiring tokens from WAM on Windows, MacBroker on Mac)
|
||||
*/
|
||||
allowPlatformBroker?: boolean;
|
||||
/**
|
||||
* Sets the timeout for waiting for the native broker handshake to resolve
|
||||
*/
|
||||
nativeBrokerHandshakeTimeout?: number;
|
||||
/**
|
||||
* Enum that represents the protocol that msal follows. Used for configuring proper endpoints.
|
||||
*/
|
||||
protocolMode?: ProtocolMode;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export type BrowserExperimentalOptions = {
|
||||
/**
|
||||
* Enables iframe timeout telemetry experiment for silent iframe bridge monitoring.
|
||||
*/
|
||||
iframeTimeoutTelemetry?: boolean;
|
||||
/**
|
||||
* Flag to enable native broker support through DOM APIs in Edge
|
||||
*/
|
||||
allowPlatformBrokerWithDOM?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Telemetry Options
|
||||
*/
|
||||
export type BrowserTelemetryOptions = {
|
||||
/**
|
||||
* Telemetry information sent on request
|
||||
* - appName: Unique string name of an application
|
||||
* - appVersion: Version of the application using MSAL
|
||||
*/
|
||||
application?: ApplicationTelemetry;
|
||||
|
||||
client?: IPerformanceClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This object allows you to configure important elements of MSAL functionality and is passed into the constructor of PublicClientApplication
|
||||
*/
|
||||
export type Configuration = {
|
||||
/**
|
||||
* This is where you configure auth elements like clientID, authority used for authenticating against the Microsoft Identity Platform
|
||||
*/
|
||||
auth: BrowserAuthOptions;
|
||||
/**
|
||||
* This is where you configure cache location and whether to store cache in cookies
|
||||
*/
|
||||
cache?: CacheOptions;
|
||||
/**
|
||||
* This is where you can configure the network client, logger, token renewal offset
|
||||
*/
|
||||
system?: BrowserSystemOptions;
|
||||
/**
|
||||
* This is where you can configure experimental features. These do not follow semver and may be changed or removed without a major version bump. Use with caution.
|
||||
*/
|
||||
experimental?: BrowserExperimentalOptions;
|
||||
/**
|
||||
* This is where you can configure telemetry data and options
|
||||
*/
|
||||
telemetry?: BrowserTelemetryOptions;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export type BrowserConfiguration = {
|
||||
auth: InternalAuthOptions;
|
||||
cache: Required<CacheOptions>;
|
||||
system: Required<BrowserSystemOptions>;
|
||||
experimental: Required<BrowserExperimentalOptions>;
|
||||
telemetry: Required<BrowserTelemetryOptions>;
|
||||
};
|
||||
|
||||
/**
|
||||
* MSAL function that sets the default options when not explicitly configured from app developer
|
||||
*
|
||||
* @param auth
|
||||
* @param cache
|
||||
* @param system
|
||||
*
|
||||
* @returns Configuration object
|
||||
*/
|
||||
export function buildConfiguration(
|
||||
{
|
||||
auth: userInputAuth,
|
||||
cache: userInputCache,
|
||||
system: userInputSystem,
|
||||
experimental: userInputExperimental,
|
||||
telemetry: userInputTelemetry,
|
||||
}: Configuration,
|
||||
isBrowserEnvironment: boolean
|
||||
): BrowserConfiguration {
|
||||
// Default auth options for browser
|
||||
const DEFAULT_AUTH_OPTIONS: InternalAuthOptions = {
|
||||
clientId: "",
|
||||
authority: `${Constants.DEFAULT_AUTHORITY}`,
|
||||
knownAuthorities: [],
|
||||
cloudDiscoveryMetadata: "",
|
||||
authorityMetadata: "",
|
||||
redirectUri:
|
||||
typeof window !== "undefined" && window.location
|
||||
? window.location.href.split("?")[0].split("#")[0]
|
||||
: "",
|
||||
postLogoutRedirectUri: "",
|
||||
clientCapabilities: [],
|
||||
OIDCOptions: {
|
||||
responseMode: Constants.ResponseMode.FRAGMENT,
|
||||
defaultScopes: [
|
||||
Constants.OPENID_SCOPE,
|
||||
Constants.PROFILE_SCOPE,
|
||||
Constants.OFFLINE_ACCESS_SCOPE,
|
||||
],
|
||||
},
|
||||
azureCloudOptions: {
|
||||
azureCloudInstance: AzureCloudInstance.None,
|
||||
tenant: "",
|
||||
},
|
||||
instanceAware: false,
|
||||
isMcp: false,
|
||||
verifySSO: false,
|
||||
};
|
||||
|
||||
// Default cache options for browser
|
||||
const DEFAULT_CACHE_OPTIONS: Required<CacheOptions> = {
|
||||
cacheLocation: BrowserCacheLocation.SessionStorage,
|
||||
cacheRetentionDays: 5,
|
||||
};
|
||||
|
||||
// Default logger options for browser
|
||||
const DEFAULT_LOGGER_OPTIONS: LoggerOptions = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
loggerCallback: (): void => {
|
||||
// allow users to not set logger call back
|
||||
},
|
||||
logLevel: LogLevel.Info,
|
||||
piiLoggingEnabled: false,
|
||||
};
|
||||
|
||||
// Default system options for browser
|
||||
const DEFAULT_BROWSER_SYSTEM_OPTIONS: Required<BrowserSystemOptions> = {
|
||||
...DEFAULT_SYSTEM_OPTIONS,
|
||||
loggerOptions: DEFAULT_LOGGER_OPTIONS,
|
||||
networkClient: isBrowserEnvironment
|
||||
? new FetchClient()
|
||||
: StubbedNetworkModule,
|
||||
navigationClient: new NavigationClient(),
|
||||
popupBridgeTimeout:
|
||||
userInputSystem?.popupBridgeTimeout || DEFAULT_POPUP_TIMEOUT_MS,
|
||||
iframeBridgeTimeout:
|
||||
userInputSystem?.iframeBridgeTimeout || DEFAULT_IFRAME_TIMEOUT_MS,
|
||||
redirectNavigationTimeout: DEFAULT_REDIRECT_TIMEOUT_MS,
|
||||
allowRedirectInIframe: false,
|
||||
navigatePopups: true,
|
||||
allowPlatformBroker: false,
|
||||
nativeBrokerHandshakeTimeout:
|
||||
userInputSystem?.nativeBrokerHandshakeTimeout ||
|
||||
DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS,
|
||||
protocolMode: ProtocolMode.AAD,
|
||||
};
|
||||
|
||||
const providedSystemOptions: Required<BrowserSystemOptions> = {
|
||||
...DEFAULT_BROWSER_SYSTEM_OPTIONS,
|
||||
...userInputSystem,
|
||||
loggerOptions: userInputSystem?.loggerOptions || DEFAULT_LOGGER_OPTIONS,
|
||||
};
|
||||
|
||||
const DEFAULT_TELEMETRY_OPTIONS: Required<BrowserTelemetryOptions> = {
|
||||
application: {
|
||||
appName: "",
|
||||
appVersion: "",
|
||||
},
|
||||
client: new StubPerformanceClient(),
|
||||
};
|
||||
|
||||
const DEFAULT_EXPERIMENTAL_OPTIONS: Required<BrowserExperimentalOptions> = {
|
||||
iframeTimeoutTelemetry: false,
|
||||
allowPlatformBrokerWithDOM: false,
|
||||
};
|
||||
|
||||
// Throw an error if user has set OIDCOptions without being in OIDC protocol mode
|
||||
if (
|
||||
userInputSystem?.protocolMode !== ProtocolMode.OIDC &&
|
||||
userInputAuth?.OIDCOptions
|
||||
) {
|
||||
const logger = new Logger(providedSystemOptions.loggerOptions);
|
||||
logger.warning(
|
||||
JSON.stringify(
|
||||
createClientConfigurationError(
|
||||
ClientConfigurationErrorCodes.cannotSetOIDCOptions
|
||||
)
|
||||
),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
// Throw an error if user has set allowPlatformBroker to true with OIDC protocol mode
|
||||
if (
|
||||
userInputSystem?.protocolMode &&
|
||||
userInputSystem.protocolMode === ProtocolMode.OIDC &&
|
||||
providedSystemOptions?.allowPlatformBroker
|
||||
) {
|
||||
throw createClientConfigurationError(
|
||||
ClientConfigurationErrorCodes.cannotAllowPlatformBroker
|
||||
);
|
||||
}
|
||||
|
||||
const overlayedConfig: BrowserConfiguration = {
|
||||
auth: {
|
||||
...DEFAULT_AUTH_OPTIONS,
|
||||
...userInputAuth,
|
||||
OIDCOptions: {
|
||||
...DEFAULT_AUTH_OPTIONS.OIDCOptions,
|
||||
...userInputAuth?.OIDCOptions,
|
||||
},
|
||||
},
|
||||
cache: { ...DEFAULT_CACHE_OPTIONS, ...userInputCache },
|
||||
system: providedSystemOptions,
|
||||
experimental: {
|
||||
...DEFAULT_EXPERIMENTAL_OPTIONS,
|
||||
...userInputExperimental,
|
||||
},
|
||||
telemetry: { ...DEFAULT_TELEMETRY_OPTIONS, ...userInputTelemetry },
|
||||
};
|
||||
|
||||
return overlayedConfig;
|
||||
}
|
||||
8
backend/node_modules/@azure/msal-browser/src/controllers/IController.ts
generated
vendored
Normal file
8
backend/node_modules/@azure/msal-browser/src/controllers/IController.ts
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { IPublicClientApplication } from "../app/IPublicClientApplication.js";
|
||||
|
||||
export type IController = IPublicClientApplication;
|
||||
868
backend/node_modules/@azure/msal-browser/src/controllers/NestedAppAuthController.ts
generated
vendored
Normal file
868
backend/node_modules/@azure/msal-browser/src/controllers/NestedAppAuthController.ts
generated
vendored
Normal file
@ -0,0 +1,868 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
CommonAuthorizationUrlRequest,
|
||||
PerformanceCallbackFunction,
|
||||
AccountInfo,
|
||||
Logger,
|
||||
ICrypto,
|
||||
IPerformanceClient,
|
||||
DEFAULT_CRYPTO_IMPLEMENTATION,
|
||||
TimeUtils,
|
||||
buildStaticAuthorityOptions,
|
||||
Constants,
|
||||
BaseAuthRequest,
|
||||
AccountFilter,
|
||||
AuthError,
|
||||
AccountEntityUtils,
|
||||
AuthToken,
|
||||
enforceResourceParameter,
|
||||
} from "@azure/msal-common/browser";
|
||||
import * as RootPerformanceEvents from "../telemetry/BrowserRootPerformanceEvents.js";
|
||||
import { BrowserConfiguration } from "../config/Configuration.js";
|
||||
import { INavigationClient } from "../navigation/INavigationClient.js";
|
||||
import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js";
|
||||
import { EndSessionPopupRequest } from "../request/EndSessionPopupRequest.js";
|
||||
import { EndSessionRequest } from "../request/EndSessionRequest.js";
|
||||
import { PopupRequest } from "../request/PopupRequest.js";
|
||||
import { RedirectRequest } from "../request/RedirectRequest.js";
|
||||
import { SilentRequest } from "../request/SilentRequest.js";
|
||||
import { SsoSilentRequest } from "../request/SsoSilentRequest.js";
|
||||
import {
|
||||
WrapperSKU,
|
||||
InteractionType,
|
||||
DEFAULT_REQUEST,
|
||||
CacheLookupPolicy,
|
||||
ApiId,
|
||||
} from "../utils/BrowserConstants.js";
|
||||
import { IController } from "./IController.js";
|
||||
import { NestedAppOperatingContext } from "../operatingcontext/NestedAppOperatingContext.js";
|
||||
import { IBridgeProxy } from "../naa/IBridgeProxy.js";
|
||||
import { CryptoOps } from "../crypto/CryptoOps.js";
|
||||
import { NestedAppAuthAdapter } from "../naa/mapping/NestedAppAuthAdapter.js";
|
||||
import { NestedAppAuthError } from "../error/NestedAppAuthError.js";
|
||||
import { EventHandler } from "../event/EventHandler.js";
|
||||
import { EventType } from "../event/EventType.js";
|
||||
import { EventCallbackFunction, EventError } from "../event/EventMessage.js";
|
||||
import { AuthenticationResult } from "../response/AuthenticationResult.js";
|
||||
import {
|
||||
BrowserCacheManager,
|
||||
DEFAULT_BROWSER_CACHE_MANAGER,
|
||||
} from "../cache/BrowserCacheManager.js";
|
||||
import { ClearCacheRequest } from "../request/ClearCacheRequest.js";
|
||||
import * as AccountManager from "../cache/AccountManager.js";
|
||||
import { AccountContext } from "../naa/BridgeAccountContext.js";
|
||||
import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js";
|
||||
import { createNewGuid } from "../crypto/BrowserCrypto.js";
|
||||
import { HandleRedirectPromiseOptions } from "../request/HandleRedirectPromiseOptions.js";
|
||||
|
||||
export class NestedAppAuthController implements IController {
|
||||
// OperatingContext
|
||||
protected readonly operatingContext: NestedAppOperatingContext;
|
||||
|
||||
// BridgeProxy
|
||||
protected readonly bridgeProxy: IBridgeProxy;
|
||||
|
||||
// Crypto interface implementation
|
||||
protected readonly browserCrypto: ICrypto;
|
||||
|
||||
// Input configuration by developer/user
|
||||
protected readonly config: BrowserConfiguration;
|
||||
|
||||
// Storage interface implementation
|
||||
protected readonly browserStorage!: BrowserCacheManager;
|
||||
|
||||
// Logger
|
||||
protected logger: Logger;
|
||||
|
||||
// Performance telemetry client
|
||||
protected readonly performanceClient: IPerformanceClient;
|
||||
|
||||
// EventHandler
|
||||
protected readonly eventHandler: EventHandler;
|
||||
|
||||
// NestedAppAuthAdapter
|
||||
protected readonly nestedAppAuthAdapter: NestedAppAuthAdapter;
|
||||
|
||||
// currentAccount for NAA apps
|
||||
protected currentAccountContext: AccountContext | null;
|
||||
|
||||
constructor(operatingContext: NestedAppOperatingContext) {
|
||||
this.operatingContext = operatingContext;
|
||||
const proxy = this.operatingContext.getBridgeProxy();
|
||||
if (proxy !== undefined) {
|
||||
this.bridgeProxy = proxy;
|
||||
} else {
|
||||
throw new Error("unexpected: bridgeProxy is undefined");
|
||||
}
|
||||
|
||||
// Set the configuration.
|
||||
this.config = operatingContext.getConfig();
|
||||
|
||||
// Initialize logger
|
||||
this.logger = this.operatingContext.getLogger();
|
||||
|
||||
// Initialize performance client
|
||||
this.performanceClient = this.config.telemetry.client;
|
||||
|
||||
// Initialize the crypto class.
|
||||
this.browserCrypto = operatingContext.isBrowserEnvironment()
|
||||
? new CryptoOps(this.logger, this.performanceClient, true)
|
||||
: DEFAULT_CRYPTO_IMPLEMENTATION;
|
||||
|
||||
this.eventHandler = new EventHandler(this.logger);
|
||||
// Initialize the browser storage class.
|
||||
this.browserStorage = this.operatingContext.isBrowserEnvironment()
|
||||
? new BrowserCacheManager(
|
||||
this.config.auth.clientId,
|
||||
this.config.cache,
|
||||
this.browserCrypto,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
this.eventHandler,
|
||||
buildStaticAuthorityOptions(this.config.auth)
|
||||
)
|
||||
: DEFAULT_BROWSER_CACHE_MANAGER(
|
||||
this.config.auth.clientId,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
this.eventHandler
|
||||
);
|
||||
|
||||
this.nestedAppAuthAdapter = new NestedAppAuthAdapter(
|
||||
this.config.auth.clientId,
|
||||
this.config.auth.clientCapabilities,
|
||||
this.browserCrypto,
|
||||
this.logger
|
||||
);
|
||||
|
||||
// Set the active account if available
|
||||
const accountContext = this.bridgeProxy.getAccountContext();
|
||||
this.currentAccountContext = accountContext ? accountContext : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function to create a new instance of NestedAppAuthController
|
||||
* @param operatingContext
|
||||
* @returns Promise<IController>
|
||||
*/
|
||||
static async createController(
|
||||
operatingContext: NestedAppOperatingContext
|
||||
): Promise<IController> {
|
||||
const controller = new NestedAppAuthController(operatingContext);
|
||||
return Promise.resolve(controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific implementation of initialize function for NestedAppAuthController
|
||||
* @returns
|
||||
*/
|
||||
async initialize(
|
||||
request?: InitializeApplicationRequest,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
isBroker?: boolean
|
||||
): Promise<void> {
|
||||
const initCorrelationId = request?.correlationId || createNewGuid();
|
||||
await this.browserStorage.initialize(initCorrelationId);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the incoming request and add correlationId if not present
|
||||
* @param request
|
||||
* @returns
|
||||
*/
|
||||
private ensureValidRequest<
|
||||
T extends
|
||||
| SsoSilentRequest
|
||||
| SilentRequest
|
||||
| PopupRequest
|
||||
| RedirectRequest
|
||||
>(request: T): T {
|
||||
if (request?.correlationId) {
|
||||
return request;
|
||||
}
|
||||
return {
|
||||
...request,
|
||||
correlationId: this.browserCrypto.createNewGuid(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation of acquireTokenInteractive flow
|
||||
* @param request
|
||||
* @returns
|
||||
*/
|
||||
private async acquireTokenInteractive(
|
||||
request: PopupRequest | RedirectRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
const validRequest = this.ensureValidRequest(request);
|
||||
const correlationId = validRequest.correlationId || createNewGuid();
|
||||
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_START,
|
||||
correlationId,
|
||||
InteractionType.Popup,
|
||||
validRequest
|
||||
);
|
||||
|
||||
const atPopupMeasurement = this.performanceClient.startMeasurement(
|
||||
RootPerformanceEvents.AcquireTokenPopup,
|
||||
correlationId
|
||||
);
|
||||
|
||||
atPopupMeasurement.add({ nestedAppAuthRequest: true });
|
||||
|
||||
try {
|
||||
enforceResourceParameter(this.config.auth.isMcp, validRequest);
|
||||
const naaRequest =
|
||||
this.nestedAppAuthAdapter.toNaaTokenRequest(validRequest);
|
||||
const reqTimestamp = TimeUtils.nowSeconds();
|
||||
const response = await this.bridgeProxy.getTokenInteractive(
|
||||
naaRequest
|
||||
);
|
||||
const result: AuthenticationResult = {
|
||||
...this.nestedAppAuthAdapter.fromNaaTokenResponse(
|
||||
naaRequest,
|
||||
response,
|
||||
reqTimestamp
|
||||
),
|
||||
};
|
||||
|
||||
// cache the tokens in the response
|
||||
try {
|
||||
// cache hydration can fail in JS Runtime scenario that doesn't support full crypto API
|
||||
await this.hydrateCache(result, request);
|
||||
} catch (error) {
|
||||
this.logger.warningPii(
|
||||
`Failed to hydrate cache. Error: ${error}`,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
|
||||
// cache the account context in memory after successful token fetch
|
||||
this.currentAccountContext = {
|
||||
homeAccountId: result.account.homeAccountId,
|
||||
environment: result.account.environment,
|
||||
tenantId: result.account.tenantId,
|
||||
};
|
||||
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_SUCCESS,
|
||||
correlationId,
|
||||
InteractionType.Popup,
|
||||
result
|
||||
);
|
||||
|
||||
atPopupMeasurement.add({
|
||||
accessTokenSize: result.accessToken.length,
|
||||
idTokenSize: result.idToken.length,
|
||||
});
|
||||
|
||||
atPopupMeasurement.end(
|
||||
{
|
||||
success: true,
|
||||
requestId: result.requestId,
|
||||
},
|
||||
undefined,
|
||||
result.account
|
||||
);
|
||||
|
||||
return result;
|
||||
} catch (e) {
|
||||
const error =
|
||||
e instanceof AuthError
|
||||
? e
|
||||
: this.nestedAppAuthAdapter.fromBridgeError(e);
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_FAILURE,
|
||||
correlationId,
|
||||
InteractionType.Popup,
|
||||
null,
|
||||
e as EventError
|
||||
);
|
||||
|
||||
atPopupMeasurement.end(
|
||||
{
|
||||
success: false,
|
||||
},
|
||||
e,
|
||||
request.account
|
||||
);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation of acquireTokenSilent flow
|
||||
* @param request
|
||||
* @returns
|
||||
*/
|
||||
private async acquireTokenSilentInternal(
|
||||
request: SilentRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
const validRequest = this.ensureValidRequest(request);
|
||||
const correlationId = validRequest.correlationId || createNewGuid();
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_START,
|
||||
correlationId,
|
||||
InteractionType.Silent,
|
||||
validRequest
|
||||
);
|
||||
|
||||
// Look for tokens in the cache first
|
||||
const result = await this.acquireTokenFromCache(validRequest);
|
||||
if (result) {
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_SUCCESS,
|
||||
correlationId,
|
||||
InteractionType.Silent,
|
||||
result
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
// proceed with acquiring tokens via the host
|
||||
const ssoSilentMeasurement = this.performanceClient.startMeasurement(
|
||||
RootPerformanceEvents.SsoSilent,
|
||||
correlationId
|
||||
);
|
||||
|
||||
ssoSilentMeasurement.increment({
|
||||
visibilityChangeCount: 0,
|
||||
});
|
||||
ssoSilentMeasurement.add({
|
||||
nestedAppAuthRequest: true,
|
||||
});
|
||||
|
||||
try {
|
||||
enforceResourceParameter(this.config.auth.isMcp, validRequest);
|
||||
const naaRequest =
|
||||
this.nestedAppAuthAdapter.toNaaTokenRequest(validRequest);
|
||||
naaRequest.forceRefresh = validRequest.forceRefresh;
|
||||
const reqTimestamp = TimeUtils.nowSeconds();
|
||||
const response = await this.bridgeProxy.getTokenSilent(naaRequest);
|
||||
|
||||
const result: AuthenticationResult =
|
||||
this.nestedAppAuthAdapter.fromNaaTokenResponse(
|
||||
naaRequest,
|
||||
response,
|
||||
reqTimestamp
|
||||
);
|
||||
|
||||
// cache the tokens in the response
|
||||
try {
|
||||
// cache hydration can fail in JS Runtime scenario that doesn't support full crypto API
|
||||
await this.hydrateCache(result, request);
|
||||
} catch (error) {
|
||||
this.logger.warningPii(
|
||||
`Failed to hydrate cache. Error: ${error}`,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
|
||||
// cache the account context in memory after successful token fetch
|
||||
this.currentAccountContext = {
|
||||
homeAccountId: result.account.homeAccountId,
|
||||
environment: result.account.environment,
|
||||
tenantId: result.account.tenantId,
|
||||
};
|
||||
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_SUCCESS,
|
||||
correlationId,
|
||||
InteractionType.Silent,
|
||||
result
|
||||
);
|
||||
ssoSilentMeasurement?.add({
|
||||
accessTokenSize: result.accessToken.length,
|
||||
idTokenSize: result.idToken.length,
|
||||
});
|
||||
ssoSilentMeasurement?.end(
|
||||
{
|
||||
success: true,
|
||||
requestId: result.requestId,
|
||||
},
|
||||
undefined,
|
||||
result.account
|
||||
);
|
||||
return result;
|
||||
} catch (e) {
|
||||
const error =
|
||||
e instanceof AuthError
|
||||
? e
|
||||
: this.nestedAppAuthAdapter.fromBridgeError(e);
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_FAILURE,
|
||||
correlationId,
|
||||
InteractionType.Silent,
|
||||
null,
|
||||
e as EventError
|
||||
);
|
||||
ssoSilentMeasurement?.end(
|
||||
{
|
||||
success: false,
|
||||
},
|
||||
e,
|
||||
request.account
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* acquires tokens from cache
|
||||
* @param request
|
||||
* @returns
|
||||
*/
|
||||
private async acquireTokenFromCache(
|
||||
request: SilentRequest
|
||||
): Promise<AuthenticationResult | null> {
|
||||
const correlationId = request.correlationId || createNewGuid();
|
||||
const atsMeasurement = this.performanceClient.startMeasurement(
|
||||
RootPerformanceEvents.AcquireTokenSilent,
|
||||
correlationId
|
||||
);
|
||||
|
||||
atsMeasurement?.add({
|
||||
nestedAppAuthRequest: true,
|
||||
});
|
||||
|
||||
// if the request has claims, we cannot look up in the cache
|
||||
if (request.claims) {
|
||||
this.logger.verbose(
|
||||
"Claims are present in the request, skipping cache lookup",
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// if the request has forceRefresh, we cannot look up in the cache
|
||||
if (request.forceRefresh) {
|
||||
this.logger.verbose(
|
||||
"forceRefresh is set to true, skipping cache lookup",
|
||||
correlationId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// respect cache lookup policy
|
||||
let result: AuthenticationResult | null = null;
|
||||
if (!request.cacheLookupPolicy) {
|
||||
request.cacheLookupPolicy = CacheLookupPolicy.Default;
|
||||
}
|
||||
|
||||
switch (request.cacheLookupPolicy) {
|
||||
case CacheLookupPolicy.Default:
|
||||
case CacheLookupPolicy.AccessToken:
|
||||
case CacheLookupPolicy.AccessTokenAndRefreshToken:
|
||||
result = await this.acquireTokenFromCacheInternal(request);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_SUCCESS,
|
||||
correlationId,
|
||||
InteractionType.Silent,
|
||||
result
|
||||
);
|
||||
atsMeasurement.add({
|
||||
accessTokenSize: result.accessToken.length,
|
||||
idTokenSize: result.idToken.length,
|
||||
});
|
||||
atsMeasurement.end(
|
||||
{
|
||||
success: true,
|
||||
},
|
||||
undefined,
|
||||
result.account
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
this.logger.warning(
|
||||
"Cached tokens are not found for the account, proceeding with silent token request.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
this.eventHandler.emitEvent(
|
||||
EventType.ACQUIRE_TOKEN_FAILURE,
|
||||
correlationId,
|
||||
InteractionType.Silent,
|
||||
null
|
||||
);
|
||||
atsMeasurement.end(
|
||||
{
|
||||
success: false,
|
||||
},
|
||||
undefined,
|
||||
request.account
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param request
|
||||
* @returns
|
||||
*/
|
||||
private async acquireTokenFromCacheInternal(
|
||||
request: SilentRequest
|
||||
): Promise<AuthenticationResult | null> {
|
||||
// always prioritize the account context from the bridge
|
||||
const accountContext =
|
||||
this.bridgeProxy.getAccountContext() || this.currentAccountContext;
|
||||
const correlationId = request.correlationId || createNewGuid();
|
||||
let currentAccount: AccountInfo | null = null;
|
||||
if (accountContext) {
|
||||
currentAccount = AccountManager.getAccount(
|
||||
accountContext,
|
||||
this.logger,
|
||||
this.browserStorage,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
|
||||
// fall back to brokering if no cached account is found
|
||||
if (!currentAccount) {
|
||||
this.logger.verbose(
|
||||
"No active account found, falling back to the host",
|
||||
correlationId
|
||||
);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
this.logger.verbose(
|
||||
"active account found, attempting to acquire token silently",
|
||||
correlationId
|
||||
);
|
||||
|
||||
const authRequest: BaseAuthRequest = {
|
||||
...request,
|
||||
correlationId: correlationId,
|
||||
authority: request.authority || currentAccount.environment,
|
||||
scopes: request.scopes?.length
|
||||
? request.scopes
|
||||
: [...Constants.OIDC_DEFAULT_SCOPES],
|
||||
};
|
||||
|
||||
// fetch access token and check for expiry
|
||||
const tokenKeys = this.browserStorage.getTokenKeys();
|
||||
const cachedAccessToken = this.browserStorage.getAccessToken(
|
||||
currentAccount,
|
||||
authRequest,
|
||||
tokenKeys,
|
||||
currentAccount.tenantId
|
||||
);
|
||||
|
||||
// If there is no access token, log it and return null
|
||||
if (!cachedAccessToken) {
|
||||
this.logger.verbose("No cached access token found", correlationId);
|
||||
return Promise.resolve(null);
|
||||
} else if (
|
||||
TimeUtils.wasClockTurnedBack(cachedAccessToken.cachedAt) ||
|
||||
TimeUtils.isTokenExpired(
|
||||
cachedAccessToken.expiresOn,
|
||||
this.config.system.tokenRenewalOffsetSeconds
|
||||
)
|
||||
) {
|
||||
this.logger.verbose(
|
||||
"Cached access token has expired",
|
||||
correlationId
|
||||
);
|
||||
return Promise.resolve(null);
|
||||
} else if (authRequest.resource) {
|
||||
const requestedResource = authRequest.resource;
|
||||
const cachedResource = cachedAccessToken.resource;
|
||||
|
||||
if (!cachedResource || cachedResource !== requestedResource) {
|
||||
this.logger.verbose(
|
||||
"Cached access token resource does not match requested resource for MCP flow",
|
||||
correlationId
|
||||
);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
const cachedIdToken = this.browserStorage.getIdToken(
|
||||
currentAccount,
|
||||
authRequest.correlationId,
|
||||
tokenKeys,
|
||||
currentAccount.tenantId
|
||||
);
|
||||
|
||||
if (!cachedIdToken) {
|
||||
this.logger.verbose("No cached id token found", correlationId);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return this.nestedAppAuthAdapter.toAuthenticationResultFromCache(
|
||||
currentAccount,
|
||||
cachedIdToken,
|
||||
cachedAccessToken,
|
||||
authRequest,
|
||||
authRequest.correlationId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* acquireTokenPopup flow implementation
|
||||
* @param request
|
||||
* @returns
|
||||
*/
|
||||
async acquireTokenPopup(
|
||||
request: PopupRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
return this.acquireTokenInteractive(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* acquireTokenRedirect flow is not supported in nested app auth
|
||||
* @param request
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
acquireTokenRedirect(request: RedirectRequest): Promise<void> {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
|
||||
/**
|
||||
* acquireTokenSilent flow implementation
|
||||
* @param silentRequest
|
||||
* @returns
|
||||
*/
|
||||
async acquireTokenSilent(
|
||||
silentRequest: SilentRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
return this.acquireTokenSilentInternal(silentRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hybrid flow is not currently supported in nested app auth
|
||||
* @param request
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
acquireTokenByCode(
|
||||
request: AuthorizationCodeRequest // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
): Promise<AuthenticationResult> {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds event callbacks to array
|
||||
* @param callback
|
||||
* @param eventTypes
|
||||
*/
|
||||
addEventCallback(
|
||||
callback: EventCallbackFunction,
|
||||
eventTypes?: Array<EventType>
|
||||
): string | null {
|
||||
return this.eventHandler.addEventCallback(callback, eventTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes callback with provided id from callback array
|
||||
* @param callbackId
|
||||
*/
|
||||
removeEventCallback(callbackId: string): void {
|
||||
this.eventHandler.removeEventCallback(callbackId);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
addPerformanceCallback(callback: PerformanceCallbackFunction): string {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
removePerformanceCallback(callbackId: string): boolean {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
|
||||
// #region Account APIs
|
||||
|
||||
/**
|
||||
* Returns all the accounts in the cache that match the optional filter. If no filter is provided, all accounts are returned.
|
||||
* @param accountFilter - (Optional) filter to narrow down the accounts returned
|
||||
* @returns Array of AccountInfo objects in cache
|
||||
*/
|
||||
getAllAccounts(accountFilter?: AccountFilter): AccountInfo[] {
|
||||
return AccountManager.getAllAccounts(
|
||||
this.logger,
|
||||
this.browserStorage,
|
||||
this.isBrowserEnv(),
|
||||
createNewGuid(),
|
||||
accountFilter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first account found in the cache that matches the account filter passed in.
|
||||
* @param accountFilter
|
||||
* @returns The first account found in the cache matching the provided filter or null if no account could be found.
|
||||
*/
|
||||
getAccount(accountFilter: AccountFilter): AccountInfo | null {
|
||||
return AccountManager.getAccount(
|
||||
accountFilter,
|
||||
this.logger,
|
||||
this.browserStorage,
|
||||
createNewGuid()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the account to use as the active account. If no account is passed to the acquireToken APIs, then MSAL will use this active account.
|
||||
* @param account
|
||||
*/
|
||||
setActiveAccount(account: AccountInfo | null): void {
|
||||
/*
|
||||
* StandardController uses this to allow the developer to set the active account
|
||||
* in the nested app auth scenario the active account is controlled by the app hosting the nested app
|
||||
*/
|
||||
return AccountManager.setActiveAccount(
|
||||
account,
|
||||
this.browserStorage,
|
||||
createNewGuid()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently active account
|
||||
*/
|
||||
getActiveAccount(): AccountInfo | null {
|
||||
return AccountManager.getActiveAccount(
|
||||
this.browserStorage,
|
||||
createNewGuid()
|
||||
);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
handleRedirectPromise(
|
||||
options?: HandleRedirectPromiseOptions // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
): Promise<AuthenticationResult | null> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
loginPopup(
|
||||
request?: PopupRequest | undefined // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
): Promise<AuthenticationResult> {
|
||||
return this.acquireTokenInteractive(request || DEFAULT_REQUEST);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
loginRedirect(request?: RedirectRequest | undefined): Promise<void> {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
logoutRedirect(
|
||||
logoutRequest?: EndSessionRequest | undefined // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
): Promise<void> {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
logoutPopup(
|
||||
logoutRequest?: EndSessionPopupRequest | undefined // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
): Promise<void> {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
ssoSilent(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
request: Partial<
|
||||
Omit<
|
||||
CommonAuthorizationUrlRequest,
|
||||
| "responseMode"
|
||||
| "earJwk"
|
||||
| "codeChallenge"
|
||||
| "codeChallengeMethod"
|
||||
| "platformBroker"
|
||||
>
|
||||
>
|
||||
): Promise<AuthenticationResult> {
|
||||
return this.acquireTokenSilentInternal(request as SilentRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logger instance
|
||||
*/
|
||||
public getLogger(): Logger {
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the default logger set in configurations with new Logger with new configurations
|
||||
* @param logger Logger instance
|
||||
*/
|
||||
setLogger(logger: Logger): void {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
initializeWrapperLibrary(sku: WrapperSKU, version: string): void {
|
||||
/*
|
||||
* Standard controller uses this to set the sku and version of the wrapper library in the storage
|
||||
* we do nothing here
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
setNavigationClient(navigationClient: INavigationClient): void {
|
||||
this.logger.warning(
|
||||
"setNavigationClient is not supported in nested app auth",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
getConfiguration(): BrowserConfiguration {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
isBrowserEnv(): boolean {
|
||||
return this.operatingContext.isBrowserEnvironment();
|
||||
}
|
||||
|
||||
getBrowserCrypto(): ICrypto {
|
||||
return this.browserCrypto;
|
||||
}
|
||||
|
||||
getPerformanceClient(): IPerformanceClient {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
|
||||
getRedirectResponse(): Map<string, Promise<AuthenticationResult | null>> {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async clearCache(logoutRequest?: ClearCacheRequest): Promise<void> {
|
||||
throw NestedAppAuthError.createUnsupportedError();
|
||||
}
|
||||
|
||||
async hydrateCache(
|
||||
result: AuthenticationResult,
|
||||
request:
|
||||
| SilentRequest
|
||||
| SsoSilentRequest
|
||||
| RedirectRequest
|
||||
| PopupRequest
|
||||
): Promise<void> {
|
||||
this.logger.verbose("hydrateCache called", result.correlationId);
|
||||
|
||||
const accountEntity =
|
||||
AccountEntityUtils.createAccountEntityFromAccountInfo(
|
||||
result.account,
|
||||
result.cloudGraphHostName,
|
||||
result.msGraphHost
|
||||
);
|
||||
await this.browserStorage.setAccount(
|
||||
accountEntity,
|
||||
result.correlationId,
|
||||
AuthToken.isKmsi(result.idTokenClaims),
|
||||
ApiId.hydrateCache
|
||||
);
|
||||
return this.browserStorage.hydrateCache(result, request);
|
||||
}
|
||||
}
|
||||
2691
backend/node_modules/@azure/msal-browser/src/controllers/StandardController.ts
generated
vendored
Normal file
2691
backend/node_modules/@azure/msal-browser/src/controllers/StandardController.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
299
backend/node_modules/@azure/msal-browser/src/controllers/UnknownOperatingContextController.ts
generated
vendored
Normal file
299
backend/node_modules/@azure/msal-browser/src/controllers/UnknownOperatingContextController.ts
generated
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
CommonAuthorizationUrlRequest,
|
||||
PerformanceCallbackFunction,
|
||||
AccountInfo,
|
||||
Logger,
|
||||
ICrypto,
|
||||
IPerformanceClient,
|
||||
DEFAULT_CRYPTO_IMPLEMENTATION,
|
||||
AccountFilter,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { BrowserConfiguration } from "../config/Configuration.js";
|
||||
import {
|
||||
BrowserCacheManager,
|
||||
DEFAULT_BROWSER_CACHE_MANAGER,
|
||||
} from "../cache/BrowserCacheManager.js";
|
||||
import { INavigationClient } from "../navigation/INavigationClient.js";
|
||||
import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js";
|
||||
import { EndSessionPopupRequest } from "../request/EndSessionPopupRequest.js";
|
||||
import { EndSessionRequest } from "../request/EndSessionRequest.js";
|
||||
import { PopupRequest } from "../request/PopupRequest.js";
|
||||
import { RedirectRequest } from "../request/RedirectRequest.js";
|
||||
import { SilentRequest } from "../request/SilentRequest.js";
|
||||
import { SsoSilentRequest } from "../request/SsoSilentRequest.js";
|
||||
import { AuthenticationResult } from "../response/AuthenticationResult.js";
|
||||
import { WrapperSKU } from "../utils/BrowserConstants.js";
|
||||
import { IController } from "./IController.js";
|
||||
import { UnknownOperatingContext } from "../operatingcontext/UnknownOperatingContext.js";
|
||||
import { CryptoOps } from "../crypto/CryptoOps.js";
|
||||
import {
|
||||
blockAPICallsBeforeInitialize,
|
||||
blockNonBrowserEnvironment,
|
||||
} from "../utils/BrowserUtils.js";
|
||||
import { EventCallbackFunction } from "../event/EventMessage.js";
|
||||
import { ClearCacheRequest } from "../request/ClearCacheRequest.js";
|
||||
import { EventType } from "../event/EventType.js";
|
||||
import { EventHandler } from "../event/EventHandler.js";
|
||||
import { HandleRedirectPromiseOptions } from "../request/HandleRedirectPromiseOptions.js";
|
||||
|
||||
/**
|
||||
* UnknownOperatingContextController class
|
||||
*
|
||||
* - Until initialize method is called, this controller is the default
|
||||
* - AFter initialize method is called, this controller will be swapped out for the appropriate controller
|
||||
* if the operating context can be determined; otherwise this controller will continued be used
|
||||
*
|
||||
* - Why do we have this? We don't want to dynamically import (download) all of the code in StandardController if we don't need to.
|
||||
*
|
||||
* - Only includes implementation for getAccounts and handleRedirectPromise
|
||||
* - All other methods are will throw initialization error (because either initialize method or the factory method were not used)
|
||||
* - This controller is necessary for React Native wrapper, server side rendering and any other scenario where we don't have a DOM
|
||||
*
|
||||
*/
|
||||
export class UnknownOperatingContextController implements IController {
|
||||
// OperatingContext
|
||||
protected readonly operatingContext: UnknownOperatingContext;
|
||||
|
||||
// Logger
|
||||
protected logger: Logger;
|
||||
|
||||
// Storage interface implementation
|
||||
protected readonly browserStorage: BrowserCacheManager;
|
||||
|
||||
// Input configuration by developer/user
|
||||
protected readonly config: BrowserConfiguration;
|
||||
|
||||
// Performance telemetry client
|
||||
protected readonly performanceClient: IPerformanceClient;
|
||||
|
||||
// Event handler
|
||||
private readonly eventHandler: EventHandler;
|
||||
|
||||
// Crypto interface implementation
|
||||
protected readonly browserCrypto: ICrypto;
|
||||
|
||||
// Flag to indicate if in browser environment
|
||||
protected isBrowserEnvironment: boolean;
|
||||
|
||||
// Flag representing whether or not the initialize API has been called and completed
|
||||
protected initialized: boolean = false;
|
||||
|
||||
constructor(operatingContext: UnknownOperatingContext) {
|
||||
this.operatingContext = operatingContext;
|
||||
|
||||
this.isBrowserEnvironment =
|
||||
this.operatingContext.isBrowserEnvironment();
|
||||
|
||||
this.config = operatingContext.getConfig();
|
||||
|
||||
this.logger = operatingContext.getLogger();
|
||||
|
||||
// Initialize performance client
|
||||
this.performanceClient = this.config.telemetry.client;
|
||||
|
||||
// Initialize the crypto class.
|
||||
this.browserCrypto = this.isBrowserEnvironment
|
||||
? new CryptoOps(this.logger, this.performanceClient)
|
||||
: DEFAULT_CRYPTO_IMPLEMENTATION;
|
||||
|
||||
this.eventHandler = new EventHandler(this.logger);
|
||||
|
||||
// Initialize the browser storage class.
|
||||
this.browserStorage = this.isBrowserEnvironment
|
||||
? new BrowserCacheManager(
|
||||
this.config.auth.clientId,
|
||||
this.config.cache,
|
||||
this.browserCrypto,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
this.eventHandler
|
||||
)
|
||||
: DEFAULT_BROWSER_CACHE_MANAGER(
|
||||
this.config.auth.clientId,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
this.eventHandler
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
getAccount(accountFilter: AccountFilter): AccountInfo | null {
|
||||
return null;
|
||||
}
|
||||
getAllAccounts(): AccountInfo[] {
|
||||
return [];
|
||||
}
|
||||
initialize(): Promise<void> {
|
||||
this.initialized = true;
|
||||
return Promise.resolve();
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
acquireTokenPopup(request: PopupRequest): Promise<AuthenticationResult> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<AuthenticationResult>;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
acquireTokenRedirect(request: RedirectRequest): Promise<void> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return Promise.resolve();
|
||||
}
|
||||
acquireTokenSilent(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
silentRequest: SilentRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<AuthenticationResult>;
|
||||
}
|
||||
acquireTokenByCode(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
request: AuthorizationCodeRequest
|
||||
): Promise<AuthenticationResult> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<AuthenticationResult>;
|
||||
}
|
||||
addEventCallback(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
callback: EventCallbackFunction,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
eventTypes?: Array<EventType>
|
||||
): string | null {
|
||||
return null;
|
||||
}
|
||||
removeEventCallback(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
callbackId: string
|
||||
): void {}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
addPerformanceCallback(callback: PerformanceCallbackFunction): string {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return "";
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
removePerformanceCallback(callbackId: string): boolean {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return true;
|
||||
}
|
||||
|
||||
handleRedirectPromise(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
options?: HandleRedirectPromiseOptions
|
||||
): Promise<AuthenticationResult | null> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
loginPopup(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
request?: PopupRequest | undefined
|
||||
): Promise<AuthenticationResult> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<AuthenticationResult>;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
loginRedirect(request?: RedirectRequest | undefined): Promise<void> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<void>;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
logout(logoutRequest?: EndSessionRequest | undefined): Promise<void> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<void>;
|
||||
}
|
||||
logoutRedirect(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
logoutRequest?: EndSessionRequest | undefined
|
||||
): Promise<void> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<void>;
|
||||
}
|
||||
logoutPopup(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
logoutRequest?: EndSessionPopupRequest | undefined
|
||||
): Promise<void> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<void>;
|
||||
}
|
||||
ssoSilent(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
request: Partial<
|
||||
Omit<
|
||||
CommonAuthorizationUrlRequest,
|
||||
| "responseMode"
|
||||
| "earJwk"
|
||||
| "codeChallenge"
|
||||
| "codeChallengeMethod"
|
||||
| "platformBroker"
|
||||
>
|
||||
>
|
||||
): Promise<AuthenticationResult> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return {} as Promise<AuthenticationResult>;
|
||||
}
|
||||
getLogger(): Logger {
|
||||
return this.logger;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
setLogger(logger: Logger): void {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
setActiveAccount(account: AccountInfo | null): void {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
}
|
||||
getActiveAccount(): AccountInfo | null {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
return null;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
initializeWrapperLibrary(sku: WrapperSKU, version: string): void {
|
||||
this.browserStorage.setWrapperMetadata(sku, version);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
setNavigationClient(navigationClient: INavigationClient): void {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
}
|
||||
getConfiguration(): BrowserConfiguration {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async clearCache(logoutRequest?: ClearCacheRequest): Promise<void> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async hydrateCache(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
result: AuthenticationResult,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
request:
|
||||
| SilentRequest
|
||||
| SsoSilentRequest
|
||||
| RedirectRequest
|
||||
| PopupRequest
|
||||
): Promise<void> {
|
||||
blockAPICallsBeforeInitialize(this.initialized);
|
||||
blockNonBrowserEnvironment();
|
||||
}
|
||||
}
|
||||
422
backend/node_modules/@azure/msal-browser/src/crypto/BrowserCrypto.ts
generated
vendored
Normal file
422
backend/node_modules/@azure/msal-browser/src/crypto/BrowserCrypto.ts
generated
vendored
Normal file
@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
createBrowserAuthError,
|
||||
BrowserAuthErrorCodes,
|
||||
} from "../error/BrowserAuthError.js";
|
||||
import { KEY_FORMAT_JWK } from "../utils/BrowserConstants.js";
|
||||
import { base64Encode, urlEncodeArr } from "../encode/Base64Encode.js";
|
||||
import { base64Decode, base64DecToArr } from "../encode/Base64Decode.js";
|
||||
|
||||
/**
|
||||
* This file defines functions used by the browser library to perform cryptography operations such as
|
||||
* hashing and encoding. It also has helper functions to validate the availability of specific APIs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* See here for more info on RsaHashedKeyGenParams: https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams
|
||||
*/
|
||||
// Algorithms
|
||||
const PKCS1_V15_KEYGEN_ALG = "RSASSA-PKCS1-v1_5";
|
||||
const AES_GCM = "AES-GCM";
|
||||
const HKDF = "HKDF";
|
||||
// SHA-256 hashing algorithm
|
||||
const S256_HASH_ALG = "SHA-256";
|
||||
// MOD length for PoP tokens
|
||||
const MODULUS_LENGTH = 2048;
|
||||
// Public Exponent
|
||||
const PUBLIC_EXPONENT: Uint8Array = new Uint8Array([0x01, 0x00, 0x01]);
|
||||
// UUID hex digits
|
||||
const UUID_CHARS = "0123456789abcdef";
|
||||
// Array to store UINT32 random value
|
||||
const UINT32_ARR = new Uint32Array(1);
|
||||
|
||||
// Key Format
|
||||
const RAW = "raw";
|
||||
// Key Usages
|
||||
const ENCRYPT = "encrypt";
|
||||
const DECRYPT = "decrypt";
|
||||
const DERIVE_KEY = "deriveKey";
|
||||
|
||||
// Suberror
|
||||
const SUBTLE_SUBERROR = "crypto_subtle_undefined";
|
||||
|
||||
const keygenAlgorithmOptions: RsaHashedKeyGenParams = {
|
||||
name: PKCS1_V15_KEYGEN_ALG,
|
||||
hash: S256_HASH_ALG,
|
||||
modulusLength: MODULUS_LENGTH,
|
||||
publicExponent: PUBLIC_EXPONENT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether browser crypto is available.
|
||||
*/
|
||||
export function validateCryptoAvailable(
|
||||
skipValidateSubtleCrypto: boolean
|
||||
): void {
|
||||
if (!window) {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.nonBrowserEnvironment
|
||||
);
|
||||
}
|
||||
if (!window.crypto) {
|
||||
throw createBrowserAuthError(BrowserAuthErrorCodes.cryptoNonExistent);
|
||||
}
|
||||
if (!skipValidateSubtleCrypto && !window.crypto.subtle) {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.cryptoNonExistent,
|
||||
SUBTLE_SUBERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sha-256 hash of the given dataString as an ArrayBuffer.
|
||||
* @param dataString {string} data string
|
||||
* @param performanceClient {?IPerformanceClient}
|
||||
* @param correlationId {?string} correlation id
|
||||
*/
|
||||
export async function sha256Digest(dataString: string): Promise<ArrayBuffer> {
|
||||
const encoder = new TextEncoder();
|
||||
const data = encoder.encode(dataString);
|
||||
return window.crypto.subtle.digest(
|
||||
S256_HASH_ALG,
|
||||
data
|
||||
) as Promise<ArrayBuffer>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates buffer with cryptographically random values.
|
||||
* @param dataBuffer
|
||||
*/
|
||||
export function getRandomValues(dataBuffer: Uint8Array): Uint8Array {
|
||||
return window.crypto.getRandomValues(dataBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns random Uint32 value.
|
||||
* @returns {number}
|
||||
*/
|
||||
function getRandomUint32(): number {
|
||||
window.crypto.getRandomValues(UINT32_ARR);
|
||||
return UINT32_ARR[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a UUID v7 from the current timestamp.
|
||||
* Implementation relies on the system clock to guarantee increasing order of generated identifiers.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function createNewGuid(): string {
|
||||
const currentTimestamp = Date.now();
|
||||
const baseRand = getRandomUint32() * 0x400 + (getRandomUint32() & 0x3ff);
|
||||
|
||||
// Result byte array
|
||||
const bytes = new Uint8Array(16);
|
||||
// A 12-bit `rand_a` field value
|
||||
const randA = Math.trunc(baseRand / 2 ** 30);
|
||||
// The higher 30 bits of 62-bit `rand_b` field value
|
||||
const randBHi = baseRand & (2 ** 30 - 1);
|
||||
// The lower 32 bits of 62-bit `rand_b` field value
|
||||
const randBLo = getRandomUint32();
|
||||
|
||||
bytes[0] = currentTimestamp / 2 ** 40;
|
||||
bytes[1] = currentTimestamp / 2 ** 32;
|
||||
bytes[2] = currentTimestamp / 2 ** 24;
|
||||
bytes[3] = currentTimestamp / 2 ** 16;
|
||||
bytes[4] = currentTimestamp / 2 ** 8;
|
||||
bytes[5] = currentTimestamp;
|
||||
bytes[6] = 0x70 | (randA >>> 8);
|
||||
bytes[7] = randA;
|
||||
bytes[8] = 0x80 | (randBHi >>> 24);
|
||||
bytes[9] = randBHi >>> 16;
|
||||
bytes[10] = randBHi >>> 8;
|
||||
bytes[11] = randBHi;
|
||||
bytes[12] = randBLo >>> 24;
|
||||
bytes[13] = randBLo >>> 16;
|
||||
bytes[14] = randBLo >>> 8;
|
||||
bytes[15] = randBLo;
|
||||
|
||||
let text = "";
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
text += UUID_CHARS.charAt(bytes[i] >>> 4);
|
||||
text += UUID_CHARS.charAt(bytes[i] & 0xf);
|
||||
if (i === 3 || i === 5 || i === 7 || i === 9) {
|
||||
text += "-";
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a keypair based on current keygen algorithm config.
|
||||
* @param extractable
|
||||
* @param usages
|
||||
*/
|
||||
export async function generateKeyPair(
|
||||
extractable: boolean,
|
||||
usages: Array<KeyUsage>
|
||||
): Promise<CryptoKeyPair> {
|
||||
return window.crypto.subtle.generateKey(
|
||||
keygenAlgorithmOptions,
|
||||
extractable,
|
||||
usages
|
||||
) as Promise<CryptoKeyPair>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export key as Json Web Key (JWK)
|
||||
* @param key
|
||||
*/
|
||||
export async function exportJwk(key: CryptoKey): Promise<JsonWebKey> {
|
||||
return window.crypto.subtle.exportKey(
|
||||
KEY_FORMAT_JWK,
|
||||
key
|
||||
) as Promise<JsonWebKey>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports key as Json Web Key (JWK), can set extractable and usages.
|
||||
* @param key
|
||||
* @param extractable
|
||||
* @param usages
|
||||
*/
|
||||
export async function importJwk(
|
||||
key: JsonWebKey,
|
||||
extractable: boolean,
|
||||
usages: Array<KeyUsage>
|
||||
): Promise<CryptoKey> {
|
||||
return window.crypto.subtle.importKey(
|
||||
KEY_FORMAT_JWK,
|
||||
key,
|
||||
keygenAlgorithmOptions,
|
||||
extractable,
|
||||
usages
|
||||
) as Promise<CryptoKey>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs given data with given key
|
||||
* @param key
|
||||
* @param data
|
||||
*/
|
||||
export async function sign(
|
||||
key: CryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return window.crypto.subtle.sign(
|
||||
keygenAlgorithmOptions,
|
||||
key,
|
||||
data
|
||||
) as Promise<ArrayBuffer>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates Base64 encoded jwk used in the Encrypted Authorize Response (EAR) flow
|
||||
*/
|
||||
export async function generateEarKey(): Promise<string> {
|
||||
const key = await generateBaseKey();
|
||||
const keyStr = urlEncodeArr(new Uint8Array(key));
|
||||
|
||||
const jwk = {
|
||||
alg: "dir",
|
||||
kty: "oct",
|
||||
k: keyStr,
|
||||
};
|
||||
|
||||
return base64Encode(JSON.stringify(jwk));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses earJwk for encryption key and returns CryptoKey object
|
||||
* @param earJwk
|
||||
* @returns
|
||||
*/
|
||||
export async function importEarKey(earJwk: string): Promise<CryptoKey> {
|
||||
const b64DecodedJwk = base64Decode(earJwk);
|
||||
const jwkJson = JSON.parse(b64DecodedJwk);
|
||||
const rawKey = jwkJson.k;
|
||||
const keyBuffer = base64DecToArr(rawKey);
|
||||
|
||||
return window.crypto.subtle.importKey(RAW, keyBuffer, AES_GCM, false, [
|
||||
DECRYPT,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt ear_jwe response returned in the Encrypted Authorize Response (EAR) flow
|
||||
* @param earJwk
|
||||
* @param earJwe
|
||||
* @returns
|
||||
*/
|
||||
export async function decryptEarResponse(
|
||||
earJwk: string,
|
||||
earJwe: string
|
||||
): Promise<string> {
|
||||
const earJweParts = earJwe.split(".");
|
||||
if (earJweParts.length !== 5) {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.failedToDecryptEarResponse,
|
||||
"jwe_length"
|
||||
);
|
||||
}
|
||||
|
||||
const key = await importEarKey(earJwk).catch(() => {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.failedToDecryptEarResponse,
|
||||
"import_key"
|
||||
);
|
||||
});
|
||||
|
||||
try {
|
||||
const header = new TextEncoder().encode(earJweParts[0]);
|
||||
const iv = base64DecToArr(earJweParts[2]);
|
||||
const ciphertext = base64DecToArr(earJweParts[3]);
|
||||
const tag = base64DecToArr(earJweParts[4]);
|
||||
const tagLengthBits = tag.byteLength * 8;
|
||||
|
||||
// Concat ciphertext and tag
|
||||
const encryptedData = new Uint8Array(ciphertext.length + tag.length);
|
||||
encryptedData.set(ciphertext);
|
||||
encryptedData.set(tag, ciphertext.length);
|
||||
|
||||
const decryptedData = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: AES_GCM,
|
||||
iv: iv,
|
||||
tagLength: tagLengthBits,
|
||||
additionalData: header,
|
||||
},
|
||||
key,
|
||||
encryptedData
|
||||
);
|
||||
|
||||
return new TextDecoder().decode(decryptedData);
|
||||
} catch (e) {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.failedToDecryptEarResponse,
|
||||
"decrypt"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates symmetric base encryption key. This may be stored as all encryption/decryption keys will be derived from this one.
|
||||
*/
|
||||
export async function generateBaseKey(): Promise<ArrayBuffer> {
|
||||
const key = await window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: AES_GCM,
|
||||
length: 256,
|
||||
},
|
||||
true,
|
||||
[ENCRYPT, DECRYPT]
|
||||
);
|
||||
return window.crypto.subtle.exportKey(RAW, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw key to be passed into the key derivation function
|
||||
* @param baseKey
|
||||
* @returns
|
||||
*/
|
||||
export async function generateHKDF(baseKey: ArrayBuffer): Promise<CryptoKey> {
|
||||
return window.crypto.subtle.importKey(RAW, baseKey, HKDF, false, [
|
||||
DERIVE_KEY,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a base key and a nonce generates a derived key to be used in encryption and decryption.
|
||||
* Note: every time we encrypt a new key is derived
|
||||
* @param baseKey
|
||||
* @param nonce
|
||||
* @returns
|
||||
*/
|
||||
async function deriveKey(
|
||||
baseKey: CryptoKey,
|
||||
nonce: ArrayBuffer,
|
||||
context: string
|
||||
): Promise<CryptoKey> {
|
||||
return window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: HKDF,
|
||||
salt: nonce,
|
||||
hash: S256_HASH_ALG,
|
||||
info: new TextEncoder().encode(context),
|
||||
},
|
||||
baseKey,
|
||||
{ name: AES_GCM, length: 256 },
|
||||
false,
|
||||
[ENCRYPT, DECRYPT]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the given data given a base key. Returns encrypted data and a nonce that must be provided during decryption
|
||||
* @param key
|
||||
* @param rawData
|
||||
*/
|
||||
export async function encrypt(
|
||||
baseKey: CryptoKey,
|
||||
rawData: string,
|
||||
context: string
|
||||
): Promise<{ data: string; nonce: string }> {
|
||||
const encodedData = new TextEncoder().encode(rawData);
|
||||
// The nonce must never be reused with a given key.
|
||||
const nonce = window.crypto.getRandomValues(new Uint8Array(16));
|
||||
const derivedKey = await deriveKey(baseKey, nonce, context);
|
||||
const encryptedData = await window.crypto.subtle.encrypt(
|
||||
{
|
||||
name: AES_GCM,
|
||||
iv: new Uint8Array(12), // New key is derived for every encrypt so we don't need a new nonce
|
||||
},
|
||||
derivedKey,
|
||||
encodedData
|
||||
);
|
||||
|
||||
return {
|
||||
data: urlEncodeArr(new Uint8Array(encryptedData)),
|
||||
nonce: urlEncodeArr(nonce),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data with the given key and nonce
|
||||
* @param key
|
||||
* @param nonce
|
||||
* @param encryptedData
|
||||
* @returns
|
||||
*/
|
||||
export async function decrypt(
|
||||
baseKey: CryptoKey,
|
||||
nonce: string,
|
||||
context: string,
|
||||
encryptedData: string
|
||||
): Promise<string> {
|
||||
const encodedData = base64DecToArr(encryptedData);
|
||||
const derivedKey = await deriveKey(baseKey, base64DecToArr(nonce), context);
|
||||
const decryptedData = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: AES_GCM,
|
||||
iv: new Uint8Array(12), // New key is derived for every encrypt so we don't need a new nonce
|
||||
},
|
||||
derivedKey,
|
||||
encodedData
|
||||
);
|
||||
|
||||
return new TextDecoder().decode(decryptedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SHA-256 hash of an input string
|
||||
* @param plainText
|
||||
*/
|
||||
export async function hashString(plainText: string): Promise<string> {
|
||||
const hashBuffer: ArrayBuffer = await sha256Digest(plainText);
|
||||
const hashBytes = new Uint8Array(hashBuffer);
|
||||
return urlEncodeArr(hashBytes);
|
||||
}
|
||||
305
backend/node_modules/@azure/msal-browser/src/crypto/CryptoOps.ts
generated
vendored
Normal file
305
backend/node_modules/@azure/msal-browser/src/crypto/CryptoOps.ts
generated
vendored
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ClientAuthErrorCodes,
|
||||
createClientAuthError,
|
||||
ICrypto,
|
||||
IPerformanceClient,
|
||||
JoseHeader,
|
||||
Logger,
|
||||
ShrOptions,
|
||||
SignedHttpRequest,
|
||||
SignedHttpRequestParameters,
|
||||
} from "@azure/msal-common/browser";
|
||||
import * as BrowserPerformanceEvents from "../telemetry/BrowserPerformanceEvents.js";
|
||||
import {
|
||||
base64Encode,
|
||||
urlEncode,
|
||||
urlEncodeArr,
|
||||
} from "../encode/Base64Encode.js";
|
||||
import { base64Decode } from "../encode/Base64Decode.js";
|
||||
import * as BrowserCrypto from "./BrowserCrypto.js";
|
||||
import {
|
||||
createBrowserAuthError,
|
||||
BrowserAuthErrorCodes,
|
||||
} from "../error/BrowserAuthError.js";
|
||||
import { AsyncMemoryStorage } from "../cache/AsyncMemoryStorage.js";
|
||||
|
||||
export type CachedKeyPair = {
|
||||
publicKey: CryptoKey;
|
||||
privateKey: CryptoKey;
|
||||
requestMethod?: string;
|
||||
requestUri?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements MSAL's crypto interface, which allows it to perform base64 encoding and decoding, generating cryptographically random GUIDs and
|
||||
* implementing Proof Key for Code Exchange specs for the OAuth Authorization Code Flow using PKCE (rfc here: https://tools.ietf.org/html/rfc7636).
|
||||
*/
|
||||
export class CryptoOps implements ICrypto {
|
||||
private logger: Logger;
|
||||
|
||||
/**
|
||||
* CryptoOps can be used in contexts outside a PCA instance,
|
||||
* meaning there won't be a performance manager available.
|
||||
*/
|
||||
private performanceClient: IPerformanceClient | undefined;
|
||||
|
||||
private static POP_KEY_USAGES: Array<KeyUsage> = ["sign", "verify"];
|
||||
private static EXTRACTABLE: boolean = true;
|
||||
private cache: AsyncMemoryStorage<CachedKeyPair>;
|
||||
|
||||
constructor(
|
||||
logger: Logger,
|
||||
performanceClient?: IPerformanceClient,
|
||||
skipValidateSubtleCrypto?: boolean
|
||||
) {
|
||||
this.logger = logger;
|
||||
// Browser crypto needs to be validated first before any other classes can be set.
|
||||
BrowserCrypto.validateCryptoAvailable(
|
||||
skipValidateSubtleCrypto ?? false
|
||||
);
|
||||
this.cache = new AsyncMemoryStorage<CachedKeyPair>(this.logger);
|
||||
this.performanceClient = performanceClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new random GUID - used to populate state and nonce.
|
||||
* @returns string (GUID)
|
||||
*/
|
||||
createNewGuid(): string {
|
||||
return BrowserCrypto.createNewGuid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes input string to base64.
|
||||
* @param input
|
||||
*/
|
||||
base64Encode(input: string): string {
|
||||
return base64Encode(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes input string from base64.
|
||||
* @param input
|
||||
*/
|
||||
base64Decode(input: string): string {
|
||||
return base64Decode(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes input string to base64 URL safe string.
|
||||
* @param input
|
||||
*/
|
||||
base64UrlEncode(input: string): string {
|
||||
return urlEncode(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stringifies and base64Url encodes input public key
|
||||
* @param inputKid
|
||||
* @returns Base64Url encoded public key
|
||||
*/
|
||||
encodeKid(inputKid: string): string {
|
||||
return this.base64UrlEncode(JSON.stringify({ kid: inputKid }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a keypair, stores it and returns a thumbprint
|
||||
* @param request
|
||||
*/
|
||||
async getPublicKeyThumbprint(
|
||||
request: SignedHttpRequestParameters
|
||||
): Promise<string> {
|
||||
const publicKeyThumbMeasurement =
|
||||
this.performanceClient?.startMeasurement(
|
||||
BrowserPerformanceEvents.CryptoOptsGetPublicKeyThumbprint,
|
||||
request.correlationId
|
||||
);
|
||||
|
||||
// Generate Keypair
|
||||
const keyPair: CryptoKeyPair = await BrowserCrypto.generateKeyPair(
|
||||
CryptoOps.EXTRACTABLE,
|
||||
CryptoOps.POP_KEY_USAGES
|
||||
);
|
||||
|
||||
// Generate Thumbprint for Public Key
|
||||
const publicKeyJwk: JsonWebKey = await BrowserCrypto.exportJwk(
|
||||
keyPair.publicKey
|
||||
);
|
||||
|
||||
const pubKeyThumprintObj: JsonWebKey = {
|
||||
e: publicKeyJwk.e,
|
||||
kty: publicKeyJwk.kty,
|
||||
n: publicKeyJwk.n,
|
||||
};
|
||||
|
||||
const publicJwkString: string =
|
||||
getSortedObjectString(pubKeyThumprintObj);
|
||||
const publicJwkHash = await this.hashString(publicJwkString);
|
||||
|
||||
// Generate Thumbprint for Private Key
|
||||
const privateKeyJwk: JsonWebKey = await BrowserCrypto.exportJwk(
|
||||
keyPair.privateKey
|
||||
);
|
||||
// Re-import private key to make it unextractable
|
||||
const unextractablePrivateKey: CryptoKey =
|
||||
await BrowserCrypto.importJwk(privateKeyJwk, false, ["sign"]);
|
||||
|
||||
// Store Keypair data in keystore
|
||||
await this.cache.setItem(
|
||||
publicJwkHash,
|
||||
{
|
||||
privateKey: unextractablePrivateKey,
|
||||
publicKey: keyPair.publicKey,
|
||||
requestMethod: request.resourceRequestMethod,
|
||||
requestUri: request.resourceRequestUri,
|
||||
},
|
||||
request.correlationId
|
||||
);
|
||||
|
||||
if (publicKeyThumbMeasurement) {
|
||||
publicKeyThumbMeasurement.end({
|
||||
success: true,
|
||||
});
|
||||
}
|
||||
|
||||
return publicJwkHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes cryptographic keypair from key store matching the keyId passed in
|
||||
* @param kid
|
||||
* @param correlationId
|
||||
*/
|
||||
async removeTokenBindingKey(
|
||||
kid: string,
|
||||
correlationId: string
|
||||
): Promise<void> {
|
||||
await this.cache.removeItem(kid, correlationId);
|
||||
const keyFound = await this.cache.containsKey(kid, correlationId);
|
||||
if (keyFound) {
|
||||
throw createClientAuthError(
|
||||
ClientAuthErrorCodes.bindingKeyNotRemoved
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all cryptographic keys from IndexedDB storage
|
||||
* @param correlationId
|
||||
*/
|
||||
async clearKeystore(correlationId: string): Promise<boolean> {
|
||||
// Delete in-memory keystores
|
||||
this.cache.clearInMemory(correlationId);
|
||||
|
||||
/**
|
||||
* There is only one database, so calling clearPersistent on asymmetric keystore takes care of
|
||||
* every persistent keystore
|
||||
*/
|
||||
try {
|
||||
await this.cache.clearPersistent(correlationId);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
this.logger.error(
|
||||
`Clearing keystore failed with error: '${e.message}'`,
|
||||
correlationId
|
||||
);
|
||||
} else {
|
||||
this.logger.error(
|
||||
"Clearing keystore failed with unknown error",
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs the given object as a jwt payload with private key retrieved by given kid.
|
||||
* @param payload
|
||||
* @param kid
|
||||
*/
|
||||
async signJwt(
|
||||
payload: SignedHttpRequest,
|
||||
kid: string,
|
||||
shrOptions?: ShrOptions,
|
||||
correlationId?: string
|
||||
): Promise<string> {
|
||||
const signJwtMeasurement = this.performanceClient?.startMeasurement(
|
||||
BrowserPerformanceEvents.CryptoOptsSignJwt,
|
||||
correlationId
|
||||
);
|
||||
const cachedKeyPair = await this.cache.getItem(
|
||||
kid,
|
||||
correlationId || ""
|
||||
);
|
||||
|
||||
if (!cachedKeyPair) {
|
||||
throw createBrowserAuthError(
|
||||
BrowserAuthErrorCodes.cryptoKeyNotFound
|
||||
);
|
||||
}
|
||||
|
||||
// Get public key as JWK
|
||||
const publicKeyJwk = await BrowserCrypto.exportJwk(
|
||||
cachedKeyPair.publicKey
|
||||
);
|
||||
const publicKeyJwkString = getSortedObjectString(publicKeyJwk);
|
||||
// Base64URL encode public key thumbprint with keyId only: BASE64URL({ kid: "FULL_PUBLIC_KEY_HASH" })
|
||||
const encodedKeyIdThumbprint = urlEncode(JSON.stringify({ kid: kid }));
|
||||
// Generate header
|
||||
const shrHeader = JoseHeader.getShrHeaderString({
|
||||
...shrOptions?.header,
|
||||
alg: publicKeyJwk.alg,
|
||||
kid: encodedKeyIdThumbprint,
|
||||
});
|
||||
|
||||
const encodedShrHeader = urlEncode(shrHeader);
|
||||
|
||||
// Generate payload
|
||||
payload.cnf = {
|
||||
jwk: JSON.parse(publicKeyJwkString),
|
||||
};
|
||||
const encodedPayload = urlEncode(JSON.stringify(payload));
|
||||
|
||||
// Form token string
|
||||
const tokenString = `${encodedShrHeader}.${encodedPayload}`;
|
||||
|
||||
// Sign token
|
||||
const encoder = new TextEncoder();
|
||||
const tokenBuffer = encoder.encode(tokenString);
|
||||
const signatureBuffer = await BrowserCrypto.sign(
|
||||
cachedKeyPair.privateKey,
|
||||
tokenBuffer
|
||||
);
|
||||
const encodedSignature = urlEncodeArr(new Uint8Array(signatureBuffer));
|
||||
|
||||
const signedJwt = `${tokenString}.${encodedSignature}`;
|
||||
|
||||
if (signJwtMeasurement) {
|
||||
signJwtMeasurement.end({
|
||||
success: true,
|
||||
});
|
||||
}
|
||||
|
||||
return signedJwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SHA-256 hash of an input string
|
||||
* @param plainText
|
||||
*/
|
||||
async hashString(plainText: string): Promise<string> {
|
||||
return BrowserCrypto.hashString(plainText);
|
||||
}
|
||||
}
|
||||
|
||||
function getSortedObjectString(obj: object): string {
|
||||
return JSON.stringify(obj, Object.keys(obj).sort());
|
||||
}
|
||||
107
backend/node_modules/@azure/msal-browser/src/crypto/PkceGenerator.ts
generated
vendored
Normal file
107
backend/node_modules/@azure/msal-browser/src/crypto/PkceGenerator.ts
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
IPerformanceClient,
|
||||
Logger,
|
||||
PkceCodes,
|
||||
invoke,
|
||||
invokeAsync,
|
||||
} from "@azure/msal-common/browser";
|
||||
import * as BrowserPerformanceEvents from "../telemetry/BrowserPerformanceEvents.js";
|
||||
import {
|
||||
createBrowserAuthError,
|
||||
BrowserAuthErrorCodes,
|
||||
} from "../error/BrowserAuthError.js";
|
||||
import { urlEncodeArr } from "../encode/Base64Encode.js";
|
||||
import { getRandomValues, sha256Digest } from "./BrowserCrypto.js";
|
||||
|
||||
// Constant byte array length
|
||||
const RANDOM_BYTE_ARR_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* This file defines APIs to generate PKCE codes and code verifiers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates PKCE Codes. See the RFC for more information: https://tools.ietf.org/html/rfc7636
|
||||
*/
|
||||
export async function generatePkceCodes(
|
||||
performanceClient: IPerformanceClient,
|
||||
logger: Logger,
|
||||
correlationId: string
|
||||
): Promise<PkceCodes> {
|
||||
const codeVerifier = invoke(
|
||||
generateCodeVerifier,
|
||||
BrowserPerformanceEvents.GenerateCodeVerifier,
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
)(performanceClient, logger, correlationId);
|
||||
const codeChallenge = await invokeAsync(
|
||||
generateCodeChallengeFromVerifier,
|
||||
BrowserPerformanceEvents.GenerateCodeChallengeFromVerifier,
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
)(codeVerifier, performanceClient, logger, correlationId);
|
||||
return {
|
||||
verifier: codeVerifier,
|
||||
challenge: codeChallenge,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random 32 byte buffer and returns the base64
|
||||
* encoded string to be used as a PKCE Code Verifier
|
||||
*/
|
||||
function generateCodeVerifier(
|
||||
performanceClient: IPerformanceClient,
|
||||
logger: Logger,
|
||||
correlationId: string
|
||||
): string {
|
||||
try {
|
||||
// Generate random values as utf-8
|
||||
const buffer: Uint8Array = new Uint8Array(RANDOM_BYTE_ARR_LENGTH);
|
||||
invoke(
|
||||
getRandomValues,
|
||||
BrowserPerformanceEvents.GetRandomValues,
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
)(buffer);
|
||||
// encode verifier as base64
|
||||
const pkceCodeVerifierB64: string = urlEncodeArr(buffer);
|
||||
return pkceCodeVerifierB64;
|
||||
} catch (e) {
|
||||
throw createBrowserAuthError(BrowserAuthErrorCodes.pkceNotCreated);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a base64 encoded PKCE Code Challenge string from the
|
||||
* hash created from the PKCE Code Verifier supplied
|
||||
*/
|
||||
async function generateCodeChallengeFromVerifier(
|
||||
pkceCodeVerifier: string,
|
||||
performanceClient: IPerformanceClient,
|
||||
logger: Logger,
|
||||
correlationId: string
|
||||
): Promise<string> {
|
||||
try {
|
||||
// hashed verifier
|
||||
const pkceHashedCodeVerifier = await invokeAsync(
|
||||
sha256Digest,
|
||||
BrowserPerformanceEvents.Sha256Digest,
|
||||
logger,
|
||||
performanceClient,
|
||||
correlationId
|
||||
)(pkceCodeVerifier);
|
||||
// encode hash as base64
|
||||
return urlEncodeArr(new Uint8Array(pkceHashedCodeVerifier));
|
||||
} catch (e) {
|
||||
throw createBrowserAuthError(BrowserAuthErrorCodes.pkceNotCreated);
|
||||
}
|
||||
}
|
||||
87
backend/node_modules/@azure/msal-browser/src/crypto/SignedHttpRequest.ts
generated
vendored
Normal file
87
backend/node_modules/@azure/msal-browser/src/crypto/SignedHttpRequest.ts
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CryptoOps } from "./CryptoOps.js";
|
||||
import {
|
||||
Logger,
|
||||
LoggerOptions,
|
||||
PopTokenGenerator,
|
||||
SignedHttpRequestParameters,
|
||||
StubPerformanceClient,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { version, name } from "../packageMetadata.js";
|
||||
|
||||
export type SignedHttpRequestOptions = {
|
||||
loggerOptions: LoggerOptions;
|
||||
};
|
||||
|
||||
export class SignedHttpRequest {
|
||||
private popTokenGenerator: PopTokenGenerator;
|
||||
private cryptoOps: CryptoOps;
|
||||
private shrParameters: SignedHttpRequestParameters;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
shrParameters: SignedHttpRequestParameters,
|
||||
shrOptions?: SignedHttpRequestOptions
|
||||
) {
|
||||
const loggerOptions = (shrOptions && shrOptions.loggerOptions) || {};
|
||||
this.logger = new Logger(loggerOptions, name, version);
|
||||
this.cryptoOps = new CryptoOps(this.logger);
|
||||
this.popTokenGenerator = new PopTokenGenerator(
|
||||
this.cryptoOps,
|
||||
new StubPerformanceClient()
|
||||
);
|
||||
this.shrParameters = shrParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and caches a keypair for the given request options.
|
||||
* @returns Public key digest, which should be sent to the token issuer.
|
||||
*/
|
||||
async generatePublicKeyThumbprint(): Promise<string> {
|
||||
const { kid } = await this.popTokenGenerator.generateKid(
|
||||
this.shrParameters
|
||||
);
|
||||
|
||||
return kid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a signed http request for the given payload with the given key.
|
||||
* @param payload Payload to sign (e.g. access token)
|
||||
* @param publicKeyThumbprint Public key digest (from generatePublicKeyThumbprint API)
|
||||
* @param claims Additional claims to include/override in the signed JWT
|
||||
* @returns Pop token signed with the corresponding private key
|
||||
*/
|
||||
async signRequest(
|
||||
payload: string,
|
||||
publicKeyThumbprint: string,
|
||||
claims?: object
|
||||
): Promise<string> {
|
||||
return this.popTokenGenerator.signPayload(
|
||||
payload,
|
||||
publicKeyThumbprint,
|
||||
this.shrParameters,
|
||||
claims
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes cached keys from browser for given public key thumbprint
|
||||
* @param publicKeyThumbprint Public key digest (from generatePublicKeyThumbprint API)
|
||||
* @param correlationId
|
||||
* @returns If keys are properly deleted
|
||||
*/
|
||||
async removeKeys(
|
||||
publicKeyThumbprint: string,
|
||||
correlationId: string
|
||||
): Promise<void> {
|
||||
return this.cryptoOps.removeTokenBindingKey(
|
||||
publicKeyThumbprint,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
}
|
||||
40
backend/node_modules/@azure/msal-browser/src/custom_auth/CustomAuthActionInputs.ts
generated
vendored
Normal file
40
backend/node_modules/@azure/msal-browser/src/custom_auth/CustomAuthActionInputs.ts
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { UserAccountAttributes } from "./UserAccountAttributes.js";
|
||||
|
||||
export type CustomAuthActionInputs = {
|
||||
correlationId?: string;
|
||||
};
|
||||
|
||||
export type AccountRetrievalInputs = CustomAuthActionInputs;
|
||||
|
||||
export type SignInInputs = CustomAuthActionInputs & {
|
||||
username: string;
|
||||
password?: string;
|
||||
scopes?: Array<string>;
|
||||
claims?: string;
|
||||
};
|
||||
|
||||
export type SignUpInputs = CustomAuthActionInputs & {
|
||||
username: string;
|
||||
password?: string;
|
||||
attributes?: UserAccountAttributes;
|
||||
};
|
||||
|
||||
export type ResetPasswordInputs = CustomAuthActionInputs & {
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type AccessTokenRetrievalInputs = {
|
||||
forceRefresh: boolean;
|
||||
scopes?: Array<string>;
|
||||
claims?: string;
|
||||
};
|
||||
|
||||
export type SignInWithContinuationTokenInputs = {
|
||||
scopes?: Array<string>;
|
||||
claims?: string;
|
||||
};
|
||||
62
backend/node_modules/@azure/msal-browser/src/custom_auth/CustomAuthConstants.ts
generated
vendored
Normal file
62
backend/node_modules/@azure/msal-browser/src/custom_auth/CustomAuthConstants.ts
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { Constants } from "@azure/msal-common/browser";
|
||||
import { version } from "../packageMetadata.js";
|
||||
|
||||
export const GrantType = {
|
||||
PASSWORD: "password",
|
||||
OOB: "oob",
|
||||
CONTINUATION_TOKEN: "continuation_token",
|
||||
REDIRECT: "redirect",
|
||||
ATTRIBUTES: "attributes",
|
||||
MFA_OOB: "mfa_oob",
|
||||
} as const;
|
||||
|
||||
export const ChallengeType = {
|
||||
PASSWORD: "password",
|
||||
OOB: "oob",
|
||||
REDIRECT: "redirect",
|
||||
PREVERIFIED: "preverified",
|
||||
} as const;
|
||||
|
||||
export const DefaultScopes = [
|
||||
Constants.OPENID_SCOPE,
|
||||
Constants.PROFILE_SCOPE,
|
||||
Constants.OFFLINE_ACCESS_SCOPE,
|
||||
] as const;
|
||||
|
||||
export const HttpHeaderKeys = {
|
||||
CONTENT_TYPE: "Content-Type",
|
||||
X_MS_REQUEST_ID: "x-ms-request-id",
|
||||
} as const;
|
||||
|
||||
export const CustomHeaderConstants = {
|
||||
REQUIRED_PREFIX: "x-",
|
||||
RESERVED_PREFIXES: [
|
||||
"x-client-",
|
||||
"x-ms-",
|
||||
"x-broker-",
|
||||
"x-app-",
|
||||
] as ReadonlyArray<string>,
|
||||
} as const;
|
||||
|
||||
export const DefaultPackageInfo = {
|
||||
SKU: "msal.browser",
|
||||
VERSION: version,
|
||||
OS: "",
|
||||
CPU: "",
|
||||
} as const;
|
||||
|
||||
export const ResetPasswordPollStatus = {
|
||||
IN_PROGRESS: "in_progress",
|
||||
SUCCEEDED: "succeeded",
|
||||
FAILED: "failed",
|
||||
NOT_STARTED: "not_started",
|
||||
} as const;
|
||||
|
||||
export const DefaultCustomAuthApiCodeLength = -1; // Default value indicating that the code length is not specified
|
||||
export const DefaultCustomAuthApiCodeResendIntervalInSec = 300; // seconds
|
||||
export const PasswordResetPollingTimeoutInMs = 300000; // milliseconds
|
||||
158
backend/node_modules/@azure/msal-browser/src/custom_auth/CustomAuthPublicClientApplication.ts
generated
vendored
Normal file
158
backend/node_modules/@azure/msal-browser/src/custom_auth/CustomAuthPublicClientApplication.ts
generated
vendored
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { GetAccountResult } from "./get_account/auth_flow/result/GetAccountResult.js";
|
||||
import { SignInResult } from "./sign_in/auth_flow/result/SignInResult.js";
|
||||
import { SignUpResult } from "./sign_up/auth_flow/result/SignUpResult.js";
|
||||
import { ICustomAuthStandardController } from "./controller/ICustomAuthStandardController.js";
|
||||
import { CustomAuthStandardController } from "./controller/CustomAuthStandardController.js";
|
||||
import { ICustomAuthPublicClientApplication } from "./ICustomAuthPublicClientApplication.js";
|
||||
import {
|
||||
AccountRetrievalInputs,
|
||||
SignInInputs,
|
||||
SignUpInputs,
|
||||
ResetPasswordInputs,
|
||||
} from "./CustomAuthActionInputs.js";
|
||||
import { CustomAuthConfiguration } from "./configuration/CustomAuthConfiguration.js";
|
||||
import { CustomAuthOperatingContext } from "./operating_context/CustomAuthOperatingContext.js";
|
||||
import { ResetPasswordStartResult } from "./reset_password/auth_flow/result/ResetPasswordStartResult.js";
|
||||
import { InvalidConfigurationError } from "./core/error/InvalidConfigurationError.js";
|
||||
import { ChallengeType } from "./CustomAuthConstants.js";
|
||||
import { PublicClientApplication } from "../app/PublicClientApplication.js";
|
||||
import {
|
||||
InvalidAuthority,
|
||||
InvalidChallengeType,
|
||||
MissingConfiguration,
|
||||
} from "./core/error/InvalidConfigurationErrorCodes.js";
|
||||
|
||||
export class CustomAuthPublicClientApplication
|
||||
extends PublicClientApplication
|
||||
implements ICustomAuthPublicClientApplication
|
||||
{
|
||||
private readonly customAuthController: ICustomAuthStandardController;
|
||||
|
||||
/**
|
||||
* Creates a new instance of a PublicClientApplication with the given configuration and controller to start Native authentication flows
|
||||
* @param {CustomAuthConfiguration} config - A configuration object for the PublicClientApplication instance
|
||||
* @returns {Promise<ICustomAuthPublicClientApplication>} - A promise that resolves to a CustomAuthPublicClientApplication instance
|
||||
*/
|
||||
static async create(
|
||||
config: CustomAuthConfiguration
|
||||
): Promise<ICustomAuthPublicClientApplication> {
|
||||
CustomAuthPublicClientApplication.validateConfig(config);
|
||||
|
||||
const customAuthController = new CustomAuthStandardController(
|
||||
new CustomAuthOperatingContext(config)
|
||||
);
|
||||
|
||||
await customAuthController.initialize();
|
||||
|
||||
const app = new CustomAuthPublicClientApplication(
|
||||
config,
|
||||
customAuthController
|
||||
);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
private constructor(
|
||||
config: CustomAuthConfiguration,
|
||||
controller: ICustomAuthStandardController
|
||||
) {
|
||||
super(config, controller);
|
||||
|
||||
this.customAuthController = controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current account from the browser cache.
|
||||
* @param {AccountRetrievalInputs} accountRetrievalInputs?:AccountRetrievalInputs
|
||||
* @returns {GetAccountResult} - The result of the get account operation
|
||||
*/
|
||||
getCurrentAccount(
|
||||
accountRetrievalInputs?: AccountRetrievalInputs
|
||||
): GetAccountResult {
|
||||
return this.customAuthController.getCurrentAccount(
|
||||
accountRetrievalInputs
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the sign-in flow.
|
||||
* This method results in sign-in completion, or extra actions (password, code, etc.) required to complete the sign-in.
|
||||
* Create result with error details if any exception thrown.
|
||||
* @param {SignInInputs} signInInputs - Inputs for the sign-in flow
|
||||
* @returns {Promise<SignInResult>} - A promise that resolves to SignInResult
|
||||
*/
|
||||
signIn(signInInputs: SignInInputs): Promise<SignInResult> {
|
||||
return this.customAuthController.signIn(signInInputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the sign-up flow.
|
||||
* This method results in sign-up completion, or extra actions (password, code, etc.) required to complete the sign-up.
|
||||
* Create result with error details if any exception thrown.
|
||||
* @param {SignUpInputs} signUpInputs
|
||||
* @returns {Promise<SignUpResult>} - A promise that resolves to SignUpResult
|
||||
*/
|
||||
signUp(signUpInputs: SignUpInputs): Promise<SignUpResult> {
|
||||
return this.customAuthController.signUp(signUpInputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the reset password flow.
|
||||
* This method results in triggering extra action (submit code) to complete the reset password.
|
||||
* Create result with error details if any exception thrown.
|
||||
* @param {ResetPasswordInputs} resetPasswordInputs - Inputs for the reset password flow
|
||||
* @returns {Promise<ResetPasswordStartResult>} - A promise that resolves to ResetPasswordStartResult
|
||||
*/
|
||||
resetPassword(
|
||||
resetPasswordInputs: ResetPasswordInputs
|
||||
): Promise<ResetPasswordStartResult> {
|
||||
return this.customAuthController.resetPassword(resetPasswordInputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the configuration to ensure it is a valid CustomAuthConfiguration object.
|
||||
* @param {CustomAuthConfiguration} config - The configuration object for the PublicClientApplication.
|
||||
* @returns {void}
|
||||
*/
|
||||
private static validateConfig(config: CustomAuthConfiguration): void {
|
||||
// Ensure the configuration object has a valid CIAM authority URL.
|
||||
if (!config) {
|
||||
throw new InvalidConfigurationError(
|
||||
MissingConfiguration,
|
||||
"The configuration is missing."
|
||||
);
|
||||
}
|
||||
|
||||
if (!config.auth?.authority) {
|
||||
throw new InvalidConfigurationError(
|
||||
InvalidAuthority,
|
||||
`The authority URL '${config.auth?.authority}' is not set.`
|
||||
);
|
||||
}
|
||||
|
||||
const challengeTypes = config.customAuth.challengeTypes;
|
||||
|
||||
if (!!challengeTypes && challengeTypes.length > 0) {
|
||||
challengeTypes.forEach((challengeType) => {
|
||||
const lowerCaseChallengeType = challengeType.toLowerCase();
|
||||
if (
|
||||
lowerCaseChallengeType !== ChallengeType.PASSWORD &&
|
||||
lowerCaseChallengeType !== ChallengeType.OOB &&
|
||||
lowerCaseChallengeType !== ChallengeType.REDIRECT
|
||||
) {
|
||||
throw new InvalidConfigurationError(
|
||||
InvalidChallengeType,
|
||||
`Challenge type ${challengeType} in the configuration are not valid. Supported challenge types are ${Object.values(
|
||||
ChallengeType
|
||||
)}`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
51
backend/node_modules/@azure/msal-browser/src/custom_auth/ICustomAuthPublicClientApplication.ts
generated
vendored
Normal file
51
backend/node_modules/@azure/msal-browser/src/custom_auth/ICustomAuthPublicClientApplication.ts
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { GetAccountResult } from "./get_account/auth_flow/result/GetAccountResult.js";
|
||||
import { SignInResult } from "./sign_in/auth_flow/result/SignInResult.js";
|
||||
import { SignUpResult } from "./sign_up/auth_flow/result/SignUpResult.js";
|
||||
import {
|
||||
AccountRetrievalInputs,
|
||||
ResetPasswordInputs,
|
||||
SignInInputs,
|
||||
SignUpInputs,
|
||||
} from "./CustomAuthActionInputs.js";
|
||||
import { ResetPasswordStartResult } from "./reset_password/auth_flow/result/ResetPasswordStartResult.js";
|
||||
import { IPublicClientApplication } from "../app/IPublicClientApplication.js";
|
||||
|
||||
export interface ICustomAuthPublicClientApplication
|
||||
extends IPublicClientApplication {
|
||||
/**
|
||||
* Gets the current account from the cache.
|
||||
* @param {AccountRetrievalInputs} accountRetrievalInputs - Inputs for getting the current cached account
|
||||
* @returns {GetAccountResult} The result of the operation
|
||||
*/
|
||||
getCurrentAccount(
|
||||
accountRetrievalInputs?: AccountRetrievalInputs
|
||||
): GetAccountResult;
|
||||
|
||||
/**
|
||||
* Initiates the sign-in flow.
|
||||
* @param {SignInInputs} signInInputs - Inputs for the sign-in flow
|
||||
* @returns {Promise<SignInResult>} A promise that resolves to SignInResult
|
||||
*/
|
||||
signIn(signInInputs: SignInInputs): Promise<SignInResult>;
|
||||
|
||||
/**
|
||||
* Initiates the sign-up flow.
|
||||
* @param {SignUpInputs} signUpInputs - Inputs for the sign-up flow
|
||||
* @returns {Promise<SignUpResult>} A promise that resolves to SignUpResult
|
||||
*/
|
||||
signUp(signUpInputs: SignUpInputs): Promise<SignUpResult>;
|
||||
|
||||
/**
|
||||
* Initiates the reset password flow.
|
||||
* @param {ResetPasswordInputs} resetPasswordInputs - Inputs for the reset password flow
|
||||
* @returns {Promise<ResetPasswordStartResult>} A promise that resolves to ResetPasswordStartResult
|
||||
*/
|
||||
resetPassword(
|
||||
resetPasswordInputs: ResetPasswordInputs
|
||||
): Promise<ResetPasswordStartResult>;
|
||||
}
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/UserAccountAttributes.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/UserAccountAttributes.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export type UserAccountAttributes = Record<string, string> & {
|
||||
city?: string;
|
||||
country?: string;
|
||||
displayName?: string;
|
||||
flatusername?: string;
|
||||
givenName?: string;
|
||||
jobTitle?: string;
|
||||
postalCode?: string;
|
||||
state?: string;
|
||||
streetAddress?: string;
|
||||
surname?: string;
|
||||
};
|
||||
26
backend/node_modules/@azure/msal-browser/src/custom_auth/configuration/CustomAuthConfiguration.ts
generated
vendored
Normal file
26
backend/node_modules/@azure/msal-browser/src/custom_auth/configuration/CustomAuthConfiguration.ts
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
BrowserConfiguration,
|
||||
Configuration,
|
||||
} from "../../config/Configuration.js";
|
||||
import { CustomAuthRequestInterceptor } from "./CustomAuthRequestInterceptor.js";
|
||||
|
||||
export type CustomAuthOptions = {
|
||||
challengeTypes?: Array<string>;
|
||||
authApiProxyUrl: string;
|
||||
customAuthApiQueryParams?: Record<string, string>;
|
||||
capabilities?: Array<string>;
|
||||
requestInterceptor?: CustomAuthRequestInterceptor;
|
||||
};
|
||||
|
||||
export type CustomAuthConfiguration = Configuration & {
|
||||
customAuth: CustomAuthOptions;
|
||||
};
|
||||
|
||||
export type CustomAuthBrowserConfiguration = BrowserConfiguration & {
|
||||
customAuth: CustomAuthOptions;
|
||||
};
|
||||
54
backend/node_modules/@azure/msal-browser/src/custom_auth/configuration/CustomAuthRequestInterceptor.ts
generated
vendored
Normal file
54
backend/node_modules/@azure/msal-browser/src/custom_auth/configuration/CustomAuthRequestInterceptor.ts
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Result type returned by {@link CustomAuthRequestInterceptor.addAdditionalHeaderFields}.
|
||||
*
|
||||
* Implementations may return either a synchronous value or a `Promise` resolving to one of
|
||||
* the following:
|
||||
* - A `Record<string, string>` of additional headers to add to the outgoing request.
|
||||
* - `null` (or `undefined`) when no additional headers should be added for the request.
|
||||
*/
|
||||
export type CustomAuthAdditionalHeaderFieldsResult =
|
||||
| Record<string, string>
|
||||
| null
|
||||
| undefined;
|
||||
|
||||
/**
|
||||
* Interface for intercepting custom auth network requests in order to attach additional
|
||||
* headers to outgoing requests.
|
||||
*
|
||||
* Implementations are invoked by MSAL before each backend request used by custom auth
|
||||
* (sign-in, sign-up, reset-password, and register endpoints). Use this hook to integrate
|
||||
* with third-party fraud and bot-detection SDKs that require custom `x-*` headers.
|
||||
*
|
||||
* MSAL applies the following rules when evaluating the headers you provide:
|
||||
* - Headers must start with `x-` (case-insensitive). Headers that don't start with `x-`
|
||||
* are ignored.
|
||||
* - Headers that start with any of the following reserved prefixes are ignored:
|
||||
* `x-client-`, `x-ms-`, `x-broker-`, `x-app-`.
|
||||
* - Headers that pass both rules are added to the network request. If a header you
|
||||
* provide has the same name as one of MSAL's own internal headers, your value takes
|
||||
* precedence.
|
||||
*/
|
||||
export interface CustomAuthRequestInterceptor {
|
||||
/**
|
||||
* Returns additional headers to add to a custom-auth network request.
|
||||
*
|
||||
* Scope your headers to specific endpoints by inspecting `requestUrl`. Sending
|
||||
* headers to unrelated endpoints can degrade signal quality and increase false
|
||||
* positives for fraud/bot-detection vendors.
|
||||
*
|
||||
* @param requestUrl - The full URL of the outgoing custom-auth request.
|
||||
* @returns A record of headers to add (or `null`/`undefined` if no extra headers
|
||||
* are needed for the request). May be returned synchronously or as a
|
||||
* `Promise`.
|
||||
*/
|
||||
addAdditionalHeaderFields(
|
||||
requestUrl: URL
|
||||
):
|
||||
| CustomAuthAdditionalHeaderFieldsResult
|
||||
| Promise<CustomAuthAdditionalHeaderFieldsResult>;
|
||||
}
|
||||
604
backend/node_modules/@azure/msal-browser/src/custom_auth/controller/CustomAuthStandardController.ts
generated
vendored
Normal file
604
backend/node_modules/@azure/msal-browser/src/custom_auth/controller/CustomAuthStandardController.ts
generated
vendored
Normal file
@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { GetAccountResult } from "../get_account/auth_flow/result/GetAccountResult.js";
|
||||
import { SignInResult } from "../sign_in/auth_flow/result/SignInResult.js";
|
||||
import { SignUpResult } from "../sign_up/auth_flow/result/SignUpResult.js";
|
||||
import {
|
||||
SignInStartParams,
|
||||
SignInSubmitPasswordParams,
|
||||
} from "../sign_in/interaction_client/parameter/SignInParams.js";
|
||||
import { SignInClient } from "../sign_in/interaction_client/SignInClient.js";
|
||||
import {
|
||||
AccountRetrievalInputs,
|
||||
SignInInputs,
|
||||
SignUpInputs,
|
||||
ResetPasswordInputs,
|
||||
CustomAuthActionInputs,
|
||||
} from "../CustomAuthActionInputs.js";
|
||||
import { CustomAuthBrowserConfiguration } from "../configuration/CustomAuthConfiguration.js";
|
||||
import { CustomAuthOperatingContext } from "../operating_context/CustomAuthOperatingContext.js";
|
||||
import { ICustomAuthStandardController } from "./ICustomAuthStandardController.js";
|
||||
import { CustomAuthAccountData } from "../get_account/auth_flow/CustomAuthAccountData.js";
|
||||
import { UnexpectedError } from "../core/error/UnexpectedError.js";
|
||||
import { ResetPasswordStartResult } from "../reset_password/auth_flow/result/ResetPasswordStartResult.js";
|
||||
import { CustomAuthAuthority } from "../core/CustomAuthAuthority.js";
|
||||
import { DefaultPackageInfo } from "../CustomAuthConstants.js";
|
||||
import {
|
||||
SIGN_IN_CODE_SEND_RESULT_TYPE,
|
||||
SIGN_IN_PASSWORD_REQUIRED_RESULT_TYPE,
|
||||
SIGN_IN_COMPLETED_RESULT_TYPE,
|
||||
SIGN_IN_JIT_REQUIRED_RESULT_TYPE,
|
||||
SIGN_IN_MFA_REQUIRED_RESULT_TYPE,
|
||||
} from "../sign_in/interaction_client/result/SignInActionResult.js";
|
||||
import { SignUpClient } from "../sign_up/interaction_client/SignUpClient.js";
|
||||
import { CustomAuthInterationClientFactory } from "../core/interaction_client/CustomAuthInterationClientFactory.js";
|
||||
import {
|
||||
SIGN_UP_CODE_REQUIRED_RESULT_TYPE,
|
||||
SIGN_UP_PASSWORD_REQUIRED_RESULT_TYPE,
|
||||
} from "../sign_up/interaction_client/result/SignUpActionResult.js";
|
||||
import { ICustomAuthApiClient } from "../core/network_client/custom_auth_api/ICustomAuthApiClient.js";
|
||||
import { CustomAuthApiClient } from "../core/network_client/custom_auth_api/CustomAuthApiClient.js";
|
||||
import { FetchHttpClient } from "../core/network_client/http_client/FetchHttpClient.js";
|
||||
import { ResetPasswordClient } from "../reset_password/interaction_client/ResetPasswordClient.js";
|
||||
import { JitClient } from "../core/interaction_client/jit/JitClient.js";
|
||||
import { MfaClient } from "../core/interaction_client/mfa/MfaClient.js";
|
||||
import { NoCachedAccountFoundError } from "../core/error/NoCachedAccountFoundError.js";
|
||||
import * as ArgumentValidator from "../core/utils/ArgumentValidator.js";
|
||||
import { UserAlreadySignedInError } from "../core/error/UserAlreadySignedInError.js";
|
||||
import { CustomAuthSilentCacheClient } from "../get_account/interaction_client/CustomAuthSilentCacheClient.js";
|
||||
import { UnsupportedEnvironmentError } from "../core/error/UnsupportedEnvironmentError.js";
|
||||
import { SignInCodeRequiredState } from "../sign_in/auth_flow/state/SignInCodeRequiredState.js";
|
||||
import { SignInPasswordRequiredState } from "../sign_in/auth_flow/state/SignInPasswordRequiredState.js";
|
||||
import { SignInCompletedState } from "../sign_in/auth_flow/state/SignInCompletedState.js";
|
||||
import { AuthMethodRegistrationRequiredState } from "../core/auth_flow/jit/state/AuthMethodRegistrationState.js";
|
||||
import { MfaAwaitingState } from "../core/auth_flow/mfa/state/MfaState.js";
|
||||
import { SignUpCodeRequiredState } from "../sign_up/auth_flow/state/SignUpCodeRequiredState.js";
|
||||
import { SignUpPasswordRequiredState } from "../sign_up/auth_flow/state/SignUpPasswordRequiredState.js";
|
||||
import { ResetPasswordCodeRequiredState } from "../reset_password/auth_flow/state/ResetPasswordCodeRequiredState.js";
|
||||
import { StandardController } from "../../controllers/StandardController.js";
|
||||
|
||||
/*
|
||||
* Controller for standard native auth operations.
|
||||
*/
|
||||
export class CustomAuthStandardController
|
||||
extends StandardController
|
||||
implements ICustomAuthStandardController
|
||||
{
|
||||
private readonly signInClient: SignInClient;
|
||||
private readonly signUpClient: SignUpClient;
|
||||
private readonly resetPasswordClient: ResetPasswordClient;
|
||||
private readonly jitClient: JitClient;
|
||||
private readonly mfaClient: MfaClient;
|
||||
private readonly cacheClient: CustomAuthSilentCacheClient;
|
||||
private readonly customAuthConfig: CustomAuthBrowserConfiguration;
|
||||
private readonly authority: CustomAuthAuthority;
|
||||
|
||||
/*
|
||||
* Constructor for CustomAuthStandardController.
|
||||
* @param operatingContext - The operating context for the controller.
|
||||
* @param customAuthApiClient - The client to use for custom auth API operations.
|
||||
*/
|
||||
constructor(
|
||||
operatingContext: CustomAuthOperatingContext,
|
||||
customAuthApiClient?: ICustomAuthApiClient
|
||||
) {
|
||||
super(operatingContext);
|
||||
|
||||
if (!this.isBrowserEnvironment) {
|
||||
this.logger.verbose(
|
||||
"The SDK can only be used in a browser environment.",
|
||||
""
|
||||
);
|
||||
throw new UnsupportedEnvironmentError();
|
||||
}
|
||||
|
||||
this.logger = this.logger.clone(
|
||||
DefaultPackageInfo.SKU,
|
||||
DefaultPackageInfo.VERSION
|
||||
);
|
||||
this.customAuthConfig = operatingContext.getCustomAuthConfig();
|
||||
|
||||
this.authority = new CustomAuthAuthority(
|
||||
this.customAuthConfig.auth.authority,
|
||||
this.customAuthConfig,
|
||||
this.networkClient,
|
||||
this.browserStorage,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
this.customAuthConfig.customAuth?.authApiProxyUrl
|
||||
);
|
||||
|
||||
const interactionClientFactory = new CustomAuthInterationClientFactory(
|
||||
this.customAuthConfig,
|
||||
this.browserStorage,
|
||||
this.browserCrypto,
|
||||
this.logger,
|
||||
this.eventHandler,
|
||||
this.navigationClient,
|
||||
this.performanceClient,
|
||||
customAuthApiClient ??
|
||||
new CustomAuthApiClient(
|
||||
this.authority.getCustomAuthApiDomain(),
|
||||
this.customAuthConfig.auth.clientId,
|
||||
new FetchHttpClient(this.logger),
|
||||
this.customAuthConfig.customAuth?.capabilities?.join(" "),
|
||||
this.customAuthConfig.customAuth?.customAuthApiQueryParams,
|
||||
this.customAuthConfig.customAuth?.requestInterceptor,
|
||||
this.logger
|
||||
),
|
||||
this.authority
|
||||
);
|
||||
|
||||
this.signInClient = interactionClientFactory.create(SignInClient);
|
||||
this.signUpClient = interactionClientFactory.create(SignUpClient);
|
||||
this.resetPasswordClient =
|
||||
interactionClientFactory.create(ResetPasswordClient);
|
||||
this.jitClient = interactionClientFactory.create(JitClient);
|
||||
this.mfaClient = interactionClientFactory.create(MfaClient);
|
||||
this.cacheClient = interactionClientFactory.create(
|
||||
CustomAuthSilentCacheClient
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the current account from the cache.
|
||||
* @param accountRetrievalInputs - Inputs for getting the current cached account
|
||||
* @returns {GetAccountResult} The account result
|
||||
*/
|
||||
getCurrentAccount(
|
||||
accountRetrievalInputs?: AccountRetrievalInputs
|
||||
): GetAccountResult {
|
||||
const correlationId = this.getCorrelationId(accountRetrievalInputs);
|
||||
try {
|
||||
this.logger.verbose("Getting current account data.", correlationId);
|
||||
|
||||
const account = this.cacheClient.getCurrentAccount(correlationId);
|
||||
|
||||
if (account) {
|
||||
this.logger.verbose("Account data found.", correlationId);
|
||||
|
||||
return new GetAccountResult(
|
||||
new CustomAuthAccountData(
|
||||
account,
|
||||
this.customAuthConfig,
|
||||
this.cacheClient,
|
||||
this.logger,
|
||||
correlationId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
throw new NoCachedAccountFoundError(correlationId);
|
||||
} catch (error) {
|
||||
this.logger.errorPii(
|
||||
`An error occurred during getting current account: '${error}'`,
|
||||
correlationId
|
||||
);
|
||||
|
||||
return GetAccountResult.createWithError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Signs the user in.
|
||||
* @param signInInputs - Inputs for signing in the user.
|
||||
* @returns {Promise<SignInResult>} The result of the operation.
|
||||
*/
|
||||
async signIn(signInInputs: SignInInputs): Promise<SignInResult> {
|
||||
const correlationId = this.getCorrelationId(signInInputs);
|
||||
|
||||
try {
|
||||
ArgumentValidator.ensureArgumentIsNotNullOrUndefined(
|
||||
"signInInputs",
|
||||
signInInputs,
|
||||
correlationId
|
||||
);
|
||||
|
||||
ArgumentValidator.ensureArgumentIsNotEmptyString(
|
||||
"signInInputs.username",
|
||||
signInInputs.username,
|
||||
correlationId
|
||||
);
|
||||
this.ensureUserNotSignedIn(correlationId);
|
||||
|
||||
if (signInInputs.claims) {
|
||||
ArgumentValidator.ensureArgumentIsJSONString(
|
||||
"signInInputs.claims",
|
||||
signInInputs.claims,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
|
||||
// start the signin flow
|
||||
const signInStartParams: SignInStartParams = {
|
||||
clientId: this.customAuthConfig.auth.clientId,
|
||||
correlationId: correlationId,
|
||||
challengeType:
|
||||
this.customAuthConfig.customAuth.challengeTypes ?? [],
|
||||
username: signInInputs.username,
|
||||
password: signInInputs.password,
|
||||
};
|
||||
|
||||
this.logger.verbose(
|
||||
`Starting sign-in flow '${
|
||||
!!signInInputs.password ? "with" : "without"
|
||||
}' password.`,
|
||||
correlationId
|
||||
);
|
||||
|
||||
const startResult = await this.signInClient.start(
|
||||
signInStartParams
|
||||
);
|
||||
|
||||
this.logger.verbose("Sign-in flow started.", correlationId);
|
||||
|
||||
if (startResult.type === SIGN_IN_CODE_SEND_RESULT_TYPE) {
|
||||
// require code
|
||||
this.logger.verbose(
|
||||
"Code required for sign-in.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
return new SignInResult(
|
||||
new SignInCodeRequiredState({
|
||||
correlationId: startResult.correlationId,
|
||||
continuationToken: startResult.continuationToken,
|
||||
logger: this.logger,
|
||||
config: this.customAuthConfig,
|
||||
signInClient: this.signInClient,
|
||||
cacheClient: this.cacheClient,
|
||||
jitClient: this.jitClient,
|
||||
mfaClient: this.mfaClient,
|
||||
username: signInInputs.username,
|
||||
codeLength: startResult.codeLength,
|
||||
scopes: signInInputs.scopes ?? [],
|
||||
claims: signInInputs.claims,
|
||||
})
|
||||
);
|
||||
} else if (
|
||||
startResult.type === SIGN_IN_PASSWORD_REQUIRED_RESULT_TYPE
|
||||
) {
|
||||
// require password
|
||||
this.logger.verbose(
|
||||
"Password required for sign-in.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
if (!signInInputs.password) {
|
||||
this.logger.verbose(
|
||||
"Password required but not provided. Returning password required state.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
return new SignInResult(
|
||||
new SignInPasswordRequiredState({
|
||||
correlationId: startResult.correlationId,
|
||||
continuationToken: startResult.continuationToken,
|
||||
logger: this.logger,
|
||||
config: this.customAuthConfig,
|
||||
signInClient: this.signInClient,
|
||||
cacheClient: this.cacheClient,
|
||||
jitClient: this.jitClient,
|
||||
mfaClient: this.mfaClient,
|
||||
username: signInInputs.username,
|
||||
scopes: signInInputs.scopes ?? [],
|
||||
claims: signInInputs.claims,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.verbose(
|
||||
"Submitting password for sign-in.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
// if the password is provided, then try to get token silently.
|
||||
const submitPasswordParams: SignInSubmitPasswordParams = {
|
||||
clientId: this.customAuthConfig.auth.clientId,
|
||||
correlationId: correlationId,
|
||||
challengeType:
|
||||
this.customAuthConfig.customAuth.challengeTypes ?? [],
|
||||
scopes: signInInputs.scopes ?? [],
|
||||
continuationToken: startResult.continuationToken,
|
||||
password: signInInputs.password,
|
||||
username: signInInputs.username,
|
||||
claims: signInInputs.claims,
|
||||
};
|
||||
|
||||
const submitPasswordResult =
|
||||
await this.signInClient.submitPassword(
|
||||
submitPasswordParams
|
||||
);
|
||||
|
||||
this.logger.verbose("Sign-in flow completed.", correlationId);
|
||||
|
||||
if (
|
||||
submitPasswordResult.type === SIGN_IN_COMPLETED_RESULT_TYPE
|
||||
) {
|
||||
const accountInfo = new CustomAuthAccountData(
|
||||
submitPasswordResult.authenticationResult.account,
|
||||
this.customAuthConfig,
|
||||
this.cacheClient,
|
||||
this.logger,
|
||||
correlationId
|
||||
);
|
||||
|
||||
return new SignInResult(
|
||||
new SignInCompletedState(),
|
||||
accountInfo
|
||||
);
|
||||
} else if (
|
||||
submitPasswordResult.type ===
|
||||
SIGN_IN_JIT_REQUIRED_RESULT_TYPE
|
||||
) {
|
||||
// Authentication method registration is required - create AuthMethodRegistrationRequiredState
|
||||
this.logger.verbose(
|
||||
"Authentication method registration required for sign-in.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
return new SignInResult(
|
||||
new AuthMethodRegistrationRequiredState({
|
||||
correlationId: correlationId,
|
||||
continuationToken:
|
||||
submitPasswordResult.continuationToken,
|
||||
logger: this.logger,
|
||||
config: this.customAuthConfig,
|
||||
jitClient: this.jitClient,
|
||||
cacheClient: this.cacheClient,
|
||||
authMethods: submitPasswordResult.authMethods,
|
||||
username: signInInputs.username,
|
||||
scopes: signInInputs.scopes ?? [],
|
||||
claims: signInInputs.claims,
|
||||
})
|
||||
);
|
||||
} else if (
|
||||
submitPasswordResult.type ===
|
||||
SIGN_IN_MFA_REQUIRED_RESULT_TYPE
|
||||
) {
|
||||
// MFA is required - create MfaAwaitingState
|
||||
this.logger.verbose(
|
||||
"MFA required for sign-in.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
return new SignInResult(
|
||||
new MfaAwaitingState({
|
||||
correlationId: correlationId,
|
||||
continuationToken:
|
||||
submitPasswordResult.continuationToken,
|
||||
logger: this.logger,
|
||||
config: this.customAuthConfig,
|
||||
mfaClient: this.mfaClient,
|
||||
cacheClient: this.cacheClient,
|
||||
scopes: signInInputs.scopes ?? [],
|
||||
authMethods: submitPasswordResult.authMethods ?? [],
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Unexpected result type
|
||||
const result = submitPasswordResult as { type: string };
|
||||
const error = new Error(
|
||||
`Unexpected result type: ${result.type}`
|
||||
);
|
||||
return SignInResult.createWithError(error);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.error(
|
||||
"Unexpected sign-in result type. Returning error.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
throw new UnexpectedError(
|
||||
"Unknow sign-in result type",
|
||||
correlationId
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.errorPii(
|
||||
`An error occurred during starting sign-in: '${error}'`,
|
||||
correlationId
|
||||
);
|
||||
|
||||
return SignInResult.createWithError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Signs the user up.
|
||||
* @param signUpInputs - Inputs for signing up the user.
|
||||
* @returns {Promise<SignUpResult>} The result of the operation
|
||||
*/
|
||||
async signUp(signUpInputs: SignUpInputs): Promise<SignUpResult> {
|
||||
const correlationId = this.getCorrelationId(signUpInputs);
|
||||
|
||||
try {
|
||||
ArgumentValidator.ensureArgumentIsNotNullOrUndefined(
|
||||
"signUpInputs",
|
||||
signUpInputs,
|
||||
correlationId
|
||||
);
|
||||
|
||||
ArgumentValidator.ensureArgumentIsNotEmptyString(
|
||||
"signUpInputs.username",
|
||||
signUpInputs.username,
|
||||
correlationId
|
||||
);
|
||||
this.ensureUserNotSignedIn(correlationId);
|
||||
|
||||
this.logger.verbose(
|
||||
`Starting sign-up flow'${
|
||||
!!signUpInputs.password
|
||||
? ` with ${
|
||||
!!signUpInputs.attributes
|
||||
? "password and attributes"
|
||||
: "password"
|
||||
}`
|
||||
: ""
|
||||
}'.`,
|
||||
correlationId
|
||||
);
|
||||
|
||||
const startResult = await this.signUpClient.start({
|
||||
clientId: this.customAuthConfig.auth.clientId,
|
||||
correlationId: correlationId,
|
||||
challengeType:
|
||||
this.customAuthConfig.customAuth.challengeTypes ?? [],
|
||||
username: signUpInputs.username,
|
||||
password: signUpInputs.password,
|
||||
attributes: signUpInputs.attributes,
|
||||
});
|
||||
|
||||
this.logger.verbose("Sign-up flow started.", correlationId);
|
||||
|
||||
if (startResult.type === SIGN_UP_CODE_REQUIRED_RESULT_TYPE) {
|
||||
// Code required
|
||||
this.logger.verbose(
|
||||
"Code required for sign-up.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
return new SignUpResult(
|
||||
new SignUpCodeRequiredState({
|
||||
correlationId: startResult.correlationId,
|
||||
continuationToken: startResult.continuationToken,
|
||||
logger: this.logger,
|
||||
config: this.customAuthConfig,
|
||||
signInClient: this.signInClient,
|
||||
signUpClient: this.signUpClient,
|
||||
cacheClient: this.cacheClient,
|
||||
jitClient: this.jitClient,
|
||||
mfaClient: this.mfaClient,
|
||||
username: signUpInputs.username,
|
||||
codeLength: startResult.codeLength,
|
||||
codeResendInterval: startResult.interval,
|
||||
})
|
||||
);
|
||||
} else if (
|
||||
startResult.type === SIGN_UP_PASSWORD_REQUIRED_RESULT_TYPE
|
||||
) {
|
||||
// Password required
|
||||
this.logger.verbose(
|
||||
"Password required for sign-up.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
return new SignUpResult(
|
||||
new SignUpPasswordRequiredState({
|
||||
correlationId: startResult.correlationId,
|
||||
continuationToken: startResult.continuationToken,
|
||||
logger: this.logger,
|
||||
config: this.customAuthConfig,
|
||||
signInClient: this.signInClient,
|
||||
signUpClient: this.signUpClient,
|
||||
cacheClient: this.cacheClient,
|
||||
jitClient: this.jitClient,
|
||||
mfaClient: this.mfaClient,
|
||||
username: signUpInputs.username,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.error(
|
||||
"Unexpected sign-up result type. Returning error.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
throw new UnexpectedError(
|
||||
"Unknown sign-up result type",
|
||||
correlationId
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.errorPii(
|
||||
`An error occurred during starting sign-up: '${error}'`,
|
||||
correlationId
|
||||
);
|
||||
|
||||
return SignUpResult.createWithError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Resets the user's password.
|
||||
* @param resetPasswordInputs - Inputs for resetting the user's password.
|
||||
* @returns {Promise<ResetPasswordStartResult>} The result of the operation.
|
||||
*/
|
||||
async resetPassword(
|
||||
resetPasswordInputs: ResetPasswordInputs
|
||||
): Promise<ResetPasswordStartResult> {
|
||||
const correlationId = this.getCorrelationId(resetPasswordInputs);
|
||||
|
||||
try {
|
||||
ArgumentValidator.ensureArgumentIsNotNullOrUndefined(
|
||||
"resetPasswordInputs",
|
||||
resetPasswordInputs,
|
||||
correlationId
|
||||
);
|
||||
|
||||
ArgumentValidator.ensureArgumentIsNotEmptyString(
|
||||
"resetPasswordInputs.username",
|
||||
resetPasswordInputs.username,
|
||||
correlationId
|
||||
);
|
||||
this.ensureUserNotSignedIn(correlationId);
|
||||
|
||||
this.logger.verbose("Starting password-reset flow.", correlationId);
|
||||
|
||||
const startResult = await this.resetPasswordClient.start({
|
||||
clientId: this.customAuthConfig.auth.clientId,
|
||||
correlationId: correlationId,
|
||||
challengeType:
|
||||
this.customAuthConfig.customAuth.challengeTypes ?? [],
|
||||
username: resetPasswordInputs.username,
|
||||
});
|
||||
|
||||
this.logger.verbose("Password-reset flow started.", correlationId);
|
||||
|
||||
return new ResetPasswordStartResult(
|
||||
new ResetPasswordCodeRequiredState({
|
||||
correlationId: startResult.correlationId,
|
||||
continuationToken: startResult.continuationToken,
|
||||
logger: this.logger,
|
||||
config: this.customAuthConfig,
|
||||
signInClient: this.signInClient,
|
||||
resetPasswordClient: this.resetPasswordClient,
|
||||
cacheClient: this.cacheClient,
|
||||
jitClient: this.jitClient,
|
||||
mfaClient: this.mfaClient,
|
||||
username: resetPasswordInputs.username,
|
||||
codeLength: startResult.codeLength,
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.errorPii(
|
||||
`An error occurred during starting reset-password: '${error}'`,
|
||||
correlationId
|
||||
);
|
||||
|
||||
return ResetPasswordStartResult.createWithError(error);
|
||||
}
|
||||
}
|
||||
|
||||
private getCorrelationId(
|
||||
actionInputs: CustomAuthActionInputs | undefined
|
||||
): string {
|
||||
return (
|
||||
actionInputs?.correlationId || this.browserCrypto.createNewGuid()
|
||||
);
|
||||
}
|
||||
|
||||
private ensureUserNotSignedIn(correlationId: string): void {
|
||||
const account = this.getCurrentAccount({
|
||||
correlationId: correlationId,
|
||||
});
|
||||
|
||||
if (account && !!account.data) {
|
||||
this.logger.error("User has already signed in.", correlationId);
|
||||
|
||||
throw new UserAlreadySignedInError(correlationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
backend/node_modules/@azure/msal-browser/src/custom_auth/controller/ICustomAuthStandardController.ts
generated
vendored
Normal file
53
backend/node_modules/@azure/msal-browser/src/custom_auth/controller/ICustomAuthStandardController.ts
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { GetAccountResult } from "../get_account/auth_flow/result/GetAccountResult.js";
|
||||
import { SignInResult } from "../sign_in/auth_flow/result/SignInResult.js";
|
||||
import { SignUpResult } from "../sign_up/auth_flow/result/SignUpResult.js";
|
||||
import {
|
||||
AccountRetrievalInputs,
|
||||
ResetPasswordInputs,
|
||||
SignInInputs,
|
||||
SignUpInputs,
|
||||
} from "../CustomAuthActionInputs.js";
|
||||
import { ResetPasswordStartResult } from "../reset_password/auth_flow/result/ResetPasswordStartResult.js";
|
||||
import { IController } from "../../controllers/IController.js";
|
||||
|
||||
/*
|
||||
* Controller interface for standard authentication operations.
|
||||
*/
|
||||
export interface ICustomAuthStandardController extends IController {
|
||||
/*
|
||||
* Gets the current account from the cache.
|
||||
* @param accountRetrievalInputs - Inputs for getting the current cached account
|
||||
* @returns - The result of the operation
|
||||
*/
|
||||
getCurrentAccount(
|
||||
accountRetrievalInputs?: AccountRetrievalInputs
|
||||
): GetAccountResult;
|
||||
|
||||
/*
|
||||
* Signs the current user out.
|
||||
* @param signInInputs - Inputs for signing in.
|
||||
* @returns The result of the operation.
|
||||
*/
|
||||
signIn(signInInputs: SignInInputs): Promise<SignInResult>;
|
||||
|
||||
/*
|
||||
* Signs the current user up.
|
||||
* @param signUpInputs - Inputs for signing up.
|
||||
* @returns The result of the operation.
|
||||
*/
|
||||
signUp(signUpInputs: SignUpInputs): Promise<SignUpResult>;
|
||||
|
||||
/*
|
||||
* Resets the password for the current user.
|
||||
* @param resetPasswordInputs - Inputs for resetting the password.
|
||||
* @returns The result of the operation.
|
||||
*/
|
||||
resetPassword(
|
||||
resetPasswordInputs: ResetPasswordInputs
|
||||
): Promise<ResetPasswordStartResult>;
|
||||
}
|
||||
119
backend/node_modules/@azure/msal-browser/src/custom_auth/core/CustomAuthAuthority.ts
generated
vendored
Normal file
119
backend/node_modules/@azure/msal-browser/src/custom_auth/core/CustomAuthAuthority.ts
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Authority,
|
||||
AuthorityOptions,
|
||||
INetworkModule,
|
||||
IPerformanceClient,
|
||||
Logger,
|
||||
} from "@azure/msal-common/browser";
|
||||
import * as CustomAuthApiEndpoint from "./network_client/custom_auth_api/CustomAuthApiEndpoint.js";
|
||||
import { buildUrl } from "./utils/UrlUtils.js";
|
||||
import { BrowserConfiguration } from "../../config/Configuration.js";
|
||||
import { BrowserCacheManager } from "../../cache/BrowserCacheManager.js";
|
||||
|
||||
/**
|
||||
* Authority class which can be used to create an authority object for Custom Auth features.
|
||||
*/
|
||||
export class CustomAuthAuthority extends Authority {
|
||||
/**
|
||||
* Constructor for the Custom Auth Authority.
|
||||
* @param authority - The authority URL for the authority.
|
||||
* @param networkInterface - The network interface implementation to make requests.
|
||||
* @param cacheManager - The cache manager.
|
||||
* @param authorityOptions - The options for the authority.
|
||||
* @param logger - The logger for the authority.
|
||||
* @param customAuthProxyDomain - The custom auth proxy domain.
|
||||
*/
|
||||
constructor(
|
||||
authority: string,
|
||||
config: BrowserConfiguration,
|
||||
networkInterface: INetworkModule,
|
||||
cacheManager: BrowserCacheManager,
|
||||
logger: Logger,
|
||||
performanceClient: IPerformanceClient,
|
||||
private customAuthProxyDomain?: string
|
||||
) {
|
||||
const ciamAuthorityUrl =
|
||||
CustomAuthAuthority.transformCIAMAuthority(authority);
|
||||
|
||||
const authorityOptions: AuthorityOptions = {
|
||||
protocolMode: config.system.protocolMode,
|
||||
OIDCOptions: config.auth.OIDCOptions,
|
||||
knownAuthorities: config.auth.knownAuthorities,
|
||||
cloudDiscoveryMetadata: config.auth.cloudDiscoveryMetadata,
|
||||
authorityMetadata: config.auth.authorityMetadata,
|
||||
};
|
||||
|
||||
super(
|
||||
ciamAuthorityUrl,
|
||||
networkInterface,
|
||||
cacheManager,
|
||||
authorityOptions,
|
||||
logger,
|
||||
"",
|
||||
performanceClient
|
||||
);
|
||||
|
||||
// Set the metadata for the authority
|
||||
const metadataEntity = {
|
||||
aliases: [this.hostnameAndPort],
|
||||
preferred_cache: this.getPreferredCache(),
|
||||
preferred_network: this.hostnameAndPort,
|
||||
canonical_authority: this.canonicalAuthority,
|
||||
authorization_endpoint: "",
|
||||
token_endpoint: this.tokenEndpoint,
|
||||
end_session_endpoint: "",
|
||||
issuer: "",
|
||||
aliasesFromNetwork: false,
|
||||
endpointsFromNetwork: false,
|
||||
/*
|
||||
* give max value to make sure it doesn't expire,
|
||||
* as we only initiate the authority metadata entity once and it doesn't change
|
||||
*/
|
||||
expiresAt: Number.MAX_SAFE_INTEGER,
|
||||
jwks_uri: "",
|
||||
};
|
||||
const cacheKey = this.cacheManager.generateAuthorityMetadataCacheKey(
|
||||
metadataEntity.preferred_cache,
|
||||
this.correlationId
|
||||
);
|
||||
cacheManager.setAuthorityMetadata(
|
||||
cacheKey,
|
||||
metadataEntity,
|
||||
this.correlationId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the custom auth endpoint.
|
||||
* The open id configuration doesn't have the correct endpoint for the auth APIs.
|
||||
* We need to generate the endpoint manually based on the authority URL.
|
||||
* @returns The custom auth endpoint
|
||||
*/
|
||||
getCustomAuthApiDomain(): string {
|
||||
/*
|
||||
* The customAuthProxyDomain is used to resolve the CORS issue when calling the auth APIs.
|
||||
* If the customAuthProxyDomain is not provided, we will generate the auth API domain based on the authority URL.
|
||||
*/
|
||||
return !this.customAuthProxyDomain
|
||||
? this.canonicalAuthority
|
||||
: this.customAuthProxyDomain;
|
||||
}
|
||||
|
||||
override getPreferredCache(): string {
|
||||
return this.canonicalAuthorityUrlComponents.HostNameAndPort;
|
||||
}
|
||||
|
||||
override get tokenEndpoint(): string {
|
||||
const endpointUrl = buildUrl(
|
||||
this.getCustomAuthApiDomain(),
|
||||
CustomAuthApiEndpoint.SIGNIN_TOKEN
|
||||
);
|
||||
|
||||
return endpointUrl.href;
|
||||
}
|
||||
}
|
||||
179
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/AuthFlowErrorBase.ts
generated
vendored
Normal file
179
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/AuthFlowErrorBase.ts
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
CustomAuthApiError,
|
||||
RedirectError,
|
||||
} from "../error/CustomAuthApiError.js";
|
||||
import { CustomAuthError } from "../error/CustomAuthError.js";
|
||||
import { NoCachedAccountFoundError } from "../error/NoCachedAccountFoundError.js";
|
||||
import { InvalidArgumentError } from "../error/InvalidArgumentError.js";
|
||||
import * as CustomAuthApiErrorCode from "../network_client/custom_auth_api/types/ApiErrorCodes.js";
|
||||
import * as CustomAuthApiSuberror from "../network_client/custom_auth_api/types/ApiSuberrors.js";
|
||||
/**
|
||||
* Base class for all auth flow errors.
|
||||
*/
|
||||
export abstract class AuthFlowErrorBase {
|
||||
constructor(public errorData: CustomAuthError) {}
|
||||
|
||||
protected isUserNotFoundError(): boolean {
|
||||
return this.errorData.error === CustomAuthApiErrorCode.USER_NOT_FOUND;
|
||||
}
|
||||
|
||||
protected isUserInvalidError(): boolean {
|
||||
return (
|
||||
(this.errorData instanceof InvalidArgumentError &&
|
||||
this.errorData.errorDescription?.includes("username")) ||
|
||||
(this.errorData instanceof CustomAuthApiError &&
|
||||
!!this.errorData.errorDescription?.includes(
|
||||
"username parameter is empty or not valid"
|
||||
) &&
|
||||
!!this.errorData.errorCodes?.includes(90100))
|
||||
);
|
||||
}
|
||||
|
||||
protected isUnsupportedChallengeTypeError(): boolean {
|
||||
return (
|
||||
(this.errorData.error === CustomAuthApiErrorCode.INVALID_REQUEST &&
|
||||
(this.errorData.errorDescription?.includes(
|
||||
"The challenge_type list parameter contains an unsupported challenge type"
|
||||
) ??
|
||||
false)) ||
|
||||
this.errorData.error ===
|
||||
CustomAuthApiErrorCode.UNSUPPORTED_CHALLENGE_TYPE
|
||||
);
|
||||
}
|
||||
|
||||
protected isPasswordIncorrectError(): boolean {
|
||||
const isIncorrectPassword =
|
||||
this.errorData.error === CustomAuthApiErrorCode.INVALID_GRANT &&
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
(this.errorData.errorCodes ?? []).includes(50126);
|
||||
|
||||
const isPasswordEmpty =
|
||||
this.errorData instanceof InvalidArgumentError &&
|
||||
this.errorData.errorDescription?.includes("password") === true;
|
||||
|
||||
return isIncorrectPassword || isPasswordEmpty;
|
||||
}
|
||||
|
||||
protected isInvalidCodeError(): boolean {
|
||||
return (
|
||||
(this.errorData.error === CustomAuthApiErrorCode.INVALID_GRANT &&
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.subError ===
|
||||
CustomAuthApiSuberror.INVALID_OOB_VALUE) ||
|
||||
(this.errorData instanceof InvalidArgumentError &&
|
||||
(this.errorData.errorDescription?.includes("code") ||
|
||||
this.errorData.errorDescription?.includes("challenge")) ===
|
||||
true)
|
||||
);
|
||||
}
|
||||
|
||||
protected isRedirectError(): boolean {
|
||||
return this.errorData instanceof RedirectError;
|
||||
}
|
||||
|
||||
protected isInvalidNewPasswordError(): boolean {
|
||||
const invalidPasswordSubErrors = new Set<string>([
|
||||
CustomAuthApiSuberror.PASSWORD_BANNED,
|
||||
CustomAuthApiSuberror.PASSWORD_IS_INVALID,
|
||||
CustomAuthApiSuberror.PASSWORD_RECENTLY_USED,
|
||||
CustomAuthApiSuberror.PASSWORD_TOO_LONG,
|
||||
CustomAuthApiSuberror.PASSWORD_TOO_SHORT,
|
||||
CustomAuthApiSuberror.PASSWORD_TOO_WEAK,
|
||||
]);
|
||||
|
||||
return (
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.error === CustomAuthApiErrorCode.INVALID_GRANT &&
|
||||
invalidPasswordSubErrors.has(this.errorData.subError ?? "")
|
||||
);
|
||||
}
|
||||
|
||||
protected isUserAlreadyExistsError(): boolean {
|
||||
return (
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.error === CustomAuthApiErrorCode.USER_ALREADY_EXISTS
|
||||
);
|
||||
}
|
||||
|
||||
protected isAttributeRequiredError(): boolean {
|
||||
return (
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.error === CustomAuthApiErrorCode.ATTRIBUTES_REQUIRED
|
||||
);
|
||||
}
|
||||
|
||||
protected isAttributeValidationFailedError(): boolean {
|
||||
return (
|
||||
(this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.error === CustomAuthApiErrorCode.INVALID_GRANT &&
|
||||
this.errorData.subError ===
|
||||
CustomAuthApiSuberror.ATTRIBUTE_VALIATION_FAILED) ||
|
||||
(this.errorData instanceof InvalidArgumentError &&
|
||||
this.errorData.errorDescription?.includes("attributes") ===
|
||||
true)
|
||||
);
|
||||
}
|
||||
|
||||
protected isNoCachedAccountFoundError(): boolean {
|
||||
return this.errorData instanceof NoCachedAccountFoundError;
|
||||
}
|
||||
|
||||
protected isTokenExpiredError(): boolean {
|
||||
return (
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.error === CustomAuthApiErrorCode.EXPIRED_TOKEN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo verify the password change required error can be detected once the MFA is in place.
|
||||
* This error will be raised during signin and refresh tokens when calling /token endpoint.
|
||||
*/
|
||||
protected isPasswordResetRequiredError(): boolean {
|
||||
return (
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.error === CustomAuthApiErrorCode.INVALID_REQUEST &&
|
||||
this.errorData.errorCodes?.includes(50142) === true
|
||||
);
|
||||
}
|
||||
|
||||
protected isInvalidInputError(): boolean {
|
||||
return (
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.error === CustomAuthApiErrorCode.INVALID_REQUEST &&
|
||||
this.errorData.errorCodes?.includes(901001) === true
|
||||
);
|
||||
}
|
||||
|
||||
protected isVerificationContactBlockedError(): boolean {
|
||||
return (
|
||||
this.errorData instanceof CustomAuthApiError &&
|
||||
this.errorData.error === CustomAuthApiErrorCode.ACCESS_DENIED &&
|
||||
this.errorData.subError ===
|
||||
CustomAuthApiSuberror.PROVIDER_BLOCKED_BY_REPUTATION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AuthActionErrorBase extends AuthFlowErrorBase {
|
||||
/**
|
||||
* Checks if the error is due to the expired continuation token.
|
||||
* @returns {boolean} True if the error is due to the expired continuation token, false otherwise.
|
||||
*/
|
||||
isTokenExpired(): boolean {
|
||||
return this.isTokenExpiredError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if client app supports the challenge type configured in Entra.
|
||||
* @returns {boolean} True if client app doesn't support the challenge type configured in Entra, "loginPopup" function is required to continue the operation.
|
||||
*/
|
||||
isRedirectRequired(): boolean {
|
||||
return this.isRedirectError();
|
||||
}
|
||||
}
|
||||
69
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/AuthFlowResultBase.ts
generated
vendored
Normal file
69
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/AuthFlowResultBase.ts
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthError } from "@azure/msal-common/browser";
|
||||
import { CustomAuthError } from "../error/CustomAuthError.js";
|
||||
import { MsalCustomAuthError } from "../error/MsalCustomAuthError.js";
|
||||
import { UnexpectedError } from "../error/UnexpectedError.js";
|
||||
import { AuthFlowErrorBase } from "./AuthFlowErrorBase.js";
|
||||
import { AuthFlowStateBase } from "./AuthFlowState.js";
|
||||
|
||||
/*
|
||||
* Base class for a result of an authentication operation.
|
||||
* @typeParam TState - The type of the auth flow state.
|
||||
* @typeParam TError - The type of error.
|
||||
* @typeParam TData - The type of the result data.
|
||||
*/
|
||||
export abstract class AuthFlowResultBase<
|
||||
TState extends AuthFlowStateBase,
|
||||
TError extends AuthFlowErrorBase,
|
||||
TData = void
|
||||
> {
|
||||
/*
|
||||
*constructor for ResultBase
|
||||
* @param state - The state.
|
||||
* @param data - The result data.
|
||||
*/
|
||||
constructor(public state: TState, public data?: TData) {}
|
||||
|
||||
/*
|
||||
* The error that occurred during the authentication operation.
|
||||
*/
|
||||
error?: TError;
|
||||
|
||||
/*
|
||||
* Creates a CustomAuthError with an error.
|
||||
* @param error - The error that occurred.
|
||||
* @returns The auth error.
|
||||
*/
|
||||
protected static createErrorData(error: unknown): CustomAuthError {
|
||||
if (error instanceof CustomAuthError) {
|
||||
return error;
|
||||
} else if (error instanceof AuthError) {
|
||||
const errorCodes: Array<number> = [];
|
||||
|
||||
if ("errorNo" in error) {
|
||||
if (typeof error.errorNo === "string") {
|
||||
const code = Number(error.errorNo);
|
||||
if (!isNaN(code)) {
|
||||
errorCodes.push(code);
|
||||
}
|
||||
} else if (typeof error.errorNo === "number") {
|
||||
errorCodes.push(error.errorNo);
|
||||
}
|
||||
}
|
||||
|
||||
return new MsalCustomAuthError(
|
||||
error.errorCode,
|
||||
error.errorMessage,
|
||||
error.subError,
|
||||
errorCodes,
|
||||
error.correlationId
|
||||
);
|
||||
} else {
|
||||
return new UnexpectedError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/AuthFlowState.ts
generated
vendored
Normal file
78
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/AuthFlowState.ts
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { InvalidArgumentError } from "../error/InvalidArgumentError.js";
|
||||
import { CustomAuthBrowserConfiguration } from "../../configuration/CustomAuthConfiguration.js";
|
||||
import { Logger } from "@azure/msal-common/browser";
|
||||
import { ensureArgumentIsNotEmptyString } from "../utils/ArgumentValidator.js";
|
||||
import { DefaultCustomAuthApiCodeLength } from "../../CustomAuthConstants.js";
|
||||
|
||||
export interface AuthFlowActionRequiredStateParameters {
|
||||
correlationId: string;
|
||||
logger: Logger;
|
||||
config: CustomAuthBrowserConfiguration;
|
||||
continuationToken?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for the state of an authentication flow.
|
||||
*/
|
||||
export abstract class AuthFlowStateBase {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
abstract stateType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for the action requried state in an authentication flow.
|
||||
*/
|
||||
export abstract class AuthFlowActionRequiredStateBase<
|
||||
TParameter extends AuthFlowActionRequiredStateParameters
|
||||
> extends AuthFlowStateBase {
|
||||
/**
|
||||
* Creates a new instance of AuthFlowActionRequiredStateBase.
|
||||
* @param stateParameters The parameters for the auth state.
|
||||
*/
|
||||
constructor(protected readonly stateParameters: TParameter) {
|
||||
ensureArgumentIsNotEmptyString(
|
||||
"correlationId",
|
||||
stateParameters.correlationId
|
||||
);
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
protected ensureCodeIsValid(code: string, codeLength: number): void {
|
||||
if (
|
||||
codeLength !== DefaultCustomAuthApiCodeLength &&
|
||||
(!code || code.length !== codeLength)
|
||||
) {
|
||||
this.stateParameters.logger.error(
|
||||
"Code parameter is not provided or invalid for authentication flow.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
throw new InvalidArgumentError(
|
||||
"code",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected ensurePasswordIsNotEmpty(password: string): void {
|
||||
if (!password) {
|
||||
this.stateParameters.logger.error(
|
||||
"Password parameter is not provided for authentication flow.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
throw new InvalidArgumentError(
|
||||
"password",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/AuthFlowStateTypes.ts
generated
vendored
Normal file
60
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/AuthFlowStateTypes.ts
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
// Sign in state types
|
||||
export const SIGN_IN_CODE_REQUIRED_STATE_TYPE = "SignInCodeRequiredState";
|
||||
export const SIGN_IN_PASSWORD_REQUIRED_STATE_TYPE =
|
||||
"SignInPasswordRequiredState";
|
||||
export const SIGN_IN_CONTINUATION_STATE_TYPE = "SignInContinuationState";
|
||||
export const SIGN_IN_COMPLETED_STATE_TYPE = "SignInCompletedState";
|
||||
export const SIGN_IN_FAILED_STATE_TYPE = "SignInFailedState";
|
||||
|
||||
// Sign up state types
|
||||
export const SIGN_UP_CODE_REQUIRED_STATE_TYPE = "SignUpCodeRequiredState";
|
||||
export const SIGN_UP_PASSWORD_REQUIRED_STATE_TYPE =
|
||||
"SignUpPasswordRequiredState";
|
||||
export const SIGN_UP_ATTRIBUTES_REQUIRED_STATE_TYPE =
|
||||
"SignUpAttributesRequiredState";
|
||||
export const SIGN_UP_COMPLETED_STATE_TYPE = "SignUpCompletedState";
|
||||
export const SIGN_UP_FAILED_STATE_TYPE = "SignUpFailedState";
|
||||
|
||||
// Reset password state types
|
||||
export const RESET_PASSWORD_CODE_REQUIRED_STATE_TYPE =
|
||||
"ResetPasswordCodeRequiredState";
|
||||
export const RESET_PASSWORD_PASSWORD_REQUIRED_STATE_TYPE =
|
||||
"ResetPasswordPasswordRequiredState";
|
||||
export const RESET_PASSWORD_COMPLETED_STATE_TYPE =
|
||||
"ResetPasswordCompletedState";
|
||||
export const RESET_PASSWORD_FAILED_STATE_TYPE = "ResetPasswordFailedState";
|
||||
|
||||
// Get account state types
|
||||
export const GET_ACCOUNT_COMPLETED_STATE_TYPE = "GetAccountCompletedState";
|
||||
export const GET_ACCOUNT_FAILED_STATE_TYPE = "GetAccountFailedState";
|
||||
|
||||
// Get access token state types
|
||||
export const GET_ACCESS_TOKEN_COMPLETED_STATE_TYPE =
|
||||
"GetAccessTokenCompletedState";
|
||||
export const GET_ACCESS_TOKEN_FAILED_STATE_TYPE = "GetAccessTokenFailedState";
|
||||
|
||||
// Sign out state types
|
||||
export const SIGN_OUT_COMPLETED_STATE_TYPE = "SignOutCompletedState";
|
||||
export const SIGN_OUT_FAILED_STATE_TYPE = "SignOutFailedState";
|
||||
|
||||
// MFA state types
|
||||
export const MFA_AWAITING_STATE_TYPE = "MfaAwaitingState";
|
||||
export const MFA_VERIFICATION_REQUIRED_STATE_TYPE =
|
||||
"MfaVerificationRequiredState";
|
||||
export const MFA_COMPLETED_STATE_TYPE = "MfaCompletedState";
|
||||
export const MFA_FAILED_STATE_TYPE = "MfaFailedState";
|
||||
|
||||
// Auth method registration (JIT) state types
|
||||
export const AUTH_METHOD_REGISTRATION_REQUIRED_STATE_TYPE =
|
||||
"AuthMethodRegistrationRequiredState";
|
||||
export const AUTH_METHOD_VERIFICATION_REQUIRED_STATE_TYPE =
|
||||
"AuthMethodVerificationRequiredState";
|
||||
export const AUTH_METHOD_REGISTRATION_COMPLETED_STATE_TYPE =
|
||||
"AuthMethodRegistrationCompletedState";
|
||||
export const AUTH_METHOD_REGISTRATION_FAILED_STATE_TYPE =
|
||||
"AuthMethodRegistrationFailedState";
|
||||
21
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/AuthMethodDetails.ts
generated
vendored
Normal file
21
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/AuthMethodDetails.ts
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthenticationMethod } from "../../network_client/custom_auth_api/types/ApiResponseTypes.js";
|
||||
|
||||
/**
|
||||
* Details for an authentication method to be registered.
|
||||
*/
|
||||
export interface AuthMethodDetails {
|
||||
/**
|
||||
* The authentication method type to register.
|
||||
*/
|
||||
authMethodType: AuthenticationMethod;
|
||||
|
||||
/**
|
||||
* The verification contact (email, phone number) for the authentication method.
|
||||
*/
|
||||
verificationContact: string;
|
||||
}
|
||||
40
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/error_type/AuthMethodRegistrationError.ts
generated
vendored
Normal file
40
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/error_type/AuthMethodRegistrationError.ts
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthActionErrorBase } from "../../AuthFlowErrorBase.js";
|
||||
|
||||
/**
|
||||
* Error that occurred during authentication method challenge request.
|
||||
*/
|
||||
export class AuthMethodRegistrationChallengeMethodError extends AuthActionErrorBase {
|
||||
/**
|
||||
* Checks if the input for auth method registration is incorrect.
|
||||
* @returns true if the input is incorrect, false otherwise.
|
||||
*/
|
||||
isInvalidInput(): boolean {
|
||||
return this.isInvalidInputError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the error is due to the verification contact (e.g., phone number or email) being blocked. Consider using a different email/phone number or a different authentication method.
|
||||
* @returns true if the error is due to the verification contact being blocked, false otherwise.
|
||||
*/
|
||||
isVerificationContactBlocked(): boolean {
|
||||
return this.isVerificationContactBlockedError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error that occurred during authentication method challenge submission.
|
||||
*/
|
||||
export class AuthMethodRegistrationSubmitChallengeError extends AuthActionErrorBase {
|
||||
/**
|
||||
* Checks if the submitted challenge code is incorrect.
|
||||
* @returns true if the challenge code is incorrect, false otherwise.
|
||||
*/
|
||||
isIncorrectChallenge(): boolean {
|
||||
return this.isInvalidCodeError();
|
||||
}
|
||||
}
|
||||
92
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/result/AuthMethodRegistrationChallengeMethodResult.ts
generated
vendored
Normal file
92
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/result/AuthMethodRegistrationChallengeMethodResult.ts
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowResultBase } from "../../AuthFlowResultBase.js";
|
||||
import { AuthMethodRegistrationChallengeMethodError } from "../error_type/AuthMethodRegistrationError.js";
|
||||
import type { AuthMethodVerificationRequiredState } from "../state/AuthMethodRegistrationState.js";
|
||||
import { CustomAuthAccountData } from "../../../../get_account/auth_flow/CustomAuthAccountData.js";
|
||||
import { AuthMethodRegistrationCompletedState } from "../state/AuthMethodRegistrationCompletedState.js";
|
||||
import { AuthMethodRegistrationFailedState } from "../state/AuthMethodRegistrationFailedState.js";
|
||||
import {
|
||||
AUTH_METHOD_VERIFICATION_REQUIRED_STATE_TYPE,
|
||||
AUTH_METHOD_REGISTRATION_COMPLETED_STATE_TYPE,
|
||||
AUTH_METHOD_REGISTRATION_FAILED_STATE_TYPE,
|
||||
} from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* Result of challenging an authentication method for registration.
|
||||
* Uses base state type to avoid circular dependencies.
|
||||
*/
|
||||
export class AuthMethodRegistrationChallengeMethodResult extends AuthFlowResultBase<
|
||||
AuthMethodRegistrationChallengeMethodResultState,
|
||||
AuthMethodRegistrationChallengeMethodError,
|
||||
CustomAuthAccountData
|
||||
> {
|
||||
/**
|
||||
* Creates an AuthMethodRegistrationChallengeMethodResult with an error.
|
||||
* @param error The error that occurred.
|
||||
* @returns The AuthMethodRegistrationChallengeMethodResult with error.
|
||||
*/
|
||||
static createWithError(
|
||||
error: unknown
|
||||
): AuthMethodRegistrationChallengeMethodResult {
|
||||
const result = new AuthMethodRegistrationChallengeMethodResult(
|
||||
new AuthMethodRegistrationFailedState()
|
||||
);
|
||||
result.error = new AuthMethodRegistrationChallengeMethodError(
|
||||
AuthMethodRegistrationChallengeMethodResult.createErrorData(error)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result indicates that verification is required.
|
||||
* @returns true if verification is required, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isVerificationRequired(): this is AuthMethodRegistrationChallengeMethodResult & {
|
||||
state: AuthMethodVerificationRequiredState;
|
||||
} {
|
||||
return (
|
||||
this.state.stateType ===
|
||||
AUTH_METHOD_VERIFICATION_REQUIRED_STATE_TYPE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result indicates that registration is completed (fast-pass scenario).
|
||||
* @returns true if registration is completed, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isCompleted(): this is AuthMethodRegistrationChallengeMethodResult & {
|
||||
state: AuthMethodRegistrationCompletedState;
|
||||
} {
|
||||
return (
|
||||
this.state.stateType ===
|
||||
AUTH_METHOD_REGISTRATION_COMPLETED_STATE_TYPE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result is in a failed state.
|
||||
* @returns true if the result is failed, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isFailed(): this is AuthMethodRegistrationChallengeMethodResult & {
|
||||
state: AuthMethodRegistrationFailedState;
|
||||
} {
|
||||
return (
|
||||
this.state.stateType === AUTH_METHOD_REGISTRATION_FAILED_STATE_TYPE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type definition for possible states in AuthMethodRegistrationChallengeMethodResult.
|
||||
*/
|
||||
export type AuthMethodRegistrationChallengeMethodResultState =
|
||||
| AuthMethodVerificationRequiredState
|
||||
| AuthMethodRegistrationCompletedState
|
||||
| AuthMethodRegistrationFailedState;
|
||||
74
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/result/AuthMethodRegistrationSubmitChallengeResult.ts
generated
vendored
Normal file
74
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/result/AuthMethodRegistrationSubmitChallengeResult.ts
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowResultBase } from "../../AuthFlowResultBase.js";
|
||||
import { AuthMethodRegistrationSubmitChallengeError } from "../error_type/AuthMethodRegistrationError.js";
|
||||
import { CustomAuthAccountData } from "../../../../get_account/auth_flow/CustomAuthAccountData.js";
|
||||
import { AuthMethodRegistrationFailedState } from "../state/AuthMethodRegistrationFailedState.js";
|
||||
import { AuthMethodRegistrationCompletedState } from "../state/AuthMethodRegistrationCompletedState.js";
|
||||
import {
|
||||
AUTH_METHOD_REGISTRATION_COMPLETED_STATE_TYPE,
|
||||
AUTH_METHOD_REGISTRATION_FAILED_STATE_TYPE,
|
||||
} from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* Result of submitting a challenge for authentication method registration.
|
||||
*/
|
||||
export class AuthMethodRegistrationSubmitChallengeResult extends AuthFlowResultBase<
|
||||
AuthMethodRegistrationSubmitChallengeResultState,
|
||||
AuthMethodRegistrationSubmitChallengeError,
|
||||
CustomAuthAccountData
|
||||
> {
|
||||
/**
|
||||
* Creates an AuthMethodRegistrationSubmitChallengeResult with an error.
|
||||
* @param error The error that occurred.
|
||||
* @returns The AuthMethodRegistrationSubmitChallengeResult with error.
|
||||
*/
|
||||
static createWithError(
|
||||
error: unknown
|
||||
): AuthMethodRegistrationSubmitChallengeResult {
|
||||
const result = new AuthMethodRegistrationSubmitChallengeResult(
|
||||
new AuthMethodRegistrationFailedState()
|
||||
);
|
||||
result.error = new AuthMethodRegistrationSubmitChallengeError(
|
||||
AuthMethodRegistrationSubmitChallengeResult.createErrorData(error)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result indicates that registration is completed.
|
||||
* @returns true if registration is completed, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isCompleted(): this is AuthMethodRegistrationSubmitChallengeResult & {
|
||||
state: AuthMethodRegistrationCompletedState;
|
||||
} {
|
||||
return (
|
||||
this.state.stateType ===
|
||||
AUTH_METHOD_REGISTRATION_COMPLETED_STATE_TYPE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result is in a failed state.
|
||||
* @returns true if the result is failed, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isFailed(): this is AuthMethodRegistrationSubmitChallengeResult & {
|
||||
state: AuthMethodRegistrationFailedState;
|
||||
} {
|
||||
return (
|
||||
this.state.stateType === AUTH_METHOD_REGISTRATION_FAILED_STATE_TYPE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type definition for possible states in AuthMethodRegistrationSubmitChallengeResult.
|
||||
*/
|
||||
export type AuthMethodRegistrationSubmitChallengeResultState =
|
||||
| AuthMethodRegistrationCompletedState
|
||||
| AuthMethodRegistrationFailedState;
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/state/AuthMethodRegistrationCompletedState.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/state/AuthMethodRegistrationCompletedState.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowStateBase } from "../../AuthFlowState.js";
|
||||
import { AUTH_METHOD_REGISTRATION_COMPLETED_STATE_TYPE } from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* State indicating that the auth method registration flow has completed successfully.
|
||||
*/
|
||||
export class AuthMethodRegistrationCompletedState extends AuthFlowStateBase {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
stateType = AUTH_METHOD_REGISTRATION_COMPLETED_STATE_TYPE;
|
||||
}
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/state/AuthMethodRegistrationFailedState.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/state/AuthMethodRegistrationFailedState.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowStateBase } from "../../AuthFlowState.js";
|
||||
import { AUTH_METHOD_REGISTRATION_FAILED_STATE_TYPE } from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* State indicating that the auth method registration flow has failed.
|
||||
*/
|
||||
export class AuthMethodRegistrationFailedState extends AuthFlowStateBase {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
stateType = AUTH_METHOD_REGISTRATION_FAILED_STATE_TYPE;
|
||||
}
|
||||
274
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/state/AuthMethodRegistrationState.ts
generated
vendored
Normal file
274
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/state/AuthMethodRegistrationState.ts
generated
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AuthMethodRegistrationStateParameters,
|
||||
AuthMethodRegistrationRequiredStateParameters,
|
||||
AuthMethodVerificationRequiredStateParameters,
|
||||
} from "./AuthMethodRegistrationStateParameters.js";
|
||||
import { AuthMethodDetails } from "../AuthMethodDetails.js";
|
||||
import {
|
||||
JitChallengeAuthMethodParams,
|
||||
JitSubmitChallengeParams,
|
||||
} from "../../../interaction_client/jit/parameter/JitParams.js";
|
||||
import { CustomAuthAccountData } from "../../../../get_account/auth_flow/CustomAuthAccountData.js";
|
||||
import {
|
||||
JIT_VERIFICATION_REQUIRED_RESULT_TYPE,
|
||||
JIT_COMPLETED_RESULT_TYPE,
|
||||
} from "../../../interaction_client/jit/result/JitActionResult.js";
|
||||
import { UnexpectedError } from "../../../error/UnexpectedError.js";
|
||||
import { AuthenticationMethod } from "../../../network_client/custom_auth_api/types/ApiResponseTypes.js";
|
||||
import { AuthFlowActionRequiredStateBase } from "../../AuthFlowState.js";
|
||||
import { GrantType } from "../../../../CustomAuthConstants.js";
|
||||
import { AuthMethodRegistrationChallengeMethodResult } from "../result/AuthMethodRegistrationChallengeMethodResult.js";
|
||||
import { AuthMethodRegistrationSubmitChallengeResult } from "../result/AuthMethodRegistrationSubmitChallengeResult.js";
|
||||
import { AuthMethodRegistrationCompletedState } from "./AuthMethodRegistrationCompletedState.js";
|
||||
import {
|
||||
AUTH_METHOD_REGISTRATION_REQUIRED_STATE_TYPE,
|
||||
AUTH_METHOD_VERIFICATION_REQUIRED_STATE_TYPE,
|
||||
} from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* Abstract base class for authentication method registration states.
|
||||
*/
|
||||
abstract class AuthMethodRegistrationState<
|
||||
TParameters extends AuthMethodRegistrationStateParameters
|
||||
> extends AuthFlowActionRequiredStateBase<TParameters> {
|
||||
/**
|
||||
* Internal method to challenge an authentication method.
|
||||
* @param authMethodDetails The authentication method details to challenge.
|
||||
* @returns Promise that resolves to AuthMethodRegistrationChallengeMethodResult.
|
||||
*/
|
||||
protected async challengeAuthMethodInternal(
|
||||
authMethodDetails: AuthMethodDetails
|
||||
): Promise<AuthMethodRegistrationChallengeMethodResult> {
|
||||
try {
|
||||
this.stateParameters.logger.verbose(
|
||||
`Challenging authentication method - '${authMethodDetails.authMethodType.id}' for auth method registration.`,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
const challengeParams: JitChallengeAuthMethodParams = {
|
||||
correlationId: this.stateParameters.correlationId,
|
||||
continuationToken: this.stateParameters.continuationToken ?? "",
|
||||
authMethod: authMethodDetails.authMethodType,
|
||||
verificationContact: authMethodDetails.verificationContact,
|
||||
scopes: this.stateParameters.scopes ?? [],
|
||||
username: this.stateParameters.username,
|
||||
claims: this.stateParameters.claims,
|
||||
};
|
||||
|
||||
const result =
|
||||
await this.stateParameters.jitClient.challengeAuthMethod(
|
||||
challengeParams
|
||||
);
|
||||
|
||||
this.stateParameters.logger.verbose(
|
||||
"Authentication method challenged successfully for auth method registration.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
if (result.type === JIT_VERIFICATION_REQUIRED_RESULT_TYPE) {
|
||||
// Verification required
|
||||
this.stateParameters.logger.verbose(
|
||||
"Auth method verification required.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
return new AuthMethodRegistrationChallengeMethodResult(
|
||||
new AuthMethodVerificationRequiredState({
|
||||
correlationId: result.correlationId,
|
||||
continuationToken: result.continuationToken,
|
||||
config: this.stateParameters.config,
|
||||
logger: this.stateParameters.logger,
|
||||
jitClient: this.stateParameters.jitClient,
|
||||
cacheClient: this.stateParameters.cacheClient,
|
||||
challengeChannel: result.challengeChannel,
|
||||
challengeTargetLabel: result.challengeTargetLabel,
|
||||
codeLength: result.codeLength,
|
||||
scopes: this.stateParameters.scopes ?? [],
|
||||
username: this.stateParameters.username,
|
||||
claims: this.stateParameters.claims,
|
||||
})
|
||||
);
|
||||
} else if (result.type === JIT_COMPLETED_RESULT_TYPE) {
|
||||
// Registration completed (fast-pass scenario)
|
||||
this.stateParameters.logger.verbose(
|
||||
"Auth method registration completed via fast-pass.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
const accountInfo = new CustomAuthAccountData(
|
||||
result.authenticationResult.account,
|
||||
this.stateParameters.config,
|
||||
this.stateParameters.cacheClient,
|
||||
this.stateParameters.logger,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
return new AuthMethodRegistrationChallengeMethodResult(
|
||||
new AuthMethodRegistrationCompletedState(),
|
||||
accountInfo
|
||||
);
|
||||
} else {
|
||||
// Handle unexpected result type with proper typing
|
||||
this.stateParameters.logger.error(
|
||||
"Unexpected result type from auth challenge method",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
throw new UnexpectedError(
|
||||
"Unexpected result type from auth challenge method"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.stateParameters.logger.errorPii(
|
||||
`Failed to challenge authentication method for auth method registration. Error: '${error}'.`,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
return AuthMethodRegistrationChallengeMethodResult.createWithError(
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State indicating that authentication method registration is required.
|
||||
*/
|
||||
export class AuthMethodRegistrationRequiredState extends AuthMethodRegistrationState<AuthMethodRegistrationRequiredStateParameters> {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
stateType = AUTH_METHOD_REGISTRATION_REQUIRED_STATE_TYPE;
|
||||
|
||||
/**
|
||||
* Gets the available authentication methods for registration.
|
||||
* @returns Array of available authentication methods.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
getAuthMethods(): AuthenticationMethod[] {
|
||||
return this.stateParameters.authMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Challenges an authentication method for registration.
|
||||
* @param authMethodDetails The authentication method details to challenge.
|
||||
* @returns Promise that resolves to AuthMethodRegistrationChallengeMethodResult.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
async challengeAuthMethod(
|
||||
authMethodDetails: AuthMethodDetails
|
||||
): Promise<AuthMethodRegistrationChallengeMethodResult> {
|
||||
return this.challengeAuthMethodInternal(authMethodDetails);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State indicating that verification is required for the challenged authentication method.
|
||||
*/
|
||||
export class AuthMethodVerificationRequiredState extends AuthMethodRegistrationState<AuthMethodVerificationRequiredStateParameters> {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
stateType = AUTH_METHOD_VERIFICATION_REQUIRED_STATE_TYPE;
|
||||
|
||||
/**
|
||||
* Gets the length of the expected verification code.
|
||||
* @returns The code length.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
getCodeLength(): number {
|
||||
return this.stateParameters.codeLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the channel through which the challenge was sent.
|
||||
* @returns The challenge channel (e.g., "email").
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
getChannel(): string {
|
||||
return this.stateParameters.challengeChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target label indicating where the challenge was sent.
|
||||
* @returns The challenge target label (e.g., masked email address).
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
getSentTo(): string {
|
||||
return this.stateParameters.challengeTargetLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the verification challenge to complete the authentication method registration.
|
||||
* @param code The verification code entered by the user.
|
||||
* @returns Promise that resolves to AuthMethodRegistrationSubmitChallengeResult.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
async submitChallenge(
|
||||
code: string
|
||||
): Promise<AuthMethodRegistrationSubmitChallengeResult> {
|
||||
try {
|
||||
this.ensureCodeIsValid(code, this.getCodeLength());
|
||||
|
||||
this.stateParameters.logger.verbose(
|
||||
"Submitting auth method challenge.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
const submitParams: JitSubmitChallengeParams = {
|
||||
correlationId: this.stateParameters.correlationId,
|
||||
continuationToken: this.stateParameters.continuationToken ?? "",
|
||||
scopes: this.stateParameters.scopes ?? [],
|
||||
grantType: GrantType.OOB,
|
||||
challenge: code,
|
||||
username: this.stateParameters.username,
|
||||
claims: this.stateParameters.claims,
|
||||
};
|
||||
|
||||
const result = await this.stateParameters.jitClient.submitChallenge(
|
||||
submitParams
|
||||
);
|
||||
|
||||
this.stateParameters.logger.verbose(
|
||||
"Auth method challenge submitted successfully.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
const accountInfo = new CustomAuthAccountData(
|
||||
result.authenticationResult.account,
|
||||
this.stateParameters.config,
|
||||
this.stateParameters.cacheClient,
|
||||
this.stateParameters.logger,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
return new AuthMethodRegistrationSubmitChallengeResult(
|
||||
new AuthMethodRegistrationCompletedState(),
|
||||
accountInfo
|
||||
);
|
||||
} catch (error) {
|
||||
this.stateParameters.logger.errorPii(
|
||||
`Failed to submit auth method challenge. Error: '${error}'.`,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
return AuthMethodRegistrationSubmitChallengeResult.createWithError(
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Challenges a different authentication method for registration.
|
||||
* @param authMethodDetails The authentication method details to challenge.
|
||||
* @returns Promise that resolves to AuthMethodRegistrationChallengeMethodResult.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
async challengeAuthMethod(
|
||||
authMethodDetails: AuthMethodDetails
|
||||
): Promise<AuthMethodRegistrationChallengeMethodResult> {
|
||||
return this.challengeAuthMethodInternal(authMethodDetails);
|
||||
}
|
||||
}
|
||||
30
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/state/AuthMethodRegistrationStateParameters.ts
generated
vendored
Normal file
30
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/jit/state/AuthMethodRegistrationStateParameters.ts
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowActionRequiredStateParameters } from "../../AuthFlowState.js";
|
||||
import { JitClient } from "../../../interaction_client/jit/JitClient.js";
|
||||
import { AuthenticationMethod } from "../../../network_client/custom_auth_api/types/ApiResponseTypes.js";
|
||||
import { CustomAuthSilentCacheClient } from "../../../../get_account/interaction_client/CustomAuthSilentCacheClient.js";
|
||||
|
||||
export interface AuthMethodRegistrationStateParameters
|
||||
extends AuthFlowActionRequiredStateParameters {
|
||||
jitClient: JitClient;
|
||||
cacheClient: CustomAuthSilentCacheClient;
|
||||
scopes?: string[];
|
||||
username?: string;
|
||||
claims?: string;
|
||||
}
|
||||
|
||||
export interface AuthMethodRegistrationRequiredStateParameters
|
||||
extends AuthMethodRegistrationStateParameters {
|
||||
authMethods: AuthenticationMethod[];
|
||||
}
|
||||
|
||||
export interface AuthMethodVerificationRequiredStateParameters
|
||||
extends AuthMethodRegistrationStateParameters {
|
||||
challengeChannel: string;
|
||||
challengeTargetLabel: string;
|
||||
codeLength: number;
|
||||
}
|
||||
40
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/error_type/MfaError.ts
generated
vendored
Normal file
40
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/error_type/MfaError.ts
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthActionErrorBase } from "../../AuthFlowErrorBase.js";
|
||||
|
||||
/**
|
||||
* Error that occurred during MFA challenge request.
|
||||
*/
|
||||
export class MfaRequestChallengeError extends AuthActionErrorBase {
|
||||
/**
|
||||
* Checks if the input for MFA challenge is incorrect.
|
||||
* @returns true if the input is incorrect, false otherwise.
|
||||
*/
|
||||
isInvalidInput(): boolean {
|
||||
return this.isInvalidInputError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the error is due to the verification contact (e.g., phone number or email) being blocked. Consider contacting customer support for assistance.
|
||||
* @returns true if the error is due to the verification contact being blocked, false otherwise.
|
||||
*/
|
||||
isVerificationContactBlocked(): boolean {
|
||||
return this.isVerificationContactBlockedError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error that occurred during MFA challenge submission.
|
||||
*/
|
||||
export class MfaSubmitChallengeError extends AuthActionErrorBase {
|
||||
/**
|
||||
* Checks if the submitted challenge code (e.g., OTP code) is incorrect.
|
||||
* @returns true if the challenge code is invalid, false otherwise.
|
||||
*/
|
||||
isIncorrectChallenge(): boolean {
|
||||
return this.isInvalidCodeError();
|
||||
}
|
||||
}
|
||||
67
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/result/MfaRequestChallengeResult.ts
generated
vendored
Normal file
67
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/result/MfaRequestChallengeResult.ts
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowResultBase } from "../../AuthFlowResultBase.js";
|
||||
import { MfaRequestChallengeError } from "../error_type/MfaError.js";
|
||||
import { MfaFailedState } from "../state/MfaFailedState.js";
|
||||
import type { MfaVerificationRequiredState } from "../state/MfaState.js";
|
||||
import {
|
||||
MFA_VERIFICATION_REQUIRED_STATE_TYPE,
|
||||
MFA_FAILED_STATE_TYPE,
|
||||
} from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* Result of requesting an MFA challenge.
|
||||
* Uses base state type to avoid circular dependencies.
|
||||
*/
|
||||
export class MfaRequestChallengeResult extends AuthFlowResultBase<
|
||||
MfaRequestChallengeResultState,
|
||||
MfaRequestChallengeError
|
||||
> {
|
||||
/**
|
||||
* Creates an MfaRequestChallengeResult with an error.
|
||||
* @param error The error that occurred.
|
||||
* @returns The MfaRequestChallengeResult with error.
|
||||
*/
|
||||
static createWithError(error: unknown): MfaRequestChallengeResult {
|
||||
const result = new MfaRequestChallengeResult(new MfaFailedState());
|
||||
result.error = new MfaRequestChallengeError(
|
||||
MfaRequestChallengeResult.createErrorData(error)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result indicates that verification is required.
|
||||
* @returns true if verification is required, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isVerificationRequired(): this is MfaRequestChallengeResult & {
|
||||
state: MfaVerificationRequiredState;
|
||||
} {
|
||||
return this.state.stateType === MFA_VERIFICATION_REQUIRED_STATE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result is in a failed state.
|
||||
* @returns true if the result is failed, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isFailed(): this is MfaRequestChallengeResult & {
|
||||
state: MfaFailedState;
|
||||
} {
|
||||
return this.state.stateType === MFA_FAILED_STATE_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The possible states for the MfaRequestChallengeResult.
|
||||
* This includes:
|
||||
* - MfaVerificationRequiredState: The user needs to verify their challenge.
|
||||
* - MfaFailedState: The MFA request failed.
|
||||
*/
|
||||
export type MfaRequestChallengeResultState =
|
||||
| MfaVerificationRequiredState
|
||||
| MfaFailedState;
|
||||
60
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/result/MfaSubmitChallengeResult.ts
generated
vendored
Normal file
60
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/result/MfaSubmitChallengeResult.ts
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowResultBase } from "../../AuthFlowResultBase.js";
|
||||
import { MfaSubmitChallengeError } from "../error_type/MfaError.js";
|
||||
import { CustomAuthAccountData } from "../../../../get_account/auth_flow/CustomAuthAccountData.js";
|
||||
import { MfaCompletedState } from "../state/MfaCompletedState.js";
|
||||
import { MfaFailedState } from "../state/MfaFailedState.js";
|
||||
import {
|
||||
MFA_COMPLETED_STATE_TYPE,
|
||||
MFA_FAILED_STATE_TYPE,
|
||||
} from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* Result of submitting an MFA challenge.
|
||||
*/
|
||||
export class MfaSubmitChallengeResult extends AuthFlowResultBase<
|
||||
MfaSubmitChallengeResultState,
|
||||
MfaSubmitChallengeError,
|
||||
CustomAuthAccountData
|
||||
> {
|
||||
/**
|
||||
* Creates an MfaSubmitChallengeResult with an error.
|
||||
* @param error The error that occurred.
|
||||
* @returns The MfaSubmitChallengeResult with error.
|
||||
*/
|
||||
static createWithError(error: unknown): MfaSubmitChallengeResult {
|
||||
const result = new MfaSubmitChallengeResult(new MfaFailedState());
|
||||
result.error = new MfaSubmitChallengeError(
|
||||
MfaSubmitChallengeResult.createErrorData(error)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the MFA flow is completed successfully.
|
||||
* @returns true if completed, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isCompleted(): this is MfaSubmitChallengeResult & {
|
||||
state: MfaCompletedState;
|
||||
} {
|
||||
return this.state.stateType === MFA_COMPLETED_STATE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the result is in a failed state.
|
||||
* @returns true if the result is failed, false otherwise.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
isFailed(): this is MfaSubmitChallengeResult & {
|
||||
state: MfaFailedState;
|
||||
} {
|
||||
return this.state.stateType === MFA_FAILED_STATE_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
export type MfaSubmitChallengeResultState = MfaCompletedState | MfaFailedState;
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/state/MfaCompletedState.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/state/MfaCompletedState.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowStateBase } from "../../AuthFlowState.js";
|
||||
import { MFA_COMPLETED_STATE_TYPE } from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* State indicating that the MFA flow has completed successfully.
|
||||
*/
|
||||
export class MfaCompletedState extends AuthFlowStateBase {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
stateType = MFA_COMPLETED_STATE_TYPE;
|
||||
}
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/state/MfaFailedState.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/state/MfaFailedState.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowStateBase } from "../../AuthFlowState.js";
|
||||
import { MFA_FAILED_STATE_TYPE } from "../../AuthFlowStateTypes.js";
|
||||
|
||||
/**
|
||||
* State indicating that the MFA flow has failed.
|
||||
*/
|
||||
export class MfaFailedState extends AuthFlowStateBase {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
stateType = MFA_FAILED_STATE_TYPE;
|
||||
}
|
||||
202
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/state/MfaState.ts
generated
vendored
Normal file
202
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/state/MfaState.ts
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
MfaAwaitingStateParameters,
|
||||
MfaStateParameters,
|
||||
MfaVerificationRequiredStateParameters,
|
||||
} from "./MfaStateParameters.js";
|
||||
import { MfaSubmitChallengeResult } from "../result/MfaSubmitChallengeResult.js";
|
||||
import { MfaRequestChallengeResult } from "../result/MfaRequestChallengeResult.js";
|
||||
import {
|
||||
MfaSubmitChallengeParams,
|
||||
MfaRequestChallengeParams,
|
||||
} from "../../../interaction_client/mfa/parameter/MfaClientParameters.js";
|
||||
import { CustomAuthAccountData } from "../../../../get_account/auth_flow/CustomAuthAccountData.js";
|
||||
import { MfaCompletedState } from "./MfaCompletedState.js";
|
||||
import { ensureArgumentIsNotEmptyString } from "../../../utils/ArgumentValidator.js";
|
||||
import { AuthenticationMethod } from "../../../network_client/custom_auth_api/types/ApiResponseTypes.js";
|
||||
import { AuthFlowActionRequiredStateBase } from "../../AuthFlowState.js";
|
||||
import {
|
||||
MFA_AWAITING_STATE_TYPE,
|
||||
MFA_VERIFICATION_REQUIRED_STATE_TYPE,
|
||||
} from "../../AuthFlowStateTypes.js";
|
||||
|
||||
abstract class MfaState<
|
||||
TParameters extends MfaStateParameters
|
||||
> extends AuthFlowActionRequiredStateBase<TParameters> {
|
||||
/**
|
||||
* Requests an MFA challenge for a specific authentication method.
|
||||
* @param authMethodId The authentication method ID to use for the challenge.
|
||||
* @returns Promise that resolves to MfaRequestChallengeResult.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
async requestChallenge(
|
||||
authMethodId: string
|
||||
): Promise<MfaRequestChallengeResult> {
|
||||
try {
|
||||
ensureArgumentIsNotEmptyString("authMethodId", authMethodId);
|
||||
|
||||
this.stateParameters.logger.verbose(
|
||||
`Requesting MFA challenge with authentication method - '${authMethodId}'.`,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
const requestParams: MfaRequestChallengeParams = {
|
||||
correlationId: this.stateParameters.correlationId,
|
||||
continuationToken: this.stateParameters.continuationToken ?? "",
|
||||
challengeType:
|
||||
this.stateParameters.config.customAuth.challengeTypes ?? [],
|
||||
authMethodId: authMethodId,
|
||||
};
|
||||
|
||||
const result =
|
||||
await this.stateParameters.mfaClient.requestChallenge(
|
||||
requestParams
|
||||
);
|
||||
|
||||
this.stateParameters.logger.verbose(
|
||||
"MFA challenge requested successfully.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
return new MfaRequestChallengeResult(
|
||||
new MfaVerificationRequiredState({
|
||||
correlationId: result.correlationId,
|
||||
continuationToken: result.continuationToken,
|
||||
config: this.stateParameters.config,
|
||||
logger: this.stateParameters.logger,
|
||||
mfaClient: this.stateParameters.mfaClient,
|
||||
cacheClient: this.stateParameters.cacheClient,
|
||||
challengeChannel: result.challengeChannel,
|
||||
challengeTargetLabel: result.challengeTargetLabel,
|
||||
codeLength: result.codeLength,
|
||||
selectedAuthMethodId: authMethodId,
|
||||
scopes: this.stateParameters.scopes ?? [],
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
this.stateParameters.logger.errorPii(
|
||||
`Failed to request MFA challenge. Error: '${error}'.`,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
return MfaRequestChallengeResult.createWithError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State indicating that MFA is required and awaiting user action.
|
||||
* This state allows the developer to pause execution before sending the code to the user's email.
|
||||
*/
|
||||
export class MfaAwaitingState extends MfaState<MfaAwaitingStateParameters> {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
stateType = MFA_AWAITING_STATE_TYPE;
|
||||
|
||||
/**
|
||||
* Gets the available authentication methods for MFA.
|
||||
* @returns Array of available authentication methods.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
getAuthMethods(): AuthenticationMethod[] {
|
||||
return this.stateParameters.authMethods;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State indicating that MFA verification is required.
|
||||
* The challenge has been sent and the user needs to provide the code.
|
||||
*/
|
||||
export class MfaVerificationRequiredState extends MfaState<MfaVerificationRequiredStateParameters> {
|
||||
/**
|
||||
* The type of the state.
|
||||
*/
|
||||
stateType = MFA_VERIFICATION_REQUIRED_STATE_TYPE;
|
||||
|
||||
/**
|
||||
* Gets the length of the code that the user needs to provide.
|
||||
* @returns The expected code length.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
getCodeLength(): number {
|
||||
return this.stateParameters.codeLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the channel through which the challenge was sent.
|
||||
* @returns The challenge channel (e.g., "email").
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
getChannel(): string {
|
||||
return this.stateParameters.challengeChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target label indicating where the challenge was sent.
|
||||
* @returns The challenge target label (e.g., masked email address).
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
getSentTo(): string {
|
||||
return this.stateParameters.challengeTargetLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the MFA challenge (e.g., OTP code) to complete the authentication.
|
||||
* @param challenge The challenge code (e.g., OTP code) entered by the user.
|
||||
* @returns Promise that resolves to MfaSubmitChallengeResult.
|
||||
* @warning This API is experimental. It may be changed in the future without notice. Do not use in production applications.
|
||||
*/
|
||||
async submitChallenge(
|
||||
challenge: string
|
||||
): Promise<MfaSubmitChallengeResult> {
|
||||
try {
|
||||
this.ensureCodeIsValid(challenge, this.getCodeLength());
|
||||
|
||||
this.stateParameters.logger.verbose(
|
||||
"Submitting MFA challenge.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
const submitParams: MfaSubmitChallengeParams = {
|
||||
correlationId: this.stateParameters.correlationId,
|
||||
continuationToken: this.stateParameters.continuationToken ?? "",
|
||||
scopes: this.stateParameters.scopes ?? [],
|
||||
challenge: challenge,
|
||||
};
|
||||
|
||||
const result = await this.stateParameters.mfaClient.submitChallenge(
|
||||
submitParams
|
||||
);
|
||||
|
||||
this.stateParameters.logger.verbose(
|
||||
"MFA challenge submitted successfully.",
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
const accountInfo = new CustomAuthAccountData(
|
||||
result.authenticationResult.account,
|
||||
this.stateParameters.config,
|
||||
this.stateParameters.cacheClient,
|
||||
this.stateParameters.logger,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
return new MfaSubmitChallengeResult(
|
||||
new MfaCompletedState(),
|
||||
accountInfo
|
||||
);
|
||||
} catch (error) {
|
||||
this.stateParameters.logger.errorPii(
|
||||
`Failed to submit MFA challenge. Error: '${error}'.`,
|
||||
this.stateParameters.correlationId
|
||||
);
|
||||
|
||||
return MfaSubmitChallengeResult.createWithError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/state/MfaStateParameters.ts
generated
vendored
Normal file
28
backend/node_modules/@azure/msal-browser/src/custom_auth/core/auth_flow/mfa/state/MfaStateParameters.ts
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthFlowActionRequiredStateParameters } from "../../AuthFlowState.js";
|
||||
import { MfaClient } from "../../../interaction_client/mfa/MfaClient.js";
|
||||
import { AuthenticationMethod } from "../../../network_client/custom_auth_api/types/ApiResponseTypes.js";
|
||||
import { CustomAuthSilentCacheClient } from "../../../../get_account/interaction_client/CustomAuthSilentCacheClient.js";
|
||||
|
||||
export interface MfaStateParameters
|
||||
extends AuthFlowActionRequiredStateParameters {
|
||||
mfaClient: MfaClient;
|
||||
cacheClient: CustomAuthSilentCacheClient;
|
||||
scopes?: string[];
|
||||
}
|
||||
|
||||
export interface MfaVerificationRequiredStateParameters
|
||||
extends MfaStateParameters {
|
||||
challengeChannel: string;
|
||||
challengeTargetLabel: string;
|
||||
codeLength: number;
|
||||
selectedAuthMethodId?: string;
|
||||
}
|
||||
|
||||
export interface MfaAwaitingStateParameters extends MfaStateParameters {
|
||||
authMethods: AuthenticationMethod[];
|
||||
}
|
||||
42
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/CustomAuthApiError.ts
generated
vendored
Normal file
42
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/CustomAuthApiError.ts
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { UserAttribute } from "../network_client/custom_auth_api/types/ApiErrorResponseTypes.js";
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
/**
|
||||
* Error when no required authentication method by Microsoft Entra is supported
|
||||
*/
|
||||
export class RedirectError extends CustomAuthError {
|
||||
constructor(correlationId?: string, public redirectReason?: string) {
|
||||
super(
|
||||
"redirect",
|
||||
redirectReason ||
|
||||
"Redirect Error, a fallback to the browser-delegated authentication is needed. Use loginPopup instead.",
|
||||
correlationId
|
||||
);
|
||||
Object.setPrototypeOf(this, RedirectError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Auth API error.
|
||||
*/
|
||||
export class CustomAuthApiError extends CustomAuthError {
|
||||
constructor(
|
||||
error: string,
|
||||
errorDescription: string,
|
||||
correlationId?: string,
|
||||
errorCodes?: Array<number>,
|
||||
subError?: string,
|
||||
public attributes?: Array<UserAttribute>,
|
||||
public continuationToken?: string,
|
||||
public traceId?: string,
|
||||
public timestamp?: string
|
||||
) {
|
||||
super(error, errorDescription, correlationId, errorCodes, subError);
|
||||
Object.setPrototypeOf(this, CustomAuthApiError.prototype);
|
||||
}
|
||||
}
|
||||
20
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/CustomAuthError.ts
generated
vendored
Normal file
20
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/CustomAuthError.ts
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export class CustomAuthError extends Error {
|
||||
constructor(
|
||||
public error: string,
|
||||
public errorDescription?: string,
|
||||
public correlationId?: string,
|
||||
public errorCodes?: Array<number>,
|
||||
public subError?: string
|
||||
) {
|
||||
super(`${error}: ${errorDescription ?? ""}`);
|
||||
Object.setPrototypeOf(this, CustomAuthError.prototype);
|
||||
|
||||
this.errorCodes = errorCodes ?? [];
|
||||
this.subError = subError ?? "";
|
||||
}
|
||||
}
|
||||
13
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/HttpError.ts
generated
vendored
Normal file
13
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/HttpError.ts
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class HttpError extends CustomAuthError {
|
||||
constructor(error: string, message: string, correlationId?: string) {
|
||||
super(error, message, correlationId);
|
||||
Object.setPrototypeOf(this, HttpError.prototype);
|
||||
}
|
||||
}
|
||||
7
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/HttpErrorCodes.ts
generated
vendored
Normal file
7
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/HttpErrorCodes.ts
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export const NoNetworkConnectivity = "no_network_connectivity";
|
||||
export const FailedSendRequest = "failed_send_request";
|
||||
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/InvalidArgumentError.ts
generated
vendored
Normal file
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/InvalidArgumentError.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class InvalidArgumentError extends CustomAuthError {
|
||||
constructor(argName: string, correlationId?: string) {
|
||||
const errorDescription = `The argument '${argName}' is invalid.`;
|
||||
|
||||
super("invalid_argument", errorDescription, correlationId);
|
||||
Object.setPrototypeOf(this, InvalidArgumentError.prototype);
|
||||
}
|
||||
}
|
||||
13
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/InvalidConfigurationError.ts
generated
vendored
Normal file
13
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/InvalidConfigurationError.ts
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class InvalidConfigurationError extends CustomAuthError {
|
||||
constructor(error: string, message: string, correlationId?: string) {
|
||||
super(error, message, correlationId);
|
||||
Object.setPrototypeOf(this, InvalidConfigurationError.prototype);
|
||||
}
|
||||
}
|
||||
8
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/InvalidConfigurationErrorCodes.ts
generated
vendored
Normal file
8
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/InvalidConfigurationErrorCodes.ts
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export const MissingConfiguration = "missing_configuration";
|
||||
export const InvalidAuthority = "invalid_authority";
|
||||
export const InvalidChallengeType = "invalid_challenge_type";
|
||||
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/MethodNotImplementedError.ts
generated
vendored
Normal file
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/MethodNotImplementedError.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class MethodNotImplementedError extends CustomAuthError {
|
||||
constructor(method: string, correlationId?: string) {
|
||||
const errorDescription = `The method '${method}' is not implemented, please do not use.`;
|
||||
|
||||
super("method_not_implemented", errorDescription, correlationId);
|
||||
Object.setPrototypeOf(this, MethodNotImplementedError.prototype);
|
||||
}
|
||||
}
|
||||
19
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/MsalCustomAuthError.ts
generated
vendored
Normal file
19
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/MsalCustomAuthError.ts
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class MsalCustomAuthError extends CustomAuthError {
|
||||
constructor(
|
||||
error: string,
|
||||
errorDescription?: string,
|
||||
subError?: string,
|
||||
errorCodes?: Array<number>,
|
||||
correlationId?: string
|
||||
) {
|
||||
super(error, errorDescription, correlationId, errorCodes, subError);
|
||||
Object.setPrototypeOf(this, MsalCustomAuthError.prototype);
|
||||
}
|
||||
}
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/NoCachedAccountFoundError.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/NoCachedAccountFoundError.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class NoCachedAccountFoundError extends CustomAuthError {
|
||||
constructor(correlationId?: string) {
|
||||
super(
|
||||
"no_cached_account_found",
|
||||
"No account found in the cache",
|
||||
correlationId
|
||||
);
|
||||
Object.setPrototypeOf(this, NoCachedAccountFoundError.prototype);
|
||||
}
|
||||
}
|
||||
13
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/ParsedUrlError.ts
generated
vendored
Normal file
13
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/ParsedUrlError.ts
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class ParsedUrlError extends CustomAuthError {
|
||||
constructor(error: string, message: string, correlationId?: string) {
|
||||
super(error, message, correlationId);
|
||||
Object.setPrototypeOf(this, ParsedUrlError.prototype);
|
||||
}
|
||||
}
|
||||
6
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/ParsedUrlErrorCodes.ts
generated
vendored
Normal file
6
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/ParsedUrlErrorCodes.ts
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export const InvalidUrl = "invalid_url";
|
||||
25
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UnexpectedError.ts
generated
vendored
Normal file
25
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UnexpectedError.ts
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class UnexpectedError extends CustomAuthError {
|
||||
constructor(errorData: unknown, correlationId?: string) {
|
||||
let errorDescription: string;
|
||||
|
||||
if (errorData instanceof Error) {
|
||||
errorDescription = errorData.message;
|
||||
} else if (typeof errorData === "string") {
|
||||
errorDescription = errorData;
|
||||
} else if (typeof errorData === "object" && errorData !== null) {
|
||||
errorDescription = JSON.stringify(errorData);
|
||||
} else {
|
||||
errorDescription = "An unexpected error occurred.";
|
||||
}
|
||||
|
||||
super("unexpected_error", errorDescription, correlationId);
|
||||
Object.setPrototypeOf(this, UnexpectedError.prototype);
|
||||
}
|
||||
}
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UnsupportedEnvironmentError.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UnsupportedEnvironmentError.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class UnsupportedEnvironmentError extends CustomAuthError {
|
||||
constructor(correlationId?: string) {
|
||||
super(
|
||||
"unsupported_env",
|
||||
"The current environment is not browser",
|
||||
correlationId
|
||||
);
|
||||
Object.setPrototypeOf(this, UnsupportedEnvironmentError.prototype);
|
||||
}
|
||||
}
|
||||
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UserAccountAttributeError.ts
generated
vendored
Normal file
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UserAccountAttributeError.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class UserAccountAttributeError extends CustomAuthError {
|
||||
constructor(error: string, attributeName: string, attributeValue: string) {
|
||||
const errorDescription = `Failed to set attribute '${attributeName}' with value '${attributeValue}'`;
|
||||
|
||||
super(error, errorDescription);
|
||||
Object.setPrototypeOf(this, UserAccountAttributeError.prototype);
|
||||
}
|
||||
}
|
||||
6
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UserAccountAttributeErrorCodes.ts
generated
vendored
Normal file
6
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UserAccountAttributeErrorCodes.ts
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export const InvalidAttributeErrorCode = "invalid_attribute";
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UserAlreadySignedInError.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/error/UserAlreadySignedInError.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthError } from "./CustomAuthError.js";
|
||||
|
||||
export class UserAlreadySignedInError extends CustomAuthError {
|
||||
constructor(correlationId?: string) {
|
||||
super(
|
||||
"user_already_signed_in",
|
||||
"The user has already signed in.",
|
||||
correlationId
|
||||
);
|
||||
Object.setPrototypeOf(this, UserAlreadySignedInError.prototype);
|
||||
}
|
||||
}
|
||||
142
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/CustomAuthInteractionClientBase.ts
generated
vendored
Normal file
142
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/CustomAuthInteractionClientBase.ts
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { ICustomAuthApiClient } from "../network_client/custom_auth_api/ICustomAuthApiClient.js";
|
||||
import { MethodNotImplementedError } from "../error/MethodNotImplementedError.js";
|
||||
import { CustomAuthAuthority } from "../CustomAuthAuthority.js";
|
||||
import { ChallengeType } from "../../CustomAuthConstants.js";
|
||||
import { StandardInteractionClient } from "../../../interaction_client/StandardInteractionClient.js";
|
||||
import { BrowserConfiguration } from "../../../config/Configuration.js";
|
||||
import { BrowserCacheManager } from "../../../cache/BrowserCacheManager.js";
|
||||
import {
|
||||
Constants,
|
||||
ICrypto,
|
||||
IPerformanceClient,
|
||||
Logger,
|
||||
ResponseHandler,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { EventHandler } from "../../../event/EventHandler.js";
|
||||
import { INavigationClient } from "../../../navigation/INavigationClient.js";
|
||||
import { RedirectRequest } from "../../../request/RedirectRequest.js";
|
||||
import { PopupRequest } from "../../../request/PopupRequest.js";
|
||||
import { SsoSilentRequest } from "../../../request/SsoSilentRequest.js";
|
||||
import { EndSessionRequest } from "../../../request/EndSessionRequest.js";
|
||||
import { ClearCacheRequest } from "../../../request/ClearCacheRequest.js";
|
||||
import { AuthenticationResult } from "../../../response/AuthenticationResult.js";
|
||||
import { SignInTokenResponse } from "../network_client/custom_auth_api/types/ApiResponseTypes.js";
|
||||
|
||||
export abstract class CustomAuthInteractionClientBase extends StandardInteractionClient {
|
||||
private readonly tokenResponseHandler: ResponseHandler;
|
||||
|
||||
constructor(
|
||||
config: BrowserConfiguration,
|
||||
storageImpl: BrowserCacheManager,
|
||||
browserCrypto: ICrypto,
|
||||
logger: Logger,
|
||||
eventHandler: EventHandler,
|
||||
navigationClient: INavigationClient,
|
||||
performanceClient: IPerformanceClient,
|
||||
protected customAuthApiClient: ICustomAuthApiClient,
|
||||
protected customAuthAuthority: CustomAuthAuthority
|
||||
) {
|
||||
super(
|
||||
config,
|
||||
storageImpl,
|
||||
browserCrypto,
|
||||
logger,
|
||||
eventHandler,
|
||||
navigationClient,
|
||||
performanceClient,
|
||||
""
|
||||
);
|
||||
|
||||
this.tokenResponseHandler = new ResponseHandler(
|
||||
this.config.auth.clientId,
|
||||
this.browserStorage,
|
||||
this.browserCrypto,
|
||||
this.logger,
|
||||
this.performanceClient,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
protected getChallengeTypes(
|
||||
configuredChallengeTypes: string[] | undefined
|
||||
): string {
|
||||
const challengeType = configuredChallengeTypes ?? [];
|
||||
if (
|
||||
!challengeType.some(
|
||||
(type) => type.toLowerCase() === ChallengeType.REDIRECT
|
||||
)
|
||||
) {
|
||||
challengeType.push(ChallengeType.REDIRECT);
|
||||
}
|
||||
return challengeType.join(" ");
|
||||
}
|
||||
|
||||
protected getScopes(scopes: string[] | undefined): string[] {
|
||||
if (!!scopes && scopes.length > 0) {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
return [
|
||||
Constants.OPENID_SCOPE,
|
||||
Constants.PROFILE_SCOPE,
|
||||
Constants.OFFLINE_ACCESS_SCOPE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Common method to handle token response processing.
|
||||
* @param tokenResponse The token response from the API
|
||||
* @param requestScopes Scopes for the token request
|
||||
* @param correlationId Correlation ID for logging
|
||||
* @returns Authentication result from the token response
|
||||
*/
|
||||
protected async handleTokenResponse(
|
||||
tokenResponse: SignInTokenResponse,
|
||||
requestScopes: string[],
|
||||
correlationId: string,
|
||||
apiId: number
|
||||
): Promise<AuthenticationResult> {
|
||||
this.logger.verbose("Processing token response.", correlationId);
|
||||
|
||||
const requestTimestamp = Math.round(new Date().getTime() / 1000.0);
|
||||
|
||||
// Save tokens and create authentication result
|
||||
const result =
|
||||
await this.tokenResponseHandler.handleServerTokenResponse(
|
||||
tokenResponse,
|
||||
this.customAuthAuthority,
|
||||
requestTimestamp,
|
||||
{
|
||||
authority: this.customAuthAuthority.canonicalAuthority,
|
||||
correlationId:
|
||||
tokenResponse.correlation_id ?? correlationId,
|
||||
scopes: requestScopes,
|
||||
},
|
||||
apiId
|
||||
);
|
||||
|
||||
return result as AuthenticationResult;
|
||||
}
|
||||
|
||||
// It is not necessary to implement this method from base class.
|
||||
acquireToken(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
request: RedirectRequest | PopupRequest | SsoSilentRequest
|
||||
): Promise<AuthenticationResult | void> {
|
||||
throw new MethodNotImplementedError("SignInClient.acquireToken");
|
||||
}
|
||||
|
||||
// It is not necessary to implement this method from base class.
|
||||
logout(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
request: EndSessionRequest | ClearCacheRequest | undefined
|
||||
): Promise<void> {
|
||||
throw new MethodNotImplementedError("SignInClient.logout");
|
||||
}
|
||||
}
|
||||
57
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/CustomAuthInterationClientFactory.ts
generated
vendored
Normal file
57
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/CustomAuthInterationClientFactory.ts
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { ICustomAuthApiClient } from "../network_client/custom_auth_api/ICustomAuthApiClient.js";
|
||||
import { CustomAuthAuthority } from "../CustomAuthAuthority.js";
|
||||
import { CustomAuthInteractionClientBase } from "./CustomAuthInteractionClientBase.js";
|
||||
import { BrowserConfiguration } from "../../../config/Configuration.js";
|
||||
import { BrowserCacheManager } from "../../../cache/BrowserCacheManager.js";
|
||||
import {
|
||||
ICrypto,
|
||||
IPerformanceClient,
|
||||
Logger,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { EventHandler } from "../../../event/EventHandler.js";
|
||||
import { INavigationClient } from "../../../navigation/INavigationClient.js";
|
||||
|
||||
export class CustomAuthInterationClientFactory {
|
||||
constructor(
|
||||
private config: BrowserConfiguration,
|
||||
private storageImpl: BrowserCacheManager,
|
||||
private browserCrypto: ICrypto,
|
||||
private logger: Logger,
|
||||
private eventHandler: EventHandler,
|
||||
private navigationClient: INavigationClient,
|
||||
private performanceClient: IPerformanceClient,
|
||||
private customAuthApiClient: ICustomAuthApiClient,
|
||||
private customAuthAuthority: CustomAuthAuthority
|
||||
) {}
|
||||
|
||||
create<TClient extends CustomAuthInteractionClientBase>(
|
||||
clientConstructor: new (
|
||||
config: BrowserConfiguration,
|
||||
storageImpl: BrowserCacheManager,
|
||||
browserCrypto: ICrypto,
|
||||
logger: Logger,
|
||||
eventHandler: EventHandler,
|
||||
navigationClient: INavigationClient,
|
||||
performanceClient: IPerformanceClient,
|
||||
customAuthApiClient: ICustomAuthApiClient,
|
||||
customAuthAuthority: CustomAuthAuthority
|
||||
) => TClient
|
||||
): TClient {
|
||||
return new clientConstructor(
|
||||
this.config,
|
||||
this.storageImpl,
|
||||
this.browserCrypto,
|
||||
this.logger,
|
||||
this.eventHandler,
|
||||
this.navigationClient,
|
||||
this.performanceClient,
|
||||
this.customAuthApiClient,
|
||||
this.customAuthAuthority
|
||||
);
|
||||
}
|
||||
}
|
||||
184
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/jit/JitClient.ts
generated
vendored
Normal file
184
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/jit/JitClient.ts
generated
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthInteractionClientBase } from "../CustomAuthInteractionClientBase.js";
|
||||
import {
|
||||
JitChallengeAuthMethodParams,
|
||||
JitSubmitChallengeParams,
|
||||
} from "./parameter/JitParams.js";
|
||||
import {
|
||||
JitVerificationRequiredResult,
|
||||
JitCompletedResult,
|
||||
createJitVerificationRequiredResult,
|
||||
createJitCompletedResult,
|
||||
} from "./result/JitActionResult.js";
|
||||
import {
|
||||
DefaultCustomAuthApiCodeLength,
|
||||
ChallengeType,
|
||||
GrantType,
|
||||
} from "../../../CustomAuthConstants.js";
|
||||
import * as PublicApiId from "../../telemetry/PublicApiId.js";
|
||||
import {
|
||||
RegisterChallengeRequest,
|
||||
RegisterContinueRequest,
|
||||
SignInContinuationTokenRequest,
|
||||
} from "../../network_client/custom_auth_api/types/ApiRequestTypes.js";
|
||||
import { initializeServerTelemetryManager } from "../../../../interaction_client/BaseInteractionClient.js";
|
||||
|
||||
/**
|
||||
* JIT client for handling just-in-time authentication method registration flows.
|
||||
*/
|
||||
export class JitClient extends CustomAuthInteractionClientBase {
|
||||
/**
|
||||
* Challenges an authentication method for JIT registration.
|
||||
* @param parameters The parameters for challenging the auth method.
|
||||
* @returns Promise that resolves to either JitVerificationRequiredResult or JitCompletedResult.
|
||||
*/
|
||||
async challengeAuthMethod(
|
||||
parameters: JitChallengeAuthMethodParams
|
||||
): Promise<JitVerificationRequiredResult | JitCompletedResult> {
|
||||
const correlationId = parameters.correlationId || this.correlationId;
|
||||
const apiId = PublicApiId.JIT_CHALLENGE_AUTH_METHOD;
|
||||
const telemetryManager = initializeServerTelemetryManager(
|
||||
apiId,
|
||||
this.config.auth.clientId,
|
||||
correlationId,
|
||||
this.browserStorage,
|
||||
this.logger
|
||||
);
|
||||
|
||||
this.logger.verbose(
|
||||
"Calling challenge endpoint for getting auth method.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
const challengeReq: RegisterChallengeRequest = {
|
||||
continuation_token: parameters.continuationToken,
|
||||
challenge_type: parameters.authMethod.challenge_type,
|
||||
challenge_target: parameters.verificationContact,
|
||||
challenge_channel: parameters.authMethod.challenge_channel,
|
||||
correlationId: correlationId,
|
||||
telemetryManager: telemetryManager,
|
||||
};
|
||||
|
||||
const challengeResponse =
|
||||
await this.customAuthApiClient.registerApi.challenge(challengeReq);
|
||||
|
||||
this.logger.verbose(
|
||||
"Challenge endpoint called for auth method registration.",
|
||||
challengeResponse.correlation_id || correlationId
|
||||
);
|
||||
|
||||
/*
|
||||
* Handle fast-pass scenario (preverified)
|
||||
* This occurs when the user selects the same email used during sign-up
|
||||
* Since the email was already verified during sign-up, no additional verification is needed
|
||||
*/
|
||||
if (challengeResponse.challenge_type === ChallengeType.PREVERIFIED) {
|
||||
this.logger.verbose(
|
||||
"Fast-pass scenario detected - completing registration without additional verification.",
|
||||
challengeResponse.correlation_id || correlationId
|
||||
);
|
||||
|
||||
// Use submitChallenge for fast-pass scenario with continuation_token grant type
|
||||
const fastPassParams: JitSubmitChallengeParams = {
|
||||
correlationId:
|
||||
challengeResponse.correlation_id || correlationId,
|
||||
continuationToken: challengeResponse.continuation_token,
|
||||
grantType: GrantType.CONTINUATION_TOKEN,
|
||||
scopes: parameters.scopes,
|
||||
username: parameters.username,
|
||||
claims: parameters.claims,
|
||||
};
|
||||
|
||||
const completedResult = await this.submitChallenge(fastPassParams);
|
||||
return completedResult;
|
||||
}
|
||||
|
||||
// Verification required
|
||||
return createJitVerificationRequiredResult({
|
||||
correlationId: challengeResponse.correlation_id || correlationId,
|
||||
continuationToken: challengeResponse.continuation_token,
|
||||
challengeChannel: challengeResponse.challenge_channel,
|
||||
challengeTargetLabel: challengeResponse.challenge_target,
|
||||
codeLength:
|
||||
challengeResponse.code_length || DefaultCustomAuthApiCodeLength,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits challenge response and completes JIT registration.
|
||||
* @param parameters The parameters for submitting the challenge.
|
||||
* @returns Promise that resolves to JitCompletedResult.
|
||||
*/
|
||||
async submitChallenge(
|
||||
parameters: JitSubmitChallengeParams
|
||||
): Promise<JitCompletedResult> {
|
||||
const correlationId = parameters.correlationId || this.correlationId;
|
||||
const apiId = PublicApiId.JIT_SUBMIT_CHALLENGE;
|
||||
const telemetryManager = initializeServerTelemetryManager(
|
||||
apiId,
|
||||
this.config.auth.clientId,
|
||||
correlationId,
|
||||
this.browserStorage,
|
||||
this.logger
|
||||
);
|
||||
|
||||
this.logger.verbose(
|
||||
"Calling continue endpoint for auth method challenge submission.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
// Submit challenge to complete registration
|
||||
const continueReq: RegisterContinueRequest = {
|
||||
continuation_token: parameters.continuationToken,
|
||||
grant_type: parameters.grantType,
|
||||
...(parameters.challenge && {
|
||||
oob: parameters.challenge,
|
||||
}),
|
||||
correlationId: correlationId,
|
||||
telemetryManager: telemetryManager,
|
||||
};
|
||||
|
||||
const continueResponse =
|
||||
await this.customAuthApiClient.registerApi.continue(continueReq);
|
||||
|
||||
this.logger.verbose(
|
||||
"Continue endpoint called for auth method challenge submission.",
|
||||
parameters.correlationId
|
||||
);
|
||||
|
||||
// Use continuation token to get authentication tokens
|
||||
const scopes = this.getScopes(parameters.scopes);
|
||||
const tokenRequest: SignInContinuationTokenRequest = {
|
||||
continuation_token: continueResponse.continuation_token,
|
||||
scope: scopes.join(" "),
|
||||
correlationId: continueResponse.correlation_id || correlationId,
|
||||
telemetryManager: telemetryManager,
|
||||
...(parameters.claims && {
|
||||
claims: parameters.claims,
|
||||
}),
|
||||
};
|
||||
|
||||
const tokenResponse =
|
||||
await this.customAuthApiClient.signInApi.requestTokenWithContinuationToken(
|
||||
tokenRequest
|
||||
);
|
||||
|
||||
const authResult = await this.handleTokenResponse(
|
||||
tokenResponse,
|
||||
scopes,
|
||||
tokenResponse.correlation_id ||
|
||||
continueResponse.correlation_id ||
|
||||
correlationId,
|
||||
apiId
|
||||
);
|
||||
|
||||
return createJitCompletedResult({
|
||||
correlationId: continueResponse.correlation_id || correlationId,
|
||||
authenticationResult: authResult,
|
||||
});
|
||||
}
|
||||
}
|
||||
27
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/jit/parameter/JitParams.ts
generated
vendored
Normal file
27
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/jit/parameter/JitParams.ts
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthenticationMethod } from "../../../network_client/custom_auth_api/types/ApiResponseTypes.js";
|
||||
|
||||
export interface JitClientParametersBase {
|
||||
correlationId: string;
|
||||
continuationToken: string;
|
||||
}
|
||||
|
||||
export interface JitChallengeAuthMethodParams extends JitClientParametersBase {
|
||||
authMethod: AuthenticationMethod;
|
||||
verificationContact: string;
|
||||
scopes: string[];
|
||||
username?: string;
|
||||
claims?: string;
|
||||
}
|
||||
|
||||
export interface JitSubmitChallengeParams extends JitClientParametersBase {
|
||||
grantType: string;
|
||||
challenge?: string;
|
||||
scopes: string[];
|
||||
username?: string;
|
||||
claims?: string;
|
||||
}
|
||||
47
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/jit/result/JitActionResult.ts
generated
vendored
Normal file
47
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/jit/result/JitActionResult.ts
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthenticationResult } from "../../../../../response/AuthenticationResult.js";
|
||||
|
||||
interface JitActionResult {
|
||||
type: string;
|
||||
correlationId: string;
|
||||
}
|
||||
|
||||
export interface JitVerificationRequiredResult extends JitActionResult {
|
||||
type: typeof JIT_VERIFICATION_REQUIRED_RESULT_TYPE;
|
||||
continuationToken: string;
|
||||
challengeChannel: string;
|
||||
challengeTargetLabel: string;
|
||||
codeLength: number;
|
||||
}
|
||||
|
||||
export interface JitCompletedResult extends JitActionResult {
|
||||
type: typeof JIT_COMPLETED_RESULT_TYPE;
|
||||
authenticationResult: AuthenticationResult;
|
||||
}
|
||||
|
||||
// Result type constants
|
||||
export const JIT_VERIFICATION_REQUIRED_RESULT_TYPE =
|
||||
"JitVerificationRequiredResult";
|
||||
export const JIT_COMPLETED_RESULT_TYPE = "JitCompletedResult";
|
||||
|
||||
export function createJitVerificationRequiredResult(
|
||||
input: Omit<JitVerificationRequiredResult, "type">
|
||||
): JitVerificationRequiredResult {
|
||||
return {
|
||||
type: JIT_VERIFICATION_REQUIRED_RESULT_TYPE,
|
||||
...input,
|
||||
};
|
||||
}
|
||||
|
||||
export function createJitCompletedResult(
|
||||
input: Omit<JitCompletedResult, "type">
|
||||
): JitCompletedResult {
|
||||
return {
|
||||
type: JIT_COMPLETED_RESULT_TYPE,
|
||||
...input,
|
||||
};
|
||||
}
|
||||
166
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/mfa/MfaClient.ts
generated
vendored
Normal file
166
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/mfa/MfaClient.ts
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { CustomAuthInteractionClientBase } from "../CustomAuthInteractionClientBase.js";
|
||||
import {
|
||||
MfaRequestChallengeParams,
|
||||
MfaSubmitChallengeParams,
|
||||
} from "./parameter/MfaClientParameters.js";
|
||||
import {
|
||||
MfaVerificationRequiredResult,
|
||||
MfaCompletedResult,
|
||||
createMfaVerificationRequiredResult,
|
||||
createMfaCompletedResult,
|
||||
} from "./result/MfaActionResult.js";
|
||||
import {
|
||||
DefaultCustomAuthApiCodeLength,
|
||||
ChallengeType,
|
||||
GrantType,
|
||||
} from "../../../CustomAuthConstants.js";
|
||||
import * as PublicApiId from "../../telemetry/PublicApiId.js";
|
||||
import {
|
||||
SignInChallengeRequest,
|
||||
SignInOobTokenRequest,
|
||||
} from "../../network_client/custom_auth_api/types/ApiRequestTypes.js";
|
||||
import { ensureArgumentIsNotEmptyString } from "../../utils/ArgumentValidator.js";
|
||||
import { CustomAuthApiError } from "../../error/CustomAuthApiError.js";
|
||||
import * as CustomAuthApiErrorCode from "../../network_client/custom_auth_api/types/ApiErrorCodes.js";
|
||||
import { initializeServerTelemetryManager } from "../../../../interaction_client/BaseInteractionClient.js";
|
||||
|
||||
/**
|
||||
* MFA client for handling multi-factor authentication flows.
|
||||
*/
|
||||
export class MfaClient extends CustomAuthInteractionClientBase {
|
||||
/**
|
||||
* Requests an MFA challenge to be sent to the user.
|
||||
* @param parameters The parameters for requesting the challenge.
|
||||
* @returns Promise that resolves to either MfaVerificationRequiredResult.
|
||||
*/
|
||||
async requestChallenge(
|
||||
parameters: MfaRequestChallengeParams
|
||||
): Promise<MfaVerificationRequiredResult> {
|
||||
const apiId = PublicApiId.MFA_REQUEST_CHALLENGE;
|
||||
const correlationId = parameters.correlationId || this.correlationId;
|
||||
const telemetryManager = initializeServerTelemetryManager(
|
||||
apiId,
|
||||
this.config.auth.clientId,
|
||||
correlationId,
|
||||
this.browserStorage,
|
||||
this.logger
|
||||
);
|
||||
|
||||
this.logger.verbose(
|
||||
"Calling challenge endpoint for MFA.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
const challengeReq: SignInChallengeRequest = {
|
||||
challenge_type: this.getChallengeTypes(parameters.challengeType),
|
||||
continuation_token: parameters.continuationToken,
|
||||
id: parameters.authMethodId,
|
||||
correlationId: correlationId,
|
||||
telemetryManager: telemetryManager,
|
||||
};
|
||||
|
||||
const challengeResponse =
|
||||
await this.customAuthApiClient.signInApi.requestChallenge(
|
||||
challengeReq
|
||||
);
|
||||
|
||||
this.logger.verbose(
|
||||
"Challenge endpoint called for MFA.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
if (challengeResponse.challenge_type === ChallengeType.OOB) {
|
||||
// Verification required - code will be sent
|
||||
return createMfaVerificationRequiredResult({
|
||||
correlationId:
|
||||
challengeResponse.correlation_id || correlationId,
|
||||
continuationToken: challengeResponse.continuation_token ?? "",
|
||||
challengeChannel: challengeResponse.challenge_channel ?? "",
|
||||
challengeTargetLabel:
|
||||
challengeResponse.challenge_target_label ?? "",
|
||||
codeLength:
|
||||
challengeResponse.code_length ??
|
||||
DefaultCustomAuthApiCodeLength,
|
||||
bindingMethod: challengeResponse.binding_method ?? "",
|
||||
});
|
||||
}
|
||||
|
||||
this.logger.error(
|
||||
`Unsupported challenge type '${challengeResponse.challenge_type}' for MFA.`,
|
||||
challengeResponse.correlation_id || correlationId
|
||||
);
|
||||
|
||||
throw new CustomAuthApiError(
|
||||
CustomAuthApiErrorCode.UNSUPPORTED_CHALLENGE_TYPE,
|
||||
`Unsupported challenge type '${challengeResponse.challenge_type}'.`,
|
||||
challengeResponse.correlation_id || correlationId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the MFA challenge response (e.g., OTP code).
|
||||
* @param parameters The parameters for submitting the challenge.
|
||||
* @returns Promise that resolves to MfaCompletedResult.
|
||||
*/
|
||||
async submitChallenge(
|
||||
parameters: MfaSubmitChallengeParams
|
||||
): Promise<MfaCompletedResult> {
|
||||
const correlationId = parameters.correlationId || this.correlationId;
|
||||
|
||||
ensureArgumentIsNotEmptyString(
|
||||
"parameters.challenge",
|
||||
parameters.challenge,
|
||||
correlationId
|
||||
);
|
||||
|
||||
const apiId = PublicApiId.MFA_SUBMIT_CHALLENGE;
|
||||
const telemetryManager = initializeServerTelemetryManager(
|
||||
apiId,
|
||||
this.config.auth.clientId,
|
||||
correlationId,
|
||||
this.browserStorage,
|
||||
this.logger
|
||||
);
|
||||
const scopes = this.getScopes(parameters.scopes);
|
||||
|
||||
const request: SignInOobTokenRequest = {
|
||||
continuation_token: parameters.continuationToken,
|
||||
oob: parameters.challenge,
|
||||
grant_type: GrantType.MFA_OOB,
|
||||
scope: scopes.join(" "),
|
||||
correlationId: correlationId,
|
||||
telemetryManager: telemetryManager,
|
||||
...(parameters.claims && {
|
||||
claims: parameters.claims,
|
||||
}),
|
||||
};
|
||||
|
||||
this.logger.verbose(
|
||||
"Calling token endpoint for MFA challenge submission.",
|
||||
correlationId
|
||||
);
|
||||
|
||||
const tokenResponse =
|
||||
await this.customAuthApiClient.signInApi.requestTokensWithOob(
|
||||
request
|
||||
);
|
||||
|
||||
// Save tokens and create authentication result
|
||||
const result = await this.handleTokenResponse(
|
||||
tokenResponse,
|
||||
scopes,
|
||||
tokenResponse.correlation_id || correlationId,
|
||||
apiId
|
||||
);
|
||||
|
||||
return createMfaCompletedResult({
|
||||
correlationId: tokenResponse.correlation_id || correlationId,
|
||||
authenticationResult: result,
|
||||
});
|
||||
}
|
||||
}
|
||||
20
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/mfa/parameter/MfaClientParameters.ts
generated
vendored
Normal file
20
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/mfa/parameter/MfaClientParameters.ts
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export interface MfaClientParametersBase {
|
||||
correlationId: string;
|
||||
continuationToken: string;
|
||||
}
|
||||
|
||||
export interface MfaRequestChallengeParams extends MfaClientParametersBase {
|
||||
challengeType: string[];
|
||||
authMethodId: string;
|
||||
}
|
||||
|
||||
export interface MfaSubmitChallengeParams extends MfaClientParametersBase {
|
||||
challenge: string;
|
||||
scopes: string[];
|
||||
claims?: string;
|
||||
}
|
||||
48
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/mfa/result/MfaActionResult.ts
generated
vendored
Normal file
48
backend/node_modules/@azure/msal-browser/src/custom_auth/core/interaction_client/mfa/result/MfaActionResult.ts
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { AuthenticationResult } from "../../../../../response/AuthenticationResult.js";
|
||||
|
||||
interface MfaActionResult {
|
||||
type: string;
|
||||
correlationId: string;
|
||||
}
|
||||
|
||||
export interface MfaVerificationRequiredResult extends MfaActionResult {
|
||||
type: typeof MFA_VERIFICATION_REQUIRED_RESULT_TYPE;
|
||||
continuationToken: string;
|
||||
challengeChannel: string;
|
||||
challengeTargetLabel: string;
|
||||
codeLength: number;
|
||||
bindingMethod: string;
|
||||
}
|
||||
|
||||
export interface MfaCompletedResult extends MfaActionResult {
|
||||
type: typeof MFA_COMPLETED_RESULT_TYPE;
|
||||
authenticationResult: AuthenticationResult;
|
||||
}
|
||||
|
||||
// Result type constants
|
||||
export const MFA_VERIFICATION_REQUIRED_RESULT_TYPE =
|
||||
"MfaVerificationRequiredResult";
|
||||
export const MFA_COMPLETED_RESULT_TYPE = "MfaCompletedResult";
|
||||
|
||||
export function createMfaVerificationRequiredResult(
|
||||
input: Omit<MfaVerificationRequiredResult, "type">
|
||||
): MfaVerificationRequiredResult {
|
||||
return {
|
||||
type: MFA_VERIFICATION_REQUIRED_RESULT_TYPE,
|
||||
...input,
|
||||
};
|
||||
}
|
||||
|
||||
export function createMfaCompletedResult(
|
||||
input: Omit<MfaCompletedResult, "type">
|
||||
): MfaCompletedResult {
|
||||
return {
|
||||
type: MFA_COMPLETED_RESULT_TYPE,
|
||||
...input,
|
||||
};
|
||||
}
|
||||
215
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/BaseApiClient.ts
generated
vendored
Normal file
215
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/BaseApiClient.ts
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ChallengeType,
|
||||
DefaultPackageInfo,
|
||||
HttpHeaderKeys,
|
||||
} from "../../../CustomAuthConstants.js";
|
||||
import { IHttpClient } from "../http_client/IHttpClient.js";
|
||||
import * as CustomAuthApiErrorCode from "./types/ApiErrorCodes.js";
|
||||
import { buildUrl, parseUrl } from "../../utils/UrlUtils.js";
|
||||
import {
|
||||
CustomAuthApiError,
|
||||
RedirectError,
|
||||
} from "../../error/CustomAuthApiError.js";
|
||||
import {
|
||||
AADServerParamKeys,
|
||||
Logger,
|
||||
ServerTelemetryManager,
|
||||
} from "@azure/msal-common/browser";
|
||||
import { ApiErrorResponse } from "./types/ApiErrorResponseTypes.js";
|
||||
import { CustomAuthRequestInterceptor } from "../../../configuration/CustomAuthRequestInterceptor.js";
|
||||
import { filterCustomHeaders } from "../../utils/CustomHeaderUtils.js";
|
||||
|
||||
export abstract class BaseApiClient {
|
||||
private readonly baseRequestUrl: URL;
|
||||
|
||||
constructor(
|
||||
baseUrl: string,
|
||||
private readonly clientId: string,
|
||||
private httpClient: IHttpClient,
|
||||
private customAuthApiQueryParams?: Record<string, string>,
|
||||
private requestInterceptor?: CustomAuthRequestInterceptor,
|
||||
private logger?: Logger
|
||||
) {
|
||||
this.baseRequestUrl = parseUrl(
|
||||
!baseUrl.endsWith("/") ? `${baseUrl}/` : baseUrl
|
||||
);
|
||||
}
|
||||
|
||||
protected async request<T>(
|
||||
endpoint: string,
|
||||
data: Record<string, string | boolean>,
|
||||
telemetryManager: ServerTelemetryManager,
|
||||
correlationId: string
|
||||
): Promise<T> {
|
||||
const formData = new URLSearchParams({
|
||||
client_id: this.clientId,
|
||||
...data,
|
||||
});
|
||||
const commonHeaders = this.getCommonHeaders(
|
||||
correlationId,
|
||||
telemetryManager
|
||||
);
|
||||
const url = buildUrl(
|
||||
this.baseRequestUrl.href,
|
||||
endpoint,
|
||||
this.customAuthApiQueryParams
|
||||
);
|
||||
|
||||
const additionalHeaders = await this.getAdditionalHeaders(
|
||||
url,
|
||||
correlationId
|
||||
);
|
||||
|
||||
const headers = { ...commonHeaders, ...additionalHeaders };
|
||||
|
||||
let response: Response;
|
||||
|
||||
try {
|
||||
response = await this.httpClient.post(url, formData, headers);
|
||||
} catch (e) {
|
||||
throw new CustomAuthApiError(
|
||||
CustomAuthApiErrorCode.HTTP_REQUEST_FAILED,
|
||||
`Failed to perform '${endpoint}' request: ${e}`,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
|
||||
return this.handleApiResponse(response, correlationId);
|
||||
}
|
||||
|
||||
protected ensureContinuationTokenIsValid(
|
||||
continuationToken: string | undefined,
|
||||
correlationId: string
|
||||
): void {
|
||||
if (!continuationToken) {
|
||||
throw new CustomAuthApiError(
|
||||
CustomAuthApiErrorCode.CONTINUATION_TOKEN_MISSING,
|
||||
"Continuation token is missing in the response body",
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private readResponseCorrelationId(
|
||||
response: Response,
|
||||
requestCorrelationId: string
|
||||
): string {
|
||||
return (
|
||||
response.headers.get(HttpHeaderKeys.X_MS_REQUEST_ID) ||
|
||||
requestCorrelationId
|
||||
);
|
||||
}
|
||||
|
||||
private getCommonHeaders(
|
||||
correlationId: string,
|
||||
telemetryManager: ServerTelemetryManager
|
||||
): Record<string, string> {
|
||||
return {
|
||||
[HttpHeaderKeys.CONTENT_TYPE]: "application/x-www-form-urlencoded",
|
||||
[AADServerParamKeys.X_CLIENT_SKU]: DefaultPackageInfo.SKU,
|
||||
[AADServerParamKeys.X_CLIENT_VER]: DefaultPackageInfo.VERSION,
|
||||
[AADServerParamKeys.X_CLIENT_OS]: DefaultPackageInfo.OS,
|
||||
[AADServerParamKeys.X_CLIENT_CPU]: DefaultPackageInfo.CPU,
|
||||
[AADServerParamKeys.X_CLIENT_CURR_TELEM]:
|
||||
telemetryManager.generateCurrentRequestHeaderValue(),
|
||||
[AADServerParamKeys.X_CLIENT_LAST_TELEM]:
|
||||
telemetryManager.generateLastRequestHeaderValue(),
|
||||
[AADServerParamKeys.CLIENT_REQUEST_ID]: correlationId,
|
||||
};
|
||||
}
|
||||
|
||||
private async handleApiResponse<T>(
|
||||
response: Response | undefined,
|
||||
requestCorrelationId: string
|
||||
): Promise<T> {
|
||||
if (!response) {
|
||||
throw new CustomAuthApiError(
|
||||
"empty_response",
|
||||
"Response is empty",
|
||||
requestCorrelationId
|
||||
);
|
||||
}
|
||||
|
||||
const correlationId = this.readResponseCorrelationId(
|
||||
response,
|
||||
requestCorrelationId
|
||||
);
|
||||
|
||||
const responseData = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
// Ensure the response doesn't have redirect challenge type
|
||||
if (
|
||||
typeof responseData === "object" &&
|
||||
responseData.challenge_type === ChallengeType.REDIRECT
|
||||
) {
|
||||
throw new RedirectError(
|
||||
correlationId,
|
||||
responseData.redirect_reason
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...responseData,
|
||||
correlation_id: correlationId,
|
||||
};
|
||||
}
|
||||
|
||||
const responseError = responseData as ApiErrorResponse;
|
||||
|
||||
if (!responseError) {
|
||||
throw new CustomAuthApiError(
|
||||
CustomAuthApiErrorCode.INVALID_RESPONSE_BODY,
|
||||
"Response error body is empty or invalid",
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
|
||||
const attributes =
|
||||
!!responseError.required_attributes &&
|
||||
responseError.required_attributes.length > 0
|
||||
? responseError.required_attributes
|
||||
: responseError.invalid_attributes ?? [];
|
||||
|
||||
throw new CustomAuthApiError(
|
||||
responseError.error,
|
||||
responseError.error_description,
|
||||
responseError.correlation_id,
|
||||
responseError.error_codes,
|
||||
responseError.suberror,
|
||||
attributes,
|
||||
responseError.continuation_token,
|
||||
responseError.trace_id,
|
||||
responseError.timestamp
|
||||
);
|
||||
}
|
||||
|
||||
private async getAdditionalHeaders(
|
||||
url: URL,
|
||||
correlationId: string
|
||||
): Promise<Record<string, string>> {
|
||||
if (!this.requestInterceptor) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await Promise.resolve(
|
||||
this.requestInterceptor.addAdditionalHeaderFields(url)
|
||||
);
|
||||
|
||||
return filterCustomHeaders(result, this.logger, correlationId);
|
||||
} catch (e) {
|
||||
this.logger?.warningPii(
|
||||
`CustomAuthRequestInterceptor.addAdditionalHeaderFields threw an error; continuing without additional headers: ${e}`,
|
||||
correlationId
|
||||
);
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
66
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/CustomAuthApiClient.ts
generated
vendored
Normal file
66
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/CustomAuthApiClient.ts
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { ResetPasswordApiClient } from "./ResetPasswordApiClient.js";
|
||||
import { SignupApiClient } from "./SignupApiClient.js";
|
||||
import { SignInApiClient } from "./SignInApiClient.js";
|
||||
import { RegisterApiClient } from "./RegisterApiClient.js";
|
||||
import { ICustomAuthApiClient } from "./ICustomAuthApiClient.js";
|
||||
import { IHttpClient } from "../http_client/IHttpClient.js";
|
||||
import { Logger } from "@azure/msal-common/browser";
|
||||
import { CustomAuthRequestInterceptor } from "../../../configuration/CustomAuthRequestInterceptor.js";
|
||||
|
||||
export class CustomAuthApiClient implements ICustomAuthApiClient {
|
||||
signInApi: SignInApiClient;
|
||||
signUpApi: SignupApiClient;
|
||||
resetPasswordApi: ResetPasswordApiClient;
|
||||
registerApi: RegisterApiClient;
|
||||
|
||||
constructor(
|
||||
customAuthApiBaseUrl: string,
|
||||
clientId: string,
|
||||
httpClient: IHttpClient,
|
||||
capabilities?: string,
|
||||
customAuthApiQueryParams?: Record<string, string>,
|
||||
requestInterceptor?: CustomAuthRequestInterceptor,
|
||||
logger?: Logger
|
||||
) {
|
||||
this.signInApi = new SignInApiClient(
|
||||
customAuthApiBaseUrl,
|
||||
clientId,
|
||||
httpClient,
|
||||
capabilities,
|
||||
customAuthApiQueryParams,
|
||||
requestInterceptor,
|
||||
logger
|
||||
);
|
||||
this.signUpApi = new SignupApiClient(
|
||||
customAuthApiBaseUrl,
|
||||
clientId,
|
||||
httpClient,
|
||||
capabilities,
|
||||
customAuthApiQueryParams,
|
||||
requestInterceptor,
|
||||
logger
|
||||
);
|
||||
this.resetPasswordApi = new ResetPasswordApiClient(
|
||||
customAuthApiBaseUrl,
|
||||
clientId,
|
||||
httpClient,
|
||||
capabilities,
|
||||
customAuthApiQueryParams,
|
||||
requestInterceptor,
|
||||
logger
|
||||
);
|
||||
this.registerApi = new RegisterApiClient(
|
||||
customAuthApiBaseUrl,
|
||||
clientId,
|
||||
httpClient,
|
||||
customAuthApiQueryParams,
|
||||
requestInterceptor,
|
||||
logger
|
||||
);
|
||||
}
|
||||
}
|
||||
23
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/CustomAuthApiEndpoint.ts
generated
vendored
Normal file
23
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/CustomAuthApiEndpoint.ts
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export const SIGNIN_INITIATE = "/oauth2/v2.0/initiate";
|
||||
export const SIGNIN_CHALLENGE = "/oauth2/v2.0/challenge";
|
||||
export const SIGNIN_TOKEN = "/oauth2/v2.0/token";
|
||||
export const SIGNIN_INTROSPECT = "/oauth2/v2.0/introspect";
|
||||
|
||||
export const SIGNUP_START = "/signup/v1.0/start";
|
||||
export const SIGNUP_CHALLENGE = "/signup/v1.0/challenge";
|
||||
export const SIGNUP_CONTINUE = "/signup/v1.0/continue";
|
||||
|
||||
export const RESET_PWD_START = "/resetpassword/v1.0/start";
|
||||
export const RESET_PWD_CHALLENGE = "/resetpassword/v1.0/challenge";
|
||||
export const RESET_PWD_CONTINUE = "/resetpassword/v1.0/continue";
|
||||
export const RESET_PWD_SUBMIT = "/resetpassword/v1.0/submit";
|
||||
export const RESET_PWD_POLL = "/resetpassword/v1.0/poll_completion";
|
||||
|
||||
export const REGISTER_INTROSPECT = "/register/v1.0/introspect";
|
||||
export const REGISTER_CHALLENGE = "/register/v1.0/challenge";
|
||||
export const REGISTER_CONTINUE = "/register/v1.0/continue";
|
||||
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/ICustomAuthApiClient.ts
generated
vendored
Normal file
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/ICustomAuthApiClient.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { ResetPasswordApiClient } from "./ResetPasswordApiClient.js";
|
||||
import { SignupApiClient } from "./SignupApiClient.js";
|
||||
import { SignInApiClient } from "./SignInApiClient.js";
|
||||
import { RegisterApiClient } from "./RegisterApiClient.js";
|
||||
export interface ICustomAuthApiClient {
|
||||
signInApi: SignInApiClient;
|
||||
signUpApi: SignupApiClient;
|
||||
resetPasswordApi: ResetPasswordApiClient;
|
||||
registerApi: RegisterApiClient;
|
||||
}
|
||||
95
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/RegisterApiClient.ts
generated
vendored
Normal file
95
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/RegisterApiClient.ts
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { BaseApiClient } from "./BaseApiClient.js";
|
||||
import * as CustomAuthApiEndpoint from "./CustomAuthApiEndpoint.js";
|
||||
import {
|
||||
RegisterIntrospectRequest,
|
||||
RegisterChallengeRequest,
|
||||
RegisterContinueRequest,
|
||||
} from "./types/ApiRequestTypes.js";
|
||||
import {
|
||||
RegisterIntrospectResponse,
|
||||
RegisterChallengeResponse,
|
||||
RegisterContinueResponse,
|
||||
} from "./types/ApiResponseTypes.js";
|
||||
|
||||
export class RegisterApiClient extends BaseApiClient {
|
||||
/**
|
||||
* Gets available authentication methods for registration
|
||||
*/
|
||||
async introspect(
|
||||
params: RegisterIntrospectRequest
|
||||
): Promise<RegisterIntrospectResponse> {
|
||||
const result = await this.request<RegisterIntrospectResponse>(
|
||||
CustomAuthApiEndpoint.REGISTER_INTROSPECT,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends challenge to specified authentication method
|
||||
*/
|
||||
async challenge(
|
||||
params: RegisterChallengeRequest
|
||||
): Promise<RegisterChallengeResponse> {
|
||||
const result = await this.request<RegisterChallengeResponse>(
|
||||
CustomAuthApiEndpoint.REGISTER_CHALLENGE,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
challenge_type: params.challenge_type,
|
||||
challenge_target: params.challenge_target,
|
||||
...(params.challenge_channel && {
|
||||
challenge_channel: params.challenge_channel,
|
||||
}),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits challenge response and continues registration
|
||||
*/
|
||||
async continue(
|
||||
params: RegisterContinueRequest
|
||||
): Promise<RegisterContinueResponse> {
|
||||
const result = await this.request<RegisterContinueResponse>(
|
||||
CustomAuthApiEndpoint.REGISTER_CONTINUE,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
grant_type: params.grant_type,
|
||||
...(params.oob && { oob: params.oob }),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
200
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/ResetPasswordApiClient.ts
generated
vendored
Normal file
200
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/ResetPasswordApiClient.ts
generated
vendored
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import {
|
||||
GrantType,
|
||||
ResetPasswordPollStatus,
|
||||
} from "../../../CustomAuthConstants.js";
|
||||
import { CustomAuthApiError } from "../../error/CustomAuthApiError.js";
|
||||
import { BaseApiClient } from "./BaseApiClient.js";
|
||||
import { IHttpClient } from "../http_client/IHttpClient.js";
|
||||
import { Logger } from "@azure/msal-common/browser";
|
||||
import * as CustomAuthApiEndpoint from "./CustomAuthApiEndpoint.js";
|
||||
import * as CustomAuthApiErrorCode from "./types/ApiErrorCodes.js";
|
||||
import {
|
||||
ResetPasswordChallengeRequest,
|
||||
ResetPasswordContinueRequest,
|
||||
ResetPasswordPollCompletionRequest,
|
||||
ResetPasswordStartRequest,
|
||||
ResetPasswordSubmitRequest,
|
||||
} from "./types/ApiRequestTypes.js";
|
||||
import {
|
||||
ResetPasswordChallengeResponse,
|
||||
ResetPasswordContinueResponse,
|
||||
ResetPasswordPollCompletionResponse,
|
||||
ResetPasswordStartResponse,
|
||||
ResetPasswordSubmitResponse,
|
||||
} from "./types/ApiResponseTypes.js";
|
||||
import { CustomAuthRequestInterceptor } from "../../../configuration/CustomAuthRequestInterceptor.js";
|
||||
|
||||
export class ResetPasswordApiClient extends BaseApiClient {
|
||||
private readonly capabilities?: string;
|
||||
|
||||
constructor(
|
||||
customAuthApiBaseUrl: string,
|
||||
clientId: string,
|
||||
httpClient: IHttpClient,
|
||||
capabilities?: string,
|
||||
customAuthApiQueryParams?: Record<string, string>,
|
||||
requestInterceptor?: CustomAuthRequestInterceptor,
|
||||
logger?: Logger
|
||||
) {
|
||||
super(
|
||||
customAuthApiBaseUrl,
|
||||
clientId,
|
||||
httpClient,
|
||||
customAuthApiQueryParams,
|
||||
requestInterceptor,
|
||||
logger
|
||||
);
|
||||
this.capabilities = capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the password reset flow
|
||||
*/
|
||||
async start(
|
||||
params: ResetPasswordStartRequest
|
||||
): Promise<ResetPasswordStartResponse> {
|
||||
const result = await this.request<ResetPasswordStartResponse>(
|
||||
CustomAuthApiEndpoint.RESET_PWD_START,
|
||||
{
|
||||
challenge_type: params.challenge_type,
|
||||
username: params.username,
|
||||
...(this.capabilities && {
|
||||
capabilities: this.capabilities,
|
||||
}),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a challenge (OTP) to be sent to the user's email
|
||||
* @param ChallengeResetPasswordRequest Parameters for the challenge request
|
||||
*/
|
||||
async requestChallenge(
|
||||
params: ResetPasswordChallengeRequest
|
||||
): Promise<ResetPasswordChallengeResponse> {
|
||||
const result = await this.request<ResetPasswordChallengeResponse>(
|
||||
CustomAuthApiEndpoint.RESET_PWD_CHALLENGE,
|
||||
{
|
||||
challenge_type: params.challenge_type,
|
||||
continuation_token: params.continuation_token,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the code for verification
|
||||
* @param ContinueResetPasswordRequest Token from previous response
|
||||
*/
|
||||
async continueWithCode(
|
||||
params: ResetPasswordContinueRequest
|
||||
): Promise<ResetPasswordContinueResponse> {
|
||||
const result = await this.request<ResetPasswordContinueResponse>(
|
||||
CustomAuthApiEndpoint.RESET_PWD_CONTINUE,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
grant_type: GrantType.OOB,
|
||||
oob: params.oob,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the new password
|
||||
* @param SubmitResetPasswordResponse Token from previous response
|
||||
*/
|
||||
async submitNewPassword(
|
||||
params: ResetPasswordSubmitRequest
|
||||
): Promise<ResetPasswordSubmitResponse> {
|
||||
const result = await this.request<ResetPasswordSubmitResponse>(
|
||||
CustomAuthApiEndpoint.RESET_PWD_SUBMIT,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
new_password: params.new_password,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
if (result.poll_interval === 0) {
|
||||
result.poll_interval = 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for password reset completion status
|
||||
* @param continuationToken Token from previous response
|
||||
*/
|
||||
async pollCompletion(
|
||||
params: ResetPasswordPollCompletionRequest
|
||||
): Promise<ResetPasswordPollCompletionResponse> {
|
||||
const result = await this.request<ResetPasswordPollCompletionResponse>(
|
||||
CustomAuthApiEndpoint.RESET_PWD_POLL,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensurePollStatusIsValid(result.status, params.correlationId);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected ensurePollStatusIsValid(
|
||||
status: string,
|
||||
correlationId: string
|
||||
): void {
|
||||
if (
|
||||
status !== ResetPasswordPollStatus.FAILED &&
|
||||
status !== ResetPasswordPollStatus.IN_PROGRESS &&
|
||||
status !== ResetPasswordPollStatus.SUCCEEDED &&
|
||||
status !== ResetPasswordPollStatus.NOT_STARTED
|
||||
) {
|
||||
throw new CustomAuthApiError(
|
||||
CustomAuthApiErrorCode.INVALID_POLL_STATUS,
|
||||
`The poll status '${status}' for password reset is invalid`,
|
||||
correlationId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
242
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/SignInApiClient.ts
generated
vendored
Normal file
242
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/SignInApiClient.ts
generated
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { Logger, ServerTelemetryManager } from "@azure/msal-common/browser";
|
||||
import { GrantType } from "../../../CustomAuthConstants.js";
|
||||
import { CustomAuthApiError } from "../../error/CustomAuthApiError.js";
|
||||
import { BaseApiClient } from "./BaseApiClient.js";
|
||||
import { IHttpClient } from "../http_client/IHttpClient.js";
|
||||
import * as CustomAuthApiEndpoint from "./CustomAuthApiEndpoint.js";
|
||||
import * as CustomAuthApiErrorCode from "./types/ApiErrorCodes.js";
|
||||
import {
|
||||
SignInChallengeRequest,
|
||||
SignInContinuationTokenRequest,
|
||||
SignInInitiateRequest,
|
||||
SignInIntrospectRequest,
|
||||
SignInOobTokenRequest,
|
||||
SignInPasswordTokenRequest,
|
||||
} from "./types/ApiRequestTypes.js";
|
||||
import {
|
||||
SignInChallengeResponse,
|
||||
SignInInitiateResponse,
|
||||
SignInIntrospectResponse,
|
||||
SignInTokenResponse,
|
||||
} from "./types/ApiResponseTypes.js";
|
||||
import { CustomAuthRequestInterceptor } from "../../../configuration/CustomAuthRequestInterceptor.js";
|
||||
|
||||
export class SignInApiClient extends BaseApiClient {
|
||||
private readonly capabilities?: string;
|
||||
|
||||
constructor(
|
||||
customAuthApiBaseUrl: string,
|
||||
clientId: string,
|
||||
httpClient: IHttpClient,
|
||||
capabilities?: string,
|
||||
customAuthApiQueryParams?: Record<string, string>,
|
||||
requestInterceptor?: CustomAuthRequestInterceptor,
|
||||
logger?: Logger
|
||||
) {
|
||||
super(
|
||||
customAuthApiBaseUrl,
|
||||
clientId,
|
||||
httpClient,
|
||||
customAuthApiQueryParams,
|
||||
requestInterceptor,
|
||||
logger
|
||||
);
|
||||
this.capabilities = capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the sign-in flow
|
||||
* @param username User's email
|
||||
* @param authMethod 'email-otp' | 'email-password'
|
||||
*/
|
||||
async initiate(
|
||||
params: SignInInitiateRequest
|
||||
): Promise<SignInInitiateResponse> {
|
||||
const result = await this.request<SignInInitiateResponse>(
|
||||
CustomAuthApiEndpoint.SIGNIN_INITIATE,
|
||||
{
|
||||
username: params.username,
|
||||
challenge_type: params.challenge_type,
|
||||
...(this.capabilities && {
|
||||
capabilities: this.capabilities,
|
||||
}),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests authentication challenge (OTP or password validation)
|
||||
* @param continuationToken Token from initiate response
|
||||
* @param authMethod 'email-otp' | 'email-password'
|
||||
*/
|
||||
async requestChallenge(
|
||||
params: SignInChallengeRequest
|
||||
): Promise<SignInChallengeResponse> {
|
||||
const result = await this.request<SignInChallengeResponse>(
|
||||
CustomAuthApiEndpoint.SIGNIN_CHALLENGE,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
challenge_type: params.challenge_type,
|
||||
...(params.id && { id: params.id }),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests security tokens using either password or OTP
|
||||
* @param continuationToken Token from challenge response
|
||||
* @param credentials Password or OTP
|
||||
* @param authMethod 'email-otp' | 'email-password'
|
||||
*/
|
||||
async requestTokensWithPassword(
|
||||
params: SignInPasswordTokenRequest
|
||||
): Promise<SignInTokenResponse> {
|
||||
return this.requestTokens(
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
grant_type: GrantType.PASSWORD,
|
||||
scope: params.scope,
|
||||
password: params.password,
|
||||
...(params.claims && { claims: params.claims }),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
}
|
||||
|
||||
async requestTokensWithOob(
|
||||
params: SignInOobTokenRequest
|
||||
): Promise<SignInTokenResponse> {
|
||||
return this.requestTokens(
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
scope: params.scope,
|
||||
oob: params.oob,
|
||||
grant_type: params.grant_type,
|
||||
...(params.claims && { claims: params.claims }),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
}
|
||||
|
||||
async requestTokenWithContinuationToken(
|
||||
params: SignInContinuationTokenRequest
|
||||
): Promise<SignInTokenResponse> {
|
||||
return this.requestTokens(
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
scope: params.scope,
|
||||
grant_type: GrantType.CONTINUATION_TOKEN,
|
||||
...(params.claims && { claims: params.claims }),
|
||||
...(params.username && { username: params.username }),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests available authentication methods for MFA
|
||||
* @param continuationToken Token from previous response
|
||||
*/
|
||||
async requestAuthMethods(
|
||||
params: SignInIntrospectRequest
|
||||
): Promise<SignInIntrospectResponse> {
|
||||
const result = await this.request<SignInIntrospectResponse>(
|
||||
CustomAuthApiEndpoint.SIGNIN_INTROSPECT,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async requestTokens(
|
||||
requestData: Record<string, string>,
|
||||
telemetryManager: ServerTelemetryManager,
|
||||
correlationId: string
|
||||
): Promise<SignInTokenResponse> {
|
||||
// The client_info parameter is required for MSAL to return the uid and utid in the response.
|
||||
requestData.client_info = "1";
|
||||
|
||||
const result = await this.request<SignInTokenResponse>(
|
||||
CustomAuthApiEndpoint.SIGNIN_TOKEN,
|
||||
requestData,
|
||||
telemetryManager,
|
||||
correlationId
|
||||
);
|
||||
|
||||
SignInApiClient.ensureTokenResponseIsValid(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ensureTokenResponseIsValid(
|
||||
tokenResponse: SignInTokenResponse
|
||||
): void {
|
||||
let errorCode = "";
|
||||
let errorDescription = "";
|
||||
|
||||
if (!tokenResponse.access_token) {
|
||||
errorCode = CustomAuthApiErrorCode.ACCESS_TOKEN_MISSING;
|
||||
errorDescription = "Access token is missing in the response body";
|
||||
} else if (!tokenResponse.id_token) {
|
||||
errorCode = CustomAuthApiErrorCode.ID_TOKEN_MISSING;
|
||||
errorDescription = "Id token is missing in the response body";
|
||||
} else if (!tokenResponse.refresh_token) {
|
||||
errorCode = CustomAuthApiErrorCode.REFRESH_TOKEN_MISSING;
|
||||
errorDescription = "Refresh token is missing in the response body";
|
||||
} else if (!tokenResponse.expires_in || tokenResponse.expires_in <= 0) {
|
||||
errorCode = CustomAuthApiErrorCode.INVALID_EXPIRES_IN;
|
||||
errorDescription = "Expires in is invalid in the response body";
|
||||
} else if (tokenResponse.token_type !== "Bearer") {
|
||||
errorCode = CustomAuthApiErrorCode.INVALID_TOKEN_TYPE;
|
||||
errorDescription = `Token type '${tokenResponse.token_type}' is invalid in the response body`;
|
||||
} else if (!tokenResponse.client_info) {
|
||||
errorCode = CustomAuthApiErrorCode.CLIENT_INFO_MISSING;
|
||||
errorDescription = "Client info is missing in the response body";
|
||||
}
|
||||
|
||||
if (!errorCode && !errorDescription) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new CustomAuthApiError(
|
||||
errorCode,
|
||||
errorDescription,
|
||||
tokenResponse.correlation_id
|
||||
);
|
||||
}
|
||||
}
|
||||
169
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/SignupApiClient.ts
generated
vendored
Normal file
169
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/SignupApiClient.ts
generated
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { GrantType } from "../../../CustomAuthConstants.js";
|
||||
import { BaseApiClient } from "./BaseApiClient.js";
|
||||
import { IHttpClient } from "../http_client/IHttpClient.js";
|
||||
import { Logger } from "@azure/msal-common/browser";
|
||||
import * as CustomAuthApiEndpoint from "./CustomAuthApiEndpoint.js";
|
||||
import {
|
||||
SignUpChallengeRequest,
|
||||
SignUpContinueWithAttributesRequest,
|
||||
SignUpContinueWithOobRequest,
|
||||
SignUpContinueWithPasswordRequest,
|
||||
SignUpStartRequest,
|
||||
} from "./types/ApiRequestTypes.js";
|
||||
import {
|
||||
SignUpChallengeResponse,
|
||||
SignUpContinueResponse,
|
||||
SignUpStartResponse,
|
||||
} from "./types/ApiResponseTypes.js";
|
||||
import { CustomAuthRequestInterceptor } from "../../../configuration/CustomAuthRequestInterceptor.js";
|
||||
|
||||
export class SignupApiClient extends BaseApiClient {
|
||||
private readonly capabilities?: string;
|
||||
|
||||
constructor(
|
||||
customAuthApiBaseUrl: string,
|
||||
clientId: string,
|
||||
httpClient: IHttpClient,
|
||||
capabilities?: string,
|
||||
customAuthApiQueryParams?: Record<string, string>,
|
||||
requestInterceptor?: CustomAuthRequestInterceptor,
|
||||
logger?: Logger
|
||||
) {
|
||||
super(
|
||||
customAuthApiBaseUrl,
|
||||
clientId,
|
||||
httpClient,
|
||||
customAuthApiQueryParams,
|
||||
requestInterceptor,
|
||||
logger
|
||||
);
|
||||
this.capabilities = capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the sign-up flow
|
||||
*/
|
||||
async start(params: SignUpStartRequest): Promise<SignUpStartResponse> {
|
||||
const result = await this.request<SignUpStartResponse>(
|
||||
CustomAuthApiEndpoint.SIGNUP_START,
|
||||
{
|
||||
username: params.username,
|
||||
...(params.password && { password: params.password }),
|
||||
...(params.attributes && {
|
||||
attributes: JSON.stringify(params.attributes),
|
||||
}),
|
||||
challenge_type: params.challenge_type,
|
||||
...(this.capabilities && {
|
||||
capabilities: this.capabilities,
|
||||
}),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request challenge (e.g., OTP)
|
||||
*/
|
||||
async requestChallenge(
|
||||
params: SignUpChallengeRequest
|
||||
): Promise<SignUpChallengeResponse> {
|
||||
const result = await this.request<SignUpChallengeResponse>(
|
||||
CustomAuthApiEndpoint.SIGNUP_CHALLENGE,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
challenge_type: params.challenge_type,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue sign-up flow with code.
|
||||
*/
|
||||
async continueWithCode(
|
||||
params: SignUpContinueWithOobRequest
|
||||
): Promise<SignUpContinueResponse> {
|
||||
const result = await this.request<SignUpContinueResponse>(
|
||||
CustomAuthApiEndpoint.SIGNUP_CONTINUE,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
grant_type: GrantType.OOB,
|
||||
oob: params.oob,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async continueWithPassword(
|
||||
params: SignUpContinueWithPasswordRequest
|
||||
): Promise<SignUpContinueResponse> {
|
||||
const result = await this.request<SignUpContinueResponse>(
|
||||
CustomAuthApiEndpoint.SIGNUP_CONTINUE,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
grant_type: GrantType.PASSWORD,
|
||||
password: params.password,
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async continueWithAttributes(
|
||||
params: SignUpContinueWithAttributesRequest
|
||||
): Promise<SignUpContinueResponse> {
|
||||
const result = await this.request<SignUpContinueResponse>(
|
||||
CustomAuthApiEndpoint.SIGNUP_CONTINUE,
|
||||
{
|
||||
continuation_token: params.continuation_token,
|
||||
grant_type: GrantType.ATTRIBUTES,
|
||||
attributes: JSON.stringify(params.attributes),
|
||||
},
|
||||
params.telemetryManager,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
this.ensureContinuationTokenIsValid(
|
||||
result.continuation_token,
|
||||
params.correlationId
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
27
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiErrorCodes.ts
generated
vendored
Normal file
27
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiErrorCodes.ts
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export const CONTINUATION_TOKEN_MISSING = "continuation_token_missing";
|
||||
export const INVALID_RESPONSE_BODY = "invalid_response_body";
|
||||
export const EMPTY_RESPONSE = "empty_response";
|
||||
export const UNSUPPORTED_CHALLENGE_TYPE = "unsupported_challenge_type";
|
||||
export const ACCESS_TOKEN_MISSING = "access_token_missing";
|
||||
export const ID_TOKEN_MISSING = "id_token_missing";
|
||||
export const REFRESH_TOKEN_MISSING = "refresh_token_missing";
|
||||
export const INVALID_EXPIRES_IN = "invalid_expires_in";
|
||||
export const INVALID_TOKEN_TYPE = "invalid_token_type";
|
||||
export const HTTP_REQUEST_FAILED = "http_request_failed";
|
||||
export const INVALID_REQUEST = "invalid_request";
|
||||
export const USER_NOT_FOUND = "user_not_found";
|
||||
export const INVALID_GRANT = "invalid_grant";
|
||||
export const CREDENTIAL_REQUIRED = "credential_required";
|
||||
export const ATTRIBUTES_REQUIRED = "attributes_required";
|
||||
export const USER_ALREADY_EXISTS = "user_already_exists";
|
||||
export const INVALID_POLL_STATUS = "invalid_poll_status";
|
||||
export const PASSWORD_CHANGE_FAILED = "password_change_failed";
|
||||
export const PASSWORD_RESET_TIMEOUT = "password_reset_timeout";
|
||||
export const CLIENT_INFO_MISSING = "client_info_missing";
|
||||
export const EXPIRED_TOKEN = "expired_token";
|
||||
export const ACCESS_DENIED = "access_denied";
|
||||
36
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiErrorResponseTypes.ts
generated
vendored
Normal file
36
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiErrorResponseTypes.ts
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export interface InvalidAttribute {
|
||||
name: string;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detailed error interface for Microsoft Entra signup errors
|
||||
*/
|
||||
export interface ApiErrorResponse {
|
||||
error: string;
|
||||
error_description: string;
|
||||
correlation_id: string;
|
||||
error_codes?: number[];
|
||||
suberror?: string;
|
||||
continuation_token?: string;
|
||||
timestamp?: string;
|
||||
trace_id?: string;
|
||||
required_attributes?: Array<UserAttribute>;
|
||||
invalid_attributes?: Array<UserAttribute>;
|
||||
}
|
||||
|
||||
export interface UserAttribute {
|
||||
name: string;
|
||||
type?: string;
|
||||
required?: boolean;
|
||||
options?: UserAttributeOption;
|
||||
}
|
||||
|
||||
export interface UserAttributeOption {
|
||||
regex?: string;
|
||||
}
|
||||
117
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiRequestTypes.ts
generated
vendored
Normal file
117
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiRequestTypes.ts
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { GrantType } from "../../../../CustomAuthConstants.js";
|
||||
import { ApiRequestBase } from "./ApiTypesBase.js";
|
||||
|
||||
/* Sign-in API request types */
|
||||
export interface SignInInitiateRequest extends ApiRequestBase {
|
||||
challenge_type: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface SignInChallengeRequest extends ApiRequestBase {
|
||||
challenge_type: string;
|
||||
continuation_token: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
interface SignInTokenRequestBase extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
scope: string;
|
||||
claims?: string;
|
||||
}
|
||||
|
||||
export interface SignInPasswordTokenRequest extends SignInTokenRequestBase {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface SignInOobTokenRequest extends SignInTokenRequestBase {
|
||||
oob: string;
|
||||
grant_type: typeof GrantType.OOB | typeof GrantType.MFA_OOB;
|
||||
}
|
||||
|
||||
export interface SignInContinuationTokenRequest extends SignInTokenRequestBase {
|
||||
username?: string;
|
||||
}
|
||||
|
||||
export interface SignInIntrospectRequest extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
}
|
||||
|
||||
/* Sign-up API request types */
|
||||
export interface SignUpStartRequest extends ApiRequestBase {
|
||||
username: string;
|
||||
challenge_type: string;
|
||||
password?: string;
|
||||
attributes?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface SignUpChallengeRequest extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
challenge_type: string;
|
||||
}
|
||||
|
||||
interface SignUpContinueRequestBase extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
}
|
||||
|
||||
export interface SignUpContinueWithOobRequest
|
||||
extends SignUpContinueRequestBase {
|
||||
oob: string;
|
||||
}
|
||||
|
||||
export interface SignUpContinueWithPasswordRequest
|
||||
extends SignUpContinueRequestBase {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface SignUpContinueWithAttributesRequest
|
||||
extends SignUpContinueRequestBase {
|
||||
attributes: Record<string, string>;
|
||||
}
|
||||
|
||||
/* Reset password API request types */
|
||||
export interface ResetPasswordStartRequest extends ApiRequestBase {
|
||||
challenge_type: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface ResetPasswordChallengeRequest extends ApiRequestBase {
|
||||
challenge_type: string;
|
||||
continuation_token: string;
|
||||
}
|
||||
|
||||
export interface ResetPasswordContinueRequest extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
oob: string;
|
||||
}
|
||||
|
||||
export interface ResetPasswordSubmitRequest extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
new_password: string;
|
||||
}
|
||||
|
||||
export interface ResetPasswordPollCompletionRequest extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
}
|
||||
|
||||
/* Register API request types */
|
||||
export interface RegisterIntrospectRequest extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
}
|
||||
|
||||
export interface RegisterChallengeRequest extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
challenge_type: string;
|
||||
challenge_target: string;
|
||||
challenge_channel?: string;
|
||||
}
|
||||
|
||||
export interface RegisterContinueRequest extends ApiRequestBase {
|
||||
continuation_token: string;
|
||||
grant_type: string;
|
||||
oob?: string;
|
||||
}
|
||||
98
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiResponseTypes.ts
generated
vendored
Normal file
98
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiResponseTypes.ts
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { ApiResponseBase } from "./ApiTypesBase.js";
|
||||
|
||||
interface ContinuousResponse extends ApiResponseBase {
|
||||
continuation_token?: string;
|
||||
}
|
||||
|
||||
interface InitiateResponse extends ContinuousResponse {
|
||||
challenge_type?: string;
|
||||
}
|
||||
|
||||
interface ChallengeResponse extends ApiResponseBase {
|
||||
continuation_token?: string;
|
||||
challenge_type?: string;
|
||||
binding_method?: string;
|
||||
challenge_channel?: string;
|
||||
challenge_target_label?: string;
|
||||
code_length?: number;
|
||||
}
|
||||
|
||||
/* Sign-in API response types */
|
||||
export type SignInInitiateResponse = InitiateResponse;
|
||||
|
||||
export type SignInChallengeResponse = ChallengeResponse;
|
||||
|
||||
export interface SignInTokenResponse extends ApiResponseBase {
|
||||
token_type: "Bearer";
|
||||
scope: string;
|
||||
expires_in: number;
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
id_token: string;
|
||||
client_info: string;
|
||||
ext_expires_in?: number;
|
||||
}
|
||||
|
||||
export interface AuthenticationMethod {
|
||||
id: string;
|
||||
challenge_type: string;
|
||||
challenge_channel: string;
|
||||
login_hint?: string;
|
||||
}
|
||||
|
||||
export interface SignInIntrospectResponse extends ApiResponseBase {
|
||||
continuation_token: string;
|
||||
methods: AuthenticationMethod[];
|
||||
}
|
||||
|
||||
/* Sign-up API response types */
|
||||
export type SignUpStartResponse = InitiateResponse;
|
||||
|
||||
export interface SignUpChallengeResponse extends ChallengeResponse {
|
||||
interval?: number;
|
||||
}
|
||||
|
||||
export type SignUpContinueResponse = InitiateResponse;
|
||||
|
||||
/* Reset password API response types */
|
||||
export type ResetPasswordStartResponse = InitiateResponse;
|
||||
|
||||
export type ResetPasswordChallengeResponse = ChallengeResponse;
|
||||
|
||||
export interface ResetPasswordContinueResponse extends ContinuousResponse {
|
||||
expires_in: number;
|
||||
}
|
||||
|
||||
export interface ResetPasswordSubmitResponse extends ContinuousResponse {
|
||||
poll_interval: number;
|
||||
}
|
||||
|
||||
export interface ResetPasswordPollCompletionResponse
|
||||
extends ContinuousResponse {
|
||||
status: string;
|
||||
}
|
||||
|
||||
/* Register API response types */
|
||||
export interface RegisterIntrospectResponse extends ApiResponseBase {
|
||||
continuation_token: string;
|
||||
methods: AuthenticationMethod[];
|
||||
}
|
||||
|
||||
export interface RegisterChallengeResponse extends ApiResponseBase {
|
||||
continuation_token: string;
|
||||
challenge_type: string;
|
||||
binding_method: string;
|
||||
challenge_target: string;
|
||||
challenge_channel: string;
|
||||
code_length?: number;
|
||||
interval?: number;
|
||||
}
|
||||
|
||||
export interface RegisterContinueResponse extends ApiResponseBase {
|
||||
continuation_token: string;
|
||||
}
|
||||
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiSuberrors.ts
generated
vendored
Normal file
17
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiSuberrors.ts
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export const PASSWORD_TOO_WEAK = "password_too_weak";
|
||||
export const PASSWORD_TOO_SHORT = "password_too_short";
|
||||
export const PASSWORD_TOO_LONG = "password_too_long";
|
||||
export const PASSWORD_RECENTLY_USED = "password_recently_used";
|
||||
export const PASSWORD_BANNED = "password_banned";
|
||||
export const PASSWORD_IS_INVALID = "password_is_invalid";
|
||||
export const INVALID_OOB_VALUE = "invalid_oob_value";
|
||||
export const ATTRIBUTE_VALIATION_FAILED = "attribute_validation_failed";
|
||||
export const NATIVEAUTHAPI_DISABLED = "nativeauthapi_disabled";
|
||||
export const REGISTRATION_REQUIRED = "registration_required";
|
||||
export const MFA_REQUIRED = "mfa_required";
|
||||
export const PROVIDER_BLOCKED_BY_REPUTATION = "provider_blocked_by_rep";
|
||||
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiTypesBase.ts
generated
vendored
Normal file
15
backend/node_modules/@azure/msal-browser/src/custom_auth/core/network_client/custom_auth_api/types/ApiTypesBase.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { ServerTelemetryManager } from "@azure/msal-common/browser";
|
||||
|
||||
export type ApiRequestBase = {
|
||||
correlationId: string;
|
||||
telemetryManager: ServerTelemetryManager;
|
||||
};
|
||||
|
||||
export type ApiResponseBase = {
|
||||
correlation_id: string;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user