Path: blob/main/extensions/microsoft-authentication/src/node/flows.ts
3320 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { AuthenticationResult } from '@azure/msal-node';6import { Uri, LogOutputChannel, env } from 'vscode';7import { ICachedPublicClientApplication } from '../common/publicClientCache';8import { UriHandlerLoopbackClient } from '../common/loopbackClientAndOpener';9import { UriEventHandler } from '../UriEventHandler';10import { loopbackTemplate } from './loopbackTemplate';11import { Config } from '../common/config';1213const DEFAULT_REDIRECT_URI = 'https://vscode.dev/redirect';1415export const enum ExtensionHost {16WebWorker,17Remote,18Local19}2021interface IMsalFlowOptions {22supportsRemoteExtensionHost: boolean;23supportsWebWorkerExtensionHost: boolean;24}2526interface IMsalFlowTriggerOptions {27cachedPca: ICachedPublicClientApplication;28authority: string;29scopes: string[];30loginHint?: string;31windowHandle?: Buffer;32logger: LogOutputChannel;33uriHandler: UriEventHandler;34claims?: string;35}3637interface IMsalFlow {38readonly label: string;39readonly options: IMsalFlowOptions;40trigger(options: IMsalFlowTriggerOptions): Promise<AuthenticationResult>;41}4243class DefaultLoopbackFlow implements IMsalFlow {44label = 'default';45options: IMsalFlowOptions = {46supportsRemoteExtensionHost: false,47supportsWebWorkerExtensionHost: false48};4950async trigger({ cachedPca, authority, scopes, claims, loginHint, windowHandle, logger }: IMsalFlowTriggerOptions): Promise<AuthenticationResult> {51logger.info('Trying default msal flow...');52let redirectUri: string | undefined;53if (cachedPca.isBrokerAvailable && process.platform === 'darwin') {54redirectUri = Config.macOSBrokerRedirectUri;55}56return await cachedPca.acquireTokenInteractive({57openBrowser: async (url: string) => { await env.openExternal(Uri.parse(url)); },58scopes,59authority,60successTemplate: loopbackTemplate,61errorTemplate: loopbackTemplate,62loginHint,63prompt: loginHint ? undefined : 'select_account',64windowHandle,65claims,66});67}68}6970class UrlHandlerFlow implements IMsalFlow {71label = 'protocol handler';72options: IMsalFlowOptions = {73supportsRemoteExtensionHost: true,74supportsWebWorkerExtensionHost: false75};7677async trigger({ cachedPca, authority, scopes, claims, loginHint, windowHandle, logger, uriHandler }: IMsalFlowTriggerOptions): Promise<AuthenticationResult> {78logger.info('Trying protocol handler flow...');79const loopbackClient = new UriHandlerLoopbackClient(uriHandler, DEFAULT_REDIRECT_URI, logger);80let redirectUri: string | undefined;81if (cachedPca.isBrokerAvailable && process.platform === 'darwin') {82redirectUri = Config.macOSBrokerRedirectUri;83}84return await cachedPca.acquireTokenInteractive({85openBrowser: (url: string) => loopbackClient.openBrowser(url),86scopes,87authority,88loopbackClient,89loginHint,90prompt: loginHint ? undefined : 'select_account',91windowHandle,92claims,93});94}95}9697const allFlows: IMsalFlow[] = [98new DefaultLoopbackFlow(),99new UrlHandlerFlow()100];101102export interface IMsalFlowQuery {103extensionHost: ExtensionHost;104isBrokerSupported: boolean;105}106107export function getMsalFlows(query: IMsalFlowQuery): IMsalFlow[] {108const flows = [];109for (const flow of allFlows) {110let useFlow: boolean = true;111switch (query.extensionHost) {112case ExtensionHost.Remote:113useFlow &&= flow.options.supportsRemoteExtensionHost;114break;115case ExtensionHost.WebWorker:116useFlow &&= flow.options.supportsWebWorkerExtensionHost;117break;118}119if (useFlow) {120flows.push(flow);121if (query.isBrokerSupported) {122// If broker is supported, only use the first valid flow123return flows;124}125}126}127return flows;128}129130131