diff --git a/extensions/microsoft-authentication/src/common/env.ts b/extensions/microsoft-authentication/src/common/env.ts index 5d19183e70c..9460a27d2fe 100644 --- a/extensions/microsoft-authentication/src/common/env.ts +++ b/extensions/microsoft-authentication/src/common/env.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Uri } from 'vscode'; +export const DEFAULT_REDIRECT_URI = 'https://vscode.dev/redirect'; + const VALID_DESKTOP_CALLBACK_SCHEMES = [ 'vscode', 'vscode-insiders', diff --git a/extensions/microsoft-authentication/src/common/publicClientCache.ts b/extensions/microsoft-authentication/src/common/publicClientCache.ts index e1df0d5db82..dfbca6b5057 100644 --- a/extensions/microsoft-authentication/src/common/publicClientCache.ts +++ b/extensions/microsoft-authentication/src/common/publicClientCache.ts @@ -19,6 +19,6 @@ export interface ICachedPublicClientApplication { export interface ICachedPublicClientApplicationManager { onDidAccountsChange: Event<{ added: AccountInfo[]; changed: AccountInfo[]; deleted: AccountInfo[] }>; - getOrCreate(clientId: string, refreshTokensToMigrate?: string[]): Promise; + getOrCreate(clientId: string, migrate?: { refreshTokensToMigrate?: string[]; tenant: string }): Promise; getAll(): ICachedPublicClientApplication[]; } diff --git a/extensions/microsoft-authentication/src/node/authProvider.ts b/extensions/microsoft-authentication/src/node/authProvider.ts index 16d96e2bfad..f9f9cb5606b 100644 --- a/extensions/microsoft-authentication/src/node/authProvider.ts +++ b/extensions/microsoft-authentication/src/node/authProvider.ts @@ -15,8 +15,9 @@ import { BetterTokenStorage } from '../betterSecretStorage'; import { IStoredSession } from '../AADHelper'; import { ExtensionHost, getMsalFlows } from './flows'; import { base64Decode } from './buffer'; +import { Config } from '../common/config'; +import { DEFAULT_REDIRECT_URI } from '../common/env'; -const redirectUri = 'https://vscode.dev/redirect'; const MSA_TID = '9188040d-6c67-4c5b-b112-36a304b66dad'; const MSA_PASSTHRU_TID = 'f8cdef31-a31e-4b4a-93e4-5f571e91255a'; @@ -87,7 +88,7 @@ export class MsalAuthProvider implements AuthenticationProvider { uriHandler: UriEventHandler, env: Environment = Environment.AzureCloud ): Promise { - const publicClientManager = await CachedPublicClientApplicationManager.create(context.secrets, logger, telemetryReporter, env.name); + const publicClientManager = await CachedPublicClientApplicationManager.create(context.secrets, logger, telemetryReporter, env); context.subscriptions.push(publicClientManager); const authProvider = new MsalAuthProvider(context, telemetryReporter, logger, uriHandler, publicClientManager, env); await authProvider.initialize(); @@ -117,8 +118,8 @@ export class MsalAuthProvider implements AuthenticationProvider { clientTenantMap.get(key)!.refreshTokens.push(session.refreshToken); } - for (const { clientId, refreshTokens } of clientTenantMap.values()) { - await this._publicClientManager.getOrCreate(clientId, refreshTokens); + for (const { clientId, tenant, refreshTokens } of clientTenantMap.values()) { + await this._publicClientManager.getOrCreate(clientId, { refreshTokensToMigrate: refreshTokens, tenant }); } } @@ -483,6 +484,10 @@ export class MsalAuthProvider implements AuthenticationProvider { forceRefresh = true; claims = scopeData.claims; } + let redirectUri = DEFAULT_REDIRECT_URI; + if (cachedPca.isBrokerAvailable && process.platform === 'darwin') { + redirectUri = Config.macOSBrokerRedirectUri; + } const result = await cachedPca.acquireTokenSilent({ account, authority, diff --git a/extensions/microsoft-authentication/src/node/publicClientCache.ts b/extensions/microsoft-authentication/src/node/publicClientCache.ts index 728b89d1ecc..bea0ccf7241 100644 --- a/extensions/microsoft-authentication/src/node/publicClientCache.ts +++ b/extensions/microsoft-authentication/src/node/publicClientCache.ts @@ -9,6 +9,9 @@ import { ICachedPublicClientApplication, ICachedPublicClientApplicationManager } import { CachedPublicClientApplication } from './cachedPublicClientApplication'; import { IAccountAccess, ScopedAccountAccess } from '../common/accountAccess'; import { MicrosoftAuthenticationTelemetryReporter } from '../common/telemetryReporter'; +import { Environment } from '@azure/ms-rest-azure-env'; +import { Config } from '../common/config'; +import { DEFAULT_REDIRECT_URI } from '../common/env'; export interface IPublicClientApplicationInfo { clientId: string; @@ -26,6 +29,7 @@ export class CachedPublicClientApplicationManager implements ICachedPublicClient readonly onDidAccountsChange = this._onDidAccountsChangeEmitter.event; private constructor( + private readonly _env: Environment, private readonly _pcasSecretStorage: IPublicClientApplicationSecretStorage, private readonly _accountAccess: IAccountAccess, private readonly _secretStorage: SecretStorage, @@ -44,13 +48,13 @@ export class CachedPublicClientApplicationManager implements ICachedPublicClient secretStorage: SecretStorage, logger: LogOutputChannel, telemetryReporter: MicrosoftAuthenticationTelemetryReporter, - cloudName: string + env: Environment ): Promise { - const pcasSecretStorage = await PublicClientApplicationsSecretStorage.create(secretStorage, cloudName); + const pcasSecretStorage = await PublicClientApplicationsSecretStorage.create(secretStorage, env.name); // TODO: Remove the migrations in a version const migrations = await pcasSecretStorage.getOldValue(); - const accountAccess = await ScopedAccountAccess.create(secretStorage, cloudName, logger, migrations); - const manager = new CachedPublicClientApplicationManager(pcasSecretStorage, accountAccess, secretStorage, logger, telemetryReporter, [pcasSecretStorage, accountAccess]); + const accountAccess = await ScopedAccountAccess.create(secretStorage, env.name, logger, migrations); + const manager = new CachedPublicClientApplicationManager(env, pcasSecretStorage, accountAccess, secretStorage, logger, telemetryReporter, [pcasSecretStorage, accountAccess]); await manager.initialize(); return manager; } @@ -110,7 +114,7 @@ export class CachedPublicClientApplicationManager implements ICachedPublicClient Disposable.from(...this._pcaDisposables.values()).dispose(); } - async getOrCreate(clientId: string, refreshTokensToMigrate?: string[]): Promise { + async getOrCreate(clientId: string, migrate?: { refreshTokensToMigrate?: string[]; tenant: string }): Promise { let pca = this._pcas.get(clientId); if (pca) { this._logger.debug(`[getOrCreate] [${clientId}] PublicClientApplicationManager cache hit`); @@ -122,13 +126,24 @@ export class CachedPublicClientApplicationManager implements ICachedPublicClient } // TODO: MSAL Migration. Remove this when we remove the old flow. - if (refreshTokensToMigrate?.length) { + if (migrate?.refreshTokensToMigrate?.length) { this._logger.debug(`[getOrCreate] [${clientId}] Migrating refresh tokens to PCA...`); - for (const refreshToken of refreshTokensToMigrate) { + const authority = new URL(migrate.tenant, this._env.activeDirectoryEndpointUrl).toString(); + let redirectUri = DEFAULT_REDIRECT_URI; + if (pca.isBrokerAvailable && process.platform === 'darwin') { + redirectUri = Config.macOSBrokerRedirectUri; + } + for (const refreshToken of migrate.refreshTokensToMigrate) { try { // Use the refresh token to acquire a result. This will cache the refresh token for future operations. // The scopes don't matter here since we can create any token from the refresh token. - const result = await pca.acquireTokenByRefreshToken({ refreshToken, forceCache: true, scopes: [] }); + const result = await pca.acquireTokenByRefreshToken({ + refreshToken, + forceCache: true, + scopes: [], + authority, + redirectUri + }); if (result?.account) { this._logger.debug(`[getOrCreate] [${clientId}] Refresh token migrated to PCA.`); }