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.
@@ -0,0 +1,338 @@
1
+ "use strict";
2
+
3
+ const helper = require("../../../helper.js");
4
+ const tenantAccess = helper.requireModule('./mw/mt/tenantAccess');
5
+ const assert = require('assert');
6
+ const http = require('http');
7
+
8
+ describe("Unit test for: mw - mt tenant access resolver", () => {
9
+
10
+ let errors = [];
11
+ let log = {
12
+ error: (msg) => {
13
+ errors.push(msg);
14
+ },
15
+ debug: () => {
16
+ }
17
+ };
18
+
19
+ function buildSoajs(port, resolver) {
20
+ return {
21
+ tenant: {
22
+ id: "dept_tenant_id",
23
+ code: "DEPT",
24
+ name: "Department",
25
+ locked: false,
26
+ type: "client",
27
+ main: { id: "main_tenant_id", code: "MAIN" },
28
+ profile: {
29
+ access: { resolver: "department", subject: "dept_1" }
30
+ },
31
+ key: { iKey: "ikey_1", eKey: "ekey_1" },
32
+ application: { product: "PROD", package: "PROD_DEFAULT", appId: "app_1" }
33
+ },
34
+ servicesConfig: {
35
+ commonFields: { a: 1 },
36
+ departments: { b: 2 },
37
+ other: { c: 3 }
38
+ },
39
+ registry: {
40
+ services: {
41
+ departments: { port: port }
42
+ },
43
+ custom: {
44
+ urac: {
45
+ value: {
46
+ tenantAccessResolvers: {
47
+ department: resolver || {
48
+ service: "departments",
49
+ version: "1",
50
+ api: "/tenant/access",
51
+ timeout: 500
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ },
58
+ awareness: {
59
+ getHost: (name, version, cb) => {
60
+ return cb("127.0.0.1");
61
+ }
62
+ },
63
+ log: log
64
+ };
65
+ }
66
+
67
+ let user = {
68
+ _id: "user_1",
69
+ id: "user_1",
70
+ username: "ann",
71
+ tenant: { id: "home_tenant_id", code: "HOME" }
72
+ };
73
+
74
+ describe("getResolver", () => {
75
+ beforeEach(() => {
76
+ errors = [];
77
+ });
78
+
79
+ it("returns null when the tenant has no access in its profile", () => {
80
+ let soajs = buildSoajs(1);
81
+ delete soajs.tenant.profile.access;
82
+ assert.strictEqual(tenantAccess.getResolver(soajs), null);
83
+ assert.strictEqual(errors.length, 0);
84
+ });
85
+
86
+ it("returns null and logs when the resolver is not in the registry", () => {
87
+ let soajs = buildSoajs(1);
88
+ soajs.tenant.profile.access.resolver = "unknown";
89
+ assert.strictEqual(tenantAccess.getResolver(soajs), null);
90
+ assert.strictEqual(errors.length, 1);
91
+ });
92
+
93
+ it("returns the resolver with its defaults", () => {
94
+ let soajs = buildSoajs(1, { service: "departments", api: "/tenant/access" });
95
+ assert.deepStrictEqual(tenantAccess.getResolver(soajs), {
96
+ name: "department",
97
+ subject: "dept_1",
98
+ service: "departments",
99
+ version: null,
100
+ method: "post",
101
+ api: "/tenant/access",
102
+ timeout: 2000
103
+ });
104
+ });
105
+ });
106
+
107
+ describe("resolve", () => {
108
+ let server = null;
109
+ let port = null;
110
+ let reply = null;
111
+ let received = null;
112
+
113
+ before((done) => {
114
+ server = http.createServer((req, res) => {
115
+ let body = "";
116
+ req.on("data", (chunk) => {
117
+ body += chunk;
118
+ });
119
+ req.on("end", () => {
120
+ received = {
121
+ method: req.method,
122
+ url: req.url,
123
+ headers: req.headers,
124
+ body: body ? JSON.parse(body) : null
125
+ };
126
+ reply(res);
127
+ });
128
+ });
129
+ server.listen(0, "127.0.0.1", () => {
130
+ port = server.address().port;
131
+ done();
132
+ });
133
+ });
134
+ after((done) => {
135
+ server.close(done);
136
+ });
137
+ beforeEach(() => {
138
+ errors = [];
139
+ received = null;
140
+ });
141
+
142
+ function json(data, status) {
143
+ return (res) => {
144
+ res.writeHead(status || 200, { "Content-Type": "application/json" });
145
+ res.end(JSON.stringify(data));
146
+ };
147
+ }
148
+
149
+ it("grants access with the groups and groupsConfig of the response", (done) => {
150
+ reply = json({
151
+ result: true,
152
+ data: {
153
+ access: true,
154
+ groups: ["member"],
155
+ groupsConfig: { allowedPackages: { PROD: ["PROD_USER"] } }
156
+ }
157
+ });
158
+ let soajs = buildSoajs(port);
159
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
160
+ try {
161
+ assert.deepStrictEqual(result, {
162
+ groups: ["member"],
163
+ groupsConfig: { allowedPackages: { PROD: ["PROD_USER"] } }
164
+ });
165
+ assert.strictEqual(received.method, "POST");
166
+ assert.strictEqual(received.url, "/tenant/access");
167
+ assert.deepStrictEqual(received.body, {
168
+ user: { id: "user_1", username: "ann", tenant: { id: "home_tenant_id", code: "HOME" } },
169
+ tenant: { id: "dept_tenant_id", code: "DEPT", main: { id: "main_tenant_id", code: "MAIN" } },
170
+ subject: "dept_1"
171
+ });
172
+ let injectObj = JSON.parse(received.headers.soajsinjectobj);
173
+ assert.deepStrictEqual(injectObj, {
174
+ tenant: {
175
+ id: "dept_tenant_id",
176
+ name: "Department",
177
+ code: "DEPT",
178
+ locked: false,
179
+ type: "client",
180
+ main: { id: "main_tenant_id", code: "MAIN" }
181
+ },
182
+ key: {
183
+ config: { commonFields: { a: 1 }, departments: { b: 2 } },
184
+ iKey: "ikey_1",
185
+ eKey: "ekey_1"
186
+ },
187
+ application: { product: "PROD", package: "PROD_DEFAULT", appId: "app_1" }
188
+ });
189
+ done();
190
+ } catch (e) {
191
+ done(e);
192
+ }
193
+ });
194
+ });
195
+
196
+ it("defaults groups to an empty array", (done) => {
197
+ reply = json({
198
+ result: true,
199
+ data: { access: true, groupsConfig: { allowedPackages: { PROD: ["PROD_USER"] } } }
200
+ });
201
+ let soajs = buildSoajs(port);
202
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
203
+ try {
204
+ assert.deepStrictEqual(result.groups, []);
205
+ done();
206
+ } catch (e) {
207
+ done(e);
208
+ }
209
+ });
210
+ });
211
+
212
+ it("no access when the resolver says no", (done) => {
213
+ reply = json({ result: true, data: { access: false } });
214
+ let soajs = buildSoajs(port);
215
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
216
+ try {
217
+ assert.strictEqual(result, null);
218
+ assert.strictEqual(errors.length, 0);
219
+ done();
220
+ } catch (e) {
221
+ done(e);
222
+ }
223
+ });
224
+ });
225
+
226
+ it("no access when access is granted without allowedPackages", (done) => {
227
+ reply = json({ result: true, data: { access: true, groups: ["member"] } });
228
+ let soajs = buildSoajs(port);
229
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
230
+ try {
231
+ assert.strictEqual(result, null);
232
+ assert.strictEqual(errors.length, 1);
233
+ done();
234
+ } catch (e) {
235
+ done(e);
236
+ }
237
+ });
238
+ });
239
+
240
+ it("no access when the service answers with an error", (done) => {
241
+ reply = json({ result: false, errors: { codes: [400] } });
242
+ let soajs = buildSoajs(port);
243
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
244
+ try {
245
+ assert.strictEqual(result, null);
246
+ assert.strictEqual(errors.length, 1);
247
+ done();
248
+ } catch (e) {
249
+ done(e);
250
+ }
251
+ });
252
+ });
253
+
254
+ it("no access on a non 2xx status", (done) => {
255
+ reply = json({ result: true, data: { access: true } }, 500);
256
+ let soajs = buildSoajs(port);
257
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
258
+ try {
259
+ assert.strictEqual(result, null);
260
+ assert.strictEqual(errors.length, 1);
261
+ done();
262
+ } catch (e) {
263
+ done(e);
264
+ }
265
+ });
266
+ });
267
+
268
+ it("no access on a response that is not JSON", (done) => {
269
+ reply = (res) => {
270
+ res.writeHead(200);
271
+ res.end("not json");
272
+ };
273
+ let soajs = buildSoajs(port);
274
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
275
+ try {
276
+ assert.strictEqual(result, null);
277
+ assert.strictEqual(errors.length, 1);
278
+ done();
279
+ } catch (e) {
280
+ done(e);
281
+ }
282
+ });
283
+ });
284
+
285
+ it("no access when the resolver times out", (done) => {
286
+ reply = () => {
287
+ //never answers
288
+ };
289
+ let soajs = buildSoajs(port, {
290
+ service: "departments",
291
+ api: "/tenant/access",
292
+ timeout: 100
293
+ });
294
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
295
+ try {
296
+ assert.strictEqual(result, null);
297
+ assert.strictEqual(errors.length, 1);
298
+ done();
299
+ } catch (e) {
300
+ done(e);
301
+ }
302
+ });
303
+ });
304
+
305
+ it("no access when the service is not in the registry", (done) => {
306
+ let soajs = buildSoajs(port);
307
+ let resolver = tenantAccess.getResolver(soajs);
308
+ delete soajs.registry.services.departments;
309
+ tenantAccess.resolve(soajs, user, resolver, (result) => {
310
+ try {
311
+ assert.strictEqual(result, null);
312
+ assert.strictEqual(received, null);
313
+ assert.strictEqual(errors.length, 1);
314
+ done();
315
+ } catch (e) {
316
+ done(e);
317
+ }
318
+ });
319
+ });
320
+
321
+ it("no access when there is no host", (done) => {
322
+ let soajs = buildSoajs(port);
323
+ soajs.awareness.getHost = (name, version, cb) => {
324
+ return cb(null);
325
+ };
326
+ tenantAccess.resolve(soajs, user, tenantAccess.getResolver(soajs), (result) => {
327
+ try {
328
+ assert.strictEqual(result, null);
329
+ assert.strictEqual(received, null);
330
+ assert.strictEqual(errors.length, 1);
331
+ done();
332
+ } catch (e) {
333
+ done(e);
334
+ }
335
+ });
336
+ });
337
+ });
338
+ });
@@ -307,4 +307,232 @@ describe("Unit test for: mw - mt URAC", () => {
307
307
  });
308
308
  });
309
309
  });
310
- });
310
+
311
+ describe("Tenant access resolver test for: mw - mt URAC", () => {
312
+ const tenantAccess = helper.requireModule('./mw/mt/tenantAccess');
313
+ const uracDriverModule = require('soajs.urac.driver');
314
+
315
+ let resolveStub = null;
316
+ let getRecordStub = null;
317
+ let provisionStub = null;
318
+ let resolverAnswer = null;
319
+ let receivedPackages = null;
320
+
321
+ function buildSoajs(options) {
322
+ options = options || {};
323
+ let soajs = {
324
+ tenant: {
325
+ id: "dept_tenant_id",
326
+ code: "DEPT",
327
+ profile: {
328
+ access: { resolver: "department", subject: "dept_1" }
329
+ },
330
+ application: { product: "PROD", package: "PROD_DEFAULT" },
331
+ key: { iKey: "ikey_1", eKey: "ekey_1" }
332
+ },
333
+ registry: {
334
+ serviceConfig: { oauth: { getUserFromToken: options.getUserFromToken !== false } },
335
+ custom: {
336
+ urac: {
337
+ value: {
338
+ tenantAccessResolvers: {
339
+ department: { service: "departments", api: "/tenant/access" }
340
+ }
341
+ }
342
+ }
343
+ }
344
+ },
345
+ log: {
346
+ error: () => {
347
+ },
348
+ debug: () => {
349
+ }
350
+ }
351
+ };
352
+ if (options.roaming) {
353
+ soajs.tenant.roaming = { tId: "home_tenant_id" };
354
+ }
355
+ return soajs;
356
+ }
357
+
358
+ function buildOauth(options) {
359
+ options = options || {};
360
+ let user = {
361
+ "_id": "user_1",
362
+ "id": "user_1",
363
+ "username": "ann",
364
+ "email": "ann@example.com",
365
+ "groups": ["owner"],
366
+ "config": {},
367
+ "tenant": { "id": options.homeTenantId || "home_tenant_id", "code": "HOME" },
368
+ "groupsConfig": { "allowedPackages": { "PROD": ["PROD_OWNER"] } },
369
+ "loginMode": "urac"
370
+ };
371
+ if (options.invited) {
372
+ user.config.allowedTenants = [{ tenant: { id: "dept_tenant_id", code: "DEPT" }, groups: ["guest"] }];
373
+ }
374
+ return {
375
+ type: 2,
376
+ bearerToken: {
377
+ clientId: options.clientId || "home_tenant_id",
378
+ user: user
379
+ }
380
+ };
381
+ }
382
+
383
+ before(() => {
384
+ const coreModules = require("soajs.core.modules");
385
+ provisionStub = sinon.stub(coreModules.provision, 'getPackagesData').callsFake((packages, cb) => {
386
+ receivedPackages = packages;
387
+ return cb(null, []);
388
+ });
389
+ resolveStub = sinon.stub(tenantAccess, 'resolve').callsFake((soajs, user, resolver, cb) => {
390
+ return cb(resolverAnswer);
391
+ });
392
+ getRecordStub = sinon.stub(uracDriverModule, 'getRecord').callsFake((soajs, input, cb) => {
393
+ return cb(null, {
394
+ "_id": "user_1",
395
+ "username": "ann",
396
+ "groups": ["guest"],
397
+ "tenant": { "id": "dept_tenant_id", "code": "DEPT" },
398
+ "groupsConfig": { "allowedPackages": { "PROD": ["PROD_GUEST"] } }
399
+ });
400
+ });
401
+ });
402
+ after(() => {
403
+ provisionStub.restore();
404
+ resolveStub.restore();
405
+ getRecordStub.restore();
406
+ });
407
+ beforeEach(() => {
408
+ resolveStub.resetHistory();
409
+ getRecordStub.resetHistory();
410
+ receivedPackages = null;
411
+ resolverAnswer = null;
412
+ });
413
+
414
+ it("resolver grants access, the driver is not called", (done) => {
415
+ resolverAnswer = { groups: ["member"], groupsConfig: { allowedPackages: { PROD: ["PROD_USER"] } } };
416
+ let uracDriver = new UracDriver({ "soajs": buildSoajs(), "oauth": buildOauth() });
417
+ uracDriver.init((error, record) => {
418
+ try {
419
+ assert.ifError(error);
420
+ assert.strictEqual(resolveStub.callCount, 1);
421
+ assert.strictEqual(resolveStub.firstCall.args[2].name, "department");
422
+ assert.strictEqual(getRecordStub.callCount, 0);
423
+ assert.deepStrictEqual(record.tenant, { id: "dept_tenant_id", code: "DEPT" });
424
+ assert.deepStrictEqual(record.groups, ["member"]);
425
+ assert.deepStrictEqual(uracDriver.getGroups(), ["member"]);
426
+ assert.deepStrictEqual(receivedPackages, ["PROD_USER"]);
427
+ assert.strictEqual(record.email, "ann@example.com");
428
+ done();
429
+ } catch (e) {
430
+ done(e);
431
+ }
432
+ });
433
+ });
434
+
435
+ it("resolver grants access with getUserFromToken off", (done) => {
436
+ resolverAnswer = { groups: ["member"], groupsConfig: { allowedPackages: { PROD: ["PROD_USER"] } } };
437
+ let uracDriver = new UracDriver({ "soajs": buildSoajs({ getUserFromToken: false }), "oauth": buildOauth() });
438
+ uracDriver.init((error, record) => {
439
+ try {
440
+ assert.strictEqual(resolveStub.callCount, 1);
441
+ assert.strictEqual(getRecordStub.callCount, 0);
442
+ assert.deepStrictEqual(record.groups, ["member"]);
443
+ done();
444
+ } catch (e) {
445
+ done(e);
446
+ }
447
+ });
448
+ });
449
+
450
+ it("resolver says no, falls back to the driver", (done) => {
451
+ resolverAnswer = null;
452
+ let uracDriver = new UracDriver({ "soajs": buildSoajs(), "oauth": buildOauth() });
453
+ uracDriver.init((error, record) => {
454
+ try {
455
+ assert.strictEqual(resolveStub.callCount, 1);
456
+ assert.strictEqual(getRecordStub.callCount, 1);
457
+ assert.deepStrictEqual(record.groups, ["guest"]);
458
+ assert.deepStrictEqual(receivedPackages, ["PROD_GUEST"]);
459
+ done();
460
+ } catch (e) {
461
+ done(e);
462
+ }
463
+ });
464
+ });
465
+
466
+ it("invited per the token, the resolver is not called", (done) => {
467
+ let uracDriver = new UracDriver({ "soajs": buildSoajs(), "oauth": buildOauth({ invited: true }) });
468
+ uracDriver.init((error, record) => {
469
+ try {
470
+ assert.strictEqual(resolveStub.callCount, 0);
471
+ assert.strictEqual(getRecordStub.callCount, 1);
472
+ assert.deepStrictEqual(record.groups, ["guest"]);
473
+ done();
474
+ } catch (e) {
475
+ done(e);
476
+ }
477
+ });
478
+ });
479
+
480
+ it("home tenant, the resolver is not called", (done) => {
481
+ let uracDriver = new UracDriver({
482
+ "soajs": buildSoajs({ getUserFromToken: false }),
483
+ "oauth": buildOauth({ homeTenantId: "dept_tenant_id", clientId: "dept_tenant_id" })
484
+ });
485
+ uracDriver.init(() => {
486
+ try {
487
+ assert.strictEqual(resolveStub.callCount, 0);
488
+ assert.strictEqual(getRecordStub.callCount, 1);
489
+ done();
490
+ } catch (e) {
491
+ done(e);
492
+ }
493
+ });
494
+ });
495
+
496
+ it("token issued for this tenant, the user comes from the token", (done) => {
497
+ let uracDriver = new UracDriver({ "soajs": buildSoajs(), "oauth": buildOauth({ clientId: "dept_tenant_id" }) });
498
+ uracDriver.init((error, record) => {
499
+ try {
500
+ assert.strictEqual(resolveStub.callCount, 0);
501
+ assert.strictEqual(getRecordStub.callCount, 0);
502
+ assert.deepStrictEqual(record.groups, ["owner"]);
503
+ done();
504
+ } catch (e) {
505
+ done(e);
506
+ }
507
+ });
508
+ });
509
+
510
+ it("roaming, the resolver is not called", (done) => {
511
+ let uracDriver = new UracDriver({ "soajs": buildSoajs({ roaming: true }), "oauth": buildOauth() });
512
+ uracDriver.init(() => {
513
+ try {
514
+ assert.strictEqual(resolveStub.callCount, 0);
515
+ assert.strictEqual(getRecordStub.callCount, 0);
516
+ done();
517
+ } catch (e) {
518
+ done(e);
519
+ }
520
+ });
521
+ });
522
+
523
+ it("tenant without access in its profile, the resolver is not called", (done) => {
524
+ let soajs = buildSoajs();
525
+ delete soajs.tenant.profile;
526
+ let uracDriver = new UracDriver({ "soajs": soajs, "oauth": buildOauth() });
527
+ uracDriver.init(() => {
528
+ try {
529
+ assert.strictEqual(resolveStub.callCount, 0);
530
+ assert.strictEqual(getRecordStub.callCount, 1);
531
+ done();
532
+ } catch (e) {
533
+ done(e);
534
+ }
535
+ });
536
+ });
537
+ });
538
+ });