mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-24 12:19:20 +00:00
Move 'incorrect account' handling into core (#224872)
So that all auth providers can take advantage of this logic. This basically will do a light enforcement that the account you signed in to matches the account that was requested (if it was specified). This is needed for finalization.
This commit is contained in:
committed by
GitHub
parent
02b638ae27
commit
04bcb01ddf
@@ -11,7 +11,7 @@ import { PromiseAdapter, arrayEquals, promiseFromEvent } from './common/utils';
|
||||
import { ExperimentationTelemetry } from './common/experimentationService';
|
||||
import { Log } from './common/logger';
|
||||
import { crypto } from './node/crypto';
|
||||
import { CANCELLATION_ERROR, TIMED_OUT_ERROR, USER_CANCELLATION_ERROR } from './common/errors';
|
||||
import { TIMED_OUT_ERROR, USER_CANCELLATION_ERROR } from './common/errors';
|
||||
|
||||
interface SessionData {
|
||||
id: string;
|
||||
@@ -316,39 +316,13 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid
|
||||
|
||||
const sessions = await this._sessionsPromise;
|
||||
|
||||
const forcedLogin = options?.account?.label;
|
||||
const backupLogin = sessions[0]?.account.label;
|
||||
this._logger.info(`Logging in with '${forcedLogin ? forcedLogin : 'any'}' account...`);
|
||||
// First we use the account specified in the options, otherwise we use the first account we have to seed auth.
|
||||
const loginWith = options?.account?.label ?? sessions[0]?.account.label;
|
||||
this._logger.info(`Logging in with '${loginWith ? loginWith : 'any'}' account...`);
|
||||
|
||||
const scopeString = sortedScopes.join(' ');
|
||||
const token = await this._githubServer.login(scopeString, forcedLogin ?? backupLogin);
|
||||
const token = await this._githubServer.login(scopeString, loginWith);
|
||||
const session = await this.tokenToSession(token, scopes);
|
||||
|
||||
// If an account was specified, we should ensure that the token we got back is for that account.
|
||||
if (forcedLogin) {
|
||||
if (session.account.label !== forcedLogin) {
|
||||
const keepNewAccount = vscode.l10n.t('Keep {0}', session.account.label);
|
||||
const tryAgain = vscode.l10n.t('Login with {0}', forcedLogin);
|
||||
const result = await vscode.window.showWarningMessage(
|
||||
vscode.l10n.t('Incorrect account detected'),
|
||||
{ modal: true, detail: vscode.l10n.t('The chosen account, {0}, does not match the requested account, {1}.', session.account.label, forcedLogin) },
|
||||
keepNewAccount,
|
||||
tryAgain
|
||||
);
|
||||
if (result === tryAgain) {
|
||||
return await this.createSession(scopes, {
|
||||
...options,
|
||||
// The id doesn't matter here, we just need to pass the label through
|
||||
account: { id: forcedLogin, label: forcedLogin }
|
||||
});
|
||||
}
|
||||
// Cancelled result
|
||||
if (!result) {
|
||||
throw new Error(CANCELLATION_ERROR);
|
||||
}
|
||||
// Keep result continues on
|
||||
}
|
||||
}
|
||||
this.afterSessionLoad(session);
|
||||
|
||||
const sessionIndex = sessions.findIndex(
|
||||
|
||||
@@ -19,6 +19,7 @@ import { IAuthenticationUsageService } from 'vs/workbench/services/authenticatio
|
||||
import { getAuthenticationProviderActivationEvent } from 'vs/workbench/services/authentication/browser/authenticationService';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { CancellationError } from 'vs/base/common/errors';
|
||||
|
||||
interface AuthenticationForceNewSessionOptions {
|
||||
detail?: string;
|
||||
@@ -159,6 +160,31 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
private async continueWithIncorrectAccountPrompt(chosenAccountLabel: string, requestedAccountLabel: string): Promise<boolean> {
|
||||
const result = await this.dialogService.prompt({
|
||||
message: nls.localize('incorrectAccount', "Incorrect account detected"),
|
||||
detail: nls.localize('incorrectAccountDetail', "The chosen account, {0}, does not match the requested account, {1}.", chosenAccountLabel, requestedAccountLabel),
|
||||
type: Severity.Warning,
|
||||
cancelButton: true,
|
||||
buttons: [
|
||||
{
|
||||
label: nls.localize('keep', 'Keep {0}', chosenAccountLabel),
|
||||
run: () => chosenAccountLabel
|
||||
},
|
||||
{
|
||||
label: nls.localize('loginWith', 'Login with {0}', requestedAccountLabel),
|
||||
run: () => requestedAccountLabel
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
if (!result.result) {
|
||||
throw new CancellationError();
|
||||
}
|
||||
|
||||
return result.result === chosenAccountLabel;
|
||||
}
|
||||
|
||||
private async doGetSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: AuthenticationGetSessionOptions): Promise<AuthenticationSession | undefined> {
|
||||
const sessions = await this.authenticationService.getSessions(providerId, scopes, options.account, true);
|
||||
const provider = this.authenticationService.getProvider(providerId);
|
||||
@@ -212,18 +238,25 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
throw new Error('User did not consent to login.');
|
||||
}
|
||||
|
||||
let session;
|
||||
let session: AuthenticationSession;
|
||||
if (sessions?.length && !options.forceNewSession) {
|
||||
session = provider.supportsMultipleAccounts && !options.account
|
||||
? await this.authenticationExtensionsService.selectSession(providerId, extensionId, extensionName, scopes, sessions)
|
||||
: sessions[0];
|
||||
} else {
|
||||
let account: AuthenticationSessionAccount | undefined = options.account;
|
||||
if (!account) {
|
||||
let accountToCreate: AuthenticationSessionAccount | undefined = options.account;
|
||||
if (!accountToCreate) {
|
||||
const sessionIdToRecreate = this.authenticationExtensionsService.getSessionPreference(providerId, extensionId, scopes);
|
||||
account = sessionIdToRecreate ? sessions.find(session => session.id === sessionIdToRecreate)?.account : undefined;
|
||||
accountToCreate = sessionIdToRecreate ? sessions.find(session => session.id === sessionIdToRecreate)?.account : undefined;
|
||||
}
|
||||
session = await this.authenticationService.createSession(providerId, scopes, { activateImmediate: true, account });
|
||||
|
||||
do {
|
||||
session = await this.authenticationService.createSession(providerId, scopes, { activateImmediate: true, account: accountToCreate });
|
||||
} while (
|
||||
accountToCreate
|
||||
&& accountToCreate.label !== session.account.label
|
||||
&& !await this.continueWithIncorrectAccountPrompt(session.account.label, accountToCreate.label)
|
||||
);
|
||||
}
|
||||
|
||||
this.authenticationAccessService.updateAllowedExtensions(providerId, session.account.label, [{ id: extensionId, name: extensionName, allowed: true }]);
|
||||
|
||||
Reference in New Issue
Block a user