soajs.controller 4.3.17 → 4.3.19
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/.github/workflows/ci.yml +4 -1
- package/.github/workflows/release.yml +4 -1
- package/ARCHITECTURE.md +1 -0
- package/docs/configuration-custom-registry.md +206 -6
- package/docs/middleware/idempotency.md +31 -2
- 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/gotoService/redirectToService.js +20 -8
- package/mw/idempotency/index.js +42 -4
- package/mw/idempotency/model/memory.js +12 -2
- package/mw/idempotency/model/mongo.js +10 -3
- package/mw/mt/tenantAccess.js +173 -0
- package/mw/mt/urac.js +61 -12
- package/package.json +1 -1
- package/test/data/provision/customRegistry/gateway.js +32 -0
- package/test/data/provision/customRegistry/urac.js +22 -0
- package/test/data/provision/environment/dev.js +9 -0
- package/test/data/provision/hosts/departments.js +12 -0
- package/test/data/provision/hosts/idempotent.js +12 -0
- package/test/data/provision/marketplace/departments.js +38 -0
- package/test/data/provision/marketplace/idempotent.js +37 -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/products/dsbrd.js +25 -0
- package/test/data/provision/tenants/dbtn.js +6 -0
- package/test/integration/UC5-tenant-access/index.js +153 -0
- package/test/integration/UC6-idempotency/index.js +197 -0
- package/test/integration/index.js +8 -0
- package/test/unit/index.js +2 -0
- package/test/unit/mw/idempotency/index.js +122 -0
- package/test/unit/mw/idempotency/memory.js +36 -4
- package/test/unit/mw/idempotency/mongo.js +62 -0
- package/test/unit/mw/mt/tenantAccess.js +338 -0
- package/test/unit/mw/mt/urac.js +229 -1
|
@@ -58,7 +58,7 @@ let model = {
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
|
|
61
|
-
'lock': async (key, ttl) => {
|
|
61
|
+
'lock': async (key, ttl, lockId) => {
|
|
62
62
|
let condition = {
|
|
63
63
|
'l1': key.l1,
|
|
64
64
|
'l2': key.l2
|
|
@@ -73,6 +73,7 @@ let model = {
|
|
|
73
73
|
'l1': key.l1,
|
|
74
74
|
'l2': key.l2,
|
|
75
75
|
'status': 'in_flight',
|
|
76
|
+
'lockId': lockId || null,
|
|
76
77
|
'lockedAt': new Date(),
|
|
77
78
|
'expiresAt': new Date(Date.now() + ttl)
|
|
78
79
|
};
|
|
@@ -108,11 +109,17 @@ let model = {
|
|
|
108
109
|
}
|
|
109
110
|
},
|
|
110
111
|
|
|
111
|
-
|
|
112
|
+
//NOTE: only a record still in flight is removed, never a completed one, and with a lockId only
|
|
113
|
+
// the lock of that request, not one taken by a retry after the ttl
|
|
114
|
+
'unlock': async (key, lockId) => {
|
|
112
115
|
let condition = {
|
|
113
116
|
'l1': key.l1,
|
|
114
|
-
'l2': key.l2
|
|
117
|
+
'l2': key.l2,
|
|
118
|
+
'status': 'in_flight'
|
|
115
119
|
};
|
|
120
|
+
if (lockId) {
|
|
121
|
+
condition.lockId = lockId;
|
|
122
|
+
}
|
|
116
123
|
try {
|
|
117
124
|
await model.mongo.deleteOne(idempotency_store, condition);
|
|
118
125
|
} catch (e) {
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright SOAJS All Rights Reserved.
|
|
6
|
+
*
|
|
7
|
+
* Use of this source code is governed by an Apache license that can be
|
|
8
|
+
* found in the LICENSE file at the root of this repository
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { httpRequestLight } = require("../../lib/request.js");
|
|
12
|
+
|
|
13
|
+
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o);
|
|
14
|
+
|
|
15
|
+
const DEFAULT_TIMEOUT = 2000;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Find the resolver that decides who can access the tenant of this request.
|
|
19
|
+
*
|
|
20
|
+
* NOTE: the tenant profile names the resolver, the urac custom registry defines what to call,
|
|
21
|
+
* so the call can move without touching every tenant
|
|
22
|
+
*
|
|
23
|
+
* @param soajs
|
|
24
|
+
* @returns {null|{name, subject, service, version, method, api, timeout}}
|
|
25
|
+
*/
|
|
26
|
+
function getResolver(soajs) {
|
|
27
|
+
let access = get(["tenant", "profile", "access"], soajs);
|
|
28
|
+
if (!access || !access.resolver) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
let resolver = get(["registry", "custom", "urac", "value", "tenantAccessResolvers", access.resolver], soajs);
|
|
32
|
+
if (!resolver || !resolver.service || !resolver.api) {
|
|
33
|
+
if (soajs.log && soajs.log.error) {
|
|
34
|
+
soajs.log.error("Tenant access resolver [" + access.resolver + "] of tenant [" + soajs.tenant.code + "] is not defined in the urac custom registry");
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
"name": access.resolver,
|
|
40
|
+
"subject": access.subject || null,
|
|
41
|
+
"service": resolver.service,
|
|
42
|
+
"version": resolver.version || null,
|
|
43
|
+
"method": resolver.method || "post",
|
|
44
|
+
"api": resolver.api,
|
|
45
|
+
"timeout": resolver.timeout || DEFAULT_TIMEOUT
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The service behind the resolver has not been through the gateway, give it the tenant and key
|
|
51
|
+
* of this request the same way the gateway does, without any ACL or user
|
|
52
|
+
*
|
|
53
|
+
* @param soajs
|
|
54
|
+
* @param serviceName
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
function buildInjectObj(soajs, serviceName) {
|
|
58
|
+
let tenant = soajs.tenant;
|
|
59
|
+
let injectObj = {
|
|
60
|
+
"tenant": {
|
|
61
|
+
"id": tenant.id,
|
|
62
|
+
"name": tenant.name,
|
|
63
|
+
"code": tenant.code,
|
|
64
|
+
"locked": tenant.locked,
|
|
65
|
+
"type": tenant.type
|
|
66
|
+
},
|
|
67
|
+
"key": {
|
|
68
|
+
"config": {},
|
|
69
|
+
"iKey": tenant.key.iKey,
|
|
70
|
+
"eKey": tenant.key.eKey
|
|
71
|
+
},
|
|
72
|
+
"application": {
|
|
73
|
+
"product": tenant.application.product,
|
|
74
|
+
"package": tenant.application.package,
|
|
75
|
+
"appId": tenant.application.appId
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
if (tenant.main) {
|
|
79
|
+
injectObj.tenant.main = tenant.main;
|
|
80
|
+
}
|
|
81
|
+
if (soajs.servicesConfig) {
|
|
82
|
+
if (soajs.servicesConfig.commonFields) {
|
|
83
|
+
injectObj.key.config.commonFields = soajs.servicesConfig.commonFields;
|
|
84
|
+
}
|
|
85
|
+
if (soajs.servicesConfig[serviceName]) {
|
|
86
|
+
injectObj.key.config[serviceName] = soajs.servicesConfig[serviceName];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return JSON.stringify(injectObj);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Ask the resolver if the user has access to the tenant of this request and with what groups.
|
|
94
|
+
*
|
|
95
|
+
* NOTE: anything but a well formed yes is no access, the caller falls back to the urac driver
|
|
96
|
+
* so an invitation made after the token was issued still works
|
|
97
|
+
*
|
|
98
|
+
* @param soajs
|
|
99
|
+
* @param user the user from the token
|
|
100
|
+
* @param resolver from getResolver
|
|
101
|
+
* @param cb (result) result is {groups, groupsConfig} or null
|
|
102
|
+
*/
|
|
103
|
+
function resolve(soajs, user, resolver, cb) {
|
|
104
|
+
let done = (result) => {
|
|
105
|
+
//NOTE: out of the promise, an error thrown further down must not come back here as a rejection
|
|
106
|
+
process.nextTick(() => {
|
|
107
|
+
return cb(result);
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
let label = "Tenant access resolver [" + resolver.name + "] for user [" + user.username + "] and tenant [" + soajs.tenant.code + "]";
|
|
111
|
+
|
|
112
|
+
if (!soajs.registry || !soajs.registry.services ||
|
|
113
|
+
!soajs.registry.services[resolver.service] || !soajs.registry.services[resolver.service].port) {
|
|
114
|
+
soajs.log.error(label + " failed, service [" + resolver.service + "] is not in the registry");
|
|
115
|
+
return done(null);
|
|
116
|
+
}
|
|
117
|
+
soajs.awareness.getHost(resolver.service, resolver.version, (host) => {
|
|
118
|
+
if (!host) {
|
|
119
|
+
soajs.log.error(label + " failed, no host for [" + resolver.service + "@" + resolver.version + "]");
|
|
120
|
+
return done(null);
|
|
121
|
+
}
|
|
122
|
+
let data = {
|
|
123
|
+
"user": {
|
|
124
|
+
"id": user.id || (user._id ? user._id.toString() : null),
|
|
125
|
+
"username": user.username,
|
|
126
|
+
"tenant": {
|
|
127
|
+
"id": user.tenant.id,
|
|
128
|
+
"code": user.tenant.code
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"tenant": {
|
|
132
|
+
"id": soajs.tenant.id,
|
|
133
|
+
"code": soajs.tenant.code
|
|
134
|
+
},
|
|
135
|
+
"subject": resolver.subject
|
|
136
|
+
};
|
|
137
|
+
if (soajs.tenant.main) {
|
|
138
|
+
data.tenant.main = soajs.tenant.main;
|
|
139
|
+
}
|
|
140
|
+
httpRequestLight({
|
|
141
|
+
"uri": "http://" + host + ":" + soajs.registry.services[resolver.service].port + resolver.api,
|
|
142
|
+
"method": resolver.method,
|
|
143
|
+
"data": data,
|
|
144
|
+
"headers": { "soajsinjectobj": buildInjectObj(soajs, resolver.service) },
|
|
145
|
+
"timeout": resolver.timeout
|
|
146
|
+
}).then((response) => {
|
|
147
|
+
let answer = (response && response.result === true) ? response.data : null;
|
|
148
|
+
if (!answer || typeof answer !== "object") {
|
|
149
|
+
soajs.log.error(label + " returned an invalid response");
|
|
150
|
+
return done(null);
|
|
151
|
+
}
|
|
152
|
+
if (answer.access !== true) {
|
|
153
|
+
return done(null);
|
|
154
|
+
}
|
|
155
|
+
if (!answer.groupsConfig || !answer.groupsConfig.allowedPackages || typeof answer.groupsConfig.allowedPackages !== "object") {
|
|
156
|
+
soajs.log.error(label + " granted access without groupsConfig.allowedPackages");
|
|
157
|
+
return done(null);
|
|
158
|
+
}
|
|
159
|
+
return done({
|
|
160
|
+
"groups": Array.isArray(answer.groups) ? answer.groups : [],
|
|
161
|
+
"groupsConfig": answer.groupsConfig
|
|
162
|
+
});
|
|
163
|
+
}).catch((error) => {
|
|
164
|
+
soajs.log.error(label + " failed: " + error.message);
|
|
165
|
+
return done(null);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = {
|
|
171
|
+
"getResolver": getResolver,
|
|
172
|
+
"resolve": resolve
|
|
173
|
+
};
|
package/mw/mt/urac.js
CHANGED
|
@@ -13,6 +13,7 @@ const coreModules = require("soajs.core.modules");
|
|
|
13
13
|
let provision = coreModules.provision;
|
|
14
14
|
|
|
15
15
|
const lib = require("./lib.js");
|
|
16
|
+
const tenantAccess = require("./tenantAccess.js");
|
|
16
17
|
|
|
17
18
|
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o);
|
|
18
19
|
|
|
@@ -57,6 +58,31 @@ function Urac(param) {
|
|
|
57
58
|
_self.username = param.username;
|
|
58
59
|
}
|
|
59
60
|
}
|
|
61
|
+
|
|
62
|
+
//NOTE: a user switching to a tenant that names a resolver in its profile is decided by the resolver,
|
|
63
|
+
// unless the token already shows an invitation to that tenant, invitations keep going through
|
|
64
|
+
// the urac driver
|
|
65
|
+
_self.tenantAccess = null;
|
|
66
|
+
if (!_self.userRecord && _self.id && _self.bearerTokenUser && _self.soajs.tenant && !_self.soajs.tenant.roaming) {
|
|
67
|
+
let user = _self.bearerTokenUser;
|
|
68
|
+
if (user.tenant && user.tenant.id !== _self.soajs.tenant.id && !isInvited(user, _self.soajs.tenant.id)) {
|
|
69
|
+
_self.tenantAccess = tenantAccess.getResolver(_self.soajs);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check the allowedTenants of the user from the token
|
|
76
|
+
* @param user
|
|
77
|
+
* @param tenantId
|
|
78
|
+
* @returns {boolean}
|
|
79
|
+
*/
|
|
80
|
+
function isInvited(user, tenantId) {
|
|
81
|
+
let allowedTenants = get(["config", "allowedTenants"], user);
|
|
82
|
+
if (!Array.isArray(allowedTenants)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return allowedTenants.some((item) => item && item.tenant && item.tenant.id === tenantId);
|
|
60
86
|
}
|
|
61
87
|
|
|
62
88
|
/**
|
|
@@ -75,20 +101,43 @@ Urac.prototype.init = function (cb) {
|
|
|
75
101
|
}
|
|
76
102
|
}
|
|
77
103
|
else if (_self.id) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
104
|
+
let getRecord = () => {
|
|
105
|
+
uracDriver.getRecord(_self.soajs, { id: _self.id.toString(), username: _self.username }, function (err, record) {
|
|
106
|
+
if (record) {
|
|
107
|
+
_self.userRecord = record;
|
|
108
|
+
_self.resolveACL(() => {
|
|
109
|
+
return cb(null, _self.userRecord);
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
if (err && err.msg) {
|
|
113
|
+
const code = err.code;
|
|
114
|
+
err = new Error(err.msg);
|
|
115
|
+
err.code = code;
|
|
116
|
+
}
|
|
117
|
+
return cb(err, null);
|
|
89
118
|
}
|
|
90
|
-
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
if (!_self.tenantAccess) {
|
|
122
|
+
return getRecord();
|
|
123
|
+
}
|
|
124
|
+
tenantAccess.resolve(_self.soajs, _self.bearerTokenUser, _self.tenantAccess, (result) => {
|
|
125
|
+
//NOTE: no access from the resolver falls back to the urac driver, it catches an invitation
|
|
126
|
+
// made after the token was issued and answers everyone else as before
|
|
127
|
+
if (!result) {
|
|
128
|
+
return getRecord();
|
|
91
129
|
}
|
|
130
|
+
_self.userRecord = Object.assign({}, _self.bearerTokenUser, {
|
|
131
|
+
"tenant": {
|
|
132
|
+
"id": _self.soajs.tenant.id,
|
|
133
|
+
"code": _self.soajs.tenant.code
|
|
134
|
+
},
|
|
135
|
+
"groups": result.groups,
|
|
136
|
+
"groupsConfig": result.groupsConfig
|
|
137
|
+
});
|
|
138
|
+
_self.resolveACL(() => {
|
|
139
|
+
return cb(null, _self.userRecord);
|
|
140
|
+
});
|
|
92
141
|
});
|
|
93
142
|
} else {
|
|
94
143
|
let error = new Error('oAuth userId is not available to pull URAC profile');
|
package/package.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
let doc = {
|
|
3
|
+
"_id": "5d7f8e43edf21900fed08cf7",
|
|
4
|
+
"name": "gateway",
|
|
5
|
+
"locked": false,
|
|
6
|
+
"plugged": true,
|
|
7
|
+
"shared": false,
|
|
8
|
+
"value": {
|
|
9
|
+
"idempotency": {
|
|
10
|
+
"model": "mongo",
|
|
11
|
+
"services": {
|
|
12
|
+
"idempotent": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"ttl": 60000,
|
|
15
|
+
"apis": ["POST /ok", "POST /fail", "POST /bad", "POST /slow", "POST /throttled"]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"traffic": {
|
|
20
|
+
"throttling": {
|
|
21
|
+
"idempotent": {
|
|
22
|
+
"publicAPIStrategy": "idempotent_tight",
|
|
23
|
+
"apis": ["/throttled"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"created": "DEV",
|
|
29
|
+
"author": "owner"
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = doc;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
let doc = {
|
|
3
|
+
"_id": "5d7f8e43edf21900fed08cf6",
|
|
4
|
+
"name": "urac",
|
|
5
|
+
"locked": false,
|
|
6
|
+
"plugged": true,
|
|
7
|
+
"shared": false,
|
|
8
|
+
"value": {
|
|
9
|
+
"tenantAccessResolvers": {
|
|
10
|
+
"department": {
|
|
11
|
+
"service": "departments",
|
|
12
|
+
"version": "1",
|
|
13
|
+
"api": "/tenant/access",
|
|
14
|
+
"timeout": 1000
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"created": "DEV",
|
|
19
|
+
"author": "owner"
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports = doc;
|
|
@@ -115,6 +115,15 @@ let env = {
|
|
|
115
115
|
"accessTokenLifetime": 7200,
|
|
116
116
|
"refreshTokenLifetime": 1209600
|
|
117
117
|
},
|
|
118
|
+
"throttling": {
|
|
119
|
+
"idempotent_tight": {
|
|
120
|
+
"type": 1,
|
|
121
|
+
"window": 60000,
|
|
122
|
+
"limit": 1,
|
|
123
|
+
"retries": 0,
|
|
124
|
+
"delay": 100
|
|
125
|
+
}
|
|
126
|
+
},
|
|
118
127
|
"ports": {
|
|
119
128
|
"controller": 4000,
|
|
120
129
|
"maintenanceInc": 1001,
|
|
@@ -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,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
let service = {
|
|
4
|
+
_id: "5da078c92357684b57effcf2",
|
|
5
|
+
"type": "service",
|
|
6
|
+
name: "idempotent",
|
|
7
|
+
configuration: {
|
|
8
|
+
group: "SOAJS test",
|
|
9
|
+
port: 4014,
|
|
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: true,
|
|
24
|
+
urac_Profile: false,
|
|
25
|
+
urac_ACL: false,
|
|
26
|
+
provision_ACL: false,
|
|
27
|
+
apis: [
|
|
28
|
+
{ l: "Answers 200", v: "/ok", m: "post", group: "Integration test" },
|
|
29
|
+
{ l: "Answers 503 the first time", v: "/fail", m: "post", group: "Integration test" },
|
|
30
|
+
{ l: "Answers 400", v: "/bad", m: "post", group: "Integration test" },
|
|
31
|
+
{ l: "Answers 200 after a delay", v: "/slow", m: "post", group: "Integration test" },
|
|
32
|
+
{ l: "Answers 200, throttled", v: "/throttled", m: "post", group: "Integration test" }
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
};
|
|
37
|
+
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;
|
|
@@ -9,6 +9,23 @@ let prod = {
|
|
|
9
9
|
"scope": {
|
|
10
10
|
"acl": {
|
|
11
11
|
"dev": {
|
|
12
|
+
"idempotent": {
|
|
13
|
+
"1": {
|
|
14
|
+
"access": true,
|
|
15
|
+
"post": [
|
|
16
|
+
{
|
|
17
|
+
"group": "Idempotent group",
|
|
18
|
+
"apis": {
|
|
19
|
+
"/ok": {},
|
|
20
|
+
"/fail": {},
|
|
21
|
+
"/bad": {},
|
|
22
|
+
"/slow": {},
|
|
23
|
+
"/throttled": {}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
12
29
|
"httpmethods": {
|
|
13
30
|
"1": {
|
|
14
31
|
"access": true,
|
|
@@ -200,6 +217,14 @@ let prod = {
|
|
|
200
217
|
"locked": true,
|
|
201
218
|
"acl": {
|
|
202
219
|
"dev": {
|
|
220
|
+
"idempotent": [
|
|
221
|
+
{
|
|
222
|
+
"version": "1",
|
|
223
|
+
"post": [
|
|
224
|
+
"Idempotent group"
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
],
|
|
203
228
|
"httpmethods": [
|
|
204
229
|
{
|
|
205
230
|
"version": "1",
|
|
@@ -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",
|