@verdaccio/auth 7.0.0-next.4 → 7.0.0-next.6

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +1 -1
  3. package/build/auth.d.ts +7 -26
  4. package/build/auth.js +38 -23
  5. package/build/auth.js.map +1 -1
  6. package/build/index.d.ts +1 -0
  7. package/build/index.js +12 -0
  8. package/build/index.js.map +1 -1
  9. package/build/signature-legacy.d.ts +5 -0
  10. package/build/signature-legacy.js +60 -0
  11. package/build/signature-legacy.js.map +1 -0
  12. package/build/signature.d.ts +4 -0
  13. package/build/signature.js +60 -0
  14. package/build/signature.js.map +1 -0
  15. package/build/types.d.ts +34 -0
  16. package/build/types.js +13 -0
  17. package/build/types.js.map +1 -0
  18. package/build/utils.d.ts +5 -15
  19. package/build/utils.js +18 -7
  20. package/build/utils.js.map +1 -1
  21. package/package.json +12 -10
  22. package/src/auth.ts +62 -50
  23. package/src/index.ts +1 -0
  24. package/src/signature-legacy.ts +66 -0
  25. package/src/signature.ts +66 -0
  26. package/src/types.ts +46 -0
  27. package/src/utils.ts +37 -31
  28. package/test/auth.spec.ts +561 -40
  29. package/test/helper/plugin.ts +8 -0
  30. package/test/partials/plugin/verdaccio-access-ok/access.js +9 -0
  31. package/test/partials/plugin/verdaccio-access-ok/package.json +5 -0
  32. package/test/partials/plugin/verdaccio-adduser/adduser.js +25 -0
  33. package/test/partials/plugin/verdaccio-adduser/package.json +5 -0
  34. package/test/partials/plugin/verdaccio-adduser-legacy/adduser.js +25 -0
  35. package/test/partials/plugin/verdaccio-adduser-legacy/package.json +5 -0
  36. package/test/partials/plugin/verdaccio-change-password/change.js +32 -0
  37. package/test/partials/plugin/verdaccio-change-password/package.json +5 -0
  38. package/test/partials/plugin/verdaccio-fail/fail.js +3 -0
@@ -0,0 +1,34 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import { VerdaccioError } from '@verdaccio/core';
3
+ import { AuthPackageAllow, JWTSignOptions, Logger, RemoteUser } from '@verdaccio/types';
4
+ export interface AESPayload {
5
+ user: string;
6
+ password: string;
7
+ }
8
+ export type BasicPayload = AESPayload | void;
9
+ export type AuthMiddlewarePayload = RemoteUser | BasicPayload;
10
+ export interface AuthTokenHeader {
11
+ scheme: string;
12
+ token: string;
13
+ }
14
+ export type AllowActionCallbackResponse = boolean | undefined;
15
+ export type AllowActionCallback = (error: VerdaccioError | null, allowed?: AllowActionCallbackResponse) => void;
16
+ export type AllowAction = (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback) => void;
17
+ export interface TokenEncryption {
18
+ jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;
19
+ aesEncrypt(buf: string): string | void;
20
+ }
21
+ export type ActionsAllowed = 'publish' | 'unpublish' | 'access';
22
+ export interface IAuthMiddleware {
23
+ apiJWTmiddleware(): $NextFunctionVer;
24
+ webUIJWTmiddleware(): $NextFunctionVer;
25
+ }
26
+ export type $RequestExtend = Request & {
27
+ remote_user?: any;
28
+ log: Logger;
29
+ };
30
+ export type $ResponseExtend = Response & {
31
+ cookies?: any;
32
+ };
33
+ export type $NextFunctionVer = NextFunction & any;
34
+ export { NextFunction };
package/build/types.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "NextFunction", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _express.NextFunction;
10
+ }
11
+ });
12
+ var _express = require("express");
13
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":["_express","require"],"sources":["../src/types.ts"],"sourcesContent":["import { NextFunction, Request, Response } from 'express';\n\nimport { VerdaccioError } from '@verdaccio/core';\nimport { AuthPackageAllow, JWTSignOptions, Logger, RemoteUser } from '@verdaccio/types';\n\nexport interface AESPayload {\n user: string;\n password: string;\n}\n\nexport type BasicPayload = AESPayload | void;\nexport type AuthMiddlewarePayload = RemoteUser | BasicPayload;\n\nexport interface AuthTokenHeader {\n scheme: string;\n token: string;\n}\nexport type AllowActionCallbackResponse = boolean | undefined;\nexport type AllowActionCallback = (\n error: VerdaccioError | null,\n allowed?: AllowActionCallbackResponse\n) => void;\n\nexport type AllowAction = (\n user: RemoteUser,\n pkg: AuthPackageAllow,\n callback: AllowActionCallback\n) => void;\n\nexport interface TokenEncryption {\n jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;\n aesEncrypt(buf: string): string | void;\n}\n\nexport type ActionsAllowed = 'publish' | 'unpublish' | 'access';\n\n// remove\nexport interface IAuthMiddleware {\n apiJWTmiddleware(): $NextFunctionVer;\n webUIJWTmiddleware(): $NextFunctionVer;\n}\n\nexport type $RequestExtend = Request & { remote_user?: any; log: Logger };\nexport type $ResponseExtend = Response & { cookies?: any };\nexport type $NextFunctionVer = NextFunction & any;\nexport { NextFunction };\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,QAAA,GAAAC,OAAA"}
package/build/utils.d.ts CHANGED
@@ -1,23 +1,14 @@
1
1
  /// <reference types="node" />
2
- import { VerdaccioError, pluginUtils } from '@verdaccio/core';
3
- import { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';
4
- import { AESPayload, TokenEncryption } from './auth';
5
- export type BasicPayload = AESPayload | void;
6
- export type AuthMiddlewarePayload = RemoteUser | BasicPayload;
7
- export interface AuthTokenHeader {
8
- scheme: string;
9
- token: string;
10
- }
11
- export type AllowActionCallbackResponse = boolean | undefined;
12
- export type AllowActionCallback = (error: VerdaccioError | null, allowed?: AllowActionCallbackResponse) => void;
13
- export type AllowAction = (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback) => void;
2
+ import { pluginUtils } from '@verdaccio/core';
3
+ import { Config, Logger, RemoteUser, Security } from '@verdaccio/types';
4
+ import { ActionsAllowed, AllowAction, AuthMiddlewarePayload, AuthTokenHeader, TokenEncryption } from './types';
14
5
  /**
15
6
  * Split authentication header eg: Bearer [secret_token]
16
7
  * @param authorizationHeader auth token
17
8
  */
18
9
  export declare function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader;
19
- export declare function parseAESCredentials(authorizationHeader: string, secret: string): string | void;
20
- export declare function getMiddlewareCredentials(security: Security, secretKey: string, authorizationHeader: string): AuthMiddlewarePayload;
10
+ export declare function parseAESCredentials(authorizationHeader: string, secret: string, enhanced: boolean): string | void;
11
+ export declare function getMiddlewareCredentials(security: Security, secretKey: string, authorizationHeader: string, enhanced?: boolean): AuthMiddlewarePayload;
21
12
  export declare function isAESLegacy(security: Security): boolean;
22
13
  export declare function getApiToken(auth: TokenEncryption, config: Config, remoteUser: RemoteUser, aesPassword: string): Promise<string | void>;
23
14
  export declare const expireReasons: string[];
@@ -29,7 +20,6 @@ export declare function isAuthHeaderValid(authorization: string): boolean;
29
20
  * @returns object of default implementations.
30
21
  */
31
22
  export declare function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config>;
32
- export type ActionsAllowed = 'publish' | 'unpublish' | 'access';
33
23
  export declare function allow_action(action: ActionsAllowed, logger: Logger): AllowAction;
34
24
  /**
35
25
  *
package/build/utils.js CHANGED
@@ -23,6 +23,7 @@ var _core = require("@verdaccio/core");
23
23
  var _signature = require("@verdaccio/signature");
24
24
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
25
25
  const debug = (0, _debug.default)('verdaccio:auth:utils');
26
+
26
27
  /**
27
28
  * Split authentication header eg: Bearer [secret_token]
28
29
  * @param authorizationHeader auth token
@@ -35,7 +36,7 @@ function parseAuthTokenHeader(authorizationHeader) {
35
36
  token
36
37
  };
37
38
  }
38
- function parseAESCredentials(authorizationHeader, secret) {
39
+ function parseAESCredentials(authorizationHeader, secret, enhanced) {
39
40
  debug('parseAESCredentials');
40
41
  const {
41
42
  scheme,
@@ -50,16 +51,19 @@ function parseAESCredentials(authorizationHeader, secret) {
50
51
  return credentials;
51
52
  } else if (scheme.toUpperCase() === _core.TOKEN_BEARER.toUpperCase()) {
52
53
  debug('legacy header bearer');
53
- const credentials = (0, _signature.aesDecrypt)(token, secret);
54
+ debug('legacy header enhanced?', enhanced);
55
+ const credentials = enhanced ? (0, _signature.aesDecrypt)(token.toString(), secret) :
56
+ // FUTURE: once deprecated legacy is removed this logic won't be longer need it
57
+ (0, _signature.aesDecryptDeprecated)(convertPayloadToBase64(token), secret).toString('utf-8');
54
58
  return credentials;
55
59
  }
56
60
  }
57
- function getMiddlewareCredentials(security, secretKey, authorizationHeader) {
61
+ function getMiddlewareCredentials(security, secretKey, authorizationHeader, enhanced = true) {
58
62
  debug('getMiddlewareCredentials');
59
63
  // comment out for debugging purposes
60
64
  if (isAESLegacy(security)) {
61
65
  debug('is legacy');
62
- const credentials = parseAESCredentials(authorizationHeader, secretKey);
66
+ const credentials = parseAESCredentials(authorizationHeader, secretKey, enhanced);
63
67
  if (!credentials) {
64
68
  debug('parse legacy credentials failed');
65
69
  return;
@@ -137,12 +141,13 @@ function isAuthHeaderValid(authorization) {
137
141
  function getDefaultPlugins(logger) {
138
142
  return {
139
143
  authenticate(_user, _password, cb) {
144
+ debug('triggered default authenticate method');
140
145
  cb(_core.errorUtils.getForbidden(_core.API_ERROR.BAD_USERNAME_PASSWORD));
141
146
  },
142
147
  adduser(_user, _password, cb) {
148
+ debug('triggered default adduser method');
143
149
  return cb(_core.errorUtils.getConflict(_core.API_ERROR.BAD_USERNAME_PASSWORD));
144
150
  },
145
- // FIXME: allow_action and allow_publish should be in the @verdaccio/types
146
151
  // @ts-ignore
147
152
  allow_access: allow_action('access', logger),
148
153
  // @ts-ignore
@@ -159,8 +164,13 @@ function allow_action(action, logger) {
159
164
  name,
160
165
  groups
161
166
  } = user;
167
+ debug('allow_action "%s": groups %s', action, groups);
162
168
  const groupAccess = pkg[action];
163
- const hasPermission = groupAccess.some(group => name === group || groups.includes(group));
169
+ debug('allow_action "%s": groupAccess %s', action, groupAccess);
170
+ const hasPermission = groupAccess.some(group => {
171
+ return name === group || groups.includes(group);
172
+ });
173
+ debug('package "%s" has permission "%s"', name, hasPermission);
164
174
  logger.trace({
165
175
  pkgName: pkg.name,
166
176
  hasPermission,
@@ -188,7 +198,8 @@ function handleSpecialUnpublish(logger) {
188
198
  return function (user, pkg, callback) {
189
199
  const action = 'unpublish';
190
200
  // verify whether the unpublish prop has been defined
191
- const isUnpublishMissing = _lodash.default.isNil(pkg[action]);
201
+ const isUnpublishMissing = !pkg[action];
202
+ debug('is unpublish method missing ? %s', isUnpublishMissing);
192
203
  const hasGroups = isUnpublishMissing ? false : pkg[action].length > 0;
193
204
  logger.trace({
194
205
  user: user.name,
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":["_debug","_interopRequireDefault","require","_lodash","_config","_core","_signature","obj","__esModule","default","debug","buildDebug","parseAuthTokenHeader","authorizationHeader","parts","split","scheme","token","parseAESCredentials","secret","toUpperCase","TOKEN_BASIC","credentials","convertPayloadToBase64","toString","TOKEN_BEARER","aesDecrypt","getMiddlewareCredentials","security","secretKey","isAESLegacy","parsedCredentials","parseBasicPayload","_","isString","verifyJWTPayload","legacy","jwt","api","isNil","getApiToken","auth","config","remoteUser","aesPassword","Promise","resolve","aesEncrypt","buildUser","name","sign","jwtEncrypt","expireReasons","exports","payload","verifyPayload","error","includes","createAnonymousRemoteUser","errorUtils","getCode","HTTP_STATUS","UNAUTHORIZED","message","isAuthHeaderValid","authorization","length","getDefaultPlugins","logger","authenticate","_user","_password","cb","getForbidden","API_ERROR","BAD_USERNAME_PASSWORD","adduser","getConflict","allow_access","allow_action","allow_publish","allow_unpublish","handleSpecialUnpublish","action","allowActionCallback","user","pkg","callback","trace","remote","groups","groupAccess","hasPermission","some","group","pkgName","getUnauthorized","isUnpublishMissing","hasGroups","undefined","password","String","Buffer","from"],"sources":["../src/utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { createAnonymousRemoteUser } from '@verdaccio/config';\nimport {\n API_ERROR,\n HTTP_STATUS,\n TOKEN_BASIC,\n TOKEN_BEARER,\n VerdaccioError,\n errorUtils,\n pluginUtils,\n} from '@verdaccio/core';\nimport { aesDecrypt, parseBasicPayload, verifyPayload } from '@verdaccio/signature';\nimport { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';\n\nimport { AESPayload, TokenEncryption } from './auth';\n\nconst debug = buildDebug('verdaccio:auth:utils');\n\nexport type BasicPayload = AESPayload | void;\nexport type AuthMiddlewarePayload = RemoteUser | BasicPayload;\n\nexport interface AuthTokenHeader {\n scheme: string;\n token: string;\n}\nexport type AllowActionCallbackResponse = boolean | undefined;\nexport type AllowActionCallback = (\n error: VerdaccioError | null,\n allowed?: AllowActionCallbackResponse\n) => void;\n\nexport type AllowAction = (\n user: RemoteUser,\n pkg: AuthPackageAllow,\n callback: AllowActionCallback\n) => void;\n\n/**\n * Split authentication header eg: Bearer [secret_token]\n * @param authorizationHeader auth token\n */\nexport function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader {\n const parts = authorizationHeader.split(' ');\n const [scheme, token] = parts;\n\n return { scheme, token };\n}\n\nexport function parseAESCredentials(authorizationHeader: string, secret: string) {\n debug('parseAESCredentials');\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n // basic is deprecated and should not be enforced\n // basic is currently being used for functional test\n if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) {\n debug('legacy header basic');\n const credentials = convertPayloadToBase64(token).toString();\n\n return credentials;\n } else if (scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n debug('legacy header bearer');\n const credentials = aesDecrypt(token, secret);\n\n return credentials;\n }\n}\n\nexport function getMiddlewareCredentials(\n security: Security,\n secretKey: string,\n authorizationHeader: string\n): AuthMiddlewarePayload {\n debug('getMiddlewareCredentials');\n // comment out for debugging purposes\n if (isAESLegacy(security)) {\n debug('is legacy');\n const credentials = parseAESCredentials(authorizationHeader, secretKey);\n if (!credentials) {\n debug('parse legacy credentials failed');\n return;\n }\n\n const parsedCredentials = parseBasicPayload(credentials);\n if (!parsedCredentials) {\n debug('parse legacy basic payload credentials failed');\n return;\n }\n\n return parsedCredentials;\n }\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n debug('is jwt');\n if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n return verifyJWTPayload(token, secretKey);\n }\n}\n\nexport function isAESLegacy(security: Security): boolean {\n const { legacy, jwt } = security.api;\n\n return _.isNil(legacy) === false && _.isNil(jwt) && legacy === true;\n}\n\nexport async function getApiToken(\n auth: TokenEncryption,\n config: Config,\n remoteUser: RemoteUser,\n aesPassword: string\n): Promise<string | void> {\n debug('get api token');\n const { security } = config;\n\n if (isAESLegacy(security)) {\n debug('security legacy enabled');\n // fallback all goes to AES encryption\n return await new Promise((resolve): void => {\n resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));\n });\n }\n const { jwt } = security.api;\n\n if (jwt?.sign) {\n return await auth.jwtEncrypt(remoteUser, jwt.sign);\n }\n return await new Promise((resolve): void => {\n resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));\n });\n}\n\nexport const expireReasons: string[] = ['JsonWebTokenError', 'TokenExpiredError'];\n\nexport function verifyJWTPayload(token: string, secret: string): RemoteUser {\n try {\n const payload: RemoteUser = verifyPayload(token, secret);\n\n return payload;\n } catch (error: any) {\n // #168 this check should be removed as soon AES encrypt is removed.\n if (expireReasons.includes(error.name)) {\n // it might be possible the jwt configuration is enabled and\n // old tokens fails still remains in usage, thus\n // we return an anonymous user to force log in.\n return createAnonymousRemoteUser();\n }\n throw errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, error.message);\n }\n}\n\nexport function isAuthHeaderValid(authorization: string): boolean {\n return authorization.split(' ').length === 2;\n}\n\n/**\n * Return a default configuration for authentication if none is provided.\n * @param logger {Logger}\n * @returns object of default implementations.\n */\nexport function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config> {\n return {\n authenticate(_user: string, _password: string, cb: pluginUtils.AuthCallback): void {\n cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n adduser(_user: string, _password: string, cb: pluginUtils.AuthUserCallback): void {\n return cb(errorUtils.getConflict(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n // FIXME: allow_action and allow_publish should be in the @verdaccio/types\n // @ts-ignore\n allow_access: allow_action('access', logger),\n // @ts-ignore\n allow_publish: allow_action('publish', logger),\n allow_unpublish: handleSpecialUnpublish(logger),\n };\n}\n\nexport type ActionsAllowed = 'publish' | 'unpublish' | 'access';\n\nexport function allow_action(action: ActionsAllowed, logger: Logger): AllowAction {\n return function allowActionCallback(\n user: RemoteUser,\n pkg: AuthPackageAllow,\n callback: AllowActionCallback\n ): void {\n logger.trace({ remote: user.name }, `[auth/allow_action]: user: @{remote}`);\n const { name, groups } = user;\n const groupAccess = pkg[action] as string[];\n const hasPermission = groupAccess.some((group) => name === group || groups.includes(group));\n logger.trace(\n { pkgName: pkg.name, hasPermission, remote: user.name, groupAccess },\n `[auth/allow_action]: hasPermission? @{hasPermission} for user: @{remote}, package: @{pkgName}`\n );\n\n if (hasPermission) {\n logger.trace({ remote: user.name }, `auth/allow_action: access granted to: @{remote}`);\n return callback(null, true);\n }\n\n if (name) {\n callback(\n errorUtils.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`)\n );\n } else {\n callback(\n errorUtils.getUnauthorized(`authorization required to ${action} package ${pkg.name}`)\n );\n }\n };\n}\n\n/**\n *\n */\nexport function handleSpecialUnpublish(logger: Logger): any {\n return function (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {\n const action = 'unpublish';\n // verify whether the unpublish prop has been defined\n const isUnpublishMissing: boolean = _.isNil(pkg[action]);\n const hasGroups: boolean = isUnpublishMissing ? false : (pkg[action] as string[]).length > 0;\n logger.trace(\n { user: user.name, name: pkg.name, hasGroups },\n `fallback unpublish for @{name} has groups: @{hasGroups} for @{user}`\n );\n\n if (isUnpublishMissing || hasGroups === false) {\n return callback(null, undefined);\n }\n\n logger.trace(\n { user: user.name, name: pkg.name, action, hasGroups },\n `allow_action for @{action} for @{name} has groups: @{hasGroups} for @{user}`\n );\n return allow_action(action, logger)(user, pkg, callback);\n };\n}\n\nexport function buildUser(name: string, password: string): string {\n return String(`${name}:${password}`);\n}\n\nexport function convertPayloadToBase64(payload: string): Buffer {\n return Buffer.from(payload, 'base64');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","names":["_debug","_interopRequireDefault","require","_lodash","_config","_core","_signature","obj","__esModule","default","debug","buildDebug","parseAuthTokenHeader","authorizationHeader","parts","split","scheme","token","parseAESCredentials","secret","enhanced","toUpperCase","TOKEN_BASIC","credentials","convertPayloadToBase64","toString","TOKEN_BEARER","aesDecrypt","aesDecryptDeprecated","getMiddlewareCredentials","security","secretKey","isAESLegacy","parsedCredentials","parseBasicPayload","_","isString","verifyJWTPayload","legacy","jwt","api","isNil","getApiToken","auth","config","remoteUser","aesPassword","Promise","resolve","aesEncrypt","buildUser","name","sign","jwtEncrypt","expireReasons","exports","payload","verifyPayload","error","includes","createAnonymousRemoteUser","errorUtils","getCode","HTTP_STATUS","UNAUTHORIZED","message","isAuthHeaderValid","authorization","length","getDefaultPlugins","logger","authenticate","_user","_password","cb","getForbidden","API_ERROR","BAD_USERNAME_PASSWORD","adduser","getConflict","allow_access","allow_action","allow_publish","allow_unpublish","handleSpecialUnpublish","action","allowActionCallback","user","pkg","callback","trace","remote","groups","groupAccess","hasPermission","some","group","pkgName","getUnauthorized","isUnpublishMissing","hasGroups","undefined","password","String","Buffer","from"],"sources":["../src/utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { createAnonymousRemoteUser } from '@verdaccio/config';\nimport {\n API_ERROR,\n HTTP_STATUS,\n TOKEN_BASIC,\n TOKEN_BEARER,\n errorUtils,\n pluginUtils,\n} from '@verdaccio/core';\nimport {\n aesDecrypt,\n aesDecryptDeprecated,\n parseBasicPayload,\n verifyPayload,\n} from '@verdaccio/signature';\nimport { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';\n\nimport {\n ActionsAllowed,\n AllowAction,\n AllowActionCallback,\n AuthMiddlewarePayload,\n AuthTokenHeader,\n TokenEncryption,\n} from './types';\n\nconst debug = buildDebug('verdaccio:auth:utils');\n\n/**\n * Split authentication header eg: Bearer [secret_token]\n * @param authorizationHeader auth token\n */\nexport function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader {\n const parts = authorizationHeader.split(' ');\n const [scheme, token] = parts;\n\n return { scheme, token };\n}\n\nexport function parseAESCredentials(\n authorizationHeader: string,\n secret: string,\n enhanced: boolean\n) {\n debug('parseAESCredentials');\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n // basic is deprecated and should not be enforced\n // basic is currently being used for functional test\n if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) {\n debug('legacy header basic');\n const credentials = convertPayloadToBase64(token).toString();\n\n return credentials;\n } else if (scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n debug('legacy header bearer');\n debug('legacy header enhanced?', enhanced);\n const credentials = enhanced\n ? aesDecrypt(token.toString(), secret)\n : // FUTURE: once deprecated legacy is removed this logic won't be longer need it\n aesDecryptDeprecated(convertPayloadToBase64(token), secret).toString('utf-8');\n\n return credentials;\n }\n}\n\nexport function getMiddlewareCredentials(\n security: Security,\n secretKey: string,\n authorizationHeader: string,\n enhanced: boolean = true\n): AuthMiddlewarePayload {\n debug('getMiddlewareCredentials');\n // comment out for debugging purposes\n if (isAESLegacy(security)) {\n debug('is legacy');\n const credentials = parseAESCredentials(authorizationHeader, secretKey, enhanced);\n if (!credentials) {\n debug('parse legacy credentials failed');\n return;\n }\n\n const parsedCredentials = parseBasicPayload(credentials);\n if (!parsedCredentials) {\n debug('parse legacy basic payload credentials failed');\n return;\n }\n\n return parsedCredentials;\n }\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n debug('is jwt');\n if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n return verifyJWTPayload(token, secretKey);\n }\n}\n\nexport function isAESLegacy(security: Security): boolean {\n const { legacy, jwt } = security.api;\n\n return _.isNil(legacy) === false && _.isNil(jwt) && legacy === true;\n}\n\nexport async function getApiToken(\n auth: TokenEncryption,\n config: Config,\n remoteUser: RemoteUser,\n aesPassword: string\n): Promise<string | void> {\n debug('get api token');\n const { security } = config;\n\n if (isAESLegacy(security)) {\n debug('security legacy enabled');\n // fallback all goes to AES encryption\n return await new Promise((resolve): void => {\n resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));\n });\n }\n const { jwt } = security.api;\n\n if (jwt?.sign) {\n return await auth.jwtEncrypt(remoteUser, jwt.sign);\n }\n return await new Promise((resolve): void => {\n resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));\n });\n}\n\nexport const expireReasons: string[] = ['JsonWebTokenError', 'TokenExpiredError'];\n\nexport function verifyJWTPayload(token: string, secret: string): RemoteUser {\n try {\n const payload: RemoteUser = verifyPayload(token, secret);\n\n return payload;\n } catch (error: any) {\n // #168 this check should be removed as soon AES encrypt is removed.\n if (expireReasons.includes(error.name)) {\n // it might be possible the jwt configuration is enabled and\n // old tokens fails still remains in usage, thus\n // we return an anonymous user to force log in.\n return createAnonymousRemoteUser();\n }\n throw errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, error.message);\n }\n}\n\nexport function isAuthHeaderValid(authorization: string): boolean {\n return authorization.split(' ').length === 2;\n}\n\n/**\n * Return a default configuration for authentication if none is provided.\n * @param logger {Logger}\n * @returns object of default implementations.\n */\nexport function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config> {\n return {\n authenticate(_user: string, _password: string, cb: pluginUtils.AuthCallback): void {\n debug('triggered default authenticate method');\n cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n adduser(_user: string, _password: string, cb: pluginUtils.AuthUserCallback): void {\n debug('triggered default adduser method');\n return cb(errorUtils.getConflict(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n // @ts-ignore\n allow_access: allow_action('access', logger),\n // @ts-ignore\n allow_publish: allow_action('publish', logger),\n allow_unpublish: handleSpecialUnpublish(logger),\n };\n}\n\nexport function allow_action(action: ActionsAllowed, logger: Logger): AllowAction {\n return function allowActionCallback(\n user: RemoteUser,\n pkg: AuthPackageAllow,\n callback: AllowActionCallback\n ): void {\n logger.trace({ remote: user.name }, `[auth/allow_action]: user: @{remote}`);\n const { name, groups } = user;\n debug('allow_action \"%s\": groups %s', action, groups);\n const groupAccess = pkg[action] as string[];\n debug('allow_action \"%s\": groupAccess %s', action, groupAccess);\n const hasPermission = groupAccess.some((group) => {\n return name === group || groups.includes(group);\n });\n debug('package \"%s\" has permission \"%s\"', name, hasPermission);\n logger.trace(\n { pkgName: pkg.name, hasPermission, remote: user.name, groupAccess },\n `[auth/allow_action]: hasPermission? @{hasPermission} for user: @{remote}, package: @{pkgName}`\n );\n\n if (hasPermission) {\n logger.trace({ remote: user.name }, `auth/allow_action: access granted to: @{remote}`);\n return callback(null, true);\n }\n\n if (name) {\n callback(\n errorUtils.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`)\n );\n } else {\n callback(\n errorUtils.getUnauthorized(`authorization required to ${action} package ${pkg.name}`)\n );\n }\n };\n}\n\n/**\n *\n */\nexport function handleSpecialUnpublish(logger: Logger): any {\n return function (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {\n const action = 'unpublish';\n // verify whether the unpublish prop has been defined\n const isUnpublishMissing: boolean = !pkg[action];\n debug('is unpublish method missing ? %s', isUnpublishMissing);\n const hasGroups: boolean = isUnpublishMissing ? false : (pkg[action] as string[]).length > 0;\n logger.trace(\n { user: user.name, name: pkg.name, hasGroups },\n `fallback unpublish for @{name} has groups: @{hasGroups} for @{user}`\n );\n\n if (isUnpublishMissing || hasGroups === false) {\n return callback(null, undefined);\n }\n\n logger.trace(\n { user: user.name, name: pkg.name, action, hasGroups },\n `allow_action for @{action} for @{name} has groups: @{hasGroups} for @{user}`\n );\n return allow_action(action, logger)(user, pkg, callback);\n };\n}\n\nexport function buildUser(name: string, password: string): string {\n return String(`${name}:${password}`);\n}\n\nexport function convertPayloadToBase64(payload: string): Buffer {\n return Buffer.from(payload, 'base64');\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/auth",
3
- "version": "7.0.0-next.4",
3
+ "version": "7.0.0-next.6",
4
4
  "description": "logger",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -29,19 +29,21 @@
29
29
  },
30
30
  "license": "MIT",
31
31
  "dependencies": {
32
- "@verdaccio/core": "7.0.0-next.4",
33
- "@verdaccio/config": "7.0.0-next.4",
34
- "@verdaccio/loaders": "7.0.0-next.4",
35
- "@verdaccio/logger": "7.0.0-next.4",
36
- "@verdaccio/signature": "7.0.0-next.2",
37
- "@verdaccio/utils": "7.0.0-next.4",
32
+ "@verdaccio/core": "7.0.0-next.6",
33
+ "@verdaccio/config": "7.0.0-next.6",
34
+ "@verdaccio/loaders": "7.0.0-next.6",
35
+ "@verdaccio/logger": "7.0.0-next.6",
36
+ "@verdaccio/signature": "7.0.0-next.3",
37
+ "@verdaccio/utils": "7.0.0-next.6",
38
38
  "debug": "4.3.4",
39
- "express": "4.18.2",
40
39
  "lodash": "4.17.21",
41
- "verdaccio-htpasswd": "12.0.0-next.4"
40
+ "verdaccio-htpasswd": "12.0.0-next.6"
42
41
  },
43
42
  "devDependencies": {
44
- "@verdaccio/types": "12.0.0-next.1"
43
+ "express": "4.18.2",
44
+ "supertest": "6.3.3",
45
+ "@verdaccio/middleware": "7.0.0-next.6",
46
+ "@verdaccio/types": "12.0.0-next.2"
45
47
  },
46
48
  "funding": {
47
49
  "type": "opencollective",
package/src/auth.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import buildDebug from 'debug';
2
- import { NextFunction, Request, Response } from 'express';
3
2
  import _ from 'lodash';
4
3
  import { HTPasswd } from 'verdaccio-htpasswd';
5
4
 
@@ -12,22 +11,36 @@ import {
12
11
  VerdaccioError,
13
12
  errorUtils,
14
13
  pluginUtils,
14
+ warningUtils,
15
15
  } from '@verdaccio/core';
16
+ import '@verdaccio/core';
16
17
  import { asyncLoadPlugin } from '@verdaccio/loaders';
17
18
  import { logger } from '@verdaccio/logger';
18
- import { aesEncrypt, parseBasicPayload, signPayload } from '@verdaccio/signature';
19
+ import {
20
+ aesEncrypt,
21
+ aesEncryptDeprecated,
22
+ parseBasicPayload,
23
+ signPayload,
24
+ } from '@verdaccio/signature';
19
25
  import {
20
26
  AllowAccess,
21
27
  Callback,
22
28
  Config,
23
29
  JWTSignOptions,
24
- Logger,
25
30
  PackageAccess,
26
31
  RemoteUser,
27
32
  Security,
28
33
  } from '@verdaccio/types';
29
34
  import { getMatchedPackagesSpec, isFunction, isNil } from '@verdaccio/utils';
30
35
 
36
+ import {
37
+ $RequestExtend,
38
+ $ResponseExtend,
39
+ AESPayload,
40
+ IAuthMiddleware,
41
+ NextFunction,
42
+ TokenEncryption,
43
+ } from './types';
31
44
  import {
32
45
  convertPayloadToBase64,
33
46
  getDefaultPlugins,
@@ -40,25 +53,6 @@ import {
40
53
 
41
54
  const debug = buildDebug('verdaccio:auth');
42
55
 
43
- export interface TokenEncryption {
44
- jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;
45
- aesEncrypt(buf: string): string | void;
46
- }
47
-
48
- // remove
49
- export interface AESPayload {
50
- user: string;
51
- password: string;
52
- }
53
- export interface IAuthMiddleware {
54
- apiJWTmiddleware(): $NextFunctionVer;
55
- webUIJWTmiddleware(): $NextFunctionVer;
56
- }
57
-
58
- export type $RequestExtend = Request & { remote_user?: any; log: Logger };
59
- export type $ResponseExtend = Response & { cookies?: any };
60
- export type $NextFunctionVer = NextFunction & any;
61
-
62
56
  class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
63
57
  public config: Config;
64
58
  public secret: string;
@@ -75,6 +69,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
75
69
 
76
70
  public async init() {
77
71
  let plugins = (await this.loadPlugin()) as pluginUtils.Auth<unknown>[];
72
+
78
73
  debug('auth plugins found %s', plugins.length);
79
74
  if (!plugins || plugins.length === 0) {
80
75
  plugins = this.loadDefaultPlugin();
@@ -226,29 +221,32 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
226
221
  debug('add user %o', user);
227
222
 
228
223
  (function next(): void {
224
+ let method = 'adduser';
229
225
  const plugin = plugins.shift() as pluginUtils.Auth<Config>;
230
- if (typeof plugin.adduser !== 'function') {
226
+ // @ts-expect-error future major (7.x) should remove this section
227
+ if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {
228
+ method = 'add_user';
229
+ warningUtils.emit(warningUtils.Codes.VERWAR006);
230
+ }
231
+ // @ts-ignore
232
+ if (typeof plugin[method] !== 'function') {
231
233
  next();
232
234
  } else {
233
- // @ts-expect-error future major (7.x) should remove this section
234
- if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {
235
- throw errorUtils.getInternalError(
236
- 'add_user method not longer supported, rename to adduser'
237
- );
238
- }
239
-
240
- plugin.adduser(
235
+ // TODO: replace by adduser whenever add_user deprecation method has been removed
236
+ // @ts-ignore
237
+ plugin[method](
241
238
  user,
242
239
  password,
243
240
  function (err: VerdaccioError | null, ok?: boolean | string): void {
244
241
  if (err) {
245
- debug('the user %o could not being added. Error: %o', user, err?.message);
242
+ debug('the user %o could not being added. Error: %o', user, err?.message);
246
243
  return cb(err);
247
244
  }
248
245
  if (ok) {
249
246
  debug('the user %o has been added', user);
250
247
  return self.authenticate(user, password, cb);
251
248
  }
249
+ debug('user could not be added, skip to next auth plugin');
252
250
  next();
253
251
  }
254
252
  );
@@ -375,7 +373,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
375
373
  })();
376
374
  }
377
375
 
378
- public apiJWTmiddleware() {
376
+ public apiJWTmiddleware(): any {
379
377
  debug('jwt middleware');
380
378
  const plugins = this.plugins.slice(0);
381
379
  const helpers = { createAnonymousRemoteUser, createRemoteUser };
@@ -387,8 +385,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
387
385
 
388
386
  return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {
389
387
  req.pause();
390
-
391
- const next = function (err?: VerdaccioError): any {
388
+ const next = function (err?: VerdaccioError): NextFunction {
392
389
  req.resume();
393
390
  // uncomment this to reject users with bad auth headers
394
391
  // return _next.apply(null, arguments)
@@ -398,13 +395,14 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
398
395
  req.remote_user.error = err.message;
399
396
  }
400
397
 
401
- return _next();
398
+ return _next() as unknown as NextFunction;
402
399
  };
403
400
 
404
- if (this._isRemoteUserValid(req.remote_user)) {
405
- debug('jwt has a valid authentication header');
406
- return next();
407
- }
401
+ // FUTURE: disabled, not removed yet but seems unreacable code
402
+ // if (this._isRemoteUserValid(req.remote_user)) {
403
+ // debug('jwt has a valid authentication header');
404
+ // return next();
405
+ // }
408
406
 
409
407
  // in case auth header does not exist we return anonymous function
410
408
  const remoteUser = createAnonymousRemoteUser();
@@ -425,20 +423,20 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
425
423
 
426
424
  if (isAESLegacy(security)) {
427
425
  debug('api middleware using legacy auth token');
428
- this._handleAESMiddleware(req, security, secret, authorization, next);
426
+ this.handleAESMiddleware(req, security, secret, authorization, next);
429
427
  } else {
430
428
  debug('api middleware using JWT auth token');
431
- this._handleJWTAPIMiddleware(req, security, secret, authorization, next);
429
+ this.handleJWTAPIMiddleware(req, security, secret, authorization, next);
432
430
  }
433
431
  };
434
432
  }
435
433
 
436
- private _handleJWTAPIMiddleware(
434
+ private handleJWTAPIMiddleware(
437
435
  req: $RequestExtend,
438
436
  security: Security,
439
437
  secret: string,
440
438
  authorization: string,
441
- next: Function
439
+ next: any
442
440
  ): void {
443
441
  debug('handle JWT api middleware');
444
442
  const { scheme, token } = parseAuthTokenHeader(authorization);
@@ -475,7 +473,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
475
473
  }
476
474
  }
477
475
 
478
- private _handleAESMiddleware(
476
+ private handleAESMiddleware(
479
477
  req: $RequestExtend,
480
478
  security: Security,
481
479
  secret: string,
@@ -485,7 +483,12 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
485
483
  debug('handle legacy api middleware');
486
484
  debug('api middleware secret %o', typeof secret === 'string');
487
485
  debug('api middleware authorization %o', typeof authorization === 'string');
488
- const credentials: any = getMiddlewareCredentials(security, secret, authorization);
486
+ const credentials: any = getMiddlewareCredentials(
487
+ security,
488
+ secret,
489
+ authorization,
490
+ this.config?.getEnhancedLegacySignature()
491
+ );
489
492
  debug('api middleware credentials %o', credentials?.name);
490
493
  if (credentials) {
491
494
  const { user, password } = credentials;
@@ -515,7 +518,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
515
518
  /**
516
519
  * JWT middleware for WebUI
517
520
  */
518
- public webUIJWTmiddleware(): $NextFunctionVer {
521
+ public webUIJWTmiddleware() {
519
522
  return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {
520
523
  if (this._isRemoteUserValid(req.remote_user)) {
521
524
  return _next();
@@ -525,7 +528,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
525
528
  const next = (err: VerdaccioError | void): void => {
526
529
  req.resume();
527
530
  if (err) {
528
- // req.remote_user.error = err.message;
531
+ req.remote_user.error = err.message;
529
532
  res.status(err.statusCode).send(err.message);
530
533
  }
531
534
 
@@ -576,7 +579,6 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
576
579
  name,
577
580
  groups: groupedGroups,
578
581
  };
579
-
580
582
  const token: string = await signPayload(payload, this.secret, signOptions);
581
583
 
582
584
  return token;
@@ -586,7 +588,17 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
586
588
  * Encrypt a string.
587
589
  */
588
590
  public aesEncrypt(value: string): string | void {
589
- return aesEncrypt(value, this.secret);
591
+ // enhancedLegacySignature enables modern aes192 algorithm signature
592
+ if (this.config?.getEnhancedLegacySignature()) {
593
+ debug('signing with enhaced aes legacy');
594
+ const token = aesEncrypt(value, this.secret);
595
+ return token;
596
+ } else {
597
+ debug('signing with enhaced aes deprecated legacy');
598
+ // deprecated aes (legacy) signature, only must be used for legacy version
599
+ const token = aesEncryptDeprecated(Buffer.from(value), this.secret).toString('base64');
600
+ return token;
601
+ }
590
602
  }
591
603
  }
592
604
 
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { Auth } from './auth';
2
2
  export * from './utils';
3
+ export * from './types';
@@ -0,0 +1,66 @@
1
+ import buildDebug from 'debug';
2
+ import _ from 'lodash';
3
+
4
+ import { TOKEN_BASIC, TOKEN_BEARER } from '@verdaccio/core';
5
+ import { aesDecryptDeprecated as aesDecrypt, parseBasicPayload } from '@verdaccio/signature';
6
+ import { Security } from '@verdaccio/types';
7
+
8
+ import { AuthMiddlewarePayload } from './types';
9
+ import {
10
+ convertPayloadToBase64,
11
+ isAESLegacy,
12
+ parseAuthTokenHeader,
13
+ verifyJWTPayload,
14
+ } from './utils';
15
+
16
+ const debug = buildDebug('verdaccio:auth:utils');
17
+
18
+ export function parseAESCredentials(authorizationHeader: string, secret: string) {
19
+ debug('parseAESCredentials');
20
+ const { scheme, token } = parseAuthTokenHeader(authorizationHeader);
21
+
22
+ // basic is deprecated and should not be enforced
23
+ // basic is currently being used for functional test
24
+ if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) {
25
+ debug('legacy header basic');
26
+ const credentials = convertPayloadToBase64(token).toString();
27
+
28
+ return credentials;
29
+ } else if (scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {
30
+ debug('legacy header bearer');
31
+ const credentials = aesDecrypt(Buffer.from(token), secret);
32
+
33
+ return credentials;
34
+ }
35
+ }
36
+
37
+ export function getMiddlewareCredentials(
38
+ security: Security,
39
+ secretKey: string,
40
+ authorizationHeader: string
41
+ ): AuthMiddlewarePayload {
42
+ debug('getMiddlewareCredentials');
43
+ // comment out for debugging purposes
44
+ if (isAESLegacy(security)) {
45
+ debug('is legacy');
46
+ const credentials = parseAESCredentials(authorizationHeader, secretKey);
47
+ if (typeof credentials !== 'string') {
48
+ debug('parse legacy credentials failed');
49
+ return;
50
+ }
51
+
52
+ const parsedCredentials = parseBasicPayload(credentials);
53
+ if (!parsedCredentials) {
54
+ debug('parse legacy basic payload credentials failed');
55
+ return;
56
+ }
57
+
58
+ return parsedCredentials;
59
+ }
60
+ const { scheme, token } = parseAuthTokenHeader(authorizationHeader);
61
+
62
+ debug('is jwt');
63
+ if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {
64
+ return verifyJWTPayload(token, secretKey);
65
+ }
66
+ }