@verdaccio/auth 8.0.0-next-8.2 → 8.0.0-next-8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,260 @@
1
+ import _ from 'lodash';
2
+ import path from 'path';
3
+ import { describe, expect, test, vi } from 'vitest';
4
+
5
+ import {
6
+ Config as AppConfig,
7
+ createAnonymousRemoteUser,
8
+ createRemoteUser,
9
+ parseConfigFile,
10
+ } from '@verdaccio/config';
11
+ import { getDefaultConfig } from '@verdaccio/config';
12
+ import { TOKEN_BEARER } from '@verdaccio/core';
13
+ import { logger, setup } from '@verdaccio/logger';
14
+ import { signPayload } from '@verdaccio/signature';
15
+ import { Config, RemoteUser, Security } from '@verdaccio/types';
16
+ import { buildToken, buildUserBuffer } from '@verdaccio/utils';
17
+
18
+ import { Auth, getApiToken, getMiddlewareCredentials, verifyJWTPayload } from '../src';
19
+
20
+ setup({});
21
+
22
+ const parseConfigurationFile = (conf) => {
23
+ const { name, ext } = path.parse(conf);
24
+ const format = ext.startsWith('.') ? ext.substring(1) : 'yaml';
25
+
26
+ return path.join(__dirname, `./partials/config/${format}/security/${name}.${format}`);
27
+ };
28
+
29
+ describe('Auth utilities', () => {
30
+ vi.setConfig({ testTimeout: 20000 });
31
+
32
+ const parseConfigurationSecurityFile = (name) => {
33
+ return parseConfigurationFile(`security/${name}`);
34
+ };
35
+
36
+ function getConfig(configFileName: string, secret: string) {
37
+ const conf = parseConfigFile(parseConfigurationSecurityFile(configFileName));
38
+ // @ts-ignore
39
+ const secConf = _.merge(getDefaultConfig(), conf);
40
+ secConf.secret = secret;
41
+ const config: Config = new AppConfig(secConf);
42
+
43
+ return config;
44
+ }
45
+
46
+ async function getTokenByConfiguration(
47
+ configFileName: string,
48
+ username: string,
49
+ password: string,
50
+ secret = '12345',
51
+ methodToSpy: string,
52
+ methodNotBeenCalled: string
53
+ ): Promise<string> {
54
+ const config: Config = getConfig(configFileName, secret);
55
+ const auth: Auth = new Auth(config, logger);
56
+ await auth.init();
57
+ // @ts-ignore
58
+ const spy = vi.spyOn(auth, methodToSpy);
59
+ // @ts-ignore
60
+ const spyNotCalled = vi.spyOn(auth, methodNotBeenCalled);
61
+ const user: RemoteUser = {
62
+ name: username,
63
+ real_groups: ['test', '$all', '$authenticated', '@all', '@authenticated', 'all'],
64
+ groups: ['company-role1', 'company-role2'],
65
+ };
66
+ const token = await getApiToken(auth, config, user, password);
67
+ expect(spy).toHaveBeenCalled();
68
+ expect(spy).toHaveBeenCalledTimes(1);
69
+ expect(spyNotCalled).not.toHaveBeenCalled();
70
+ expect(token).toBeDefined();
71
+
72
+ return token as string;
73
+ }
74
+
75
+ describe('getMiddlewareCredentials test', () => {
76
+ describe('should get AES credentials', () => {
77
+ test.concurrent('should unpack aes token and credentials bearer auth', async () => {
78
+ const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
79
+ const user = 'test';
80
+ const pass = 'test';
81
+ const token = await getTokenByConfiguration(
82
+ 'security-legacy',
83
+ user,
84
+ pass,
85
+ secret,
86
+ 'aesEncrypt',
87
+ 'jwtEncrypt'
88
+ );
89
+ const config: Config = getConfig('security-legacy', secret);
90
+ const security: Security = config.security;
91
+ const credentials = getMiddlewareCredentials(security, secret, `Bearer ${token}`);
92
+ expect(credentials).toBeDefined();
93
+ // @ts-ignore
94
+ expect(credentials.user).toEqual(user);
95
+ // @ts-ignore
96
+ expect(credentials.password).toEqual(pass);
97
+ });
98
+
99
+ test.concurrent('should unpack aes token and credentials basic auth', async () => {
100
+ const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
101
+ const user = 'test';
102
+ const pass = 'test';
103
+ // basic authentication need send user as base64
104
+ const token = buildUserBuffer(user, pass).toString('base64');
105
+ const config: Config = getConfig('security-legacy', secret);
106
+ const security: Security = config.security;
107
+ const credentials = getMiddlewareCredentials(security, secret, `Basic ${token}`);
108
+ expect(credentials).toBeDefined();
109
+ // @ts-ignore
110
+ expect(credentials.user).toEqual(user);
111
+ // @ts-ignore
112
+ expect(credentials.password).toEqual(pass);
113
+ });
114
+
115
+ test.concurrent('should return empty credential wrong secret key', async () => {
116
+ const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
117
+ const token = await getTokenByConfiguration(
118
+ 'security-legacy',
119
+ 'test',
120
+ 'test',
121
+ secret,
122
+ 'aesEncrypt',
123
+ 'jwtEncrypt'
124
+ );
125
+ const config: Config = getConfig('security-legacy', secret);
126
+ const security: Security = config.security;
127
+ const credentials = getMiddlewareCredentials(
128
+ security,
129
+ 'b2df428b9929d3ace7c598bbf4e496_BAD_TOKEN',
130
+ buildToken(TOKEN_BEARER, token)
131
+ );
132
+ expect(credentials).not.toBeDefined();
133
+ });
134
+
135
+ test.concurrent('should return empty credential wrong scheme', async () => {
136
+ const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
137
+ const token = await getTokenByConfiguration(
138
+ 'security-legacy',
139
+ 'test',
140
+ 'test',
141
+ secret,
142
+ 'aesEncrypt',
143
+ 'jwtEncrypt'
144
+ );
145
+ const config: Config = getConfig('security-legacy', secret);
146
+ const security: Security = config.security;
147
+ const credentials = getMiddlewareCredentials(
148
+ security,
149
+ secret,
150
+ buildToken('BAD_SCHEME', token)
151
+ );
152
+ expect(credentials).not.toBeDefined();
153
+ });
154
+
155
+ test.concurrent('should return empty credential corrupted payload', async () => {
156
+ const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
157
+ const config: Config = getConfig('security-legacy', secret);
158
+ const auth: Auth = new Auth(config, logger);
159
+ await auth.init();
160
+ // @ts-expect-error
161
+ const token = auth.aesEncrypt(null);
162
+ const security: Security = config.security;
163
+ const credentials = getMiddlewareCredentials(
164
+ security,
165
+ secret,
166
+ buildToken(TOKEN_BEARER, token as string)
167
+ );
168
+ expect(credentials).not.toBeDefined();
169
+ });
170
+ });
171
+
172
+ describe('verifyJWTPayload', () => {
173
+ test('should fail on verify the token and return anonymous users', () => {
174
+ expect(verifyJWTPayload('fakeToken', 'b2df428b9929d3ace7c598bbf4e496b2')).toEqual(
175
+ createAnonymousRemoteUser()
176
+ );
177
+ });
178
+
179
+ test('should verify the token and return a remote user', async () => {
180
+ const remoteUser = createRemoteUser('foo', []);
181
+ const token = await signPayload(remoteUser, '12345');
182
+ const verifiedToken = verifyJWTPayload(token, '12345');
183
+ expect(verifiedToken.groups).toEqual(remoteUser.groups);
184
+ expect(verifiedToken.name).toEqual(remoteUser.name);
185
+ });
186
+ });
187
+
188
+ describe('should get JWT credentials', () => {
189
+ test('should return anonymous whether token is corrupted', () => {
190
+ const config: Config = getConfig('security-jwt', '12345');
191
+ const security: Security = config.security;
192
+ const credentials = getMiddlewareCredentials(
193
+ security,
194
+ '12345',
195
+ buildToken(TOKEN_BEARER, 'fakeToken')
196
+ ) as RemoteUser;
197
+
198
+ expect(credentials).toBeDefined();
199
+ expect(credentials.name).not.toBeDefined();
200
+ expect(credentials.real_groups).toBeDefined();
201
+
202
+ expect(credentials.groups).toEqual(['$all', '$anonymous', '@all', '@anonymous']);
203
+ });
204
+
205
+ test('should return anonymous whether token and scheme are corrupted', () => {
206
+ const config: Config = getConfig('security-jwt', '12345');
207
+ const security: Security = config.security;
208
+ const credentials = getMiddlewareCredentials(
209
+ security,
210
+ '12345',
211
+ buildToken('FakeScheme', 'fakeToken')
212
+ );
213
+
214
+ expect(credentials).not.toBeDefined();
215
+ });
216
+
217
+ test('should verify successfully a JWT token', async () => {
218
+ const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
219
+ const user = 'test';
220
+ const config: Config = getConfig('security-jwt', secret);
221
+ const token = await getTokenByConfiguration(
222
+ 'security-jwt',
223
+ user,
224
+ 'secretTest',
225
+ secret,
226
+ 'jwtEncrypt',
227
+ 'aesEncrypt'
228
+ );
229
+ const security: Security = config.security;
230
+ const credentials = getMiddlewareCredentials(
231
+ security,
232
+ secret,
233
+ buildToken(TOKEN_BEARER, token)
234
+ ) as RemoteUser;
235
+ expect(credentials).toBeDefined();
236
+
237
+ expect(credentials.name).toEqual(user);
238
+ expect(credentials.real_groups).toBeDefined();
239
+ expect(credentials.real_groups).toEqual([
240
+ 'test',
241
+ '$all',
242
+ '$authenticated',
243
+ '@all',
244
+ '@authenticated',
245
+ 'all',
246
+ ]);
247
+ expect(credentials.groups).toEqual([
248
+ 'company-role1',
249
+ 'company-role2',
250
+ 'test',
251
+ '$all',
252
+ '$authenticated',
253
+ '@all',
254
+ '@authenticated',
255
+ 'all',
256
+ ]);
257
+ });
258
+ });
259
+ });
260
+ });
@@ -1,5 +1,6 @@
1
1
  import _ from 'lodash';
2
2
  import path from 'path';
3
+ import { describe, expect, test, vi } from 'vitest';
3
4
 
4
5
  import {
5
6
  Config as AppConfig,
@@ -9,17 +10,11 @@ import {
9
10
  parseConfigFile,
10
11
  } from '@verdaccio/config';
11
12
  import { getDefaultConfig } from '@verdaccio/config';
12
- import {
13
- API_ERROR,
14
- CHARACTER_ENCODING,
15
- TOKEN_BEARER,
16
- VerdaccioError,
17
- errorUtils,
18
- } from '@verdaccio/core';
19
- import { setup } from '@verdaccio/logger';
20
- import { aesDecrypt, signPayload, verifyPayload } from '@verdaccio/signature';
21
- import { Config, RemoteUser, Security } from '@verdaccio/types';
22
- import { buildToken, buildUserBuffer, getAuthenticatedMessage } from '@verdaccio/utils';
13
+ import { API_ERROR, CHARACTER_ENCODING, VerdaccioError, errorUtils } from '@verdaccio/core';
14
+ import { logger, setup } from '@verdaccio/logger';
15
+ import { aesDecrypt, verifyPayload } from '@verdaccio/signature';
16
+ import { Config, RemoteUser } from '@verdaccio/types';
17
+ import { getAuthenticatedMessage } from '@verdaccio/utils';
23
18
 
24
19
  import {
25
20
  ActionsAllowed,
@@ -28,8 +23,6 @@ import {
28
23
  allow_action,
29
24
  getApiToken,
30
25
  getDefaultPlugins,
31
- getMiddlewareCredentials,
32
- verifyJWTPayload,
33
26
  } from '../src';
34
27
 
35
28
  setup({});
@@ -42,7 +35,7 @@ const parseConfigurationFile = (conf) => {
42
35
  };
43
36
 
44
37
  describe('Auth utilities', () => {
45
- jest.setTimeout(20000);
38
+ vi.setConfig({ testTimeout: 20000 });
46
39
 
47
40
  const parseConfigurationSecurityFile = (name) => {
48
41
  return parseConfigurationFile(`security/${name}`);
@@ -52,6 +45,7 @@ describe('Auth utilities', () => {
52
45
  const conf = parseConfigFile(parseConfigurationSecurityFile(configFileName));
53
46
  // @ts-ignore
54
47
  const secConf = _.merge(getDefaultConfig(), conf);
48
+ // @ts-expect-error
55
49
  secConf.secret = secret;
56
50
  const config: Config = new AppConfig(secConf);
57
51
 
@@ -67,12 +61,12 @@ describe('Auth utilities', () => {
67
61
  methodNotBeenCalled: string
68
62
  ): Promise<string> {
69
63
  const config: Config = getConfig(configFileName, secret);
70
- const auth: Auth = new Auth(config);
64
+ const auth: Auth = new Auth(config, logger);
71
65
  await auth.init();
72
66
  // @ts-ignore
73
- const spy = jest.spyOn(auth, methodToSpy);
67
+ const spy = vi.spyOn(auth, methodToSpy);
74
68
  // @ts-ignore
75
- const spyNotCalled = jest.spyOn(auth, methodNotBeenCalled);
69
+ const spyNotCalled = vi.spyOn(auth, methodNotBeenCalled);
76
70
  const user: RemoteUser = {
77
71
  name: username,
78
72
  real_groups: ['test', '$all', '$authenticated', '@all', '@authenticated', 'all'],
@@ -123,14 +117,14 @@ describe('Auth utilities', () => {
123
117
 
124
118
  describe('getDefaultPlugins', () => {
125
119
  test('authentication should fail by default (default)', () => {
126
- const plugin = getDefaultPlugins({ trace: jest.fn() });
120
+ const plugin = getDefaultPlugins({ trace: vi.fn() });
127
121
  plugin.authenticate('foo', 'bar', (error: any) => {
128
122
  expect(error).toEqual(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
129
123
  });
130
124
  });
131
125
 
132
126
  test('add user should fail by default (default)', () => {
133
- const plugin = getDefaultPlugins({ trace: jest.fn() });
127
+ const plugin = getDefaultPlugins({ trace: vi.fn() });
134
128
  // @ts-ignore
135
129
  plugin.adduser('foo', 'bar', (error: any) => {
136
130
  expect(error).toEqual(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
@@ -151,7 +145,7 @@ describe('Auth utilities', () => {
151
145
  test.each(['access', 'publish', 'unpublish'])(
152
146
  'should restrict %s to anonymous users',
153
147
  (type) => {
154
- allow_action(type as ActionsAllowed, { trace: jest.fn() })(
148
+ allow_action(type as ActionsAllowed, { trace: vi.fn() })(
155
149
  createAnonymousRemoteUser(),
156
150
  {
157
151
  ...packageAccess,
@@ -168,7 +162,7 @@ describe('Auth utilities', () => {
168
162
  test.each(['access', 'publish', 'unpublish'])(
169
163
  'should allow %s to anonymous users',
170
164
  (type) => {
171
- allow_action(type as ActionsAllowed, { trace: jest.fn() })(
165
+ allow_action(type as ActionsAllowed, { trace: vi.fn() })(
172
166
  createAnonymousRemoteUser(),
173
167
  {
174
168
  ...packageAccess,
@@ -185,7 +179,7 @@ describe('Auth utilities', () => {
185
179
  test.each(['access', 'publish', 'unpublish'])(
186
180
  'should allow %s only if user is anonymous if the logged user has groups',
187
181
  (type) => {
188
- allow_action(type as ActionsAllowed, { trace: jest.fn() })(
182
+ allow_action(type as ActionsAllowed, { trace: vi.fn() })(
189
183
  createRemoteUser('juan', ['maintainer', 'admin']),
190
184
  {
191
185
  ...packageAccess,
@@ -202,7 +196,7 @@ describe('Auth utilities', () => {
202
196
  test.each(['access', 'publish', 'unpublish'])(
203
197
  'should allow %s only if user is anonymous match any other groups',
204
198
  (type) => {
205
- allow_action(type as ActionsAllowed, { trace: jest.fn() })(
199
+ allow_action(type as ActionsAllowed, { trace: vi.fn() })(
206
200
  createRemoteUser('juan', ['maintainer', 'admin']),
207
201
  {
208
202
  ...packageAccess,
@@ -219,7 +213,7 @@ describe('Auth utilities', () => {
219
213
  test.each(['access', 'publish', 'unpublish'])(
220
214
  'should not allow %s anonymous if other groups are defined and does not match',
221
215
  (type) => {
222
- allow_action(type as ActionsAllowed, { trace: jest.fn() })(
216
+ allow_action(type as ActionsAllowed, { trace: vi.fn() })(
223
217
  createRemoteUser('juan', ['maintainer', 'admin']),
224
218
  {
225
219
  ...packageAccess,
@@ -364,190 +358,4 @@ describe('Auth utilities', () => {
364
358
  expect(getAuthenticatedMessage('test')).toBe("you are authenticated as 'test'");
365
359
  });
366
360
  });
367
-
368
- describe('getMiddlewareCredentials test', () => {
369
- describe('should get AES credentials', () => {
370
- test.concurrent('should unpack aes token and credentials bearer auth', async () => {
371
- const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
372
- const user = 'test';
373
- const pass = 'test';
374
- const token = await getTokenByConfiguration(
375
- 'security-legacy',
376
- user,
377
- pass,
378
- secret,
379
- 'aesEncrypt',
380
- 'jwtEncrypt'
381
- );
382
- const config: Config = getConfig('security-legacy', secret);
383
- const security: Security = config.security;
384
- const credentials = getMiddlewareCredentials(security, secret, `Bearer ${token}`);
385
- expect(credentials).toBeDefined();
386
- // @ts-ignore
387
- expect(credentials.user).toEqual(user);
388
- // @ts-ignore
389
- expect(credentials.password).toEqual(pass);
390
- });
391
-
392
- test.concurrent('should unpack aes token and credentials basic auth', async () => {
393
- const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
394
- const user = 'test';
395
- const pass = 'test';
396
- // basic authentication need send user as base64
397
- const token = buildUserBuffer(user, pass).toString('base64');
398
- const config: Config = getConfig('security-legacy', secret);
399
- const security: Security = config.security;
400
- const credentials = getMiddlewareCredentials(security, secret, `Basic ${token}`);
401
- expect(credentials).toBeDefined();
402
- // @ts-ignore
403
- expect(credentials.user).toEqual(user);
404
- // @ts-ignore
405
- expect(credentials.password).toEqual(pass);
406
- });
407
-
408
- test.concurrent('should return empty credential wrong secret key', async () => {
409
- const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
410
- const token = await getTokenByConfiguration(
411
- 'security-legacy',
412
- 'test',
413
- 'test',
414
- secret,
415
- 'aesEncrypt',
416
- 'jwtEncrypt'
417
- );
418
- const config: Config = getConfig('security-legacy', secret);
419
- const security: Security = config.security;
420
- const credentials = getMiddlewareCredentials(
421
- security,
422
- 'b2df428b9929d3ace7c598bbf4e496_BAD_TOKEN',
423
- buildToken(TOKEN_BEARER, token)
424
- );
425
- expect(credentials).not.toBeDefined();
426
- });
427
-
428
- test.concurrent('should return empty credential wrong scheme', async () => {
429
- const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
430
- const token = await getTokenByConfiguration(
431
- 'security-legacy',
432
- 'test',
433
- 'test',
434
- secret,
435
- 'aesEncrypt',
436
- 'jwtEncrypt'
437
- );
438
- const config: Config = getConfig('security-legacy', secret);
439
- const security: Security = config.security;
440
- const credentials = getMiddlewareCredentials(
441
- security,
442
- secret,
443
- buildToken('BAD_SCHEME', token)
444
- );
445
- expect(credentials).not.toBeDefined();
446
- });
447
-
448
- test.concurrent('should return empty credential corrupted payload', async () => {
449
- const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
450
- const config: Config = getConfig('security-legacy', secret);
451
- const auth: Auth = new Auth(config);
452
- await auth.init();
453
- // @ts-expect-error
454
- const token = auth.aesEncrypt(null);
455
- const security: Security = config.security;
456
- const credentials = getMiddlewareCredentials(
457
- security,
458
- secret,
459
- buildToken(TOKEN_BEARER, token as string)
460
- );
461
- expect(credentials).not.toBeDefined();
462
- });
463
- });
464
-
465
- describe('verifyJWTPayload', () => {
466
- test('should fail on verify the token and return anonymous users', () => {
467
- expect(verifyJWTPayload('fakeToken', 'b2df428b9929d3ace7c598bbf4e496b2')).toEqual(
468
- createAnonymousRemoteUser()
469
- );
470
- });
471
-
472
- test('should verify the token and return a remote user', async () => {
473
- const remoteUser = createRemoteUser('foo', []);
474
- const token = await signPayload(remoteUser, '12345');
475
- const verifiedToken = verifyJWTPayload(token, '12345');
476
- expect(verifiedToken.groups).toEqual(remoteUser.groups);
477
- expect(verifiedToken.name).toEqual(remoteUser.name);
478
- });
479
- });
480
-
481
- describe('should get JWT credentials', () => {
482
- test('should return anonymous whether token is corrupted', () => {
483
- const config: Config = getConfig('security-jwt', '12345');
484
- const security: Security = config.security;
485
- const credentials = getMiddlewareCredentials(
486
- security,
487
- '12345',
488
- buildToken(TOKEN_BEARER, 'fakeToken')
489
- ) as RemoteUser;
490
-
491
- expect(credentials).toBeDefined();
492
- expect(credentials.name).not.toBeDefined();
493
- expect(credentials.real_groups).toBeDefined();
494
-
495
- expect(credentials.groups).toEqual(['$all', '$anonymous', '@all', '@anonymous']);
496
- });
497
-
498
- test('should return anonymous whether token and scheme are corrupted', () => {
499
- const config: Config = getConfig('security-jwt', '12345');
500
- const security: Security = config.security;
501
- const credentials = getMiddlewareCredentials(
502
- security,
503
- '12345',
504
- buildToken('FakeScheme', 'fakeToken')
505
- );
506
-
507
- expect(credentials).not.toBeDefined();
508
- });
509
-
510
- test('should verify successfully a JWT token', async () => {
511
- const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
512
- const user = 'test';
513
- const config: Config = getConfig('security-jwt', secret);
514
- const token = await getTokenByConfiguration(
515
- 'security-jwt',
516
- user,
517
- 'secretTest',
518
- secret,
519
- 'jwtEncrypt',
520
- 'aesEncrypt'
521
- );
522
- const security: Security = config.security;
523
- const credentials = getMiddlewareCredentials(
524
- security,
525
- secret,
526
- buildToken(TOKEN_BEARER, token)
527
- ) as RemoteUser;
528
- expect(credentials).toBeDefined();
529
-
530
- expect(credentials.name).toEqual(user);
531
- expect(credentials.real_groups).toBeDefined();
532
- expect(credentials.real_groups).toEqual([
533
- 'test',
534
- '$all',
535
- '$authenticated',
536
- '@all',
537
- '@authenticated',
538
- 'all',
539
- ]);
540
- expect(credentials.groups).toEqual([
541
- 'company-role1',
542
- 'company-role2',
543
- 'test',
544
- '$all',
545
- '$authenticated',
546
- '@all',
547
- '@authenticated',
548
- 'all',
549
- ]);
550
- });
551
- });
552
- });
553
361
  });