mirror of
https://github.com/Microsoft/vscode
synced 2024-10-02 17:32:41 +00:00
Implement getAccounts API over getSessions (#215874)
And plumb that through to the Microsoft auth provider
This commit is contained in:
parent
fc1a9a48ec
commit
5d7157cb03
|
@ -14,7 +14,8 @@
|
||||||
],
|
],
|
||||||
"activationEvents": [],
|
"activationEvents": [],
|
||||||
"enabledApiProposals": [
|
"enabledApiProposals": [
|
||||||
"idToken"
|
"idToken",
|
||||||
|
"authGetSessions"
|
||||||
],
|
],
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"virtualWorkspaces": true,
|
"virtualWorkspaces": true,
|
||||||
|
|
|
@ -203,11 +203,13 @@ export class AzureActiveDirectoryService {
|
||||||
return this._sessionChangeEmitter.event;
|
return this._sessionChangeEmitter.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSessions(scopes?: string[]): Promise<vscode.AuthenticationSession[]> {
|
public getSessions(scopes?: string[], account?: vscode.AuthenticationSessionAccountInformation): Promise<vscode.AuthenticationSession[]> {
|
||||||
if (!scopes) {
|
if (!scopes) {
|
||||||
this._logger.info('Getting sessions for all scopes...');
|
this._logger.info('Getting sessions for all scopes...');
|
||||||
const sessions = this._tokens.map(token => this.convertToSessionSync(token));
|
const sessions = this._tokens
|
||||||
this._logger.info(`Got ${sessions.length} sessions for all scopes...`);
|
.filter(token => !account?.label || token.account.label === account.label)
|
||||||
|
.map(token => this.convertToSessionSync(token));
|
||||||
|
this._logger.info(`Got ${sessions.length} sessions for all scopes${account ? ` for account '${account.label}'` : ''}...`);
|
||||||
return Promise.resolve(sessions);
|
return Promise.resolve(sessions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,23 +240,43 @@ export class AzureActiveDirectoryService {
|
||||||
tenant: this.getTenantId(scopes),
|
tenant: this.getTenantId(scopes),
|
||||||
};
|
};
|
||||||
|
|
||||||
this._logger.trace(`[${scopeData.scopeStr}] Queued getting sessions`);
|
this._logger.trace(`[${scopeData.scopeStr}] Queued getting sessions` + account ? ` for ${account?.label}` : '');
|
||||||
return this._sequencer.queue(modifiedScopesStr, () => this.doGetSessions(scopeData));
|
return this._sequencer.queue(modifiedScopesStr, () => this.doGetSessions(scopeData, account));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async doGetSessions(scopeData: IScopeData): Promise<vscode.AuthenticationSession[]> {
|
private async doGetSessions(scopeData: IScopeData, account?: vscode.AuthenticationSessionAccountInformation): Promise<vscode.AuthenticationSession[]> {
|
||||||
this._logger.info(`[${scopeData.scopeStr}] Getting sessions`);
|
this._logger.info(`[${scopeData.scopeStr}] Getting sessions` + account ? ` for ${account?.label}` : '');
|
||||||
|
|
||||||
const matchingTokens = this._tokens.filter(token => token.scope === scopeData.scopeStr);
|
const matchingTokens = this._tokens
|
||||||
|
.filter(token => token.scope === scopeData.scopeStr)
|
||||||
|
.filter(token => !account?.label || token.account.label === account.label);
|
||||||
// If we still don't have a matching token try to get a new token from an existing token by using
|
// If we still don't have a matching token try to get a new token from an existing token by using
|
||||||
// the refreshToken. This is documented here:
|
// the refreshToken. This is documented here:
|
||||||
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token
|
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token
|
||||||
// "Refresh tokens are valid for all permissions that your client has already received consent for."
|
// "Refresh tokens are valid for all permissions that your client has already received consent for."
|
||||||
if (!matchingTokens.length) {
|
if (!matchingTokens.length) {
|
||||||
// Get a token with the correct client id.
|
// Get a token with the correct client id and account.
|
||||||
const token = scopeData.clientId === DEFAULT_CLIENT_ID
|
let token: IToken | undefined;
|
||||||
? this._tokens.find(t => t.refreshToken && !t.scope.includes('VSCODE_CLIENT_ID'))
|
for (const t of this._tokens) {
|
||||||
: this._tokens.find(t => t.refreshToken && t.scope.includes(`VSCODE_CLIENT_ID:${scopeData.clientId}`));
|
// No refresh token, so we can't make a new token from this session
|
||||||
|
if (!t.refreshToken) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Need to make sure the account matches if we were provided one
|
||||||
|
if (account?.label && t.account.label !== account.label) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If the client id is the default client id, then check for the absence of the VSCODE_CLIENT_ID scope
|
||||||
|
if (scopeData.clientId === DEFAULT_CLIENT_ID && !t.scope.includes('VSCODE_CLIENT_ID')) {
|
||||||
|
token = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If the client id is not the default client id, then check for the matching VSCODE_CLIENT_ID scope
|
||||||
|
if (scopeData.clientId !== DEFAULT_CLIENT_ID && t.scope.includes(`VSCODE_CLIENT_ID:${scopeData.clientId}`)) {
|
||||||
|
token = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Found a matching token with a different scopes '${token.scope}'. Attempting to get a new session using the existing session.`);
|
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Found a matching token with a different scopes '${token.scope}'. Attempting to get a new session using the existing session.`);
|
||||||
|
@ -275,7 +297,7 @@ export class AzureActiveDirectoryService {
|
||||||
.map(result => (result as PromiseFulfilledResult<vscode.AuthenticationSession>).value);
|
.map(result => (result as PromiseFulfilledResult<vscode.AuthenticationSession>).value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createSession(scopes: string[]): Promise<vscode.AuthenticationSession> {
|
public createSession(scopes: string[], account?: vscode.AuthenticationSessionAccountInformation): Promise<vscode.AuthenticationSession> {
|
||||||
let modifiedScopes = [...scopes];
|
let modifiedScopes = [...scopes];
|
||||||
if (!modifiedScopes.includes('openid')) {
|
if (!modifiedScopes.includes('openid')) {
|
||||||
modifiedScopes.push('openid');
|
modifiedScopes.push('openid');
|
||||||
|
@ -301,11 +323,11 @@ export class AzureActiveDirectoryService {
|
||||||
};
|
};
|
||||||
|
|
||||||
this._logger.trace(`[${scopeData.scopeStr}] Queued creating session`);
|
this._logger.trace(`[${scopeData.scopeStr}] Queued creating session`);
|
||||||
return this._sequencer.queue(scopeData.scopeStr, () => this.doCreateSession(scopeData));
|
return this._sequencer.queue(scopeData.scopeStr, () => this.doCreateSession(scopeData, account));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async doCreateSession(scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
|
private async doCreateSession(scopeData: IScopeData, account?: vscode.AuthenticationSessionAccountInformation): Promise<vscode.AuthenticationSession> {
|
||||||
this._logger.info(`[${scopeData.scopeStr}] Creating session`);
|
this._logger.info(`[${scopeData.scopeStr}] Creating session` + account ? ` for ${account?.label}` : '');
|
||||||
|
|
||||||
const runsRemote = vscode.env.remoteName !== undefined;
|
const runsRemote = vscode.env.remoteName !== undefined;
|
||||||
const runsServerless = vscode.env.remoteName === undefined && vscode.env.uiKind === vscode.UIKind.Web;
|
const runsServerless = vscode.env.remoteName === undefined && vscode.env.uiKind === vscode.UIKind.Web;
|
||||||
|
@ -316,17 +338,17 @@ export class AzureActiveDirectoryService {
|
||||||
|
|
||||||
return await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: vscode.l10n.t('Signing in to your account...'), cancellable: true }, async (_progress, token) => {
|
return await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: vscode.l10n.t('Signing in to your account...'), cancellable: true }, async (_progress, token) => {
|
||||||
if (runsRemote || runsServerless) {
|
if (runsRemote || runsServerless) {
|
||||||
return await this.createSessionWithoutLocalServer(scopeData, token);
|
return await this.createSessionWithoutLocalServer(scopeData, account?.label, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.createSessionWithLocalServer(scopeData, token);
|
return await this.createSessionWithLocalServer(scopeData, account?.label, token);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._logger.error(`[${scopeData.scopeStr}] Error creating session: ${e}`);
|
this._logger.error(`[${scopeData.scopeStr}] Error creating session: ${e}`);
|
||||||
|
|
||||||
// If the error was about starting the server, try directly hitting the login endpoint instead
|
// If the error was about starting the server, try directly hitting the login endpoint instead
|
||||||
if (e.message === 'Error listening to server' || e.message === 'Closed' || e.message === 'Timeout waiting for port') {
|
if (e.message === 'Error listening to server' || e.message === 'Closed' || e.message === 'Timeout waiting for port') {
|
||||||
return this.createSessionWithoutLocalServer(scopeData, token);
|
return this.createSessionWithoutLocalServer(scopeData, account?.label, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -334,7 +356,7 @@ export class AzureActiveDirectoryService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createSessionWithLocalServer(scopeData: IScopeData, token: vscode.CancellationToken): Promise<vscode.AuthenticationSession> {
|
private async createSessionWithLocalServer(scopeData: IScopeData, loginHint: string | undefined, token: vscode.CancellationToken): Promise<vscode.AuthenticationSession> {
|
||||||
this._logger.trace(`[${scopeData.scopeStr}] Starting login flow with local server`);
|
this._logger.trace(`[${scopeData.scopeStr}] Starting login flow with local server`);
|
||||||
const codeVerifier = generateCodeVerifier();
|
const codeVerifier = generateCodeVerifier();
|
||||||
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
||||||
|
@ -344,11 +366,15 @@ export class AzureActiveDirectoryService {
|
||||||
client_id: scopeData.clientId,
|
client_id: scopeData.clientId,
|
||||||
redirect_uri: redirectUrl,
|
redirect_uri: redirectUrl,
|
||||||
scope: scopeData.scopesToSend,
|
scope: scopeData.scopesToSend,
|
||||||
prompt: 'select_account',
|
|
||||||
code_challenge_method: 'S256',
|
code_challenge_method: 'S256',
|
||||||
code_challenge: codeChallenge,
|
code_challenge: codeChallenge,
|
||||||
}).toString();
|
});
|
||||||
const loginUrl = new URL(`${scopeData.tenant}/oauth2/v2.0/authorize?${qs}`, this._env.activeDirectoryEndpointUrl).toString();
|
if (loginHint) {
|
||||||
|
qs.set('login_hint', loginHint);
|
||||||
|
} else {
|
||||||
|
qs.set('prompt', 'select_account');
|
||||||
|
}
|
||||||
|
const loginUrl = new URL(`${scopeData.tenant}/oauth2/v2.0/authorize?${qs.toString()}`, this._env.activeDirectoryEndpointUrl).toString();
|
||||||
const server = new LoopbackAuthServer(path.join(__dirname, '../media'), loginUrl);
|
const server = new LoopbackAuthServer(path.join(__dirname, '../media'), loginUrl);
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|
||||||
|
@ -370,7 +396,7 @@ export class AzureActiveDirectoryService {
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createSessionWithoutLocalServer(scopeData: IScopeData, token: vscode.CancellationToken): Promise<vscode.AuthenticationSession> {
|
private async createSessionWithoutLocalServer(scopeData: IScopeData, loginHint: string | undefined, token: vscode.CancellationToken): Promise<vscode.AuthenticationSession> {
|
||||||
this._logger.trace(`[${scopeData.scopeStr}] Starting login flow without local server`);
|
this._logger.trace(`[${scopeData.scopeStr}] Starting login flow without local server`);
|
||||||
let callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.microsoft-authentication`));
|
let callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.microsoft-authentication`));
|
||||||
const nonce = generateCodeVerifier();
|
const nonce = generateCodeVerifier();
|
||||||
|
@ -383,17 +409,22 @@ export class AzureActiveDirectoryService {
|
||||||
const codeVerifier = generateCodeVerifier();
|
const codeVerifier = generateCodeVerifier();
|
||||||
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
||||||
const signInUrl = new URL(`${scopeData.tenant}/oauth2/v2.0/authorize`, this._env.activeDirectoryEndpointUrl);
|
const signInUrl = new URL(`${scopeData.tenant}/oauth2/v2.0/authorize`, this._env.activeDirectoryEndpointUrl);
|
||||||
signInUrl.search = new URLSearchParams({
|
const qs = new URLSearchParams({
|
||||||
response_type: 'code',
|
response_type: 'code',
|
||||||
client_id: encodeURIComponent(scopeData.clientId),
|
client_id: encodeURIComponent(scopeData.clientId),
|
||||||
response_mode: 'query',
|
response_mode: 'query',
|
||||||
redirect_uri: redirectUrl,
|
redirect_uri: redirectUrl,
|
||||||
state,
|
state,
|
||||||
scope: scopeData.scopesToSend,
|
scope: scopeData.scopesToSend,
|
||||||
prompt: 'select_account',
|
|
||||||
code_challenge_method: 'S256',
|
code_challenge_method: 'S256',
|
||||||
code_challenge: codeChallenge,
|
code_challenge: codeChallenge,
|
||||||
}).toString();
|
});
|
||||||
|
if (loginHint) {
|
||||||
|
qs.append('login_hint', loginHint);
|
||||||
|
} else {
|
||||||
|
qs.append('prompt', 'select_account');
|
||||||
|
}
|
||||||
|
signInUrl.search = qs.toString();
|
||||||
const uri = vscode.Uri.parse(signInUrl.toString());
|
const uri = vscode.Uri.parse(signInUrl.toString());
|
||||||
vscode.env.openExternal(uri);
|
vscode.env.openExternal(uri);
|
||||||
|
|
||||||
|
|
|
@ -123,8 +123,8 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
|
|
||||||
context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('microsoft', 'Microsoft', {
|
context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('microsoft', 'Microsoft', {
|
||||||
onDidChangeSessions: loginService.onDidChangeSessions,
|
onDidChangeSessions: loginService.onDidChangeSessions,
|
||||||
getSessions: (scopes: string[]) => loginService.getSessions(scopes),
|
getSessions: (scopes: string[], options?: vscode.AuthenticationProviderSessionOptions) => loginService.getSessions(scopes, options?.account),
|
||||||
createSession: async (scopes: string[]) => {
|
createSession: async (scopes: string[], options?: vscode.AuthenticationProviderSessionOptions) => {
|
||||||
try {
|
try {
|
||||||
/* __GDPR__
|
/* __GDPR__
|
||||||
"login" : {
|
"login" : {
|
||||||
|
@ -138,7 +138,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
scopes: JSON.stringify(scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}'))),
|
scopes: JSON.stringify(scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}'))),
|
||||||
});
|
});
|
||||||
|
|
||||||
return await loginService.createSession(scopes);
|
return await loginService.createSession(scopes, options?.account);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
/* __GDPR__
|
/* __GDPR__
|
||||||
"loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." }
|
"loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." }
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*",
|
"src/**/*",
|
||||||
"../../src/vscode-dts/vscode.d.ts",
|
"../../src/vscode-dts/vscode.d.ts",
|
||||||
"../../src/vscode-dts/vscode.proposed.idToken.d.ts"
|
"../../src/vscode-dts/vscode.proposed.idToken.d.ts",
|
||||||
|
"../../src/vscode-dts/vscode.proposed.authGetSessions.d.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
import { Disposable, DisposableMap } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableMap } from 'vs/base/common/lifecycle';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||||
import { IAuthenticationCreateSessionOptions, AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationProvider, IAuthenticationService, IAuthenticationExtensionsService, INTERNAL_AUTH_PROVIDER_PREFIX as INTERNAL_MODEL_AUTH_PROVIDER_PREFIX } from 'vs/workbench/services/authentication/common/authentication';
|
import { IAuthenticationCreateSessionOptions, AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationProvider, IAuthenticationService, IAuthenticationExtensionsService, INTERNAL_AUTH_PROVIDER_PREFIX as INTERNAL_MODEL_AUTH_PROVIDER_PREFIX, AuthenticationSessionAccount, IAuthenticationProviderSessionOptions } from 'vs/workbench/services/authentication/common/authentication';
|
||||||
import { ExtHostAuthenticationShape, ExtHostContext, MainContext, MainThreadAuthenticationShape } from '../common/extHost.protocol';
|
import { ExtHostAuthenticationShape, ExtHostContext, MainContext, MainThreadAuthenticationShape } from '../common/extHost.protocol';
|
||||||
import { IDialogService, IPromptButton } from 'vs/platform/dialogs/common/dialogs';
|
import { IDialogService, IPromptButton } from 'vs/platform/dialogs/common/dialogs';
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
|
@ -31,6 +31,7 @@ interface AuthenticationGetSessionOptions {
|
||||||
createIfNone?: boolean;
|
createIfNone?: boolean;
|
||||||
forceNewSession?: boolean | AuthenticationForceNewSessionOptions;
|
forceNewSession?: boolean | AuthenticationForceNewSessionOptions;
|
||||||
silent?: boolean;
|
silent?: boolean;
|
||||||
|
account?: AuthenticationSessionAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MainThreadAuthenticationProvider extends Disposable implements IAuthenticationProvider {
|
export class MainThreadAuthenticationProvider extends Disposable implements IAuthenticationProvider {
|
||||||
|
@ -49,8 +50,8 @@ export class MainThreadAuthenticationProvider extends Disposable implements IAut
|
||||||
this.onDidChangeSessions = onDidChangeSessionsEmitter.event;
|
this.onDidChangeSessions = onDidChangeSessionsEmitter.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSessions(scopes?: string[]) {
|
async getSessions(scopes: string[] | undefined, options: IAuthenticationProviderSessionOptions) {
|
||||||
return this._proxy.$getSessions(this.id, scopes);
|
return this._proxy.$getSessions(this.id, scopes, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
createSession(scopes: string[], options: IAuthenticationCreateSessionOptions): Promise<AuthenticationSession> {
|
createSession(scopes: string[], options: IAuthenticationCreateSessionOptions): Promise<AuthenticationSession> {
|
||||||
|
@ -159,7 +160,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||||
}
|
}
|
||||||
|
|
||||||
private async doGetSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: AuthenticationGetSessionOptions): Promise<AuthenticationSession | undefined> {
|
private async doGetSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: AuthenticationGetSessionOptions): Promise<AuthenticationSession | undefined> {
|
||||||
const sessions = await this.authenticationService.getSessions(providerId, scopes, true);
|
const sessions = await this.authenticationService.getSessions(providerId, scopes, options.account, true);
|
||||||
const provider = this.authenticationService.getProvider(providerId);
|
const provider = this.authenticationService.getProvider(providerId);
|
||||||
|
|
||||||
// Error cases
|
// Error cases
|
||||||
|
@ -213,18 +214,16 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||||
|
|
||||||
let session;
|
let session;
|
||||||
if (sessions?.length && !options.forceNewSession) {
|
if (sessions?.length && !options.forceNewSession) {
|
||||||
session = provider.supportsMultipleAccounts
|
session = provider.supportsMultipleAccounts && !options.account
|
||||||
? await this.authenticationExtensionsService.selectSession(providerId, extensionId, extensionName, scopes, sessions)
|
? await this.authenticationExtensionsService.selectSession(providerId, extensionId, extensionName, scopes, sessions)
|
||||||
: sessions[0];
|
: sessions[0];
|
||||||
} else {
|
} else {
|
||||||
let sessionToRecreate: AuthenticationSession | undefined;
|
let account: AuthenticationSessionAccount | undefined = options.account;
|
||||||
if (typeof options.forceNewSession === 'object' && options.forceNewSession.sessionToRecreate) {
|
if (!account) {
|
||||||
sessionToRecreate = options.forceNewSession.sessionToRecreate as AuthenticationSession;
|
|
||||||
} else {
|
|
||||||
const sessionIdToRecreate = this.authenticationExtensionsService.getSessionPreference(providerId, extensionId, scopes);
|
const sessionIdToRecreate = this.authenticationExtensionsService.getSessionPreference(providerId, extensionId, scopes);
|
||||||
sessionToRecreate = sessionIdToRecreate ? sessions.find(session => session.id === sessionIdToRecreate) : undefined;
|
account = sessionIdToRecreate ? sessions.find(session => session.id === sessionIdToRecreate)?.account : undefined;
|
||||||
}
|
}
|
||||||
session = await this.authenticationService.createSession(providerId, scopes, { activateImmediate: true, sessionToRecreate });
|
session = await this.authenticationService.createSession(providerId, scopes, { activateImmediate: true, account });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.authenticationAccessService.updateAllowedExtensions(providerId, session.account.label, [{ id: extensionId, name: extensionName, allowed: true }]);
|
this.authenticationAccessService.updateAllowedExtensions(providerId, session.account.label, [{ id: extensionId, name: extensionName, allowed: true }]);
|
||||||
|
@ -262,7 +261,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||||
}
|
}
|
||||||
|
|
||||||
async $getSessions(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string): Promise<AuthenticationSession[]> {
|
async $getSessions(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string): Promise<AuthenticationSession[]> {
|
||||||
const sessions = await this.authenticationService.getSessions(providerId, [...scopes], true);
|
const sessions = await this.authenticationService.getSessions(providerId, [...scopes], undefined, true);
|
||||||
const accessibleSessions = sessions.filter(s => this.authenticationAccessService.isAccessAllowed(providerId, s.account.label, extensionId));
|
const accessibleSessions = sessions.filter(s => this.authenticationAccessService.isAccessAllowed(providerId, s.account.label, extensionId));
|
||||||
if (accessibleSessions.length) {
|
if (accessibleSessions.length) {
|
||||||
this.sendProviderUsageTelemetry(extensionId, providerId);
|
this.sendProviderUsageTelemetry(extensionId, providerId);
|
||||||
|
@ -273,6 +272,19 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||||
return accessibleSessions;
|
return accessibleSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async $getAccounts(providerId: string): Promise<ReadonlyArray<AuthenticationSessionAccount>> {
|
||||||
|
const sessions = await this.authenticationService.getSessions(providerId);
|
||||||
|
const accounts = new Array<AuthenticationSessionAccount>();
|
||||||
|
const seenAccounts = new Set<string>();
|
||||||
|
for (const session of sessions) {
|
||||||
|
if (!seenAccounts.has(session.account.label)) {
|
||||||
|
seenAccounts.add(session.account.label);
|
||||||
|
accounts.push(session.account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
|
||||||
private sendProviderUsageTelemetry(extensionId: string, providerId: string): void {
|
private sendProviderUsageTelemetry(extensionId: string, providerId: string): void {
|
||||||
type AuthProviderUsageClassification = {
|
type AuthProviderUsageClassification = {
|
||||||
owner: 'TylerLeonhardt';
|
owner: 'TylerLeonhardt';
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { ExtHostLanguageModelsShape, ExtHostContext, MainContext, MainThreadLang
|
||||||
import { ILanguageModelStatsService } from 'vs/workbench/contrib/chat/common/languageModelStats';
|
import { ILanguageModelStatsService } from 'vs/workbench/contrib/chat/common/languageModelStats';
|
||||||
import { ILanguageModelChatMetadata, IChatResponseFragment, ILanguageModelsService, IChatMessage, ILanguageModelChatSelector } from 'vs/workbench/contrib/chat/common/languageModels';
|
import { ILanguageModelChatMetadata, IChatResponseFragment, ILanguageModelsService, IChatMessage, ILanguageModelChatSelector } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||||
import { IAuthenticationAccessService } from 'vs/workbench/services/authentication/browser/authenticationAccessService';
|
import { IAuthenticationAccessService } from 'vs/workbench/services/authentication/browser/authenticationAccessService';
|
||||||
import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationProvider, IAuthenticationProviderCreateSessionOptions, IAuthenticationService, INTERNAL_AUTH_PROVIDER_PREFIX } from 'vs/workbench/services/authentication/common/authentication';
|
import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationProvider, IAuthenticationService, INTERNAL_AUTH_PROVIDER_PREFIX } from 'vs/workbench/services/authentication/common/authentication';
|
||||||
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
|
|
||||||
|
@ -161,9 +161,9 @@ class LanguageModelAccessAuthProvider implements IAuthenticationProvider {
|
||||||
if (this._session) {
|
if (this._session) {
|
||||||
return [this._session];
|
return [this._session];
|
||||||
}
|
}
|
||||||
return [await this.createSession(scopes || [], {})];
|
return [await this.createSession(scopes || [])];
|
||||||
}
|
}
|
||||||
async createSession(scopes: string[], options: IAuthenticationProviderCreateSessionOptions): Promise<AuthenticationSession> {
|
async createSession(scopes: string[]): Promise<AuthenticationSession> {
|
||||||
this._session = this._createFakeSession(scopes);
|
this._session = this._createFakeSession(scopes);
|
||||||
this._onDidChangeSessions.fire({ added: [this._session], changed: [], removed: [] });
|
this._onDidChangeSessions.fire({ added: [this._session], changed: [], removed: [] });
|
||||||
return this._session;
|
return this._session;
|
||||||
|
|
|
@ -287,12 +287,19 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||||
if (typeof options?.forceNewSession === 'object' && options.forceNewSession.learnMore) {
|
if (typeof options?.forceNewSession === 'object' && options.forceNewSession.learnMore) {
|
||||||
checkProposedApiEnabled(extension, 'authLearnMore');
|
checkProposedApiEnabled(extension, 'authLearnMore');
|
||||||
}
|
}
|
||||||
|
if (options?.account) {
|
||||||
|
checkProposedApiEnabled(extension, 'authGetSessions');
|
||||||
|
}
|
||||||
return extHostAuthentication.getSession(extension, providerId, scopes, options as any);
|
return extHostAuthentication.getSession(extension, providerId, scopes, options as any);
|
||||||
},
|
},
|
||||||
getSessions(providerId: string, scopes: readonly string[]) {
|
getSessions(providerId: string, scopes: readonly string[]) {
|
||||||
checkProposedApiEnabled(extension, 'authGetSessions');
|
checkProposedApiEnabled(extension, 'authGetSessions');
|
||||||
return extHostAuthentication.getSessions(extension, providerId, scopes);
|
return extHostAuthentication.getSessions(extension, providerId, scopes);
|
||||||
},
|
},
|
||||||
|
getAccounts(providerId: string) {
|
||||||
|
checkProposedApiEnabled(extension, 'authGetSessions');
|
||||||
|
return extHostAuthentication.getAccounts(providerId);
|
||||||
|
},
|
||||||
// TODO: remove this after GHPR and Codespaces move off of it
|
// TODO: remove this after GHPR and Codespaces move off of it
|
||||||
async hasSession(providerId: string, scopes: readonly string[]) {
|
async hasSession(providerId: string, scopes: readonly string[]) {
|
||||||
checkProposedApiEnabled(extension, 'authSession');
|
checkProposedApiEnabled(extension, 'authSession');
|
||||||
|
|
|
@ -68,7 +68,7 @@ import { CoverageDetails, ExtensionRunTestsRequest, ICallProfileRunHandler, IFil
|
||||||
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
|
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||||
import { TypeHierarchyItem } from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
|
import { TypeHierarchyItem } from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
|
||||||
import { RelatedInformationResult, RelatedInformationType } from 'vs/workbench/services/aiRelatedInformation/common/aiRelatedInformation';
|
import { RelatedInformationResult, RelatedInformationType } from 'vs/workbench/services/aiRelatedInformation/common/aiRelatedInformation';
|
||||||
import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationCreateSessionOptions } from 'vs/workbench/services/authentication/common/authentication';
|
import { AuthenticationSession, AuthenticationSessionAccount, AuthenticationSessionsChangeEvent, IAuthenticationCreateSessionOptions, IAuthenticationProviderSessionOptions } from 'vs/workbench/services/authentication/common/authentication';
|
||||||
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||||
import { IExtensionDescriptionDelta, IStaticWorkspaceData } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
import { IExtensionDescriptionDelta, IStaticWorkspaceData } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||||
import { IResolveAuthorityResult } from 'vs/workbench/services/extensions/common/extensionHostProxy';
|
import { IResolveAuthorityResult } from 'vs/workbench/services/extensions/common/extensionHostProxy';
|
||||||
|
@ -162,6 +162,7 @@ export interface MainThreadAuthenticationShape extends IDisposable {
|
||||||
$sendDidChangeSessions(providerId: string, event: AuthenticationSessionsChangeEvent): void;
|
$sendDidChangeSessions(providerId: string, event: AuthenticationSessionsChangeEvent): void;
|
||||||
$getSession(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean; forceNewSession?: boolean | AuthenticationForceNewSessionOptions; clearSessionPreference?: boolean }): Promise<AuthenticationSession | undefined>;
|
$getSession(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean; forceNewSession?: boolean | AuthenticationForceNewSessionOptions; clearSessionPreference?: boolean }): Promise<AuthenticationSession | undefined>;
|
||||||
$getSessions(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string): Promise<AuthenticationSession[]>;
|
$getSessions(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string): Promise<AuthenticationSession[]>;
|
||||||
|
$getAccounts(providerId: string): Promise<ReadonlyArray<AuthenticationSessionAccount>>;
|
||||||
$removeSession(providerId: string, sessionId: string): Promise<void>;
|
$removeSession(providerId: string, sessionId: string): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1806,7 +1807,7 @@ export interface ExtHostLabelServiceShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtHostAuthenticationShape {
|
export interface ExtHostAuthenticationShape {
|
||||||
$getSessions(id: string, scopes?: string[]): Promise<ReadonlyArray<AuthenticationSession>>;
|
$getSessions(id: string, scopes: string[] | undefined, options: IAuthenticationProviderSessionOptions): Promise<ReadonlyArray<AuthenticationSession>>;
|
||||||
$createSession(id: string, scopes: string[], options: IAuthenticationCreateSessionOptions): Promise<AuthenticationSession>;
|
$createSession(id: string, scopes: string[], options: IAuthenticationCreateSessionOptions): Promise<AuthenticationSession>;
|
||||||
$removeSession(id: string, sessionId: string): Promise<void>;
|
$removeSession(id: string, sessionId: string): Promise<void>;
|
||||||
$onDidChangeAuthenticationSessions(id: string, label: string): Promise<void>;
|
$onDidChangeAuthenticationSessions(id: string, label: string): Promise<void>;
|
||||||
|
|
|
@ -64,6 +64,11 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAccounts(providerId: string) {
|
||||||
|
await this._proxy.$ensureProvider(providerId);
|
||||||
|
return await this._proxy.$getAccounts(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
async removeSession(providerId: string, sessionId: string): Promise<void> {
|
async removeSession(providerId: string, sessionId: string): Promise<void> {
|
||||||
const providerData = this._authenticationProviders.get(providerId);
|
const providerData = this._authenticationProviders.get(providerId);
|
||||||
if (!providerData) {
|
if (!providerData) {
|
||||||
|
@ -89,7 +94,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async $createSession(providerId: string, scopes: string[], options: vscode.AuthenticationProviderCreateSessionOptions): Promise<vscode.AuthenticationSession> {
|
async $createSession(providerId: string, scopes: string[], options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession> {
|
||||||
const providerData = this._authenticationProviders.get(providerId);
|
const providerData = this._authenticationProviders.get(providerId);
|
||||||
if (providerData) {
|
if (providerData) {
|
||||||
return await providerData.provider.createSession(scopes, options);
|
return await providerData.provider.createSession(scopes, options);
|
||||||
|
@ -107,10 +112,10 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||||
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
|
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $getSessions(providerId: string, scopes?: string[]): Promise<ReadonlyArray<vscode.AuthenticationSession>> {
|
async $getSessions(providerId: string, scopes: ReadonlyArray<string> | undefined, options: vscode.AuthenticationProviderSessionOptions): Promise<ReadonlyArray<vscode.AuthenticationSession>> {
|
||||||
const providerData = this._authenticationProviders.get(providerId);
|
const providerData = this._authenticationProviders.get(providerId);
|
||||||
if (providerData) {
|
if (providerData) {
|
||||||
return await providerData.provider.getSessions(scopes);
|
return await providerData.provider.getSessions(scopes, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
|
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/
|
||||||
import { IProductService } from 'vs/platform/product/common/productService';
|
import { IProductService } from 'vs/platform/product/common/productService';
|
||||||
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
|
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
|
||||||
import { IAuthenticationAccessService } from 'vs/workbench/services/authentication/browser/authenticationAccessService';
|
import { IAuthenticationAccessService } from 'vs/workbench/services/authentication/browser/authenticationAccessService';
|
||||||
import { AuthenticationProviderInformation, AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationCreateSessionOptions, IAuthenticationProvider, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication';
|
import { AuthenticationProviderInformation, AuthenticationSession, AuthenticationSessionAccount, AuthenticationSessionsChangeEvent, IAuthenticationCreateSessionOptions, IAuthenticationProvider, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication';
|
||||||
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||||
import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
|
|
||||||
|
@ -164,10 +164,10 @@ export class AuthenticationService extends Disposable implements IAuthentication
|
||||||
throw new Error(`No authentication provider '${id}' is currently registered.`);
|
throw new Error(`No authentication provider '${id}' is currently registered.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSessions(id: string, scopes?: string[], activateImmediate: boolean = false): Promise<ReadonlyArray<AuthenticationSession>> {
|
async getSessions(id: string, scopes?: string[], account?: AuthenticationSessionAccount, activateImmediate: boolean = false): Promise<ReadonlyArray<AuthenticationSession>> {
|
||||||
const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate);
|
const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate);
|
||||||
if (authProvider) {
|
if (authProvider) {
|
||||||
return await authProvider.getSessions(scopes);
|
return await authProvider.getSessions(scopes, { account });
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`No authentication provider '${id}' is currently registered.`);
|
throw new Error(`No authentication provider '${id}' is currently registered.`);
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ export class AuthenticationService extends Disposable implements IAuthentication
|
||||||
const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, !!options?.activateImmediate);
|
const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, !!options?.activateImmediate);
|
||||||
if (authProvider) {
|
if (authProvider) {
|
||||||
return await authProvider.createSession(scopes, {
|
return await authProvider.createSession(scopes, {
|
||||||
sessionToRecreate: options?.sessionToRecreate
|
account: options?.account
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`No authentication provider '${id}' is currently registered.`);
|
throw new Error(`No authentication provider '${id}' is currently registered.`);
|
||||||
|
|
|
@ -35,8 +35,12 @@ export interface AuthenticationProviderInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAuthenticationCreateSessionOptions {
|
export interface IAuthenticationCreateSessionOptions {
|
||||||
sessionToRecreate?: AuthenticationSession;
|
|
||||||
activateImmediate?: boolean;
|
activateImmediate?: boolean;
|
||||||
|
/**
|
||||||
|
* The account that is being asked about. If this is passed in, the provider should
|
||||||
|
* attempt to return the sessions that are only related to this account.
|
||||||
|
*/
|
||||||
|
account?: AuthenticationSessionAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AllowedExtension {
|
export interface AllowedExtension {
|
||||||
|
@ -131,7 +135,7 @@ export interface IAuthenticationService {
|
||||||
* @param scopes The scopes for the session
|
* @param scopes The scopes for the session
|
||||||
* @param activateImmediate If true, the provider should activate immediately if it is not already
|
* @param activateImmediate If true, the provider should activate immediately if it is not already
|
||||||
*/
|
*/
|
||||||
getSessions(id: string, scopes?: string[], activateImmediate?: boolean): Promise<ReadonlyArray<AuthenticationSession>>;
|
getSessions(id: string, scopes?: string[], account?: AuthenticationSessionAccount, activateImmediate?: boolean): Promise<ReadonlyArray<AuthenticationSession>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an AuthenticationSession with the given provider and scopes
|
* Creates an AuthenticationSession with the given provider and scopes
|
||||||
|
@ -162,8 +166,12 @@ export interface IAuthenticationExtensionsService {
|
||||||
requestNewSession(providerId: string, scopes: string[], extensionId: string, extensionName: string): Promise<void>;
|
requestNewSession(providerId: string, scopes: string[], extensionId: string, extensionName: string): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAuthenticationProviderCreateSessionOptions {
|
export interface IAuthenticationProviderSessionOptions {
|
||||||
sessionToRecreate?: AuthenticationSession;
|
/**
|
||||||
|
* The account that is being asked about. If this is passed in, the provider should
|
||||||
|
* attempt to return the sessions that are only related to this account.
|
||||||
|
*/
|
||||||
|
account?: AuthenticationSessionAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -194,9 +202,10 @@ export interface IAuthenticationProvider {
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of authentication sessions.
|
* Retrieves a list of authentication sessions.
|
||||||
* @param scopes - An optional list of scopes. If provided, the sessions returned should match these permissions, otherwise all sessions should be returned.
|
* @param scopes - An optional list of scopes. If provided, the sessions returned should match these permissions, otherwise all sessions should be returned.
|
||||||
|
* @param options - Additional options for getting sessions.
|
||||||
* @returns A promise that resolves to an array of authentication sessions.
|
* @returns A promise that resolves to an array of authentication sessions.
|
||||||
*/
|
*/
|
||||||
getSessions(scopes?: string[]): Promise<readonly AuthenticationSession[]>;
|
getSessions(scopes: string[] | undefined, options: IAuthenticationProviderSessionOptions): Promise<readonly AuthenticationSession[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompts the user to log in.
|
* Prompts the user to log in.
|
||||||
|
@ -207,7 +216,7 @@ export interface IAuthenticationProvider {
|
||||||
* @param options - Additional options for creating the session.
|
* @param options - Additional options for creating the session.
|
||||||
* @returns A promise that resolves to an authentication session.
|
* @returns A promise that resolves to an authentication session.
|
||||||
*/
|
*/
|
||||||
createSession(scopes: string[], options: IAuthenticationProviderCreateSessionOptions): Promise<AuthenticationSession>;
|
createSession(scopes: string[], options: IAuthenticationProviderSessionOptions): Promise<AuthenticationSession>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the session corresponding to the specified session ID.
|
* Removes the session corresponding to the specified session ID.
|
||||||
|
|
|
@ -7,42 +7,50 @@ declare module 'vscode' {
|
||||||
|
|
||||||
// https://github.com/microsoft/vscode/issues/152399
|
// https://github.com/microsoft/vscode/issues/152399
|
||||||
|
|
||||||
export interface AuthenticationForceNewSessionOptions {
|
// FOR THE CONSUMER
|
||||||
/**
|
|
||||||
* The session that you are asking to be recreated. The Auth Provider can use this to
|
|
||||||
* help guide the user to log in to the correct account.
|
|
||||||
*/
|
|
||||||
sessionToRecreate?: AuthenticationSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace authentication {
|
export namespace authentication {
|
||||||
/**
|
/**
|
||||||
* Get all authentication sessions matching the desired scopes that this extension has access to. In order to request access,
|
* Get all accounts that the user is logged in to for the specified provider.
|
||||||
* use {@link getSession}. To request an additional account, specify {@link AuthenticationGetSessionOptions.clearSessionPreference}
|
* Use this paired with {@link getSession} in order to get an authentication session for a specific account.
|
||||||
* and {@link AuthenticationGetSessionOptions.createIfNone} together.
|
|
||||||
*
|
*
|
||||||
* Currently, there are only two authentication providers that are contributed from built in extensions
|
* Currently, there are only two authentication providers that are contributed from built in extensions
|
||||||
* to the editor that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'.
|
* to the editor that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'.
|
||||||
|
*
|
||||||
|
* Note: Getting accounts does not imply that your extension has access to that account or its authentication sessions. You can verify access to the account by calling {@link getSession}.
|
||||||
*
|
*
|
||||||
* @param providerId The id of the provider to use
|
* @param providerId The id of the provider to use
|
||||||
* @param scopes A list of scopes representing the permissions requested. These are dependent on the authentication provider
|
* @returns A thenable that resolves to a readonly array of authentication accounts.
|
||||||
* @returns A thenable that resolves to a readonly array of authentication sessions.
|
|
||||||
*/
|
*/
|
||||||
export function getSessions(providerId: string, scopes: readonly string[]): Thenable<readonly AuthenticationSession[]>;
|
export function getAccounts(providerId: string): Thenable<readonly AuthenticationSessionAccountInformation[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AuthenticationGetSessionOptions {
|
||||||
/**
|
/**
|
||||||
* The options passed in to the provider when creating a session.
|
* The account that you would like to get a session for. This is passed down to the Authentication Provider to be used for creating the correct session.
|
||||||
*/
|
*/
|
||||||
export interface AuthenticationProviderCreateSessionOptions {
|
account?: AuthenticationSessionAccountInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR THE AUTH PROVIDER
|
||||||
|
|
||||||
|
export interface AuthenticationProviderSessionOptions {
|
||||||
/**
|
/**
|
||||||
* The session that is being asked to be recreated. If this is passed in, the provider should
|
* The account that is being asked about. If this is passed in, the provider should
|
||||||
* attempt to recreate the session based on the information in this session.
|
* attempt to return the sessions that are only related to this account.
|
||||||
*/
|
*/
|
||||||
sessionToRecreate?: AuthenticationSession;
|
account?: AuthenticationSessionAccountInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthenticationProvider {
|
export interface AuthenticationProvider {
|
||||||
|
/**
|
||||||
|
* Get a list of sessions.
|
||||||
|
* @param scopes An optional list of scopes. If provided, the sessions returned should match
|
||||||
|
* these permissions, otherwise all sessions should be returned.
|
||||||
|
* @param options Additional options for getting sessions.
|
||||||
|
* @returns A promise that resolves to an array of authentication sessions.
|
||||||
|
*/
|
||||||
|
getSessions(scopes: readonly string[] | undefined, options: AuthenticationProviderSessionOptions): Thenable<AuthenticationSession[]>;
|
||||||
/**
|
/**
|
||||||
* Prompts a user to login.
|
* Prompts a user to login.
|
||||||
*
|
*
|
||||||
|
@ -57,6 +65,25 @@ declare module 'vscode' {
|
||||||
* @param options Additional options for creating a session.
|
* @param options Additional options for creating a session.
|
||||||
* @returns A promise that resolves to an authentication session.
|
* @returns A promise that resolves to an authentication session.
|
||||||
*/
|
*/
|
||||||
createSession(scopes: readonly string[], options: AuthenticationProviderCreateSessionOptions): Thenable<AuthenticationSession>;
|
createSession(scopes: readonly string[], options: AuthenticationProviderSessionOptions): Thenable<AuthenticationSession>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// THE BELOW IS THE OLD PROPOSAL WHICH WILL BE REMOVED BUT KEPT UNTIL THE NEW PROPOSAL IS ADOPTED BY ALL PARTIES
|
||||||
|
|
||||||
|
export namespace authentication {
|
||||||
|
/**
|
||||||
|
* Get all authentication sessions matching the desired scopes that this extension has access to. In order to request access,
|
||||||
|
* use {@link getSession}. To request an additional account, specify {@link AuthenticationGetSessionOptions.clearSessionPreference}
|
||||||
|
* and {@link AuthenticationGetSessionOptions.createIfNone} together.
|
||||||
|
*
|
||||||
|
* Currently, there are only two authentication providers that are contributed from built in extensions
|
||||||
|
* to the editor that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'.
|
||||||
|
*
|
||||||
|
* @param providerId The id of the provider to use
|
||||||
|
* @param scopes A list of scopes representing the permissions requested. These are dependent on the authentication provider
|
||||||
|
* @returns A thenable that resolves to a readonly array of authentication sessions.
|
||||||
|
* @deprecated Use {@link getAccounts} instead.
|
||||||
|
*/
|
||||||
|
export function getSessions(providerId: string, scopes: readonly string[]): Thenable<readonly AuthenticationSession[]>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue