Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/authentication/test/browser/authenticationService.test.ts
5251 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
6
import assert from 'assert';
7
import { Emitter, Event } from '../../../../../base/common/event.js';
8
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
9
import { URI } from '../../../../../base/common/uri.js';
10
import { AuthenticationAccessService } from '../../browser/authenticationAccessService.js';
11
import { AuthenticationService } from '../../browser/authenticationService.js';
12
import { AuthenticationProviderInformation, AuthenticationSessionsChangeEvent, IAuthenticationProvider } from '../../common/authentication.js';
13
import { TestEnvironmentService } from '../../../../test/browser/workbenchTestServices.js';
14
import { TestExtensionService, TestProductService, TestStorageService } from '../../../../test/common/workbenchTestServices.js';
15
import { NullLogService } from '../../../../../platform/log/common/log.js';
16
17
function createSession() {
18
return { id: 'session1', accessToken: 'token1', account: { id: 'account', label: 'Account' }, scopes: ['test'] };
19
}
20
21
function createProvider(overrides: Partial<IAuthenticationProvider> = {}): IAuthenticationProvider {
22
return {
23
supportsMultipleAccounts: false,
24
onDidChangeSessions: new Emitter<AuthenticationSessionsChangeEvent>().event,
25
id: 'test',
26
label: 'Test',
27
getSessions: async () => [],
28
createSession: async () => createSession(),
29
removeSession: async () => { },
30
...overrides
31
};
32
}
33
34
suite('AuthenticationService', () => {
35
const disposables = ensureNoDisposablesAreLeakedInTestSuite();
36
37
let authenticationService: AuthenticationService;
38
39
setup(() => {
40
const storageService = disposables.add(new TestStorageService());
41
const authenticationAccessService = disposables.add(new AuthenticationAccessService(storageService, TestProductService));
42
authenticationService = disposables.add(new AuthenticationService(new TestExtensionService(), authenticationAccessService, TestEnvironmentService, new NullLogService()));
43
});
44
45
teardown(() => {
46
// Dispose the authentication service after each test
47
authenticationService.dispose();
48
});
49
50
suite('declaredAuthenticationProviders', () => {
51
test('registerDeclaredAuthenticationProvider', async () => {
52
const changed = Event.toPromise(authenticationService.onDidChangeDeclaredProviders);
53
const provider: AuthenticationProviderInformation = {
54
id: 'github',
55
label: 'GitHub'
56
};
57
authenticationService.registerDeclaredAuthenticationProvider(provider);
58
59
// Assert that the provider is added to the declaredProviders array and the event fires
60
assert.equal(authenticationService.declaredProviders.length, 1);
61
assert.deepEqual(authenticationService.declaredProviders[0], provider);
62
await changed;
63
});
64
65
test('unregisterDeclaredAuthenticationProvider', async () => {
66
const provider: AuthenticationProviderInformation = {
67
id: 'github',
68
label: 'GitHub'
69
};
70
authenticationService.registerDeclaredAuthenticationProvider(provider);
71
const changed = Event.toPromise(authenticationService.onDidChangeDeclaredProviders);
72
authenticationService.unregisterDeclaredAuthenticationProvider(provider.id);
73
74
// Assert that the provider is removed from the declaredProviders array and the event fires
75
assert.equal(authenticationService.declaredProviders.length, 0);
76
await changed;
77
});
78
});
79
80
suite('authenticationProviders', () => {
81
test('isAuthenticationProviderRegistered', async () => {
82
const registered = Event.toPromise(authenticationService.onDidRegisterAuthenticationProvider);
83
const provider = createProvider();
84
assert.equal(authenticationService.isAuthenticationProviderRegistered(provider.id), false);
85
authenticationService.registerAuthenticationProvider(provider.id, provider);
86
assert.equal(authenticationService.isAuthenticationProviderRegistered(provider.id), true);
87
const result = await registered;
88
assert.deepEqual(result, { id: provider.id, label: provider.label });
89
});
90
91
test('unregisterAuthenticationProvider', async () => {
92
const unregistered = Event.toPromise(authenticationService.onDidUnregisterAuthenticationProvider);
93
const provider = createProvider();
94
authenticationService.registerAuthenticationProvider(provider.id, provider);
95
assert.equal(authenticationService.isAuthenticationProviderRegistered(provider.id), true);
96
authenticationService.unregisterAuthenticationProvider(provider.id);
97
assert.equal(authenticationService.isAuthenticationProviderRegistered(provider.id), false);
98
const result = await unregistered;
99
assert.deepEqual(result, { id: provider.id, label: provider.label });
100
});
101
102
test('getProviderIds', () => {
103
const provider1 = createProvider({
104
id: 'provider1',
105
label: 'Provider 1'
106
});
107
const provider2 = createProvider({
108
id: 'provider2',
109
label: 'Provider 2'
110
});
111
112
authenticationService.registerAuthenticationProvider(provider1.id, provider1);
113
authenticationService.registerAuthenticationProvider(provider2.id, provider2);
114
115
const providerIds = authenticationService.getProviderIds();
116
117
// Assert that the providerIds array contains the registered provider ids
118
assert.deepEqual(providerIds, [provider1.id, provider2.id]);
119
});
120
121
test('getProvider', () => {
122
const provider = createProvider();
123
124
authenticationService.registerAuthenticationProvider(provider.id, provider);
125
126
const retrievedProvider = authenticationService.getProvider(provider.id);
127
128
// Assert that the retrieved provider is the same as the registered provider
129
assert.deepEqual(retrievedProvider, provider);
130
});
131
132
test('getOrActivateProviderIdForServer - should return undefined when no provider matches the authorization server', async () => {
133
const authorizationServer = URI.parse('https://example.com');
134
const result = await authenticationService.getOrActivateProviderIdForServer(authorizationServer);
135
assert.strictEqual(result, undefined);
136
});
137
138
test('getOrActivateProviderIdForServer - should return provider id if authorizationServerGlobs matches and authorizationServers match', async () => {
139
// Register a declared provider with an authorization server glob
140
const provider: AuthenticationProviderInformation = {
141
id: 'github',
142
label: 'GitHub',
143
authorizationServerGlobs: ['https://github.com/*']
144
};
145
authenticationService.registerDeclaredAuthenticationProvider(provider);
146
147
// Register an authentication provider with matching authorization servers
148
const authProvider = createProvider({
149
id: 'github',
150
label: 'GitHub',
151
authorizationServers: [URI.parse('https://github.com/login')]
152
});
153
authenticationService.registerAuthenticationProvider('github', authProvider);
154
155
// Test with a matching URI
156
const authorizationServer = URI.parse('https://github.com/login');
157
const result = await authenticationService.getOrActivateProviderIdForServer(authorizationServer);
158
159
// Verify the result
160
assert.strictEqual(result, 'github');
161
});
162
163
test('getOrActivateProviderIdForServer - should return undefined if authorizationServerGlobs match but authorizationServers do not match', async () => {
164
// Register a declared provider with an authorization server glob
165
const provider: AuthenticationProviderInformation = {
166
id: 'github',
167
label: 'GitHub',
168
authorizationServerGlobs: ['https://github.com/*']
169
};
170
authenticationService.registerDeclaredAuthenticationProvider(provider);
171
172
// Register an authentication provider with non-matching authorization servers
173
const authProvider = createProvider({
174
id: 'github',
175
label: 'GitHub',
176
authorizationServers: [URI.parse('https://github.com/different')]
177
});
178
authenticationService.registerAuthenticationProvider('github', authProvider);
179
180
// Test with a non-matching URI
181
const authorizationServer = URI.parse('https://github.com/login');
182
const result = await authenticationService.getOrActivateProviderIdForServer(authorizationServer);
183
184
// Verify the result
185
assert.strictEqual(result, undefined);
186
});
187
188
test('getOrActivateProviderIdForAuthorizationServer - should check multiple providers and return the first match', async () => {
189
// Register two declared providers with authorization server globs
190
const provider1: AuthenticationProviderInformation = {
191
id: 'github',
192
label: 'GitHub',
193
authorizationServerGlobs: ['https://github.com/*']
194
};
195
const provider2: AuthenticationProviderInformation = {
196
id: 'microsoft',
197
label: 'Microsoft',
198
authorizationServerGlobs: ['https://login.microsoftonline.com/*']
199
};
200
authenticationService.registerDeclaredAuthenticationProvider(provider1);
201
authenticationService.registerDeclaredAuthenticationProvider(provider2);
202
203
// Register authentication providers
204
const githubProvider = createProvider({
205
id: 'github',
206
label: 'GitHub',
207
authorizationServers: [URI.parse('https://github.com/different')]
208
});
209
authenticationService.registerAuthenticationProvider('github', githubProvider);
210
211
const microsoftProvider = createProvider({
212
id: 'microsoft',
213
label: 'Microsoft',
214
authorizationServers: [URI.parse('https://login.microsoftonline.com/common')]
215
});
216
authenticationService.registerAuthenticationProvider('microsoft', microsoftProvider);
217
218
// Test with a URI that should match the second provider
219
const authorizationServer = URI.parse('https://login.microsoftonline.com/common');
220
const result = await authenticationService.getOrActivateProviderIdForServer(authorizationServer);
221
222
// Verify the result
223
assert.strictEqual(result, 'microsoft');
224
});
225
226
test('getOrActivateProviderIdForServer - should match when resourceServer matches provider resourceServer', async () => {
227
const authorizationServer = URI.parse('https://login.microsoftonline.com/common');
228
const resourceServer = URI.parse('https://graph.microsoft.com');
229
230
// Register an authentication provider with a resourceServer
231
const authProvider = createProvider({
232
id: 'microsoft',
233
label: 'Microsoft',
234
authorizationServers: [authorizationServer],
235
resourceServer: resourceServer
236
});
237
authenticationService.registerAuthenticationProvider('microsoft', authProvider);
238
239
// Test with matching authorization server and resource server
240
const result = await authenticationService.getOrActivateProviderIdForServer(authorizationServer, resourceServer);
241
242
// Verify the result
243
assert.strictEqual(result, 'microsoft');
244
});
245
246
test('getOrActivateProviderIdForServer - should not match when resourceServer does not match provider resourceServer', async () => {
247
const authorizationServer = URI.parse('https://login.microsoftonline.com/common');
248
const resourceServer = URI.parse('https://graph.microsoft.com');
249
const differentResourceServer = URI.parse('https://vault.azure.net');
250
251
// Register an authentication provider with a resourceServer
252
const authProvider = createProvider({
253
id: 'microsoft',
254
label: 'Microsoft',
255
authorizationServers: [authorizationServer],
256
resourceServer: resourceServer
257
});
258
authenticationService.registerAuthenticationProvider('microsoft', authProvider);
259
260
// Test with matching authorization server but different resource server
261
const result = await authenticationService.getOrActivateProviderIdForServer(authorizationServer, differentResourceServer);
262
263
// Verify the result - should not match because resource servers don't match
264
assert.strictEqual(result, undefined);
265
});
266
267
test('getOrActivateProviderIdForServer - should match when provider has no resourceServer and resourceServer is provided', async () => {
268
const authorizationServer = URI.parse('https://login.microsoftonline.com/common');
269
const resourceServer = URI.parse('https://graph.microsoft.com');
270
271
// Register an authentication provider without a resourceServer
272
const authProvider = createProvider({
273
id: 'microsoft',
274
label: 'Microsoft',
275
authorizationServers: [authorizationServer]
276
});
277
authenticationService.registerAuthenticationProvider('microsoft', authProvider);
278
279
// Test with matching authorization server and a resource server
280
// Should match because provider has no resourceServer defined
281
const result = await authenticationService.getOrActivateProviderIdForServer(authorizationServer, resourceServer);
282
283
// Verify the result
284
assert.strictEqual(result, 'microsoft');
285
});
286
287
test('getOrActivateProviderIdForServer - should match when provider has resourceServer but no resourceServer is provided', async () => {
288
const authorizationServer = URI.parse('https://login.microsoftonline.com/common');
289
const resourceServer = URI.parse('https://graph.microsoft.com');
290
291
// Register an authentication provider with a resourceServer
292
const authProvider = createProvider({
293
id: 'microsoft',
294
label: 'Microsoft',
295
authorizationServers: [authorizationServer],
296
resourceServer: resourceServer
297
});
298
authenticationService.registerAuthenticationProvider('microsoft', authProvider);
299
300
// Test with matching authorization server but no resource server provided
301
// Should match because no resourceServer is provided to check against
302
const result = await authenticationService.getOrActivateProviderIdForServer(authorizationServer);
303
304
// Verify the result
305
assert.strictEqual(result, 'microsoft');
306
});
307
308
test('getOrActivateProviderIdForServer - should distinguish between providers with same authorization server but different resource servers', async () => {
309
const authorizationServer = URI.parse('https://login.microsoftonline.com/common');
310
const graphResourceServer = URI.parse('https://graph.microsoft.com');
311
const vaultResourceServer = URI.parse('https://vault.azure.net');
312
313
// Register first provider with Graph resource server
314
const graphProvider = createProvider({
315
id: 'microsoft-graph',
316
label: 'Microsoft Graph',
317
authorizationServers: [authorizationServer],
318
resourceServer: graphResourceServer
319
});
320
authenticationService.registerAuthenticationProvider('microsoft-graph', graphProvider);
321
322
// Register second provider with Vault resource server
323
const vaultProvider = createProvider({
324
id: 'microsoft-vault',
325
label: 'Microsoft Vault',
326
authorizationServers: [authorizationServer],
327
resourceServer: vaultResourceServer
328
});
329
authenticationService.registerAuthenticationProvider('microsoft-vault', vaultProvider);
330
331
// Test with Graph resource server - should match the first provider
332
const graphResult = await authenticationService.getOrActivateProviderIdForServer(authorizationServer, graphResourceServer);
333
assert.strictEqual(graphResult, 'microsoft-graph');
334
335
// Test with Vault resource server - should match the second provider
336
const vaultResult = await authenticationService.getOrActivateProviderIdForServer(authorizationServer, vaultResourceServer);
337
assert.strictEqual(vaultResult, 'microsoft-vault');
338
339
// Test with different resource server - should not match either
340
const otherResourceServer = URI.parse('https://storage.azure.com');
341
const noMatchResult = await authenticationService.getOrActivateProviderIdForServer(authorizationServer, otherResourceServer);
342
assert.strictEqual(noMatchResult, undefined);
343
});
344
});
345
346
suite('authenticationSessions', () => {
347
test('getSessions - base case', async () => {
348
let isCalled = false;
349
const provider = createProvider({
350
getSessions: async () => {
351
isCalled = true;
352
return [createSession()];
353
},
354
});
355
authenticationService.registerAuthenticationProvider(provider.id, provider);
356
const sessions = await authenticationService.getSessions(provider.id);
357
358
assert.equal(sessions.length, 1);
359
assert.ok(isCalled);
360
});
361
362
test('getSessions - authorization server is not registered', async () => {
363
let isCalled = false;
364
const provider = createProvider({
365
getSessions: async () => {
366
isCalled = true;
367
return [createSession()];
368
},
369
});
370
authenticationService.registerAuthenticationProvider(provider.id, provider);
371
assert.rejects(() => authenticationService.getSessions(provider.id, [], { authorizationServer: URI.parse('https://example.com') }));
372
assert.ok(!isCalled);
373
});
374
375
test('createSession', async () => {
376
const emitter = new Emitter<AuthenticationSessionsChangeEvent>();
377
const provider = createProvider({
378
onDidChangeSessions: emitter.event,
379
createSession: async () => {
380
const session = createSession();
381
emitter.fire({ added: [session], removed: [], changed: [] });
382
return session;
383
},
384
});
385
const changed = Event.toPromise(authenticationService.onDidChangeSessions);
386
authenticationService.registerAuthenticationProvider(provider.id, provider);
387
const session = await authenticationService.createSession(provider.id, ['repo']);
388
389
// Assert that the created session matches the expected session and the event fires
390
assert.ok(session);
391
const result = await changed;
392
assert.deepEqual(result, {
393
providerId: provider.id,
394
label: provider.label,
395
event: { added: [session], removed: [], changed: [] }
396
});
397
});
398
399
test('removeSession', async () => {
400
const emitter = new Emitter<AuthenticationSessionsChangeEvent>();
401
const session = createSession();
402
const provider = createProvider({
403
onDidChangeSessions: emitter.event,
404
removeSession: async () => emitter.fire({ added: [], removed: [session], changed: [] })
405
});
406
const changed = Event.toPromise(authenticationService.onDidChangeSessions);
407
authenticationService.registerAuthenticationProvider(provider.id, provider);
408
await authenticationService.removeSession(provider.id, session.id);
409
410
const result = await changed;
411
assert.deepEqual(result, {
412
providerId: provider.id,
413
label: provider.label,
414
event: { added: [], removed: [session], changed: [] }
415
});
416
});
417
418
test('onDidChangeSessions', async () => {
419
const emitter = new Emitter<AuthenticationSessionsChangeEvent>();
420
const provider = createProvider({
421
onDidChangeSessions: emitter.event,
422
getSessions: async () => []
423
});
424
authenticationService.registerAuthenticationProvider(provider.id, provider);
425
426
const changed = Event.toPromise(authenticationService.onDidChangeSessions);
427
const session = createSession();
428
emitter.fire({ added: [], removed: [], changed: [session] });
429
430
const result = await changed;
431
assert.deepEqual(result, {
432
providerId: provider.id,
433
label: provider.label,
434
event: { added: [], removed: [], changed: [session] }
435
});
436
});
437
});
438
});
439
440