soajs.controller 4.3.23 → 4.3.25
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/docs/mcp.md +2 -2
- package/mw/mt/utils.js +87 -2
- package/mw/soajsRoutes/lib/acl.js +8 -3
- package/mw/soajsRoutes/mcp/tools.js +4 -5
- package/package.json +2 -2
- package/test/unit/mw/mt/utils.js +121 -2
- package/test/unit/mw/soajsRoutes/mcp.js +27 -5
package/docs/mcp.md
CHANGED
|
@@ -36,8 +36,8 @@ after 30 seconds.
|
|
|
36
36
|
|
|
37
37
|
The ACL the gateway computes for `/soajs/acl`: the user's ACL and packages, else the tenant
|
|
38
38
|
application's, else the package's. For each service, the latest allowed version; a restricted
|
|
39
|
-
service shows only the APIs its ACL lists, per method
|
|
40
|
-
apps, give the agent its own application, key and package in the tenant.
|
|
39
|
+
service shows only the APIs its ACL lists, per method, and none when it lists none. To give agents
|
|
40
|
+
a different list from your apps, give the agent its own application, key and package in the tenant.
|
|
41
41
|
|
|
42
42
|
A tool call is checked again by the gateway like any API call, so a tool shown by mistake is still
|
|
43
43
|
refused.
|
package/mw/mt/utils.js
CHANGED
|
@@ -15,7 +15,7 @@ const coreLibs = require("soajs.core.libs");
|
|
|
15
15
|
|
|
16
16
|
const async = require("async");
|
|
17
17
|
const Netmask = require('netmask').Netmask;
|
|
18
|
-
const
|
|
18
|
+
const UAParser = require('ua-parser-js');
|
|
19
19
|
const merge = require('merge');
|
|
20
20
|
|
|
21
21
|
const UracDriver = require("./urac.js");
|
|
@@ -49,6 +49,91 @@ function getCachedNetmask(addr) {
|
|
|
49
49
|
return netmaskCache.get(addr);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// Device rules were written against the useragent package names; map ua-parser-js names back to them
|
|
53
|
+
const UA_MAX_LENGTH = 512;
|
|
54
|
+
const UA_OS_FAMILIES = {"Mac OS": "Mac OS X", "Chromium OS": "Chrome OS"};
|
|
55
|
+
const UA_ANDROID_FAMILIES = {"Firefox": "Firefox Mobile", "Opera": "Opera Mobile", "Chrome WebView": "Chrome Mobile WebView"};
|
|
56
|
+
const UA_IOS_FAMILIES = {"Chrome": "Chrome Mobile iOS", "Firefox": "Firefox iOS", "WebKit": "Mobile Safari UI/WKWebView"};
|
|
57
|
+
const UA_FAMILIES = {"Yandex": "Yandex Browser"};
|
|
58
|
+
|
|
59
|
+
// Own keys only: the family comes from the caller and must not resolve to Object.prototype members
|
|
60
|
+
function mapName(map, name) {
|
|
61
|
+
return Object.prototype.hasOwnProperty.call(map, name) ? map[name] : name;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function splitVersion(version) {
|
|
65
|
+
let parts = (version || "").split(".");
|
|
66
|
+
return {
|
|
67
|
+
"major": parts[0] || "0",
|
|
68
|
+
"minor": parts[1] || "0",
|
|
69
|
+
"patch": parts[2] || "0"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Parses a User-Agent into {family, major, minor, patch, os: {family, major, minor, patch}}
|
|
75
|
+
*
|
|
76
|
+
* @param {String} ua
|
|
77
|
+
* @returns {Object}
|
|
78
|
+
*/
|
|
79
|
+
function parseUserAgent(ua) {
|
|
80
|
+
ua = String(ua).substring(0, UA_MAX_LENGTH);
|
|
81
|
+
let result = new UAParser(ua).getResult();
|
|
82
|
+
let family = result.browser.name;
|
|
83
|
+
let version = result.browser.version;
|
|
84
|
+
let osFamily = result.os.name;
|
|
85
|
+
let osVersion = result.os.version;
|
|
86
|
+
let match;
|
|
87
|
+
|
|
88
|
+
if (!family) {
|
|
89
|
+
// ua-parser-js guesses iOS from Darwin/CFNetwork without a version
|
|
90
|
+
if (osFamily === "iOS" && !osVersion) {
|
|
91
|
+
osFamily = null;
|
|
92
|
+
}
|
|
93
|
+
// non browser clients: curl/8.4.0, MyApp/142 CFNetwork/...
|
|
94
|
+
match = /^Mozilla\//.test(ua) ? null : /^([^\/\s]+)\/([\d.]+)/.exec(ua);
|
|
95
|
+
family = match ? match[1] : "Other";
|
|
96
|
+
version = match ? match[2] : null;
|
|
97
|
+
}
|
|
98
|
+
if (family === "Edge") {
|
|
99
|
+
if (/ Edg(A)?\//.test(ua)) {
|
|
100
|
+
match = /Chrome\/([\d.]+)/.exec(ua);
|
|
101
|
+
family = "Chrome";
|
|
102
|
+
version = match ? match[1] : null;
|
|
103
|
+
} else if (/ EdgiOS\//.test(ua)) {
|
|
104
|
+
match = /Version\/([\d.]+)/.exec(ua);
|
|
105
|
+
family = "Mobile Safari";
|
|
106
|
+
version = match ? match[1] : null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (osFamily === "Android") {
|
|
110
|
+
// useragent reported every Android version as 0.0.0, keep that so os version rules do not change
|
|
111
|
+
osVersion = null;
|
|
112
|
+
if (family === "Chrome" && / Mobile /.test(ua)) {
|
|
113
|
+
family = "Chrome Mobile";
|
|
114
|
+
} else {
|
|
115
|
+
family = mapName(UA_ANDROID_FAMILIES, family);
|
|
116
|
+
}
|
|
117
|
+
} else if (osFamily === "iOS") {
|
|
118
|
+
if (family === "WebKit") {
|
|
119
|
+
version = osVersion;
|
|
120
|
+
}
|
|
121
|
+
family = mapName(UA_IOS_FAMILIES, family);
|
|
122
|
+
}
|
|
123
|
+
family = mapName(UA_FAMILIES, family);
|
|
124
|
+
|
|
125
|
+
let uaObj = splitVersion(version);
|
|
126
|
+
uaObj.family = String(family);
|
|
127
|
+
if (osFamily === "Windows") {
|
|
128
|
+
// Windows versions are names: 10, 8.1, XP, Vista
|
|
129
|
+
uaObj.os = {"family": osFamily, "major": osVersion || "0", "minor": "0", "patch": "0"};
|
|
130
|
+
} else {
|
|
131
|
+
uaObj.os = splitVersion(osVersion);
|
|
132
|
+
uaObj.os.family = osFamily ? String(mapName(UA_OS_FAMILIES, osFamily)) : "Other";
|
|
133
|
+
}
|
|
134
|
+
return uaObj;
|
|
135
|
+
}
|
|
136
|
+
|
|
52
137
|
let sensitiveEnvCodes = ["dashboard"];
|
|
53
138
|
if (process.env.SOAJS_SENSITIVE_ENVS) {
|
|
54
139
|
let temp_sensitiveEnvCodes = null;
|
|
@@ -381,7 +466,7 @@ let utils = {
|
|
|
381
466
|
};
|
|
382
467
|
|
|
383
468
|
let checkAccess = (deviceAccessArr, ua) => {
|
|
384
|
-
let uaObj =
|
|
469
|
+
let uaObj = parseUserAgent(ua);
|
|
385
470
|
//if (uaObj && uaObj.family && uaObj.os && uaObj.os.family) {
|
|
386
471
|
if (uaObj && uaObj.family) {
|
|
387
472
|
return (deviceAccessArr.some(function (da) {
|
|
@@ -16,10 +16,12 @@ const coreLibs = require("soajs.core.libs");
|
|
|
16
16
|
*
|
|
17
17
|
* finalACL is, per service, the latest allowed version and, for a restricted service, the allowed
|
|
18
18
|
* apis per method: {"urac": {"version": "3", "get": ["/user"]}}. A service that is not restricted
|
|
19
|
-
* has only its version: all its apis are allowed.
|
|
19
|
+
* has only its version: all its apis are allowed. A restricted service that lists no apis also has
|
|
20
|
+
* only its version, so restricted says, per service, whether its latest allowed version is
|
|
21
|
+
* restricted.
|
|
20
22
|
*
|
|
21
23
|
* @param req
|
|
22
|
-
* @returns {{acl: object|null, finalACL: object|null, packages: Array|null}}
|
|
24
|
+
* @returns {{acl: object|null, finalACL: object|null, restricted: object, packages: Array|null}}
|
|
23
25
|
*/
|
|
24
26
|
function computeACL(req) {
|
|
25
27
|
let ACL = null;
|
|
@@ -42,6 +44,7 @@ function computeACL(req) {
|
|
|
42
44
|
ACL = coreLibs.utils.cloneObj(req.soajs.controller.serviceParams.packObj.acl);
|
|
43
45
|
}
|
|
44
46
|
let finalACL = null;
|
|
47
|
+
let restricted = {};
|
|
45
48
|
if (ACL) {
|
|
46
49
|
finalACL = {};
|
|
47
50
|
for (let s in ACL) {
|
|
@@ -58,7 +61,8 @@ function computeACL(req) {
|
|
|
58
61
|
finalACL[s] = {
|
|
59
62
|
"version": v
|
|
60
63
|
};
|
|
61
|
-
|
|
64
|
+
restricted[s] = !!(sv.apisPermission && sv.apisPermission === "restricted");
|
|
65
|
+
if (restricted[s]) {
|
|
62
66
|
for (let m in sv) {
|
|
63
67
|
if (sv.hasOwnProperty(m)) {
|
|
64
68
|
if (m !== "access" && m !== "apisPermission") {
|
|
@@ -91,6 +95,7 @@ function computeACL(req) {
|
|
|
91
95
|
return {
|
|
92
96
|
"acl": ACL,
|
|
93
97
|
"finalACL": finalACL,
|
|
98
|
+
"restricted": restricted,
|
|
94
99
|
"packages": ALLOWED_PACKAGES
|
|
95
100
|
};
|
|
96
101
|
}
|
|
@@ -224,11 +224,10 @@ function toolName(serviceName, tool, taken) {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
/**
|
|
227
|
-
* Whether the caller's ACL allows the api: a restricted service
|
|
227
|
+
* Whether the caller's ACL allows the api: a restricted service allows only the apis it lists per
|
|
228
|
+
* method, none when it lists none.
|
|
228
229
|
*/
|
|
229
|
-
function allowed(serviceACL, tool) {
|
|
230
|
-
let methods = ["get", "post", "put", "delete", "del"];
|
|
231
|
-
let restricted = methods.some((m) => Array.isArray(serviceACL[m]));
|
|
230
|
+
function allowed(serviceACL, tool, restricted) {
|
|
232
231
|
if (!restricted) {
|
|
233
232
|
return true;
|
|
234
233
|
}
|
|
@@ -253,7 +252,7 @@ function listTools(req, configuration, config) {
|
|
|
253
252
|
let taken = {};
|
|
254
253
|
services.forEach((serviceName, i) => {
|
|
255
254
|
lists[i].forEach((tool) => {
|
|
256
|
-
if (tools.length >= config.maxTools || !allowed(finalACL[serviceName], tool)) {
|
|
255
|
+
if (tools.length >= config.maxTools || !allowed(finalACL[serviceName], tool, computed.restricted[serviceName])) {
|
|
257
256
|
return;
|
|
258
257
|
}
|
|
259
258
|
let name = toolName(serviceName, tool, taken);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "soajs.controller",
|
|
3
3
|
"description": "soajs multi tenant API gateway",
|
|
4
|
-
"version": "4.3.
|
|
4
|
+
"version": "4.3.25",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "soajs team",
|
|
7
7
|
"email": "team@soajs.org"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"soajs.core.libs": "1.2.3",
|
|
33
33
|
"soajs.core.modules": "5.2.22",
|
|
34
34
|
"soajs.urac.driver": "3.2.20",
|
|
35
|
-
"
|
|
35
|
+
"ua-parser-js": "1.0.41"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@babel/core": "7.29.7",
|
package/test/unit/mw/mt/utils.js
CHANGED
|
@@ -309,8 +309,127 @@ describe("Unit test for: mw - mt utils", () => {
|
|
|
309
309
|
done();
|
|
310
310
|
});
|
|
311
311
|
});
|
|
312
|
-
|
|
313
|
-
|
|
312
|
+
|
|
313
|
+
// [name, User-Agent, [family, major, minor, patch], [os family, major, minor, patch]] as useragent 2.3.0 parsed them
|
|
314
|
+
let userAgents = [
|
|
315
|
+
["chrome-win", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.130 Safari/537.36", ["Chrome", "120", "0", "6099"], ["Windows", "10", "0", "0"]],
|
|
316
|
+
["chrome-mac", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.129 Safari/537.36", ["Chrome", "120", "0", "6099"], ["Mac OS X", "10", "15", "7"]],
|
|
317
|
+
["chrome-mac-old", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", ["Chrome", "58", "0", "3029"], ["Mac OS X", "10", "12", "4"]],
|
|
318
|
+
["chrome-linux", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", ["Chrome", "120", "0", "0"], ["Linux", "0", "0", "0"]],
|
|
319
|
+
["chrome-cros", "Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", ["Chrome", "120", "0", "0"], ["Chrome OS", "14541", "0", "0"]],
|
|
320
|
+
["safari-mac", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15", ["Safari", "17", "2", "0"], ["Mac OS X", "10", "15", "7"]],
|
|
321
|
+
["firefox-win", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0", ["Firefox", "121", "0", "0"], ["Windows", "10", "0", "0"]],
|
|
322
|
+
["firefox-mac", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0", ["Firefox", "121", "0", "0"], ["Mac OS X", "10", "15", "0"]],
|
|
323
|
+
["firefox-linux", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0", ["Firefox", "121", "0", "0"], ["Ubuntu", "0", "0", "0"]],
|
|
324
|
+
["edge-win", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.2210.91", ["Chrome", "120", "0", "0"], ["Windows", "10", "0", "0"]],
|
|
325
|
+
["edge-mac", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.2210.91", ["Chrome", "120", "0", "0"], ["Mac OS X", "10", "15", "7"]],
|
|
326
|
+
["edge-legacy", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19582", ["Edge", "18", "19582", "0"], ["Windows", "10", "0", "0"]],
|
|
327
|
+
["ie11", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", ["IE", "11", "0", "0"], ["Windows", "10", "0", "0"]],
|
|
328
|
+
["opera", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 OPR/106.0.0.0", ["Opera", "106", "0", "0"], ["Windows", "10", "0", "0"]],
|
|
329
|
+
["ios-safari", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1", ["Mobile Safari", "17", "2", "0"], ["iOS", "17", "2", "1"]],
|
|
330
|
+
["ipad-safari", "Mozilla/5.0 (iPad; CPU OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1", ["Mobile Safari", "16", "6", "0"], ["iOS", "16", "6", "0"]],
|
|
331
|
+
["ios-chrome", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/120.0.6099.119 Mobile/15E148 Safari/604.1", ["Chrome Mobile iOS", "120", "0", "6099"], ["iOS", "17", "2", "0"]],
|
|
332
|
+
["ios-firefox", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/121.0 Mobile/15E148 Safari/605.1.15", ["Firefox iOS", "121", "0", "0"], ["iOS", "17", "2", "0"]],
|
|
333
|
+
["ios-webview", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", ["Mobile Safari UI/WKWebView", "17", "2", "0"], ["iOS", "17", "2", "0"]],
|
|
334
|
+
["edge-ios", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 EdgiOS/120.2210.79 Mobile/15E148 Safari/605.1.15", ["Mobile Safari", "17", "0", "0"], ["iOS", "17", "2", "0"]],
|
|
335
|
+
["android-chrome", "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36", ["Chrome Mobile", "120", "0", "6099"], ["Android", "0", "0", "0"]],
|
|
336
|
+
["android-chrome-tablet", "Mozilla/5.0 (Linux; Android 13; SM-X700) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", ["Chrome", "120", "0", "0"], ["Android", "0", "0", "0"]],
|
|
337
|
+
["android-webview", "Mozilla/5.0 (Linux; Android 13; Pixel 7 Build/TQ3A.230805.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36", ["Chrome Mobile WebView", "116", "0", "0"], ["Android", "0", "0", "0"]],
|
|
338
|
+
["edge-android", "Mozilla/5.0 (Linux; Android 10; HD1913) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36 EdgA/120.0.2210.84", ["Chrome Mobile", "120", "0", "6099"], ["Android", "0", "0", "0"]],
|
|
339
|
+
["samsung", "Mozilla/5.0 (Linux; Android 13; SAMSUNG SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/23.0 Chrome/115.0.0.0 Mobile Safari/537.36", ["Samsung Internet", "23", "0", "0"], ["Android", "0", "0", "0"]],
|
|
340
|
+
["android-firefox", "Mozilla/5.0 (Android 13; Mobile; rv:121.0) Gecko/121.0 Firefox/121.0", ["Firefox Mobile", "121", "0", "0"], ["Android", "0", "0", "0"]],
|
|
341
|
+
["opera-android", "Mozilla/5.0 (Linux; Android 10; VOG-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36 OPR/79.0.4195.76523", ["Opera Mobile", "79", "0", "4195"], ["Android", "0", "0", "0"]],
|
|
342
|
+
["yandex", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 YaBrowser/23.11.0.0 Safari/537.36", ["Yandex Browser", "23", "11", "0"], ["Windows", "10", "0", "0"]],
|
|
343
|
+
["ios-app", "democav/142 CFNetwork/3826.400.120 Darwin/24.3.0", ["democav", "142", "0", "0"], ["Other", "0", "0", "0"]],
|
|
344
|
+
["curl", "curl/8.4.0", ["curl", "8", "4", "0"], ["Other", "0", "0", "0"]]
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
let deviceObj = (ua, device) => {
|
|
348
|
+
return {
|
|
349
|
+
req: {
|
|
350
|
+
getClientUserAgent: function () {
|
|
351
|
+
return ua;
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
keyObj: {
|
|
355
|
+
device: device
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
let exactRule = (b, os) => {
|
|
361
|
+
return {
|
|
362
|
+
"family": b[0], "major": b[1], "minor": b[2], "patch": b[3],
|
|
363
|
+
"os": {"family": os[0], "major": os[1], "minor": os[2], "patch": os[3]}
|
|
364
|
+
};
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
userAgents.forEach((row) => {
|
|
368
|
+
let name = row[0], ua = row[1], b = row[2], os = row[3];
|
|
369
|
+
|
|
370
|
+
it("test securityDeviceCheck - " + name + " allowed by exact rule", function (done) {
|
|
371
|
+
utils.securityDeviceCheck(deviceObj(ua, {"allow": [exactRule(b, os)]}), function (error, obj) {
|
|
372
|
+
assert.ifError(error);
|
|
373
|
+
assert.strictEqual(obj.device, ua);
|
|
374
|
+
done();
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("test securityDeviceCheck - " + name + " denied by exact rule", function (done) {
|
|
379
|
+
utils.securityDeviceCheck(deviceObj(ua, {"deny": [exactRule(b, os)]}), function (error) {
|
|
380
|
+
assert.strictEqual(error, 156);
|
|
381
|
+
done();
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it("test securityDeviceCheck - " + name + " not allowed by other family, os or version", function (done) {
|
|
386
|
+
let otherOs = exactRule(b, os);
|
|
387
|
+
otherOs.os.family = "NoSuchOS";
|
|
388
|
+
let otherVersion = exactRule(b, os);
|
|
389
|
+
otherVersion.major = {"min": b[1] + "1"};
|
|
390
|
+
let rules = {"allow": [{"family": "NoSuchBrowser"}, otherOs, otherVersion]};
|
|
391
|
+
utils.securityDeviceCheck(deviceObj(ua, rules), function (error) {
|
|
392
|
+
assert.strictEqual(error, 156);
|
|
393
|
+
done();
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
["constructor/1", "toString/2", "__proto__/1", "hasOwnProperty/1 (Linux; Android 10)"].forEach((ua) => {
|
|
399
|
+
it("test securityDeviceCheck - " + ua + " is not allowed as chrome", function (done) {
|
|
400
|
+
utils.securityDeviceCheck(deviceObj(ua, {"allow": [{"family": "chrome"}]}), function (error) {
|
|
401
|
+
assert.strictEqual(error, 156);
|
|
402
|
+
done();
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it("test securityDeviceCheck - " + ua + " is not denied as chrome", function (done) {
|
|
407
|
+
utils.securityDeviceCheck(deviceObj(ua, {"deny": [{"family": "chrome"}]}), function (error, obj) {
|
|
408
|
+
assert.ifError(error);
|
|
409
|
+
assert.strictEqual(obj.device, ua);
|
|
410
|
+
done();
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it("test securityDeviceCheck - empty User-Agent skips device rules", function (done) {
|
|
416
|
+
utils.securityDeviceCheck(deviceObj("", {"allow": [{"family": "chrome"}], "deny": [{"family": "*"}]}), function (error, obj) {
|
|
417
|
+
assert.ifError(error);
|
|
418
|
+
assert.ok(obj);
|
|
419
|
+
done();
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it("test securityDeviceCheck - long padded User-Agent is checked quickly", function (done) {
|
|
424
|
+
let ua = "Mozilla/5.0 (" + "X".repeat(16 * 1024) + ") Gecko/20100101 Firefox/77.0";
|
|
425
|
+
let start = Date.now();
|
|
426
|
+
utils.securityDeviceCheck(deviceObj(ua, {"allow": [{"family": "chrome"}], "deny": [{"family": "IE"}]}), function (error) {
|
|
427
|
+
assert.ok(Date.now() - start < 200);
|
|
428
|
+
assert.strictEqual(error, 156);
|
|
429
|
+
done();
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
314
433
|
it("test securityGeoCheck - fail on deny: Geographic security configuration failed", (done) => {
|
|
315
434
|
let obj = {
|
|
316
435
|
req: {
|
|
@@ -216,14 +216,17 @@ describe("Unit test for: mw - soajsRoutes mcp", () => {
|
|
|
216
216
|
|
|
217
217
|
describe("allowed", () => {
|
|
218
218
|
it("a service that is not restricted allows all its apis", () => {
|
|
219
|
-
assert.ok(tools.allowed({version: "1"}, {m: "delete", v: "/x"}));
|
|
219
|
+
assert.ok(tools.allowed({version: "1"}, {m: "delete", v: "/x"}, false));
|
|
220
220
|
});
|
|
221
221
|
it("a restricted service allows the apis it lists", () => {
|
|
222
222
|
let acl = {version: "1", get: ["/users"], del: ["/user/:id"]};
|
|
223
|
-
assert.ok(tools.allowed(acl, {m: "get", v: "/users"}));
|
|
224
|
-
assert.ok(!tools.allowed(acl, {m: "get", v: "/user/:id"}));
|
|
225
|
-
assert.ok(tools.allowed(acl, {m: "delete", v: "/user/:id"}));
|
|
226
|
-
assert.ok(!tools.allowed(acl, {m: "post", v: "/users"}));
|
|
223
|
+
assert.ok(tools.allowed(acl, {m: "get", v: "/users"}, true));
|
|
224
|
+
assert.ok(!tools.allowed(acl, {m: "get", v: "/user/:id"}, true));
|
|
225
|
+
assert.ok(tools.allowed(acl, {m: "delete", v: "/user/:id"}, true));
|
|
226
|
+
assert.ok(!tools.allowed(acl, {m: "post", v: "/users"}, true));
|
|
227
|
+
});
|
|
228
|
+
it("a restricted service that lists no apis allows none", () => {
|
|
229
|
+
assert.ok(!tools.allowed({version: "1"}, {m: "get", v: "/users"}, true));
|
|
227
230
|
});
|
|
228
231
|
});
|
|
229
232
|
|
|
@@ -342,6 +345,14 @@ describe("Unit test for: mw - soajsRoutes mcp", () => {
|
|
|
342
345
|
}).catch(done);
|
|
343
346
|
});
|
|
344
347
|
|
|
348
|
+
it("listTools: a restricted service that lists no apis has no tools", (done) => {
|
|
349
|
+
let acl = {urac: {"1": {access: true, apisPermission: "restricted", post: {apis: {}}}}};
|
|
350
|
+
tools.listTools(makeReq({services: services(), acl: acl}), configuration, config).then((list) => {
|
|
351
|
+
assert.deepStrictEqual(list.tools, []);
|
|
352
|
+
done();
|
|
353
|
+
}).catch(done);
|
|
354
|
+
});
|
|
355
|
+
|
|
345
356
|
describe("callTool", () => {
|
|
346
357
|
let gateway = null;
|
|
347
358
|
let gatewayPort = null;
|
|
@@ -568,5 +579,16 @@ describe("Unit test for: mw - soajsRoutes mcp", () => {
|
|
|
568
579
|
req = makeReq({acl: {urac: {"1": {access: true, apisPermission: "restricted", get: [{group: "a", apis: {"/x": {}}}, {group: "b", apis: {"/y": {}, "/x": {}}}]}}}});
|
|
569
580
|
assert.deepStrictEqual(aclLib.computeACL(req).finalACL, {"urac": {"version": "1", "get": ["/x", "/y"]}});
|
|
570
581
|
});
|
|
582
|
+
it("restricted follows the latest allowed version", () => {
|
|
583
|
+
let req = makeReq({
|
|
584
|
+
acl: {
|
|
585
|
+
urac: {"1": {access: true, apisPermission: "restricted", get: {apis: {"/x": {}}}}, "2": {access: true}},
|
|
586
|
+
oauth: {"1": {access: true, apisPermission: "restricted", post: {apis: {}}}}
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
let computed = aclLib.computeACL(req);
|
|
590
|
+
assert.deepStrictEqual(computed.finalACL, {"urac": {"version": "2"}, "oauth": {"version": "1"}});
|
|
591
|
+
assert.deepStrictEqual(computed.restricted, {"urac": false, "oauth": true});
|
|
592
|
+
});
|
|
571
593
|
});
|
|
572
594
|
});
|