@verdaccio/auth 8.0.0-next-8.11 → 8.0.0-next-8.13
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.
- package/README.md +30 -24
- package/package.json +16 -12
- package/.babelrc +0 -3
- package/CHANGELOG.md +0 -1755
- package/src/auth.ts +0 -607
- package/src/index.ts +0 -3
- package/src/signature-legacy.ts +0 -66
- package/src/types.ts +0 -46
- package/src/utils.ts +0 -252
- package/test/auth-utils-middleware.spec.ts +0 -260
- package/test/auth-utils.spec.ts +0 -362
- package/test/auth.spec.ts +0 -722
- package/test/helper/plugin.ts +0 -43
- package/test/partials/config/yaml/security/security-basic.yaml +0 -12
- package/test/partials/config/yaml/security/security-empty.yaml +0 -1
- package/test/partials/config/yaml/security/security-jwt-legacy-enabled.yaml +0 -10
- package/test/partials/config/yaml/security/security-jwt.yaml +0 -6
- package/test/partials/config/yaml/security/security-legacy-disabled.yaml +0 -3
- package/test/partials/config/yaml/security/security-legacy.yaml +0 -3
- package/test/partials/config/yaml/security/security-missing.yaml +0 -0
- package/test/partials/config/yaml/security/security-no-legacy.yaml +0 -9
- package/test/partials/plugin/verdaccio-access-ok/access.js +0 -9
- package/test/partials/plugin/verdaccio-access-ok/package.json +0 -5
- package/test/partials/plugin/verdaccio-adduser/adduser.js +0 -25
- package/test/partials/plugin/verdaccio-adduser/package.json +0 -5
- package/test/partials/plugin/verdaccio-adduser-legacy/adduser.js +0 -25
- package/test/partials/plugin/verdaccio-adduser-legacy/package.json +0 -5
- package/test/partials/plugin/verdaccio-change-password/change.js +0 -32
- package/test/partials/plugin/verdaccio-change-password/package.json +0 -5
- package/test/partials/plugin/verdaccio-fail/fail.js +0 -14
- package/test/partials/plugin/verdaccio-fail/package.json +0 -5
- package/test/partials/plugin/verdaccio-fail-invalid-method/fail.js +0 -11
- package/test/partials/plugin/verdaccio-fail-invalid-method/package.json +0 -5
- package/test/partials/plugin/verdaccio-passthroug/package.json +0 -5
- package/test/partials/plugin/verdaccio-passthroug/passthroug.js +0 -9
- package/test/partials/plugin/verdaccio-success/package.json +0 -5
- package/test/partials/plugin/verdaccio-success/success.js +0 -9
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -32
package/src/types.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { NextFunction, Request, Response } from 'express';
|
|
2
|
-
|
|
3
|
-
import { VerdaccioError } from '@verdaccio/core';
|
|
4
|
-
import { AuthPackageAllow, JWTSignOptions, Logger, RemoteUser } from '@verdaccio/types';
|
|
5
|
-
|
|
6
|
-
export interface AESPayload {
|
|
7
|
-
user: string;
|
|
8
|
-
password: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export type BasicPayload = AESPayload | void;
|
|
12
|
-
export type AuthMiddlewarePayload = RemoteUser | BasicPayload;
|
|
13
|
-
|
|
14
|
-
export interface AuthTokenHeader {
|
|
15
|
-
scheme: string;
|
|
16
|
-
token: string;
|
|
17
|
-
}
|
|
18
|
-
export type AllowActionCallbackResponse = boolean | undefined;
|
|
19
|
-
export type AllowActionCallback = (
|
|
20
|
-
error: VerdaccioError | null,
|
|
21
|
-
allowed?: AllowActionCallbackResponse
|
|
22
|
-
) => void;
|
|
23
|
-
|
|
24
|
-
export type AllowAction = (
|
|
25
|
-
user: RemoteUser,
|
|
26
|
-
pkg: AuthPackageAllow,
|
|
27
|
-
callback: AllowActionCallback
|
|
28
|
-
) => void;
|
|
29
|
-
|
|
30
|
-
export interface TokenEncryption {
|
|
31
|
-
jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;
|
|
32
|
-
aesEncrypt(buf: string): string | void;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export type ActionsAllowed = 'publish' | 'unpublish' | 'access';
|
|
36
|
-
|
|
37
|
-
// remove
|
|
38
|
-
export interface IAuthMiddleware {
|
|
39
|
-
apiJWTmiddleware(): $NextFunctionVer;
|
|
40
|
-
webUIJWTmiddleware(): $NextFunctionVer;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export type $RequestExtend = Request & { remote_user?: any; log: Logger };
|
|
44
|
-
export type $ResponseExtend = Response & { cookies?: any };
|
|
45
|
-
export type $NextFunctionVer = NextFunction & any;
|
|
46
|
-
export { NextFunction };
|
package/src/utils.ts
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import buildDebug from 'debug';
|
|
2
|
-
import _ from 'lodash';
|
|
3
|
-
|
|
4
|
-
import { createAnonymousRemoteUser } from '@verdaccio/config';
|
|
5
|
-
import {
|
|
6
|
-
API_ERROR,
|
|
7
|
-
HTTP_STATUS,
|
|
8
|
-
TOKEN_BASIC,
|
|
9
|
-
TOKEN_BEARER,
|
|
10
|
-
errorUtils,
|
|
11
|
-
pluginUtils,
|
|
12
|
-
} from '@verdaccio/core';
|
|
13
|
-
import {
|
|
14
|
-
aesDecrypt,
|
|
15
|
-
aesDecryptDeprecated,
|
|
16
|
-
parseBasicPayload,
|
|
17
|
-
verifyPayload,
|
|
18
|
-
} from '@verdaccio/signature';
|
|
19
|
-
import { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';
|
|
20
|
-
|
|
21
|
-
import {
|
|
22
|
-
ActionsAllowed,
|
|
23
|
-
AllowAction,
|
|
24
|
-
AllowActionCallback,
|
|
25
|
-
AuthMiddlewarePayload,
|
|
26
|
-
AuthTokenHeader,
|
|
27
|
-
TokenEncryption,
|
|
28
|
-
} from './types';
|
|
29
|
-
|
|
30
|
-
const debug = buildDebug('verdaccio:auth:utils');
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Split authentication header eg: Bearer [secret_token]
|
|
34
|
-
* @param authorizationHeader auth token
|
|
35
|
-
*/
|
|
36
|
-
export function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader {
|
|
37
|
-
const parts = authorizationHeader.split(' ');
|
|
38
|
-
const [scheme, token] = parts;
|
|
39
|
-
|
|
40
|
-
return { scheme, token };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function parseAESCredentials(authorizationHeader: string, secret: string) {
|
|
44
|
-
debug('parseAESCredentials init');
|
|
45
|
-
const { scheme, token } = parseAuthTokenHeader(authorizationHeader);
|
|
46
|
-
|
|
47
|
-
// basic is deprecated and should not be enforced
|
|
48
|
-
// basic is currently being used for functional test
|
|
49
|
-
if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) {
|
|
50
|
-
debug('legacy header basic');
|
|
51
|
-
const credentials = convertPayloadToBase64(token).toString();
|
|
52
|
-
|
|
53
|
-
return credentials;
|
|
54
|
-
} else if (scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {
|
|
55
|
-
debug('legacy header bearer');
|
|
56
|
-
debug('secret length %o', secret.length);
|
|
57
|
-
const isLegacyUnsecure = secret.length > 32;
|
|
58
|
-
debug('is legacy unsecure %o', isLegacyUnsecure);
|
|
59
|
-
if (isLegacyUnsecure) {
|
|
60
|
-
debug('legacy unsecure enabled');
|
|
61
|
-
return aesDecryptDeprecated(convertPayloadToBase64(token), secret).toString('utf-8');
|
|
62
|
-
} else {
|
|
63
|
-
debug('legacy secure enabled');
|
|
64
|
-
return aesDecrypt(token.toString(), secret);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function getMiddlewareCredentials(
|
|
70
|
-
security: Security,
|
|
71
|
-
secretKey: string,
|
|
72
|
-
authorizationHeader: string
|
|
73
|
-
): AuthMiddlewarePayload {
|
|
74
|
-
debug('getMiddlewareCredentials init');
|
|
75
|
-
// comment out for debugging purposes
|
|
76
|
-
if (isAESLegacy(security)) {
|
|
77
|
-
debug('is legacy');
|
|
78
|
-
const credentials = parseAESCredentials(authorizationHeader, secretKey);
|
|
79
|
-
if (!credentials) {
|
|
80
|
-
debug('parse legacy credentials failed');
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const parsedCredentials = parseBasicPayload(credentials);
|
|
85
|
-
if (!parsedCredentials) {
|
|
86
|
-
debug('parse legacy basic payload credentials failed');
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return parsedCredentials;
|
|
91
|
-
}
|
|
92
|
-
const { scheme, token } = parseAuthTokenHeader(authorizationHeader);
|
|
93
|
-
|
|
94
|
-
debug('is jwt');
|
|
95
|
-
if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {
|
|
96
|
-
return verifyJWTPayload(token, secretKey);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function isAESLegacy(security: Security): boolean {
|
|
101
|
-
const { legacy, jwt } = security.api;
|
|
102
|
-
|
|
103
|
-
return _.isNil(legacy) === false && _.isNil(jwt) && legacy === true;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export async function getApiToken(
|
|
107
|
-
auth: TokenEncryption,
|
|
108
|
-
config: Config,
|
|
109
|
-
remoteUser: RemoteUser,
|
|
110
|
-
aesPassword: string
|
|
111
|
-
): Promise<string | void> {
|
|
112
|
-
debug('get api token');
|
|
113
|
-
const { security } = config;
|
|
114
|
-
|
|
115
|
-
if (isAESLegacy(security)) {
|
|
116
|
-
debug('security legacy enabled');
|
|
117
|
-
// fallback all goes to AES encryption
|
|
118
|
-
return await new Promise((resolve): void => {
|
|
119
|
-
resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
const { jwt } = security.api;
|
|
123
|
-
|
|
124
|
-
if (jwt?.sign) {
|
|
125
|
-
return await auth.jwtEncrypt(remoteUser, jwt.sign);
|
|
126
|
-
}
|
|
127
|
-
return await new Promise((resolve): void => {
|
|
128
|
-
resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export const expireReasons: string[] = ['JsonWebTokenError', 'TokenExpiredError'];
|
|
133
|
-
|
|
134
|
-
export function verifyJWTPayload(token: string, secret: string): RemoteUser {
|
|
135
|
-
try {
|
|
136
|
-
const payload: RemoteUser = verifyPayload(token, secret);
|
|
137
|
-
|
|
138
|
-
return payload;
|
|
139
|
-
} catch (error: any) {
|
|
140
|
-
// #168 this check should be removed as soon AES encrypt is removed.
|
|
141
|
-
if (expireReasons.includes(error.name)) {
|
|
142
|
-
// it might be possible the jwt configuration is enabled and
|
|
143
|
-
// old tokens fails still remains in usage, thus
|
|
144
|
-
// we return an anonymous user to force log in.
|
|
145
|
-
return createAnonymousRemoteUser();
|
|
146
|
-
}
|
|
147
|
-
throw errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, error.message);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function isAuthHeaderValid(authorization: string): boolean {
|
|
152
|
-
return authorization.split(' ').length === 2;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Return a default configuration for authentication if none is provided.
|
|
157
|
-
* @param logger {Logger}
|
|
158
|
-
* @returns object of default implementations.
|
|
159
|
-
*/
|
|
160
|
-
export function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config> {
|
|
161
|
-
return {
|
|
162
|
-
authenticate(_user: string, _password: string, cb: pluginUtils.AuthCallback): void {
|
|
163
|
-
debug('triggered default authenticate method');
|
|
164
|
-
cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
|
165
|
-
},
|
|
166
|
-
|
|
167
|
-
adduser(_user: string, _password: string, cb: pluginUtils.AuthUserCallback): void {
|
|
168
|
-
debug('triggered default adduser method');
|
|
169
|
-
// since adduser is not implemented but optional, continue without error
|
|
170
|
-
// this assumes that the user is added by an external system
|
|
171
|
-
cb(null, true);
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
// @ts-ignore
|
|
175
|
-
allow_access: allow_action('access', logger),
|
|
176
|
-
// @ts-ignore
|
|
177
|
-
allow_publish: allow_action('publish', logger),
|
|
178
|
-
allow_unpublish: handleSpecialUnpublish(logger),
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export function allow_action(action: ActionsAllowed, logger: Logger): AllowAction {
|
|
183
|
-
return function allowActionCallback(
|
|
184
|
-
user: RemoteUser,
|
|
185
|
-
pkg: AuthPackageAllow,
|
|
186
|
-
callback: AllowActionCallback
|
|
187
|
-
): void {
|
|
188
|
-
logger.trace({ remote: user.name }, `[auth/allow_action]: user: @{remote}`);
|
|
189
|
-
const { name, groups } = user;
|
|
190
|
-
debug('allow_action "%s": groups %s', action, groups);
|
|
191
|
-
const groupAccess = pkg[action] as string[];
|
|
192
|
-
debug('allow_action "%s": groupAccess %s', action, groupAccess);
|
|
193
|
-
const hasPermission = groupAccess.some((group) => {
|
|
194
|
-
return name === group || groups.includes(group);
|
|
195
|
-
});
|
|
196
|
-
debug('package "%s" has permission "%s"', name, hasPermission);
|
|
197
|
-
logger.trace(
|
|
198
|
-
{ pkgName: pkg.name, hasPermission, remote: user.name, groupAccess },
|
|
199
|
-
`[auth/allow_action]: hasPermission? @{hasPermission} for user: @{remote}, package: @{pkgName}`
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
if (hasPermission) {
|
|
203
|
-
logger.trace({ remote: user.name }, `auth/allow_action: access granted to: @{remote}`);
|
|
204
|
-
return callback(null, true);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (name) {
|
|
208
|
-
callback(
|
|
209
|
-
errorUtils.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`)
|
|
210
|
-
);
|
|
211
|
-
} else {
|
|
212
|
-
callback(
|
|
213
|
-
errorUtils.getUnauthorized(`authorization required to ${action} package ${pkg.name}`)
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
*
|
|
221
|
-
*/
|
|
222
|
-
export function handleSpecialUnpublish(logger: Logger): any {
|
|
223
|
-
return function (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {
|
|
224
|
-
const action = 'unpublish';
|
|
225
|
-
// verify whether the unpublish prop has been defined
|
|
226
|
-
const isUnpublishMissing: boolean = !pkg[action];
|
|
227
|
-
debug('is unpublish method missing ? %s', isUnpublishMissing);
|
|
228
|
-
const hasGroups: boolean = isUnpublishMissing ? false : (pkg[action] as string[]).length > 0;
|
|
229
|
-
logger.trace(
|
|
230
|
-
{ user: user.name, name: pkg.name, hasGroups },
|
|
231
|
-
`fallback unpublish for @{name} has groups: @{hasGroups} for @{user}`
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
if (isUnpublishMissing || hasGroups === false) {
|
|
235
|
-
return callback(null, undefined);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
logger.trace(
|
|
239
|
-
{ user: user.name, name: pkg.name, action, hasGroups },
|
|
240
|
-
`allow_action for @{action} for @{name} has groups: @{hasGroups} for @{user}`
|
|
241
|
-
);
|
|
242
|
-
return allow_action(action, logger)(user, pkg, callback);
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export function buildUser(name: string, password: string): string {
|
|
247
|
-
return String(`${name}:${password}`);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export function convertPayloadToBase64(payload: string): Buffer {
|
|
251
|
-
return Buffer.from(payload, 'base64');
|
|
252
|
-
}
|
|
@@ -1,260 +0,0 @@
|
|
|
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
|
-
});
|