soajs.controller 4.3.17 → 4.3.18
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/ARCHITECTURE.md +1 -0
- package/docs/configuration-custom-registry.md +206 -6
- package/docs/middleware/mt.md +18 -0
- package/docs/multi-tenant-security.md +1 -0
- package/docs/tenant-access-resolver.md +81 -0
- package/mw/mt/tenantAccess.js +173 -0
- package/mw/mt/urac.js +61 -12
- package/package.json +1 -1
- package/test/data/provision/customRegistry/urac.js +22 -0
- package/test/data/provision/hosts/departments.js +12 -0
- package/test/data/provision/marketplace/departments.js +38 -0
- package/test/data/provision/oauth/token/department_member_token.js +72 -0
- package/test/data/provision/oauth/token/department_outsider_token.js +72 -0
- package/test/data/provision/tenants/dbtn.js +6 -0
- package/test/integration/UC5-tenant-access/index.js +153 -0
- package/test/integration/index.js +4 -0
- package/test/unit/index.js +1 -0
- package/test/unit/mw/mt/tenantAccess.js +338 -0
- package/test/unit/mw/mt/urac.js +229 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
let service = {
|
|
4
|
+
_id: "5da078c92357684b57effcf0",
|
|
5
|
+
"type": "service",
|
|
6
|
+
name: "departments",
|
|
7
|
+
configuration: {
|
|
8
|
+
group: "SOAJS test",
|
|
9
|
+
port: 4013,
|
|
10
|
+
requestTimeout: 30,
|
|
11
|
+
requestTimeoutRenewal: 5
|
|
12
|
+
},
|
|
13
|
+
versions: [{
|
|
14
|
+
"version": "1",
|
|
15
|
+
maintenance: {
|
|
16
|
+
"port": {
|
|
17
|
+
"type": "maintenance"
|
|
18
|
+
},
|
|
19
|
+
"readiness": "/heartbeat"
|
|
20
|
+
},
|
|
21
|
+
oauth: true,
|
|
22
|
+
extKeyRequired: true,
|
|
23
|
+
urac: false,
|
|
24
|
+
urac_Profile: false,
|
|
25
|
+
urac_ACL: false,
|
|
26
|
+
provision_ACL: false,
|
|
27
|
+
apis: [
|
|
28
|
+
{
|
|
29
|
+
l: "Tenant access resolver",
|
|
30
|
+
v: "/tenant/access",
|
|
31
|
+
m: "post",
|
|
32
|
+
group: "Integration test"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
module.exports = service;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
let token = {
|
|
4
|
+
_id: "5cdc190fd52c82e0ddb1dcd6",
|
|
5
|
+
type: "accessToken",
|
|
6
|
+
token: "d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d901",
|
|
7
|
+
clientId: "5c0e74ba9acc3c5a84a51260",
|
|
8
|
+
user: {
|
|
9
|
+
_id: "5c8d0c505653de3985aa1001",
|
|
10
|
+
locked: true,
|
|
11
|
+
username: "dept_member",
|
|
12
|
+
firstName: "owner3'sèį",
|
|
13
|
+
lastName: "owner",
|
|
14
|
+
email: "me@localhost.com",
|
|
15
|
+
"ts": new Date().getTime(),
|
|
16
|
+
status: "active",
|
|
17
|
+
profile: {},
|
|
18
|
+
groups: [
|
|
19
|
+
"owner"
|
|
20
|
+
],
|
|
21
|
+
config: {
|
|
22
|
+
packages: {},
|
|
23
|
+
keys: {},
|
|
24
|
+
allowedTenants: [
|
|
25
|
+
{
|
|
26
|
+
tenant: {
|
|
27
|
+
id: "THYME_tID",
|
|
28
|
+
code: "THYME_CODE",
|
|
29
|
+
pin: {
|
|
30
|
+
code: "5678",
|
|
31
|
+
allowed: true
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
groups: [
|
|
35
|
+
"waiter"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
tenant: {
|
|
40
|
+
id: "ELVIRA_tID",
|
|
41
|
+
code: "ELVIRA_CODE"
|
|
42
|
+
},
|
|
43
|
+
groups: [
|
|
44
|
+
"manager"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
tenant: {
|
|
50
|
+
id: "5c0e74ba9acc3c5a84a51260",
|
|
51
|
+
code: "HOME",
|
|
52
|
+
pin: {
|
|
53
|
+
code: "1235",
|
|
54
|
+
allowed: true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
lastLogin: new Date().getTime(),
|
|
58
|
+
groupsConfig: {
|
|
59
|
+
allowedPackages: {
|
|
60
|
+
DSBRD: [
|
|
61
|
+
"DSBRD_OWNER"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
allowedEnvironments: {}
|
|
65
|
+
},
|
|
66
|
+
loginMode: "urac",
|
|
67
|
+
id: "5c8d0c505653de3985aa1001"
|
|
68
|
+
},
|
|
69
|
+
env: "dev",
|
|
70
|
+
expires: new Date((new Date().getFullYear()) + 2, 0, 1)
|
|
71
|
+
};
|
|
72
|
+
module.exports = token;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
let token = {
|
|
4
|
+
_id: "5cdc190fd52c82e0ddb1dcd7",
|
|
5
|
+
type: "accessToken",
|
|
6
|
+
token: "d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d902",
|
|
7
|
+
clientId: "5c0e74ba9acc3c5a84a51260",
|
|
8
|
+
user: {
|
|
9
|
+
_id: "5c8d0c505653de3985aa1002",
|
|
10
|
+
locked: true,
|
|
11
|
+
username: "dept_outsider",
|
|
12
|
+
firstName: "owner3'sèį",
|
|
13
|
+
lastName: "owner",
|
|
14
|
+
email: "me@localhost.com",
|
|
15
|
+
"ts": new Date().getTime(),
|
|
16
|
+
status: "active",
|
|
17
|
+
profile: {},
|
|
18
|
+
groups: [
|
|
19
|
+
"owner"
|
|
20
|
+
],
|
|
21
|
+
config: {
|
|
22
|
+
packages: {},
|
|
23
|
+
keys: {},
|
|
24
|
+
allowedTenants: [
|
|
25
|
+
{
|
|
26
|
+
tenant: {
|
|
27
|
+
id: "THYME_tID",
|
|
28
|
+
code: "THYME_CODE",
|
|
29
|
+
pin: {
|
|
30
|
+
code: "5678",
|
|
31
|
+
allowed: true
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
groups: [
|
|
35
|
+
"waiter"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
tenant: {
|
|
40
|
+
id: "ELVIRA_tID",
|
|
41
|
+
code: "ELVIRA_CODE"
|
|
42
|
+
},
|
|
43
|
+
groups: [
|
|
44
|
+
"manager"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
tenant: {
|
|
50
|
+
id: "5c0e74ba9acc3c5a84a51260",
|
|
51
|
+
code: "HOME",
|
|
52
|
+
pin: {
|
|
53
|
+
code: "1235",
|
|
54
|
+
allowed: true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
lastLogin: new Date().getTime(),
|
|
58
|
+
groupsConfig: {
|
|
59
|
+
allowedPackages: {
|
|
60
|
+
DSBRD: [
|
|
61
|
+
"DSBRD_OWNER"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
allowedEnvironments: {}
|
|
65
|
+
},
|
|
66
|
+
loginMode: "urac",
|
|
67
|
+
id: "5c8d0c505653de3985aa1002"
|
|
68
|
+
},
|
|
69
|
+
env: "dev",
|
|
70
|
+
expires: new Date((new Date().getFullYear()) + 2, 0, 1)
|
|
71
|
+
};
|
|
72
|
+
module.exports = token;
|
|
@@ -5,6 +5,12 @@ let tenant = {
|
|
|
5
5
|
"code": "DBTN",
|
|
6
6
|
"locked": true,
|
|
7
7
|
"name": "Console Tenant",
|
|
8
|
+
"profile": {
|
|
9
|
+
"access": {
|
|
10
|
+
"resolver": "department",
|
|
11
|
+
"subject": "dept_1"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
8
14
|
"description": "This is the tenant that holds the access rights and configuration for the console users with DSBRD_GUEST as Guest default package",
|
|
9
15
|
"oauth": {
|
|
10
16
|
"secret": "this is a secret",
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const express = require('express');
|
|
5
|
+
const helper = require("../../helper.js");
|
|
6
|
+
const requester = require('../requester');
|
|
7
|
+
let Controller = helper.requireModule('./server/controller');
|
|
8
|
+
let localConfig = helper.requireModule('./config.js');
|
|
9
|
+
|
|
10
|
+
let mock = require('../UC2-http-methods/service-mock/index.js');
|
|
11
|
+
|
|
12
|
+
//NOTE: the users of these tokens live in tenant HOME, the key belongs to tenant DBTN which names
|
|
13
|
+
// the department resolver in its profile
|
|
14
|
+
const memberToken = "d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d901";
|
|
15
|
+
const outsiderToken = "d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d902";
|
|
16
|
+
const ownerToken = "cfb209a91b23896820f510aadbf1f4284b512123";
|
|
17
|
+
|
|
18
|
+
function startResolver(calls, callback) {
|
|
19
|
+
const sApp = express();
|
|
20
|
+
const mApp = express();
|
|
21
|
+
sApp.use(express.json());
|
|
22
|
+
sApp.post('/tenant/access', (req, res) => {
|
|
23
|
+
calls.push({ "body": req.body, "injectObj": JSON.parse(req.headers.soajsinjectobj) });
|
|
24
|
+
if (req.body.user.username === "dept_member" && req.body.subject === "dept_1") {
|
|
25
|
+
return res.json({
|
|
26
|
+
"result": true,
|
|
27
|
+
"data": {
|
|
28
|
+
"access": true,
|
|
29
|
+
"groups": ["member"],
|
|
30
|
+
"groupsConfig": { "allowedPackages": { "DSBRD": ["DSBRD_OWNER"] } }
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return res.json({ "result": true, "data": { "access": false } });
|
|
35
|
+
});
|
|
36
|
+
mApp.get('/heartbeat', (req, res) => {
|
|
37
|
+
res.json({ "result": true, "ts": Date.now(), "service": { "service": "departments", "type": "rest", "route": "/heartbeat" } });
|
|
38
|
+
});
|
|
39
|
+
let sAppServer = sApp.listen(4013, () => {
|
|
40
|
+
let mAppServer = mApp.listen(5014, () => {
|
|
41
|
+
return callback({ "sAppServer": sAppServer, "mAppServer": mAppServer, "name": "departments" });
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe("Integration for Usecase 5 - tenant access resolver", function () {
|
|
47
|
+
let extKey = "3d90163cf9d6b3076ad26aa5ed58556348069258e5c6c941ee0f18448b570ad1c5c790e2d2a1989680c55f4904e2005ff5f8e71606e4aa641e67882f4210ebbc5460ff305dcb36e6ec2a2299cf0448ef60b9e38f41950ec251c1cf41f05f3ce9";
|
|
48
|
+
|
|
49
|
+
let c = new Controller({
|
|
50
|
+
"serviceName": localConfig.serviceName,
|
|
51
|
+
"serviceVersion": localConfig.serviceVersion,
|
|
52
|
+
"serviceGroup": localConfig.serviceGroup,
|
|
53
|
+
"servicePort": localConfig.servicePort,
|
|
54
|
+
"maintenance": localConfig.maintenance
|
|
55
|
+
});
|
|
56
|
+
let registry = null;
|
|
57
|
+
let log = null;
|
|
58
|
+
let service = null;
|
|
59
|
+
let server = null;
|
|
60
|
+
let serverMaintenance = null;
|
|
61
|
+
let httpmethods = null;
|
|
62
|
+
let resolver = null;
|
|
63
|
+
let calls = [];
|
|
64
|
+
|
|
65
|
+
function call(token, cb) {
|
|
66
|
+
let options = {
|
|
67
|
+
uri: 'http://127.0.0.1:' + localConfig.servicePort + '/httpmethods/myroute',
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
key: extKey
|
|
71
|
+
},
|
|
72
|
+
"qs": {
|
|
73
|
+
access_token: token
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
requester('get', options, cb);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
before((done) => {
|
|
80
|
+
startResolver(calls, (servers) => {
|
|
81
|
+
resolver = servers;
|
|
82
|
+
mock.startServer(null, function (servers) {
|
|
83
|
+
httpmethods = servers;
|
|
84
|
+
});
|
|
85
|
+
c.init((_registry, _log, _service, _server, _serverMaintenance) => {
|
|
86
|
+
registry = _registry;
|
|
87
|
+
log = _log;
|
|
88
|
+
service = _service;
|
|
89
|
+
server = _server;
|
|
90
|
+
serverMaintenance = _serverMaintenance;
|
|
91
|
+
c.start(registry, log, service, server, serverMaintenance, () => {
|
|
92
|
+
setTimeout(function () {
|
|
93
|
+
done();
|
|
94
|
+
}, 5000);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
beforeEach(() => {
|
|
100
|
+
calls.length = 0;
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("department member switching to the tenant gets the resolver ACL", function (done) {
|
|
104
|
+
call(memberToken, (error, body) => {
|
|
105
|
+
assert.ifError(error);
|
|
106
|
+
assert.ok(body);
|
|
107
|
+
assert.strictEqual(body.result, true, JSON.stringify(body.errors));
|
|
108
|
+
assert.deepStrictEqual(body.data.method, 'GET');
|
|
109
|
+
assert.strictEqual(calls.length, 1);
|
|
110
|
+
assert.deepStrictEqual(calls[0].body, {
|
|
111
|
+
"user": {
|
|
112
|
+
"id": "5c8d0c505653de3985aa1001",
|
|
113
|
+
"username": "dept_member",
|
|
114
|
+
"tenant": { "id": "5c0e74ba9acc3c5a84a51260", "code": "HOME" }
|
|
115
|
+
},
|
|
116
|
+
"tenant": { "id": "5c0e74ba9acc3c5a84a51259", "code": "DBTN" },
|
|
117
|
+
"subject": "dept_1"
|
|
118
|
+
});
|
|
119
|
+
assert.strictEqual(calls[0].injectObj.tenant.id, "5c0e74ba9acc3c5a84a51259");
|
|
120
|
+
assert.strictEqual(calls[0].injectObj.application.product, "DSBRD");
|
|
121
|
+
done();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("user outside the department is refused after the urac fallback", function (done) {
|
|
126
|
+
call(outsiderToken, (error, body) => {
|
|
127
|
+
assert.ok(body);
|
|
128
|
+
assert.strictEqual(body.result, false);
|
|
129
|
+
assert.deepStrictEqual(body.errors.codes, [146]);
|
|
130
|
+
assert.strictEqual(calls.length, 1);
|
|
131
|
+
done();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("user of the tenant itself does not call the resolver", function (done) {
|
|
136
|
+
call(ownerToken, (error, body) => {
|
|
137
|
+
assert.ifError(error);
|
|
138
|
+
assert.ok(body);
|
|
139
|
+
assert.strictEqual(body.result, true, JSON.stringify(body.errors));
|
|
140
|
+
assert.strictEqual(calls.length, 0);
|
|
141
|
+
done();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
after((done) => {
|
|
146
|
+
mock.killServer(httpmethods);
|
|
147
|
+
resolver.sAppServer.close();
|
|
148
|
+
resolver.mAppServer.close();
|
|
149
|
+
c.stop(registry, log, service, server, serverMaintenance, () => {
|
|
150
|
+
done();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|