Estructura inicial del proyecto
This commit is contained in:
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;
|
||||
};
|
||||
Reference in New Issue
Block a user