@universis/janitor 1.4.1 → 1.6.0
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 +48 -0
- package/dist/OAuth2ClientService.d.ts +98 -0
- package/dist/OAuth2ClientService.js +251 -0
- package/dist/OAuth2ClientService.js.map +1 -0
- package/dist/RedisClientStore.js +20 -36
- package/dist/RedisClientStore.js.map +1 -1
- package/dist/RemoteAddressValidator.d.ts +10 -0
- package/dist/RemoteAddressValidator.js +88 -0
- package/dist/RemoteAddressValidator.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/src/OAuth2ClientService.d.ts +98 -0
- package/src/OAuth2ClientService.js +255 -0
- package/src/RedisClientStore.js +20 -36
- package/src/RemoteAddressValidator.d.ts +10 -0
- package/src/RemoteAddressValidator.js +92 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.RemoteAddressValidator = exports.HttpRemoteAddrForbiddenError = void 0;var _common = require("@themost/common");
|
|
2
|
+
var _express = _interopRequireDefault(require("express"));
|
|
3
|
+
var _jsonwebtoken = _interopRequireDefault(require("jsonwebtoken"));function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };}
|
|
4
|
+
|
|
5
|
+
class HttpRemoteAddrForbiddenError extends _common.HttpForbiddenError {
|
|
6
|
+
constructor() {
|
|
7
|
+
super('Access is denied due to remote address conflict. The client network has been changed or cannot be determined.');
|
|
8
|
+
this.statusCode = 403.6;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
}exports.HttpRemoteAddrForbiddenError = HttpRemoteAddrForbiddenError;
|
|
12
|
+
|
|
13
|
+
class RemoteAddressValidator extends _common.ApplicationService {
|
|
14
|
+
constructor(app) {
|
|
15
|
+
super(app);
|
|
16
|
+
|
|
17
|
+
// get proxy address forwarding option
|
|
18
|
+
this.proxyAddressForwarding = app.getConfiguration().getSourceAt('settings/universis/api/proxyAddressForwarding');
|
|
19
|
+
if (typeof proxyAddressForwarding !== 'boolean') {
|
|
20
|
+
this.proxyAddressForwarding = false;
|
|
21
|
+
}
|
|
22
|
+
// get token claim name
|
|
23
|
+
this.claim = app.getConfiguration().getSourceAt('settings/universis/janitor/remoteAddress/claim') || 'remoteAddress';
|
|
24
|
+
|
|
25
|
+
app.serviceRouter.subscribe((serviceRouter) => {
|
|
26
|
+
if (serviceRouter == null) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const addRouter = _express.default.Router();
|
|
30
|
+
addRouter.use((req, res, next) => {
|
|
31
|
+
void this.validateRemoteAddress(req).then((value) => {
|
|
32
|
+
if (value === false) {
|
|
33
|
+
return next(new HttpRemoteAddrForbiddenError());
|
|
34
|
+
}
|
|
35
|
+
return next();
|
|
36
|
+
}).catch((err) => {
|
|
37
|
+
return next(err);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
// insert router at the beginning of serviceRouter.stack
|
|
41
|
+
serviceRouter.stack.unshift.apply(serviceRouter.stack, addRouter.stack);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Gets remote address from request
|
|
47
|
+
* @param {import('express').Request} req
|
|
48
|
+
* @returns
|
|
49
|
+
*/
|
|
50
|
+
getRemoteAddress(req) {
|
|
51
|
+
let remoteAddress;
|
|
52
|
+
if (this.proxyAddressForwarding) {
|
|
53
|
+
// get proxy headers or remote address
|
|
54
|
+
remoteAddress = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : req.socket.remoteAddress);
|
|
55
|
+
} else {
|
|
56
|
+
remoteAddress = req.connection ? req.connection.remoteAddress : req.socket.remoteAddress;
|
|
57
|
+
}
|
|
58
|
+
return remoteAddress;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Validates token remote address with request remote address
|
|
63
|
+
* @param {import('express').Request} req
|
|
64
|
+
* @returns {Promise<boolean>}
|
|
65
|
+
*/
|
|
66
|
+
async validateRemoteAddress(req) {var _req$context, _req$context$user;
|
|
67
|
+
const authenticationToken = (_req$context = req.context) === null || _req$context === void 0 ? void 0 : (_req$context$user = _req$context.user) === null || _req$context$user === void 0 ? void 0 : _req$context$user.authenticationToken;
|
|
68
|
+
if (authenticationToken != null) {
|
|
69
|
+
const access_token = _jsonwebtoken.default.decode(authenticationToken);
|
|
70
|
+
const remoteAddress = access_token[this.claim];
|
|
71
|
+
if (remoteAddress == null) {
|
|
72
|
+
_common.TraceUtils.warn(`Remote address validation failed. Expected a valid remote address claimed by using "${this.claim}" attribute but got none.`);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
// get context remote address
|
|
76
|
+
const requestRemoteAddress = this.getRemoteAddress(req);
|
|
77
|
+
if (remoteAddress !== requestRemoteAddress) {
|
|
78
|
+
_common.TraceUtils.warn(`Remote address validation failed. Expected remote address is ${remoteAddress || 'Uknown'} but request remote address is ${requestRemoteAddress}`);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
_common.TraceUtils.warn('Remote address validation cannot be completed because authentication token is not available.');
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}exports.RemoteAddressValidator = RemoteAddressValidator;
|
|
88
|
+
//# sourceMappingURL=RemoteAddressValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RemoteAddressValidator.js","names":["_common","require","_express","_interopRequireDefault","_jsonwebtoken","obj","__esModule","default","HttpRemoteAddrForbiddenError","HttpForbiddenError","constructor","statusCode","exports","RemoteAddressValidator","ApplicationService","app","proxyAddressForwarding","getConfiguration","getSourceAt","claim","serviceRouter","subscribe","addRouter","express","Router","use","req","res","next","validateRemoteAddress","then","value","catch","err","stack","unshift","apply","getRemoteAddress","remoteAddress","headers","connection","socket","_req$context","_req$context$user","authenticationToken","context","user","access_token","jwt","decode","TraceUtils","warn","requestRemoteAddress"],"sources":["../src/RemoteAddressValidator.js"],"sourcesContent":["import { ApplicationService, HttpForbiddenError, TraceUtils } from '@themost/common';\nimport express from 'express';\nimport jwt from 'jsonwebtoken';\n\nclass HttpRemoteAddrForbiddenError extends HttpForbiddenError {\n constructor() {\n super('Access is denied due to remote address conflict. The client network has been changed or cannot be determined.');\n this.statusCode = 403.6;\n }\n \n}\n\nclass RemoteAddressValidator extends ApplicationService {\n constructor(app) {\n super(app);\n\n // get proxy address forwarding option\n this.proxyAddressForwarding = app.getConfiguration().getSourceAt('settings/universis/api/proxyAddressForwarding');\n if (typeof proxyAddressForwarding !== 'boolean') {\n this.proxyAddressForwarding = false;\n }\n // get token claim name\n this.claim = app.getConfiguration().getSourceAt('settings/universis/janitor/remoteAddress/claim') || 'remoteAddress';\n\n app.serviceRouter.subscribe((serviceRouter) => {\n if (serviceRouter == null) {\n return;\n }\n const addRouter = express.Router();\n addRouter.use((req, res, next) => {\n void this.validateRemoteAddress(req).then((value) => {\n if (value === false) {\n return next(new HttpRemoteAddrForbiddenError());\n }\n return next();\n }).catch((err) => {\n return next(err);\n });\n });\n // insert router at the beginning of serviceRouter.stack\n serviceRouter.stack.unshift.apply(serviceRouter.stack, addRouter.stack);\n });\n }\n\n /**\n * Gets remote address from request\n * @param {import('express').Request} req \n * @returns \n */\n getRemoteAddress(req) {\n let remoteAddress;\n if (this.proxyAddressForwarding) {\n // get proxy headers or remote address\n remoteAddress = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : req.socket.remoteAddress);\n } else {\n remoteAddress = req.connection ? req.connection.remoteAddress : req.socket.remoteAddress;\n }\n return remoteAddress;\n }\n\n /**\n * Validates token remote address with request remote address\n * @param {import('express').Request} req \n * @returns {Promise<boolean>}\n */\n async validateRemoteAddress(req) {\n const authenticationToken = req.context?.user?.authenticationToken;\n if (authenticationToken != null) {\n const access_token = jwt.decode(authenticationToken);\n const remoteAddress = access_token[this.claim];\n if (remoteAddress == null) {\n TraceUtils.warn(`Remote address validation failed. Expected a valid remote address claimed by using \"${this.claim}\" attribute but got none.`);\n return false;\n }\n // get context remote address\n const requestRemoteAddress = this.getRemoteAddress(req);\n if (remoteAddress !== requestRemoteAddress) {\n TraceUtils.warn(`Remote address validation failed. Expected remote address is ${remoteAddress || 'Uknown'} but request remote address is ${requestRemoteAddress}`);\n return false;\n }\n return true;\n }\n TraceUtils.warn('Remote address validation cannot be completed because authentication token is not available.');\n return false;\n }\n\n}\n\nexport {\n HttpRemoteAddrForbiddenError,\n RemoteAddressValidator\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -4,4 +4,6 @@ var _SpeedLimitService = require("./SpeedLimitService");Object.keys(_SpeedLimitS
|
|
|
4
4
|
var _RedisClientStore = require("./RedisClientStore");Object.keys(_RedisClientStore).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (key in exports && exports[key] === _RedisClientStore[key]) return;Object.defineProperty(exports, key, { enumerable: true, get: function () {return _RedisClientStore[key];} });});
|
|
5
5
|
var _ScopeAccessConfiguration = require("./ScopeAccessConfiguration");Object.keys(_ScopeAccessConfiguration).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (key in exports && exports[key] === _ScopeAccessConfiguration[key]) return;Object.defineProperty(exports, key, { enumerable: true, get: function () {return _ScopeAccessConfiguration[key];} });});
|
|
6
6
|
var _validateScope = require("./validateScope");Object.keys(_validateScope).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (key in exports && exports[key] === _validateScope[key]) return;Object.defineProperty(exports, key, { enumerable: true, get: function () {return _validateScope[key];} });});
|
|
7
|
+
var _OAuth2ClientService = require("./OAuth2ClientService");Object.keys(_OAuth2ClientService).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (key in exports && exports[key] === _OAuth2ClientService[key]) return;Object.defineProperty(exports, key, { enumerable: true, get: function () {return _OAuth2ClientService[key];} });});
|
|
8
|
+
var _RemoteAddressValidator = require("./RemoteAddressValidator");Object.keys(_RemoteAddressValidator).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (key in exports && exports[key] === _RemoteAddressValidator[key]) return;Object.defineProperty(exports, key, { enumerable: true, get: function () {return _RemoteAddressValidator[key];} });});
|
|
7
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["require","_RateLimitService","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_SpeedLimitService","_RedisClientStore","_ScopeAccessConfiguration","_validateScope"],"sources":["../src/index.js"],"sourcesContent":["import './polyfills';\nexport * from './RateLimitService';\nexport * from './SpeedLimitService';\nexport * from './RedisClientStore';\nexport * from './ScopeAccessConfiguration';\nexport * from './validateScope';\n"],"mappings":"2EAAAA,OAAA;AACA,IAAAC,iBAAA,GAAAD,OAAA,uBAAAE,MAAA,CAAAC,IAAA,CAAAF,iBAAA,EAAAG,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAJ,iBAAA,CAAAI,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAR,iBAAA,CAAAI,GAAA;AACA,IAAAK,kBAAA,GAAAV,OAAA,wBAAAE,MAAA,CAAAC,IAAA,CAAAO,kBAAA,EAAAN,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,kBAAA,CAAAL,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAC,kBAAA,CAAAL,GAAA;AACA,IAAAM,iBAAA,GAAAX,OAAA,uBAAAE,MAAA,CAAAC,IAAA,CAAAQ,iBAAA,EAAAP,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,iBAAA,CAAAN,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAE,iBAAA,CAAAN,GAAA;AACA,IAAAO,yBAAA,GAAAZ,OAAA,+BAAAE,MAAA,CAAAC,IAAA,CAAAS,yBAAA,EAAAR,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,yBAAA,CAAAP,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAG,yBAAA,CAAAP,GAAA;AACA,IAAAQ,cAAA,GAAAb,OAAA,oBAAAE,MAAA,CAAAC,IAAA,CAAAU,cAAA,EAAAT,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAQ,cAAA,CAAAR,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAI,cAAA,CAAAR,GAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["require","_RateLimitService","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_SpeedLimitService","_RedisClientStore","_ScopeAccessConfiguration","_validateScope","_OAuth2ClientService","_RemoteAddressValidator"],"sources":["../src/index.js"],"sourcesContent":["import './polyfills';\nexport * from './RateLimitService';\nexport * from './SpeedLimitService';\nexport * from './RedisClientStore';\nexport * from './ScopeAccessConfiguration';\nexport * from './validateScope';\nexport * from './OAuth2ClientService';\nexport * from './RemoteAddressValidator';\n"],"mappings":"2EAAAA,OAAA;AACA,IAAAC,iBAAA,GAAAD,OAAA,uBAAAE,MAAA,CAAAC,IAAA,CAAAF,iBAAA,EAAAG,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAJ,iBAAA,CAAAI,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAR,iBAAA,CAAAI,GAAA;AACA,IAAAK,kBAAA,GAAAV,OAAA,wBAAAE,MAAA,CAAAC,IAAA,CAAAO,kBAAA,EAAAN,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,kBAAA,CAAAL,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAC,kBAAA,CAAAL,GAAA;AACA,IAAAM,iBAAA,GAAAX,OAAA,uBAAAE,MAAA,CAAAC,IAAA,CAAAQ,iBAAA,EAAAP,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,iBAAA,CAAAN,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAE,iBAAA,CAAAN,GAAA;AACA,IAAAO,yBAAA,GAAAZ,OAAA,+BAAAE,MAAA,CAAAC,IAAA,CAAAS,yBAAA,EAAAR,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,yBAAA,CAAAP,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAG,yBAAA,CAAAP,GAAA;AACA,IAAAQ,cAAA,GAAAb,OAAA,oBAAAE,MAAA,CAAAC,IAAA,CAAAU,cAAA,EAAAT,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAQ,cAAA,CAAAR,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAI,cAAA,CAAAR,GAAA;AACA,IAAAS,oBAAA,GAAAd,OAAA,0BAAAE,MAAA,CAAAC,IAAA,CAAAW,oBAAA,EAAAV,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAS,oBAAA,CAAAT,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAK,oBAAA,CAAAT,GAAA;AACA,IAAAU,uBAAA,GAAAf,OAAA,6BAAAE,MAAA,CAAAC,IAAA,CAAAY,uBAAA,EAAAX,OAAA,WAAAC,GAAA,OAAAA,GAAA,kBAAAA,GAAA,8BAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAU,uBAAA,CAAAV,GAAA,UAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA,IAAAG,UAAA,QAAAC,GAAA,WAAAA,CAAA,UAAAM,uBAAA,CAAAV,GAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@universis/janitor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Universis api plugin for rate limiting requests",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -31,8 +31,10 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"express-rate-limit": "^7.1.1",
|
|
33
33
|
"express-slow-down": "^1.6.0",
|
|
34
|
+
"ioredis": "^5.3.2",
|
|
35
|
+
"jsonwebtoken": "^9.0.2",
|
|
34
36
|
"rate-limit-redis": "^4.2.0",
|
|
35
|
-
"
|
|
37
|
+
"superagent": "^8.1.2"
|
|
36
38
|
},
|
|
37
39
|
"peerDependencies": {
|
|
38
40
|
"@themost/common": "^2",
|
|
@@ -50,6 +52,7 @@
|
|
|
50
52
|
"@babel/register": "^7.21.0",
|
|
51
53
|
"@rollup/plugin-babel": "^6.0.3",
|
|
52
54
|
"@types/express": "^4.17.6",
|
|
55
|
+
"@types/ioredis": "^5.0.0",
|
|
53
56
|
"@types/jasmine": "^3.5.10",
|
|
54
57
|
"dotenv": "^8.2.0",
|
|
55
58
|
"eslint": "^8.39.0",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ApplicationService, ApplicationBase } from '@themost/common';
|
|
2
|
+
import { DataContext } from '@themost/data';
|
|
3
|
+
|
|
4
|
+
export declare interface OAuth2MethodOptions {
|
|
5
|
+
access_token: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export declare interface OAuth2AuthorizeUser {
|
|
9
|
+
client_id?: string;
|
|
10
|
+
client_secret?: string;
|
|
11
|
+
username: string;
|
|
12
|
+
password: string;
|
|
13
|
+
grant_type: string;
|
|
14
|
+
scope?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export declare interface OAuth2ServiceSettings {
|
|
18
|
+
unattendedExecutionAccount?: string;
|
|
19
|
+
client_id: string;
|
|
20
|
+
client_secret?: string;
|
|
21
|
+
server_uri: string;
|
|
22
|
+
userinfo_uri?: string;
|
|
23
|
+
introspect_uri?: string;
|
|
24
|
+
admin_uri?: string;
|
|
25
|
+
well_known_configuration_uri?: string;
|
|
26
|
+
adminAccount: {
|
|
27
|
+
username: string;
|
|
28
|
+
password: string;
|
|
29
|
+
client_id: string;
|
|
30
|
+
client_secret?: string;
|
|
31
|
+
scope?: string;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export declare interface OAuth2UserProfile {
|
|
36
|
+
sub: string;
|
|
37
|
+
name: string;
|
|
38
|
+
preferred_username: string;
|
|
39
|
+
given_name: string;
|
|
40
|
+
family_name: string;
|
|
41
|
+
email: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export declare interface GenericUser {
|
|
45
|
+
id?: any;
|
|
46
|
+
additionalType?: string;
|
|
47
|
+
alternateName?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
givenName?: string;
|
|
50
|
+
familyName?: string;
|
|
51
|
+
image?: string;
|
|
52
|
+
name?: string;
|
|
53
|
+
url?: string;
|
|
54
|
+
dateCreated?: Date;
|
|
55
|
+
dateModified?: Date;
|
|
56
|
+
createdBy?: any;
|
|
57
|
+
modifiedBy?: any;
|
|
58
|
+
lockoutTime?: Date;
|
|
59
|
+
logonCount?: number;
|
|
60
|
+
enabled?: boolean;
|
|
61
|
+
lastLogon?: Date;
|
|
62
|
+
userCredentials?: {
|
|
63
|
+
userPassword?: string;
|
|
64
|
+
userActivated?: boolean;
|
|
65
|
+
temporary?: boolean;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export declare interface OAuth2User {
|
|
70
|
+
id?: any;
|
|
71
|
+
username?: string;
|
|
72
|
+
email?: string;
|
|
73
|
+
enabled?: boolean;
|
|
74
|
+
emailVerified?: boolean;
|
|
75
|
+
firstName?: string;
|
|
76
|
+
lastName?: string;
|
|
77
|
+
credentials?: {
|
|
78
|
+
algorithm?: string,
|
|
79
|
+
temporary?: boolean,
|
|
80
|
+
type?: string,
|
|
81
|
+
value?: string
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export declare class OAuth2ClientService extends ApplicationService {
|
|
86
|
+
get settings(): OAuth2ServiceSettings;
|
|
87
|
+
constructor(app: ApplicationBase)
|
|
88
|
+
getUserInfo(context: DataContext, token: string): Promise<OAuth2UserProfile>;
|
|
89
|
+
getTokenInfo(context: DataContext, token: string): Promise<any>;
|
|
90
|
+
getContextTokenInfo(context: DataContext): Promise<any>;
|
|
91
|
+
authorize(authorizeUser: OAuth2AuthorizeUser): Promise<{ access_token?: string, refresh_token?: string}>;
|
|
92
|
+
getUser(username: string, options: OAuth2MethodOptions): Promise<any>;
|
|
93
|
+
getUserById(user_id: any, options: OAuth2MethodOptions): Promise<any>;
|
|
94
|
+
getUserByEmail(email: string, options: OAuth2MethodOptions): Promise<any>;
|
|
95
|
+
updateUser(user: GenericUser | any, options: OAuth2MethodOptions): Promise<any>;
|
|
96
|
+
createUser(user: GenericUser | any, options: OAuth2MethodOptions): Promise<any>;
|
|
97
|
+
deleteUser(user: { id: any }, options: OAuth2MethodOptions): Promise<any>;
|
|
98
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import {Request} from 'superagent'
|
|
2
|
+
import {URL} from 'url';
|
|
3
|
+
import {ApplicationService, DataError, HttpError} from '@themost/common';
|
|
4
|
+
|
|
5
|
+
function responseHander(resolve, reject) {
|
|
6
|
+
return function (err, response) {
|
|
7
|
+
if (err) {
|
|
8
|
+
/**
|
|
9
|
+
* @type {import('superagent').Response}
|
|
10
|
+
*/
|
|
11
|
+
const response = err.response
|
|
12
|
+
if (response && response.headers['content-type'] === 'application/json') {
|
|
13
|
+
// get body
|
|
14
|
+
const clientError = response.body;
|
|
15
|
+
const error = new HttpError(response.status);
|
|
16
|
+
return reject(Object.assign(error, {
|
|
17
|
+
clientError
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
return reject(err);
|
|
21
|
+
}
|
|
22
|
+
if (response.status === 204 && response.headers['content-type'] === 'application/json') {
|
|
23
|
+
return resolve(null);
|
|
24
|
+
}
|
|
25
|
+
return resolve(response.body);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @class
|
|
31
|
+
*/
|
|
32
|
+
class OAuth2ClientService extends ApplicationService {
|
|
33
|
+
/**
|
|
34
|
+
* @param {import('@themost/express').ExpressDataApplication} app
|
|
35
|
+
*/
|
|
36
|
+
constructor(app) {
|
|
37
|
+
super(app);
|
|
38
|
+
/**
|
|
39
|
+
* @name OAuth2ClientService#settings
|
|
40
|
+
* @type {{server_uri:string,token_uri?:string}}
|
|
41
|
+
*/
|
|
42
|
+
Object.defineProperty(this, 'settings', {
|
|
43
|
+
writable: false,
|
|
44
|
+
value: app.getConfiguration().getSourceAt('settings/auth'),
|
|
45
|
+
enumerable: false,
|
|
46
|
+
configurable: false
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Gets keycloak server root
|
|
52
|
+
* @returns {string}
|
|
53
|
+
*/
|
|
54
|
+
getServer() {
|
|
55
|
+
return this.settings.server_uri;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Gets keycloak server root
|
|
60
|
+
* @returns {string}
|
|
61
|
+
*/
|
|
62
|
+
getAdminRoot() {
|
|
63
|
+
return this.settings.admin_uri;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// noinspection JSUnusedGlobalSymbols
|
|
67
|
+
/**
|
|
68
|
+
* Gets user's profile by calling OAuth2 server profile endpoint
|
|
69
|
+
* @param {ExpressDataContext} context
|
|
70
|
+
* @param {string} token
|
|
71
|
+
*/
|
|
72
|
+
getUserInfo(token) {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const userinfo_uri = this.settings.userinfo_uri ? new URL(this.settings.userinfo_uri, this.getServer()) : new URL('me', this.getServer());
|
|
75
|
+
return new Request('GET', userinfo_uri)
|
|
76
|
+
.set({
|
|
77
|
+
'Authorization': `Bearer ${token}`,
|
|
78
|
+
'Accept': 'application/json'
|
|
79
|
+
})
|
|
80
|
+
.query({
|
|
81
|
+
'access_token':token
|
|
82
|
+
}).end(responseHander(resolve, reject));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// noinspection JSUnusedGlobalSymbols
|
|
87
|
+
/**
|
|
88
|
+
* Gets the token info of the current context
|
|
89
|
+
* @param {ExpressDataContext} context
|
|
90
|
+
*/
|
|
91
|
+
getContextTokenInfo(context) {
|
|
92
|
+
if (context.user == null) {
|
|
93
|
+
return Promise.reject(new Error('Context user may not be null'));
|
|
94
|
+
}
|
|
95
|
+
if (context.user.authenticationType !== 'Bearer') {
|
|
96
|
+
return Promise.reject(new Error('Invalid context authentication type'));
|
|
97
|
+
}
|
|
98
|
+
if (context.user.authenticationToken == null) {
|
|
99
|
+
return Promise.reject(new Error('Context authentication data may not be null'));
|
|
100
|
+
}
|
|
101
|
+
return this.getTokenInfo(context, context.user.authenticationToken);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Gets token info by calling OAuth2 server endpoint
|
|
105
|
+
* @param {ExpressDataContext} _context
|
|
106
|
+
* @param {string} token
|
|
107
|
+
*/
|
|
108
|
+
getTokenInfo(_context, token) {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
const introspection_uri = this.settings.introspection_uri ? new URL(this.settings.introspection_uri, this.getServer()) : new URL('tokeninfo', this.getServer());
|
|
111
|
+
return new Request('POST', introspection_uri)
|
|
112
|
+
.auth(this.settings.client_id, this.settings.client_secret)
|
|
113
|
+
.set('Accept', 'application/json')
|
|
114
|
+
.type('form')
|
|
115
|
+
.send({
|
|
116
|
+
'token_type_hint': 'access_token',
|
|
117
|
+
'token': token,
|
|
118
|
+
}).end(responseHander(resolve, reject));
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {AuthorizeUser} authorizeUser
|
|
124
|
+
*/
|
|
125
|
+
authorize(authorizeUser) {
|
|
126
|
+
const tokenURL = this.settings.token_uri ? new URL(this.settings.token_uri) : new URL('authorize', this.getServer());
|
|
127
|
+
return new Promise((resolve, reject)=> {
|
|
128
|
+
return new Request('POST', tokenURL)
|
|
129
|
+
.type('form')
|
|
130
|
+
.send(authorizeUser).end(responseHander(resolve, reject));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Gets a user by name
|
|
136
|
+
* @param {*} user_id
|
|
137
|
+
* @param {AdminMethodOptions} options
|
|
138
|
+
*/
|
|
139
|
+
getUserById(user_id, options) {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
return new Request('GET', new URL(`users/${user_id}`, this.getAdminRoot()))
|
|
142
|
+
.set('Authorization', `Bearer ${options.access_token}`)
|
|
143
|
+
.end(responseHander(resolve, reject));
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Gets a user by name
|
|
149
|
+
* @param {string} username
|
|
150
|
+
* @param {AdminMethodOptions} options
|
|
151
|
+
*/
|
|
152
|
+
getUser(username, options) {
|
|
153
|
+
return new Promise((resolve, reject)=> {
|
|
154
|
+
return new Request('GET', new URL('users', this.getAdminRoot()))
|
|
155
|
+
.set('Authorization', `Bearer ${options.access_token}`)
|
|
156
|
+
.query({
|
|
157
|
+
'$filter': `name eq '${username}'`
|
|
158
|
+
})
|
|
159
|
+
.end(responseHander(resolve, reject));
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Gets a user by email address
|
|
165
|
+
* @param {string} email
|
|
166
|
+
* @param {AdminMethodOptions} options
|
|
167
|
+
*/
|
|
168
|
+
getUserByEmail(email, options) {
|
|
169
|
+
return new Promise((resolve, reject)=> {
|
|
170
|
+
return new Request('GET', new URL('users', this.getAdminRoot()))
|
|
171
|
+
.set('Authorization', `Bearer ${options.access_token}`)
|
|
172
|
+
.query({
|
|
173
|
+
'$filter': `alternateName eq '${email}'`
|
|
174
|
+
})
|
|
175
|
+
.end(responseHander(resolve, reject));
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Updates an existing user
|
|
181
|
+
* @param {*} user
|
|
182
|
+
* @param {AdminMethodOptions} options
|
|
183
|
+
*/
|
|
184
|
+
updateUser(user, options) {
|
|
185
|
+
return new Promise((resolve, reject)=> {
|
|
186
|
+
if (user.id == null) {
|
|
187
|
+
return reject(new DataError('E_IDENTIFIER', 'User may not be empty at this context.', null, 'User', 'id'));
|
|
188
|
+
}
|
|
189
|
+
const request = new Request('PUT', new URL(`users/${user.id}`, this.getAdminRoot()));
|
|
190
|
+
return request.set('Authorization', `Bearer ${options.access_token}`)
|
|
191
|
+
.set('Content-Type', 'application/json')
|
|
192
|
+
.send(user)
|
|
193
|
+
.end(responseHander(resolve, reject));
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Creates a new user
|
|
199
|
+
* @param {*} user
|
|
200
|
+
* @param {AdminMethodOptions} options
|
|
201
|
+
*/
|
|
202
|
+
createUser(user, options) {
|
|
203
|
+
return new Promise((resolve, reject)=> {
|
|
204
|
+
const request = new Request('POST', new URL('users', this.getAdminRoot()));
|
|
205
|
+
return request.set('Authorization', `Bearer ${options.access_token}`)
|
|
206
|
+
.set('Content-Type', 'application/json')
|
|
207
|
+
.send(Object.assign({}, user, {
|
|
208
|
+
$state: 1 // for create
|
|
209
|
+
}))
|
|
210
|
+
.end(responseHander(resolve, reject));
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Deletes a user
|
|
216
|
+
* @param {{id: any}} user
|
|
217
|
+
* @param {AdminMethodOptions} options
|
|
218
|
+
*/
|
|
219
|
+
deleteUser(user, options) {
|
|
220
|
+
return new Promise((resolve, reject)=> {
|
|
221
|
+
if (user.id == null) {
|
|
222
|
+
return reject(new DataError('E_IDENTIFIER', 'User may not be empty at this context.', null, 'User', 'id'));
|
|
223
|
+
}
|
|
224
|
+
const request = new Request('DELETE', new URL(`users/${user.id}`, this.getAdminRoot()));
|
|
225
|
+
return request.set('Authorization', `Bearer ${options.access_token}`)
|
|
226
|
+
.end(responseHander(resolve, reject));
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @param {boolean=} force
|
|
232
|
+
* @returns {*}
|
|
233
|
+
*/
|
|
234
|
+
getWellKnownConfiguration(force) {
|
|
235
|
+
if (force) {
|
|
236
|
+
this.well_known_configuration = null;
|
|
237
|
+
}
|
|
238
|
+
if (this.well_known_configuration) {
|
|
239
|
+
return Promise.resolve(this.well_known_configuration);
|
|
240
|
+
}
|
|
241
|
+
return new Promise((resolve, reject) => {
|
|
242
|
+
const well_known_configuration_uri = this.settings.well_known_configuration_uri ? new URL(this.settings.well_known_configuration_uri, this.getServer()) : new URL('.well-known/openid-configuration', this.getServer());
|
|
243
|
+
return new Request('GET', well_known_configuration_uri)
|
|
244
|
+
.end(responseHander(resolve, reject));
|
|
245
|
+
}).then((configuration) => {
|
|
246
|
+
this.well_known_configuration = configuration;
|
|
247
|
+
return configuration;
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export {
|
|
253
|
+
OAuth2ClientService
|
|
254
|
+
}
|
|
255
|
+
|
package/src/RedisClientStore.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TraceUtils } from '@themost/common';
|
|
2
2
|
import RedisStore from 'rate-limit-redis';
|
|
3
|
-
import {
|
|
3
|
+
import { Redis } from 'ioredis';
|
|
4
4
|
import '@themost/promise-sequence';
|
|
5
5
|
|
|
6
6
|
let superLoadIncrementScript;
|
|
@@ -46,16 +46,15 @@ class RedisClientStore extends RedisStore {
|
|
|
46
46
|
*/
|
|
47
47
|
sendCommand: function () {
|
|
48
48
|
const args = Array.from(arguments);
|
|
49
|
+
const [command] = args.splice(0, 1);
|
|
49
50
|
const self = this;
|
|
50
|
-
if (
|
|
51
|
+
if (command === 'SCRIPT') {
|
|
51
52
|
const connectOptions = service.getApplication().getConfiguration().getSourceAt('settings/redis/options') || {
|
|
52
53
|
host: '127.0.0.1',
|
|
53
54
|
port: 6379
|
|
54
55
|
};
|
|
55
|
-
const client =
|
|
56
|
-
return client.
|
|
57
|
-
return client.sendCommand(args);
|
|
58
|
-
}).catch((error) => {
|
|
56
|
+
const client = new Redis(connectOptions);
|
|
57
|
+
return client.call(command, args).catch((error) => {
|
|
59
58
|
if (error instanceof TypeError && error.message === 'Invalid argument type') {
|
|
60
59
|
TraceUtils.warn('RedisClientStore: Invalid argument type: ' + JSON.stringify(args));
|
|
61
60
|
}
|
|
@@ -73,45 +72,30 @@ class RedisClientStore extends RedisStore {
|
|
|
73
72
|
host: '127.0.0.1',
|
|
74
73
|
port: 6379
|
|
75
74
|
};
|
|
76
|
-
self.client =
|
|
77
|
-
// handle socket close error
|
|
78
|
-
self.client.on('error', (err) => {
|
|
79
|
-
TraceUtils.error('An error occurred while using redis client as speed limit service client store.');
|
|
80
|
-
TraceUtils.error(err);
|
|
81
|
-
// handle socket close error
|
|
82
|
-
if (err.message === 'Socket closed unexpectedly') {
|
|
83
|
-
TraceUtils.info('Socket closed unexpectedly. Disconnecting...');
|
|
84
|
-
// delete increment script sha
|
|
85
|
-
self.incrementScriptSha = null;
|
|
86
|
-
// quit client
|
|
87
|
-
self.client.disconnect();
|
|
88
|
-
}
|
|
89
|
-
});
|
|
75
|
+
self.client = new Redis(connectOptions);
|
|
90
76
|
}
|
|
91
77
|
if (self.client.isOpen) {
|
|
92
|
-
return self.client.
|
|
78
|
+
return self.client.call(command, args).catch((error) => {
|
|
93
79
|
if (error instanceof TypeError && error.message === 'Invalid argument type') {
|
|
94
80
|
TraceUtils.warn('RedisClientStore: Invalid argument type: ' + JSON.stringify(args));
|
|
95
81
|
}
|
|
96
82
|
return Promise.reject(error);
|
|
97
83
|
});
|
|
98
84
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
85
|
+
// send load script commands once
|
|
86
|
+
return (() => {
|
|
87
|
+
if (self.incrementScriptSha == null) {
|
|
88
|
+
return this.postInit();
|
|
89
|
+
}
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
})().then(() => {
|
|
92
|
+
// send command
|
|
93
|
+
args[0] = self.incrementScriptSha;
|
|
94
|
+
return self.client.call(command, args).catch((error) => {
|
|
95
|
+
if (error instanceof TypeError && error.message === 'Invalid argument type') {
|
|
96
|
+
TraceUtils.warn('RedisClientStore: Invalid argument type: ' + JSON.stringify(args));
|
|
104
97
|
}
|
|
105
|
-
return Promise.
|
|
106
|
-
})().then(() => {
|
|
107
|
-
// send command
|
|
108
|
-
args[1] = self.incrementScriptSha;
|
|
109
|
-
return self.client.sendCommand(args).catch((error) => {
|
|
110
|
-
if (error instanceof TypeError && error.message === 'Invalid argument type') {
|
|
111
|
-
TraceUtils.warn('RedisClientStore: Invalid argument type: ' + JSON.stringify(args));
|
|
112
|
-
}
|
|
113
|
-
return Promise.reject(error);
|
|
114
|
-
});
|
|
98
|
+
return Promise.reject(error);
|
|
115
99
|
});
|
|
116
100
|
});
|
|
117
101
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ApplicationService } from '@themost/common';
|
|
2
|
+
import { Request } from 'express';
|
|
3
|
+
|
|
4
|
+
export declare class RemoteAddressValidator extends ApplicationService {
|
|
5
|
+
|
|
6
|
+
constructor(app: ApplicationService);
|
|
7
|
+
validateRemoteAddress(request: Request): Promise<boolean>;
|
|
8
|
+
getRemoteAddress(request: Request): string;
|
|
9
|
+
|
|
10
|
+
}
|