Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/authentication/common/authentication.ts
5252 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import { Event } from '../../../../base/common/event.js';
6
import { IDisposable } from '../../../../base/common/lifecycle.js';
7
import { IAuthenticationChallenge, IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata } from '../../../../base/common/oauth.js';
8
import { URI } from '../../../../base/common/uri.js';
9
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
10
11
/**
12
* Use this if you don't want the onDidChangeSessions event to fire in the extension host
13
*/
14
export const INTERNAL_AUTH_PROVIDER_PREFIX = '__';
15
16
export interface AuthenticationSessionAccount {
17
label: string;
18
id: string;
19
}
20
21
export interface AuthenticationSession {
22
id: string;
23
accessToken: string;
24
account: AuthenticationSessionAccount;
25
scopes: ReadonlyArray<string>;
26
idToken?: string;
27
}
28
29
export interface AuthenticationSessionsChangeEvent {
30
added: ReadonlyArray<AuthenticationSession> | undefined;
31
removed: ReadonlyArray<AuthenticationSession> | undefined;
32
changed: ReadonlyArray<AuthenticationSession> | undefined;
33
}
34
35
export interface AuthenticationProviderInformation {
36
id: string;
37
label: string;
38
authorizationServerGlobs?: ReadonlyArray<string>;
39
}
40
41
/**
42
* Options for creating an authentication session via the service.
43
*/
44
export interface IAuthenticationCreateSessionOptions {
45
activateImmediate?: boolean;
46
/**
47
* The account that is being asked about. If this is passed in, the provider should
48
* attempt to return the sessions that are only related to this account.
49
*/
50
account?: AuthenticationSessionAccount;
51
/**
52
* The authorization server URI to use for this creation request. If passed in, first we validate that
53
* the provider can use this authorization server, then it is passed down to the auth provider.
54
*/
55
authorizationServer?: URI;
56
/**
57
* Allows the authentication provider to take in additional parameters.
58
* It is up to the provider to define what these parameters are and handle them.
59
* This is useful for passing in additional information that is specific to the provider
60
* and not part of the standard authentication flow.
61
*/
62
[key: string]: any;
63
}
64
65
export interface IAuthenticationWwwAuthenticateRequest {
66
/**
67
* The raw WWW-Authenticate header value that triggered this challenge.
68
* This will be parsed by the authentication provider to extract the necessary
69
* challenge information.
70
*/
71
readonly wwwAuthenticate: string;
72
73
/**
74
* Optional scopes for the session. If not provided, the authentication provider
75
* may use default scopes or extract them from the challenge.
76
*/
77
readonly fallbackScopes?: readonly string[];
78
}
79
80
export function isAuthenticationWwwAuthenticateRequest(obj: unknown): obj is IAuthenticationWwwAuthenticateRequest {
81
return typeof obj === 'object'
82
&& obj !== null
83
&& 'wwwAuthenticate' in obj
84
&& (typeof obj.wwwAuthenticate === 'string');
85
}
86
87
/**
88
* Represents constraints for authentication, including challenges and optional scopes.
89
* This is used when creating or retrieving sessions that must satisfy specific authentication
90
* requirements from WWW-Authenticate headers.
91
*/
92
export interface IAuthenticationConstraint {
93
/**
94
* Array of authentication challenges parsed from WWW-Authenticate headers.
95
*/
96
readonly challenges: readonly IAuthenticationChallenge[];
97
98
/**
99
* Optional scopes for the session. If not provided, the authentication provider
100
* may extract scopes from the challenges or use default scopes.
101
*/
102
readonly fallbackScopes?: readonly string[];
103
}
104
105
/**
106
* Options for getting authentication sessions via the service.
107
*/
108
export interface IAuthenticationGetSessionsOptions {
109
/**
110
* The account that is being asked about. If this is passed in, the provider should
111
* attempt to return the sessions that are only related to this account.
112
*/
113
account?: AuthenticationSessionAccount;
114
/**
115
* The authorization server URI to use for this request. If passed in, first we validate that
116
* the provider can use this authorization server, then it is passed down to the auth provider.
117
*/
118
authorizationServer?: URI;
119
/**
120
* Allows the authentication provider to take in additional parameters.
121
* It is up to the provider to define what these parameters are and handle them.
122
* This is useful for passing in additional information that is specific to the provider
123
* and not part of the standard authentication flow.
124
*/
125
[key: string]: any;
126
}
127
128
export interface AllowedExtension {
129
id: string;
130
name: string;
131
/**
132
* If true or undefined, the extension is allowed to use the account
133
* If false, the extension is not allowed to use the account
134
* TODO: undefined shouldn't be a valid value, but it is for now
135
*/
136
allowed?: boolean;
137
lastUsed?: number;
138
// If true, this comes from the product.json
139
trusted?: boolean;
140
}
141
142
export interface IAuthenticationProviderHostDelegate {
143
/** Priority for this delegate, delegates are tested in descending priority order */
144
readonly priority: number;
145
create(authorizationServer: URI, serverMetadata: IAuthorizationServerMetadata, resource: IAuthorizationProtectedResourceMetadata | undefined): Promise<string>;
146
}
147
148
export const IAuthenticationService = createDecorator<IAuthenticationService>('IAuthenticationService');
149
150
export interface IAuthenticationService {
151
readonly _serviceBrand: undefined;
152
153
/**
154
* Fires when an authentication provider has been registered
155
*/
156
readonly onDidRegisterAuthenticationProvider: Event<AuthenticationProviderInformation>;
157
/**
158
* Fires when an authentication provider has been unregistered
159
*/
160
readonly onDidUnregisterAuthenticationProvider: Event<AuthenticationProviderInformation>;
161
162
/**
163
* Fires when the list of sessions for a provider has been added, removed or changed
164
*/
165
readonly onDidChangeSessions: Event<{ providerId: string; label: string; event: AuthenticationSessionsChangeEvent }>;
166
167
/**
168
* Fires when the list of declaredProviders has changed
169
*/
170
readonly onDidChangeDeclaredProviders: Event<void>;
171
172
/**
173
* All providers that have been statically declared by extensions. These may not actually be registered or active yet.
174
*/
175
readonly declaredProviders: AuthenticationProviderInformation[];
176
177
/**
178
* Registers that an extension has declared an authentication provider in their package.json
179
* @param provider The provider information to register
180
*/
181
registerDeclaredAuthenticationProvider(provider: AuthenticationProviderInformation): void;
182
183
/**
184
* Unregisters a declared authentication provider
185
* @param id The id of the provider to unregister
186
*/
187
unregisterDeclaredAuthenticationProvider(id: string): void;
188
189
/**
190
* Checks if an authentication provider has been registered
191
* @param id The id of the provider to check
192
*/
193
isAuthenticationProviderRegistered(id: string): boolean;
194
195
/**
196
* Checks if an authentication provider is dynamic
197
* @param id The id of the provider to check
198
*/
199
isDynamicAuthenticationProvider(id: string): boolean;
200
201
/**
202
* Registers an authentication provider
203
* @param id The id of the provider
204
* @param provider The implementation of the provider
205
*/
206
registerAuthenticationProvider(id: string, provider: IAuthenticationProvider): void;
207
208
/**
209
* Unregisters an authentication provider
210
* @param id The id of the provider to unregister
211
*/
212
unregisterAuthenticationProvider(id: string): void;
213
214
/**
215
* Gets the provider ids of all registered authentication providers
216
*/
217
getProviderIds(): string[];
218
219
/**
220
* Gets the provider with the given id.
221
* @param id The id of the provider to get
222
* @throws if the provider is not registered
223
*/
224
getProvider(id: string): IAuthenticationProvider;
225
226
/**
227
* Gets all accounts that are currently logged in across all sessions
228
* @param id The id of the provider to ask for accounts
229
* @returns A promise that resolves to an array of accounts
230
*/
231
getAccounts(id: string): Promise<ReadonlyArray<AuthenticationSessionAccount>>;
232
233
/**
234
* Gets all sessions that satisfy the given scopes from the provider with the given id
235
* @param id The id of the provider to ask for a session
236
* @param scopes The scopes for the session
237
* @param options Additional options for getting sessions
238
* @param activateImmediate If true, the provider should activate immediately if it is not already
239
*/
240
getSessions(id: string, scopeListOrRequest?: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, options?: IAuthenticationGetSessionsOptions, activateImmediate?: boolean): Promise<ReadonlyArray<AuthenticationSession>>;
241
242
/**
243
* Creates an AuthenticationSession with the given provider and scopes
244
* @param providerId The id of the provider
245
* @param scopes The scopes to request
246
* @param options Additional options for creating the session
247
*/
248
createSession(providerId: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, options?: IAuthenticationCreateSessionOptions): Promise<AuthenticationSession>;
249
250
/**
251
* Removes the session with the given id from the provider with the given id
252
* @param providerId The id of the provider
253
* @param sessionId The id of the session to remove
254
*/
255
removeSession(providerId: string, sessionId: string): Promise<void>;
256
257
/**
258
* Gets a provider id for a specified authorization server
259
* @param authorizationServer The authorization server url that this provider is responsible for
260
* @param resourceServer The resource server URI that should match the provider's resourceServer (if defined)
261
*/
262
getOrActivateProviderIdForServer(authorizationServer: URI, resourceServer?: URI): Promise<string | undefined>;
263
264
/**
265
* Allows the ability register a delegate that will be used to start authentication providers
266
* @param delegate The delegate to register
267
*/
268
registerAuthenticationProviderHostDelegate(delegate: IAuthenticationProviderHostDelegate): IDisposable;
269
270
/**
271
* Creates a dynamic authentication provider for the given server metadata
272
* @param serverMetadata The metadata for the server that is being authenticated against
273
*/
274
createDynamicAuthenticationProvider(authorizationServer: URI, serverMetadata: IAuthorizationServerMetadata, resourceMetadata: IAuthorizationProtectedResourceMetadata | undefined): Promise<IAuthenticationProvider | undefined>;
275
}
276
277
export function isAuthenticationSession(thing: unknown): thing is AuthenticationSession {
278
if (typeof thing !== 'object' || !thing) {
279
return false;
280
}
281
const maybe = thing as AuthenticationSession;
282
if (typeof maybe.id !== 'string') {
283
return false;
284
}
285
if (typeof maybe.accessToken !== 'string') {
286
return false;
287
}
288
if (typeof maybe.account !== 'object' || !maybe.account) {
289
return false;
290
}
291
if (typeof maybe.account.label !== 'string') {
292
return false;
293
}
294
if (typeof maybe.account.id !== 'string') {
295
return false;
296
}
297
if (!Array.isArray(maybe.scopes)) {
298
return false;
299
}
300
if (maybe.idToken && typeof maybe.idToken !== 'string') {
301
return false;
302
}
303
return true;
304
}
305
306
// TODO: Move this into MainThreadAuthentication
307
export const IAuthenticationExtensionsService = createDecorator<IAuthenticationExtensionsService>('IAuthenticationExtensionsService');
308
export interface IAuthenticationExtensionsService {
309
readonly _serviceBrand: undefined;
310
311
/**
312
* Fires when an account preference for a specific provider has changed for the specified extensions. Does not fire when:
313
* * An account preference is removed
314
* * A session preference is changed (because it's deprecated)
315
* * A session preference is removed (because it's deprecated)
316
*/
317
readonly onDidChangeAccountPreference: Event<{ extensionIds: string[]; providerId: string }>;
318
/**
319
* Returns the accountName (also known as account.label) to pair with `IAuthenticationAccessService` to get the account preference
320
* @param providerId The authentication provider id
321
* @param extensionId The extension id to get the preference for
322
* @returns The accountName of the preference, or undefined if there is no preference set
323
*/
324
getAccountPreference(extensionId: string, providerId: string): string | undefined;
325
/**
326
* Sets the account preference for the given provider and extension
327
* @param providerId The authentication provider id
328
* @param extensionId The extension id to set the preference for
329
* @param account The account to set the preference to
330
*/
331
updateAccountPreference(extensionId: string, providerId: string, account: AuthenticationSessionAccount): void;
332
/**
333
* Removes the account preference for the given provider and extension
334
* @param providerId The authentication provider id
335
* @param extensionId The extension id to remove the preference for
336
*/
337
removeAccountPreference(extensionId: string, providerId: string): void;
338
/**
339
* @deprecated Sets the session preference for the given provider and extension
340
* @param providerId
341
* @param extensionId
342
* @param session
343
*/
344
updateSessionPreference(providerId: string, extensionId: string, session: AuthenticationSession): void;
345
/**
346
* @deprecated Gets the session preference for the given provider and extension
347
* @param providerId
348
* @param extensionId
349
* @param scopes
350
*/
351
getSessionPreference(providerId: string, extensionId: string, scopes: string[]): string | undefined;
352
/**
353
* @deprecated Removes the session preference for the given provider and extension
354
* @param providerId
355
* @param extensionId
356
* @param scopes
357
*/
358
removeSessionPreference(providerId: string, extensionId: string, scopes: string[]): void;
359
selectSession(providerId: string, extensionId: string, extensionName: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, possibleSessions: readonly AuthenticationSession[]): Promise<AuthenticationSession>;
360
requestSessionAccess(providerId: string, extensionId: string, extensionName: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, possibleSessions: readonly AuthenticationSession[]): void;
361
requestNewSession(providerId: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, extensionId: string, extensionName: string): Promise<void>;
362
updateNewSessionRequests(providerId: string, addedSessions: readonly AuthenticationSession[]): void;
363
}
364
365
/**
366
* Options passed to the authentication provider when asking for sessions.
367
*/
368
export interface IAuthenticationProviderSessionOptions {
369
/**
370
* The account that is being asked about. If this is passed in, the provider should
371
* attempt to return the sessions that are only related to this account.
372
*/
373
account?: AuthenticationSessionAccount;
374
/**
375
* The authorization server that is being asked about. If this is passed in, the provider should
376
* attempt to return sessions that are only related to this authorization server.
377
*/
378
authorizationServer?: URI;
379
/**
380
* Allows the authentication provider to take in additional parameters.
381
* It is up to the provider to define what these parameters are and handle them.
382
* This is useful for passing in additional information that is specific to the provider
383
* and not part of the standard authentication flow.
384
*/
385
[key: string]: any;
386
}
387
388
/**
389
* Represents an authentication provider.
390
*/
391
export interface IAuthenticationProvider {
392
/**
393
* The unique identifier of the authentication provider.
394
*/
395
readonly id: string;
396
397
/**
398
* The display label of the authentication provider.
399
*/
400
readonly label: string;
401
402
/**
403
* The resource server URI that this provider is responsible for, if any.
404
* TODO@TylerLeonhardt: Rather than this being added to the provider, it should be passed in to
405
* getSessions/createSession/etc... this way we can have providers that handle multiple resource servers.
406
*/
407
readonly resourceServer?: URI;
408
409
/**
410
* The resolved authorization servers. These can still contain globs, but should be concrete URIs
411
*/
412
readonly authorizationServers?: ReadonlyArray<URI>;
413
414
/**
415
* Indicates whether the authentication provider supports multiple accounts.
416
*/
417
readonly supportsMultipleAccounts: boolean;
418
419
/**
420
* Optional function to provide a custom confirmation message for authentication prompts.
421
* If not implemented, the default confirmation messages will be used.
422
* @param extensionName - The name of the extension requesting authentication.
423
* @param recreatingSession - Whether this is recreating an existing session.
424
* @returns A custom confirmation message or undefined to use the default message.
425
*/
426
readonly confirmation?: (extensionName: string, recreatingSession: boolean) => string | undefined;
427
428
/**
429
* An {@link Event} which fires when the array of sessions has changed, or data
430
* within a session has changed.
431
*/
432
readonly onDidChangeSessions: Event<AuthenticationSessionsChangeEvent>;
433
434
/**
435
* Retrieves a list of authentication sessions.
436
* @param scopes - An optional list of scopes. If provided, the sessions returned should match these permissions, otherwise all sessions should be returned.
437
* @param options - Additional options for getting sessions.
438
* @returns A promise that resolves to an array of authentication sessions.
439
*/
440
getSessions(scopes: string[] | undefined, options: IAuthenticationProviderSessionOptions): Promise<readonly AuthenticationSession[]>;
441
442
/**
443
* Prompts the user to log in.
444
* If login is successful, the `onDidChangeSessions` event should be fired.
445
* If login fails, a rejected promise should be returned.
446
* If the provider does not support multiple accounts, this method should not be called if there is already an existing session matching the provided scopes.
447
* @param scopes - A list of scopes that the new session should be created with.
448
* @param options - Additional options for creating the session.
449
* @returns A promise that resolves to an authentication session.
450
*/
451
createSession(scopes: string[], options: IAuthenticationProviderSessionOptions): Promise<AuthenticationSession>;
452
453
/**
454
* Get existing sessions that match the given authentication constraints.
455
*
456
* @param constraint The authentication constraint containing challenges and optional scopes
457
* @param options Options for the session request
458
* @returns A thenable that resolves to an array of existing authentication sessions
459
*/
460
getSessionsFromChallenges?(constraint: IAuthenticationConstraint, options: IAuthenticationProviderSessionOptions): Promise<readonly AuthenticationSession[]>;
461
462
/**
463
* Create a new session based on authentication constraints.
464
* This is called when no existing session matches the constraint requirements.
465
*
466
* @param constraint The authentication constraint containing challenges and optional scopes
467
* @param options Options for the session creation
468
* @returns A thenable that resolves to a new authentication session
469
*/
470
createSessionFromChallenges?(constraint: IAuthenticationConstraint, options: IAuthenticationProviderSessionOptions): Promise<AuthenticationSession>;
471
472
/**
473
* Removes the session corresponding to the specified session ID.
474
* If the removal is successful, the `onDidChangeSessions` event should be fired.
475
* If a session cannot be removed, the provider should reject with an error message.
476
* @param sessionId - The ID of the session to remove.
477
*/
478
removeSession(sessionId: string): Promise<void>;
479
}
480
481