diff --git a/extensions/vscode-account/src/AADHelper.ts b/extensions/vscode-account/src/AADHelper.ts index a3295762d0c..cc48d464af8 100644 --- a/extensions/vscode-account/src/AADHelper.ts +++ b/extensions/vscode-account/src/AADHelper.ts @@ -175,7 +175,7 @@ export class AzureActiveDirectoryService { private convertToSession(token: IToken): vscode.AuthenticationSession { return { id: token.sessionId, - accessToken: token.accessToken, + accessToken: () => Promise.resolve(token.accessToken), accountName: token.accountName, scopes: token.scope.split(' ') }; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 5211de85bbc..6e6fbc7bcaa 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1340,7 +1340,7 @@ export interface RenameProvider { */ export interface AuthenticationSession { id: string; - accessToken: string; + accessToken(): Promise; accountName: string; } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 4aea3fcfb69..01597736559 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -20,7 +20,7 @@ declare module 'vscode' { export interface AuthenticationSession { id: string; - accessToken: string; + accessToken(): Promise; accountName: string; scopes: string[] } diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index 8dbf1647508..a42cd3fac41 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -20,8 +20,14 @@ export class MainThreadAuthenticationProvider { public readonly displayName: string ) { } - getSessions(): Promise> { - return this._proxy.$getSessions(this.id); + async getSessions(): Promise> { + return (await this._proxy.$getSessions(this.id)).map(session => { + return { + id: session.id, + accountName: session.accountName, + accessToken: () => this._proxy.$getSessionAccessToken(this.id, session.id) + }; + }); } login(scopes: string[]): Promise { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 3f2b846d933..1230e9858fb 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -919,6 +919,7 @@ export interface ExtHostLabelServiceShape { export interface ExtHostAuthenticationShape { $getSessions(id: string): Promise>; + $getSessionAccessToken(id: string, sessionId: string): Promise; $login(id: string, scopes: string[]): Promise; $logout(id: string, sessionId: string): Promise; } diff --git a/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts index 324a3bfbb7b..2d843c1a522 100644 --- a/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -29,12 +29,26 @@ export class AuthenticationProviderWrapper implements vscode.AuthenticationProvi } async getSessions(): Promise> { - const isAllowed = await this._proxy.$getSessionsPrompt(this._provider.id, this.displayName, ExtensionIdentifier.toKey(this._requestingExtension.identifier), this._requestingExtension.displayName || this._requestingExtension.name); - if (!isAllowed) { - throw new Error('User did not consent to session access.'); - } + return (await this._provider.getSessions()).map(session => { + return { + id: session.id, + accountName: session.accountName, + scopes: session.scopes, + accessToken: async () => { + const isAllowed = await this._proxy.$getSessionsPrompt( + this._provider.id, + this.displayName, + ExtensionIdentifier.toKey(this._requestingExtension.identifier), + this._requestingExtension.displayName || this._requestingExtension.name); - return this._provider.getSessions(); + if (!isAllowed) { + throw new Error('User did not consent to token access.'); + } + + return session.accessToken(); + } + }; + }); } async login(scopes: string[]): Promise { @@ -96,7 +110,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { return Promise.resolve(authProvider.login(scopes)); } - throw new Error(`Unable to find authentication provider with handle: ${0}`); + throw new Error(`Unable to find authentication provider with handle: ${providerId}`); } $logout(providerId: string, sessionId: string): Promise { @@ -105,7 +119,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { return Promise.resolve(authProvider.logout(sessionId)); } - throw new Error(`Unable to find authentication provider with handle: ${0}`); + throw new Error(`Unable to find authentication provider with handle: ${providerId}`); } $getSessions(providerId: string): Promise> { @@ -114,6 +128,21 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { return Promise.resolve(authProvider.getSessions()); } - throw new Error(`Unable to find authentication provider with handle: ${0}`); + throw new Error(`Unable to find authentication provider with handle: ${providerId}`); + } + + async $getSessionAccessToken(providerId: string, sessionId: string): Promise { + const authProvider = this._authenticationProviders.get(providerId); + if (authProvider) { + const sessions = await authProvider.getSessions(); + const session = sessions.find(session => session.id === sessionId); + if (session) { + return session.accessToken(); + } + + throw new Error(`Unable to find session with id: ${sessionId}`); + } + + throw new Error(`Unable to find authentication provider with handle: ${providerId}`); } } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 322eda165cf..4ac7696f9b4 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -135,13 +135,13 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } if (sessions.length === 0) { - this.activeAccount = undefined; + this.setActiveAccount(undefined); return; } if (sessions.length === 1) { this.logAuthenticatedEvent(sessions[0]); - this.activeAccount = sessions[0]; + this.setActiveAccount(sessions[0]); return; } @@ -155,7 +155,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo if (selectedAccount) { const selected = sessions.filter(account => selectedAccount.id === account.id)[0]; this.logAuthenticatedEvent(selected); - this.activeAccount = selected; + this.setActiveAccount(selected); } } @@ -176,11 +176,12 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo return this._activeAccount; } - set activeAccount(account: AuthenticationSession | undefined) { + async setActiveAccount(account: AuthenticationSession | undefined) { this._activeAccount = account; if (account) { - this.userDataAuthTokenService.setToken(account.accessToken); + const token = await account.accessToken(); + this.userDataAuthTokenService.setToken(token); this.authenticationState.set(AuthStatus.SignedIn); } else { this.userDataAuthTokenService.setToken(undefined); @@ -196,7 +197,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo // Try to update existing account, case where access token has been refreshed const accounts = (await this.authenticationService.getSessions(this.userDataSyncStore!.authenticationProviderId) || []); const matchingAccount = accounts.filter(a => a.id === this.activeAccount?.id)[0]; - this.activeAccount = matchingAccount; + this.setActiveAccount(matchingAccount); } else { this.initializeActiveAccount(); } @@ -211,7 +212,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo private onDidUnregisterAuthenticationProvider(providerId: string) { if (providerId === this.userDataSyncStore!.authenticationProviderId) { - this.activeAccount = undefined; + this.setActiveAccount(undefined); this.authenticationState.reset(); } } @@ -477,7 +478,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo private async signIn(): Promise { try { - this.activeAccount = await this.authenticationService.login(this.userDataSyncStore!.authenticationProviderId, ['https://management.core.windows.net/.default', 'offline_access']); + this.setActiveAccount(await this.authenticationService.login(this.userDataSyncStore!.authenticationProviderId, ['https://management.core.windows.net/.default', 'offline_access'])); } catch (e) { this.notificationService.error(e); throw e; @@ -487,7 +488,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo private async signOut(): Promise { if (this.activeAccount) { await this.authenticationService.logout(this.userDataSyncStore!.authenticationProviderId, this.activeAccount.id); - this.activeAccount = undefined; + this.setActiveAccount(undefined); } }