k2hr3-api 1.0.42 → 2.0.1

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.
Files changed (149) hide show
  1. package/config/k2hr3-init.sh.templ +4 -4
  2. package/dist/.gitkeep +0 -0
  3. package/dist/src/app.js +262 -0
  4. package/{bin → dist/src/bin}/run.sh +1 -1
  5. package/dist/src/bin/watcher.js +113 -0
  6. package/dist/src/bin/www.js +217 -0
  7. package/dist/src/lib/basicipcheck.js +392 -0
  8. package/dist/src/lib/cacerts.js +106 -0
  9. package/dist/src/lib/dbglogging.js +190 -0
  10. package/dist/src/lib/dummyuserapi.js +719 -0
  11. package/dist/src/lib/ipwatch.js +354 -0
  12. package/dist/src/lib/k2hr3acrutil.js +532 -0
  13. package/dist/src/lib/k2hr3apiutil.js +1444 -0
  14. package/dist/src/lib/k2hr3cliutil.js +183 -0
  15. package/dist/src/lib/k2hr3config.js +832 -0
  16. package/dist/src/lib/k2hr3cryptutil.js +258 -0
  17. package/dist/src/lib/k2hr3dkc.js +12121 -0
  18. package/dist/src/lib/k2hr3extdata.js +198 -0
  19. package/dist/src/lib/k2hr3keys.js +207 -0
  20. package/dist/src/lib/k2hr3resutil.js +111 -0
  21. package/dist/src/lib/k2hr3template.js +6546 -0
  22. package/dist/src/lib/k2hr3tokens.js +2643 -0
  23. package/dist/src/lib/k2hr3userdata.js +296 -0
  24. package/dist/src/lib/k8soidc.js +1000 -0
  25. package/dist/src/lib/openstackapiv2.js +695 -0
  26. package/dist/src/lib/openstackapiv3.js +932 -0
  27. package/dist/src/lib/openstackep.js +667 -0
  28. package/{tests/auto_common.js → dist/src/lib/types.js} +4 -38
  29. package/dist/src/routes/acr.js +704 -0
  30. package/dist/src/routes/debugVerify.js +294 -0
  31. package/dist/src/routes/extdata.js +219 -0
  32. package/dist/src/routes/list.js +264 -0
  33. package/dist/src/routes/policy.js +840 -0
  34. package/dist/src/routes/resource.js +1489 -0
  35. package/dist/src/routes/role.js +2627 -0
  36. package/dist/src/routes/service.js +908 -0
  37. package/dist/src/routes/tenant.js +1141 -0
  38. package/dist/src/routes/userTokens.js +482 -0
  39. package/dist/src/routes/userdata.js +212 -0
  40. package/dist/src/routes/version.js +103 -0
  41. package/package.json +152 -121
  42. package/ChangeLog +0 -378
  43. package/app.js +0 -292
  44. package/bin/watcher +0 -122
  45. package/bin/www +0 -180
  46. package/eslint.config.mjs +0 -68
  47. package/lib/basicipcheck.js +0 -376
  48. package/lib/cacerts.js +0 -71
  49. package/lib/dbglogging.js +0 -151
  50. package/lib/dummyuserapi.js +0 -766
  51. package/lib/ipwatch.js +0 -379
  52. package/lib/k2hr3acrutil.js +0 -516
  53. package/lib/k2hr3apiutil.js +0 -1494
  54. package/lib/k2hr3cliutil.js +0 -191
  55. package/lib/k2hr3config.js +0 -826
  56. package/lib/k2hr3cryptutil.js +0 -254
  57. package/lib/k2hr3dkc.js +0 -12632
  58. package/lib/k2hr3extdata.js +0 -198
  59. package/lib/k2hr3keys.js +0 -234
  60. package/lib/k2hr3resutil.js +0 -100
  61. package/lib/k2hr3template.js +0 -6925
  62. package/lib/k2hr3tokens.js +0 -2799
  63. package/lib/k2hr3userdata.js +0 -312
  64. package/lib/k8soidc.js +0 -1012
  65. package/lib/openstackapiv2.js +0 -764
  66. package/lib/openstackapiv3.js +0 -1032
  67. package/lib/openstackep.js +0 -553
  68. package/routes/acr.js +0 -738
  69. package/routes/debugVerify.js +0 -263
  70. package/routes/extdata.js +0 -232
  71. package/routes/list.js +0 -270
  72. package/routes/policy.js +0 -869
  73. package/routes/resource.js +0 -1441
  74. package/routes/role.js +0 -2664
  75. package/routes/service.js +0 -894
  76. package/routes/tenant.js +0 -1095
  77. package/routes/userTokens.js +0 -511
  78. package/routes/userdata.js +0 -218
  79. package/routes/version.js +0 -108
  80. package/templ/Dockerfile.templ +0 -71
  81. package/tests/auto_acr.js +0 -1101
  82. package/tests/auto_acr_spec.js +0 -79
  83. package/tests/auto_all_spec.js +0 -142
  84. package/tests/auto_control_subprocess.sh +0 -243
  85. package/tests/auto_extdata.js +0 -220
  86. package/tests/auto_extdata_spec.js +0 -79
  87. package/tests/auto_init_config_json.sh +0 -275
  88. package/tests/auto_k2hdkc_server.ini +0 -109
  89. package/tests/auto_k2hdkc_slave.ini +0 -83
  90. package/tests/auto_list.js +0 -439
  91. package/tests/auto_list_spec.js +0 -79
  92. package/tests/auto_policy.js +0 -1579
  93. package/tests/auto_policy_spec.js +0 -79
  94. package/tests/auto_resource.js +0 -10956
  95. package/tests/auto_resource_spec.js +0 -79
  96. package/tests/auto_role.js +0 -6150
  97. package/tests/auto_role_spec.js +0 -79
  98. package/tests/auto_service.js +0 -770
  99. package/tests/auto_service_spec.js +0 -79
  100. package/tests/auto_subprocesses.js +0 -114
  101. package/tests/auto_template.sh +0 -126
  102. package/tests/auto_tenant.js +0 -1100
  103. package/tests/auto_tenant_spec.js +0 -79
  104. package/tests/auto_token_util.js +0 -219
  105. package/tests/auto_userdata.js +0 -292
  106. package/tests/auto_userdata_spec.js +0 -79
  107. package/tests/auto_usertokens.js +0 -565
  108. package/tests/auto_usertokens_spec.js +0 -79
  109. package/tests/auto_version.js +0 -127
  110. package/tests/auto_version_spec.js +0 -79
  111. package/tests/auto_watcher.js +0 -157
  112. package/tests/auto_watcher_spec.js +0 -79
  113. package/tests/k2hdkc_test.data +0 -986
  114. package/tests/k2hdkc_test_load.sh +0 -255
  115. package/tests/k2hr3template_test.js +0 -187
  116. package/tests/k2hr3template_test.sh +0 -339
  117. package/tests/k2hr3template_test_async.js +0 -216
  118. package/tests/k2hr3template_test_template.result +0 -7117
  119. package/tests/k2hr3template_test_template.txt +0 -3608
  120. package/tests/k2hr3template_test_vars.js +0 -194
  121. package/tests/manual_acr_delete.js +0 -143
  122. package/tests/manual_acr_get.js +0 -297
  123. package/tests/manual_acr_postput.js +0 -215
  124. package/tests/manual_allusertenant_get.js +0 -113
  125. package/tests/manual_extdata_get.js +0 -191
  126. package/tests/manual_k2hr3keys_get.js +0 -84
  127. package/tests/manual_list_gethead.js +0 -230
  128. package/tests/manual_policy_delete.js +0 -132
  129. package/tests/manual_policy_gethead.js +0 -275
  130. package/tests/manual_policy_postput.js +0 -297
  131. package/tests/manual_resource_delete.js +0 -433
  132. package/tests/manual_resource_gethead.js +0 -423
  133. package/tests/manual_resource_postput.js +0 -487
  134. package/tests/manual_role_delete.js +0 -404
  135. package/tests/manual_role_gethead.js +0 -547
  136. package/tests/manual_role_postput.js +0 -544
  137. package/tests/manual_service_delete.js +0 -153
  138. package/tests/manual_service_gethead.js +0 -178
  139. package/tests/manual_service_postput.js +0 -348
  140. package/tests/manual_tenant_delete.js +0 -186
  141. package/tests/manual_tenant_gethead.js +0 -268
  142. package/tests/manual_tenant_postput.js +0 -293
  143. package/tests/manual_test.sh +0 -352
  144. package/tests/manual_userdata_get.js +0 -173
  145. package/tests/manual_usertoken_gethead.js +0 -136
  146. package/tests/manual_usertoken_postput.js +0 -310
  147. package/tests/manual_version_get.js +0 -127
  148. package/tests/run_local_test_k2hdkc.sh +0 -174
  149. package/tests/test.sh +0 -333
@@ -0,0 +1,2643 @@
1
+ "use strict";
2
+ /*
3
+ * K2HR3 REST API
4
+ *
5
+ * Copyright 2017 Yahoo Japan Corporation.
6
+ *
7
+ * K2HR3 is K2hdkc based Resource and Roles and policy Rules, gathers
8
+ * common management information for the cloud.
9
+ * K2HR3 can dynamically manage information as "who", "what", "operate".
10
+ * These are stored as roles, resources, policies in K2hdkc, and the
11
+ * client system can dynamically read and modify these information.
12
+ *
13
+ * For the full copyright and license information, please view
14
+ * the license file that was distributed with this source code.
15
+ *
16
+ * AUTHOR: Takeshi Nakatani
17
+ * CREATE: Wed Jun 8 2017
18
+ * REVISION:
19
+ *
20
+ */
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.k2hr3tokens = void 0;
26
+ const k2hr3dkc_1 = __importDefault(require("./k2hr3dkc"));
27
+ const k2hr3apiutil_1 = __importDefault(require("./k2hr3apiutil"));
28
+ const dbglogging_1 = __importDefault(require("./dbglogging"));
29
+ const k2hr3keys_1 = require("./k2hr3keys");
30
+ const r3keys = k2hr3keys_1.getK2hr3Keys;
31
+ const k2hr3config_1 = require("./k2hr3config");
32
+ const apiConf = new k2hr3config_1.r3ApiConfig();
33
+ //
34
+ // Check type
35
+ //
36
+ const rawIsDkcTypeSourceUserHostInfo = (val) => {
37
+ if (!k2hr3apiutil_1.default.isPlainObject(val)) {
38
+ return false;
39
+ }
40
+ if ((null !== val.user && !k2hr3apiutil_1.default.isString(val.user)) ||
41
+ (null !== val.hostname && !k2hr3apiutil_1.default.isString(val.hostname)) ||
42
+ (null !== val.ip && !k2hr3apiutil_1.default.isString(val.ip)) ||
43
+ !k2hr3apiutil_1.default.isSafeNumber(val.port) ||
44
+ (null !== val.cuk && !k2hr3apiutil_1.default.isString(val.cuk))) {
45
+ return false;
46
+ }
47
+ return true;
48
+ };
49
+ const rawIsValTypeUserTenantInfo = (val) => {
50
+ if (!k2hr3apiutil_1.default.isPlainObject(val)) {
51
+ return false;
52
+ }
53
+ if ((undefined !== val.user && null !== val.user && !k2hr3apiutil_1.default.isString(val.user)) ||
54
+ (undefined !== val.tenant && null !== val.tenant && !k2hr3apiutil_1.default.isString(val.tenant)) ||
55
+ (undefined !== val.userid && null !== val.userid && !k2hr3apiutil_1.default.isString(val.userid)) ||
56
+ (undefined !== val.display && null !== val.display && !k2hr3apiutil_1.default.isString(val.display)) ||
57
+ (undefined !== val.id && null !== val.id && !k2hr3apiutil_1.default.isString(val.id)) ||
58
+ (undefined !== val.description && null !== val.description && !k2hr3apiutil_1.default.isString(val.description)) ||
59
+ (undefined !== val.region && null !== val.region && !k2hr3apiutil_1.default.isString(val.region)) ||
60
+ !rawIsDkcTypeSourceUserHostInfo(val)) {
61
+ return false;
62
+ }
63
+ return true;
64
+ };
65
+ const rawIsDkcTypeBaseRoleToken = (val) => {
66
+ if (!k2hr3apiutil_1.default.isPlainObject(val)) {
67
+ return false;
68
+ }
69
+ if (!k2hr3apiutil_1.default.isString(val.date) ||
70
+ !k2hr3apiutil_1.default.isString(val.expire) ||
71
+ (undefined !== val.registerpath && !k2hr3apiutil_1.default.isString(val.registerpath))) {
72
+ return false;
73
+ }
74
+ return true;
75
+ };
76
+ const rawIsResTypeObjRoleTokens = (val) => {
77
+ if (!k2hr3apiutil_1.default.isPlainObject(val)) {
78
+ return false;
79
+ }
80
+ for (const [, value] of Object.entries(val)) {
81
+ if (!rawIsDkcTypeBaseRoleToken(value)) {
82
+ return false;
83
+ }
84
+ }
85
+ return true;
86
+ };
87
+ const rawIsResTypeCheckKindToken = (val) => {
88
+ if (!k2hr3apiutil_1.default.isPlainObject(val)) {
89
+ return false;
90
+ }
91
+ if ((null !== val.role && !k2hr3apiutil_1.default.isString(val.role)) ||
92
+ (null !== val.extra && !k2hr3apiutil_1.default.isString(val.extra)) ||
93
+ !k2hr3apiutil_1.default.isBoolean(val.scoped) ||
94
+ !rawIsDkcTypeSourceUserHostInfo(val)) {
95
+ return false;
96
+ }
97
+ return true;
98
+ };
99
+ const rawIsResTypeCheckUserToken = (val) => {
100
+ return rawIsResTypeCheckKindToken(val);
101
+ };
102
+ const rawIsResTypeCheckRoleToken = (val) => {
103
+ return rawIsResTypeCheckKindToken(val);
104
+ };
105
+ //---------------------------------------------------------
106
+ // Configuration
107
+ // * Keystone api wrapper
108
+ // * Get expiration for role tokens
109
+ //---------------------------------------------------------
110
+ // [NOTE]
111
+ // We use config which has keystone.type value.
112
+ // Default value is "keystone_v3".
113
+ //
114
+ let osapi = null;
115
+ let expire_rtoken = 0;
116
+ let expire_reg_rtoken = 0;
117
+ (async () => {
118
+ const keystone_type = './' + apiConf.getKeystoneType();
119
+ const osapiModule = await k2hr3apiutil_1.default.tryLoadModule(keystone_type);
120
+ if (k2hr3apiutil_1.default.isSafeEntity(osapiModule)) {
121
+ osapi = osapiModule;
122
+ }
123
+ expire_rtoken = apiConf.getExpireTimeRoleToken();
124
+ expire_reg_rtoken = apiConf.getExpireTimeRegRoleToken();
125
+ })();
126
+ //---------------------------------------------------------
127
+ // set user/tenant token
128
+ //---------------------------------------------------------
129
+ // tenant undefined(or null) thus token must be unscoped.
130
+ // expire UTC ISO 8601 format
131
+ //
132
+ // [NOTE] Must initialize User/Tenant before calling this function.
133
+ //
134
+ const rawSetUserToken = (user, tenant, token, expire, region, seed) => {
135
+ if (!k2hr3apiutil_1.default.isSafeString(user) || !k2hr3apiutil_1.default.isSafeString(token) || !k2hr3apiutil_1.default.isSafeString(expire) || !k2hr3apiutil_1.default.isSafeString(region)) { // allow tenant/seed is null
136
+ dbglogging_1.default.elog('some parameters are wrong : user=' + JSON.stringify(user) + ', tenant=' + JSON.stringify(tenant) + ', token=' + JSON.stringify(token) + ', expire=' + JSON.stringify(expire) + ', region=' + JSON.stringify(region));
137
+ return false;
138
+ }
139
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
140
+ const keys = r3keys(user, tenant);
141
+ if (!k2hr3apiutil_1.default.isPlainObject(dkcobj)) {
142
+ return false;
143
+ }
144
+ //
145
+ // Check user key exists and create these.
146
+ //
147
+ const expire_limit = k2hr3apiutil_1.default.calcExpire(expire); // UTC ISO 8601 to unixtime
148
+ const token_value_key = keys.TOKEN_USER_TOP_KEY + '/' + token; // "yrn:yahoo::::token:user/<token>"
149
+ const user_token_key = keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY + '/' + token; // "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>"
150
+ const user_token_seed_key = user_token_key + '/' + keys.SEED_KW; // "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>/seed"
151
+ // [NOTE]
152
+ // If tenant is null, following keys have not tenant keyword in that key string.
153
+ // [ not have tenant name ] vs [ have tenant name ]
154
+ // keys.USER_TENANT_AMBIGUOUS_KEY ---> "yrn:yahoo::::user:<user>:tenant/" or "yrn:yahoo::::user:<user>:tenant/<tenant>"
155
+ // keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY ---> "yrn:yahoo::::user:<user>:tenant//token" or "yrn:yahoo::::user:<user>:tenant/<tenant>/token"
156
+ //
157
+ // token top
158
+ let subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.USER_TENANT_AMBIGUOUS_KEY, true));
159
+ if (k2hr3apiutil_1.default.tryAddStringToArray(subkeylist, keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY)) {
160
+ if (!dkcobj.setSubkeys(keys.USER_TENANT_AMBIGUOUS_KEY, subkeylist)) { // add subkey yrn:yahoo::::user:<user>:tenant/{<tenant>}/token -> yrn:yahoo::::user:<user>:tenant/{<tenant>}
161
+ dbglogging_1.default.elog('could not add ' + keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY + ' subkey under ' + keys.USER_TENANT_AMBIGUOUS_KEY + ' key');
162
+ dkcobj.clean();
163
+ return false;
164
+ }
165
+ }
166
+ // to token key
167
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY, true));
168
+ if (k2hr3apiutil_1.default.tryAddStringToArray(subkeylist, user_token_key)) {
169
+ if (!dkcobj.setSubkeys(keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY, subkeylist)) { // add subkey yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token> -> yrn:yahoo::::user:<user>:tenant/{<tenant>}/token
170
+ dbglogging_1.default.elog('could not add ' + user_token_key + ' subkey under ' + keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY + ' key');
171
+ dkcobj.clean();
172
+ return false;
173
+ }
174
+ }
175
+ // get/set token value
176
+ let old_value = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(user_token_key, null, true, null));
177
+ if (old_value != region) {
178
+ if (!dkcobj.setValue(user_token_key, region, null, null, expire_limit)) { // update new token key(value with region and expire) -> yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>
179
+ dbglogging_1.default.elog('could not set ' + k2hr3apiutil_1.default.getSafeString(region) + '(expire=' + k2hr3apiutil_1.default.getSafeString(expire) + ') to ' + user_token_key + ' key');
180
+ dkcobj.clean();
181
+ return false;
182
+ }
183
+ }
184
+ // get/set seed value
185
+ if (k2hr3apiutil_1.default.isSafeString(seed)) {
186
+ old_value = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(user_token_seed_key, null, true, null));
187
+ if (old_value != seed) {
188
+ if (!dkcobj.setValue(user_token_seed_key, seed, null, null, expire_limit)) { // update new token seed key(value with expire) -> yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>/seed
189
+ dbglogging_1.default.elog('could not set ' + seed + '(expire=' + expire + ') to ' + user_token_seed_key + ' key');
190
+ dkcobj.clean();
191
+ return false;
192
+ }
193
+ }
194
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(user_token_key, true));
195
+ if (k2hr3apiutil_1.default.tryAddStringToArray(subkeylist, user_token_seed_key)) {
196
+ if (!dkcobj.setSubkeys(user_token_key, subkeylist)) { // add subkey yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>/seed -> yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>
197
+ dbglogging_1.default.elog('could not add ' + user_token_seed_key + ' subkey under ' + user_token_key + ' key');
198
+ dkcobj.clean();
199
+ return false;
200
+ }
201
+ }
202
+ }
203
+ // create new token under token top key
204
+ //
205
+ // [NOTE]
206
+ // This key is not set expire limit. if you need to check expire,
207
+ // you look up key under user key.
208
+ //
209
+ if (!dkcobj.setValue(token_value_key, user_token_key)) { // create(over write) value(="yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>") without expire -> yrn:yahoo::::token/<token>
210
+ dbglogging_1.default.elog('could not set ' + user_token_key + ' value without expire to ' + token_value_key + ' key');
211
+ dkcobj.clean();
212
+ return false;
213
+ }
214
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.TOKEN_USER_TOP_KEY, true));
215
+ if (k2hr3apiutil_1.default.tryAddStringToArray(subkeylist, token_value_key)) {
216
+ if (!dkcobj.setSubkeys(keys.TOKEN_USER_TOP_KEY, subkeylist)) { // add subkey yrn:yahoo::::token:user/<token> -> yrn:yahoo::::token:user
217
+ dbglogging_1.default.elog('could not add ' + token_value_key + ' subkey under ' + keys.TOKEN_USER_TOP_KEY + ' key');
218
+ dkcobj.clean();
219
+ return false;
220
+ }
221
+ }
222
+ dkcobj.clean();
223
+ return true;
224
+ };
225
+ //---------------------------------------------------------
226
+ // get user unscoped token
227
+ //---------------------------------------------------------
228
+ //
229
+ // Get user token from keystone
230
+ //
231
+ // result: null or resTypeUserToken
232
+ // {
233
+ // user: user name(if existed, from parameter)
234
+ // userid: user id(if existed, from "yrn:yahoo::::user:<user name>:id")
235
+ // scoped: false(always false)
236
+ // token: token string(id)
237
+ // expire: expire string(if existed, null)
238
+ // region: region string
239
+ // }
240
+ //
241
+ // [NOTE]
242
+ // This function is wrapper for osapi.getUserUnscopedToken().
243
+ // This function checks existing unscoped token before call it.
244
+ //
245
+ const rawGetUserUnscopedTokenWrap = (user, passwd, callback) => {
246
+ const _user = user;
247
+ const _passwd = k2hr3apiutil_1.default.getSafeString(passwd);
248
+ const _callback = callback;
249
+ if (!k2hr3apiutil_1.default.isSafeEntity(osapi)) {
250
+ const error = new Error('could not load osapi file(object)');
251
+ dbglogging_1.default.elog(error.message);
252
+ _callback(error, null);
253
+ return;
254
+ }
255
+ // get unscoped token
256
+ osapi.getUserUnscopedToken(_user, _passwd, (err, jsonres) => {
257
+ if (null !== err || null === jsonres) {
258
+ const error = new Error('could not get user access token by ' + (err?.message ?? 'unknown'));
259
+ dbglogging_1.default.elog(error.message);
260
+ _callback(error, null);
261
+ return;
262
+ }
263
+ // init user
264
+ const resobj = k2hr3dkc_1.default.initUser(jsonres.user, jsonres.userid, jsonres.user, null);
265
+ if (!resobj.result) {
266
+ const error = new Error(resobj.message ?? '');
267
+ dbglogging_1.default.elog(error.message);
268
+ _callback(error, null);
269
+ return;
270
+ }
271
+ // set unscoped token
272
+ const token_seed = k2hr3apiutil_1.default.isSafeString(jsonres.token_seed) ? jsonres.token_seed : null;
273
+ if (!rawSetUserToken(jsonres.user, null, jsonres.token, jsonres.expire, jsonres.region, token_seed)) {
274
+ const error = new Error('failed to set unscoped/scoped user token');
275
+ dbglogging_1.default.elog(error.message);
276
+ _callback(error, null);
277
+ return;
278
+ }
279
+ // succeed
280
+ _callback(null, jsonres);
281
+ return;
282
+ });
283
+ };
284
+ //---------------------------------------------------------
285
+ // Get Scoped User Token from keystone
286
+ //---------------------------------------------------------
287
+ const rawGetScopedUserToken = (unscopedtoken, username, userid, tenant, callback) => {
288
+ const _callback = callback;
289
+ if (!k2hr3apiutil_1.default.isSafeEntity(osapi)) {
290
+ const error = new Error('could not load osapi file(object)');
291
+ dbglogging_1.default.elog(error.message);
292
+ _callback(error, null);
293
+ return;
294
+ }
295
+ if (!k2hr3apiutil_1.default.isSafeString(unscopedtoken) || !k2hr3apiutil_1.default.isSafeString(username) || !k2hr3apiutil_1.default.isSafeString(userid) || !k2hr3apiutil_1.default.isSafeString(tenant)) {
296
+ const error = new Error('unscopedtoken or username or userid or tenant parameters are wrong');
297
+ dbglogging_1.default.elog(error.message);
298
+ _callback(error, null);
299
+ return;
300
+ }
301
+ const _unscopedtoken = unscopedtoken;
302
+ const _username = username;
303
+ const _userid = userid;
304
+ const _tenant = tenant.toLowerCase();
305
+ // get tenant list for check
306
+ osapi.getUserTenantList(_unscopedtoken, _userid, (err, jsonres) => {
307
+ if (null !== err || null === jsonres) {
308
+ const error = new Error('could not get tenant list for user ' + _username + '(token=' + _unscopedtoken + ') by ' + (err?.message ?? 'unknown'));
309
+ dbglogging_1.default.elog(error.message);
310
+ _callback(error, null);
311
+ return;
312
+ }
313
+ //r3logger.dlog('get user tenant list jsonres=\n' + JSON.stringify(jsonres));
314
+ // check tenants(and initialize tenants)
315
+ let _tenant_name = null;
316
+ //let _tenant_id: string | null = null;
317
+ //let _tenant_desc: string | null = null;
318
+ //let _tenant_display: string | null = null;
319
+ const _tenant_list = new Array(0);
320
+ for (let cnt = 0; cnt < jsonres.length; ++cnt) {
321
+ if (!k2hr3apiutil_1.default.isSafeEntity(jsonres[cnt])) {
322
+ continue;
323
+ }
324
+ // over write
325
+ const resobj = k2hr3dkc_1.default.initUserTenant(_username, _userid, _username, jsonres[cnt].name, jsonres[cnt].id, jsonres[cnt].description, jsonres[cnt].display);
326
+ if (!resobj.result) {
327
+ const error = new Error(resobj.message ?? '');
328
+ dbglogging_1.default.elog(error.message);
329
+ _callback(error, null);
330
+ return;
331
+ }
332
+ if (k2hr3apiutil_1.default.compareCaseString(jsonres[cnt].name, _tenant)) {
333
+ // find target tenant
334
+ _tenant_name = jsonres[cnt].name;
335
+ //_tenant_id = jsonres[cnt].id;
336
+ //_tenant_desc = jsonres[cnt].description;
337
+ //_tenant_display = jsonres[cnt].display;
338
+ }
339
+ _tenant_list.push(jsonres[cnt].name);
340
+ }
341
+ // get and add local tenants
342
+ const tmpresobj = k2hr3dkc_1.default.listLocalTenant(_username, true);
343
+ if (!k2hr3apiutil_1.default.isPlainObject(tmpresobj) || !k2hr3apiutil_1.default.isBoolean(tmpresobj.result) || false === tmpresobj.result || !k2hr3apiutil_1.default.isSafeEntity(tmpresobj.tenants)) {
344
+ if (k2hr3apiutil_1.default.isPlainObject(tmpresobj) && k2hr3apiutil_1.default.isSafeString(tmpresobj.message)) {
345
+ dbglogging_1.default.wlog('failed to get local tenant list by ' + tmpresobj.message);
346
+ }
347
+ else {
348
+ dbglogging_1.default.wlog('failed to get local tenant list.');
349
+ }
350
+ }
351
+ else {
352
+ if (k2hr3dkc_1.default.isDkcTypeTenantInfoList(tmpresobj.tenants)) {
353
+ for (let cnt2 = 0; cnt2 < tmpresobj.tenants.length; ++cnt2) {
354
+ if (!k2hr3dkc_1.default.isDkcTypeTenantInfo(tmpresobj.tenants[cnt2])) {
355
+ continue;
356
+ }
357
+ if (k2hr3apiutil_1.default.compareCaseString(tmpresobj.tenants[cnt2].name, _tenant)) {
358
+ // find target tenant
359
+ _tenant_name = tmpresobj.tenants[cnt2].name;
360
+ //_tenant_id = tmpresobj.tenants[cnt2].id;
361
+ //_tenant_desc = tmpresobj.tenants[cnt2].desc;
362
+ //_tenant_display = tmpresobj.tenants[cnt2].display;
363
+ }
364
+ _tenant_list.push(tmpresobj.tenants[cnt2].name);
365
+ }
366
+ }
367
+ }
368
+ // check and remove old tenant for user
369
+ if (!k2hr3dkc_1.default.removeComprehensionByNewTenants(_username, _tenant_list)) {
370
+ dbglogging_1.default.elog('failed to remove some tenant for user, but continue...');
371
+ }
372
+ if (!k2hr3apiutil_1.default.isSafeEntity(osapi)) {
373
+ const error = new Error('could not load osapi file(object)');
374
+ dbglogging_1.default.elog(error.message);
375
+ _callback(error, null);
376
+ return;
377
+ }
378
+ // get scoped token
379
+ osapi.getUserScopedToken(_unscopedtoken, _tenant_name, (err, jsonres) => {
380
+ if (null !== err || null === jsonres) {
381
+ const error = new Error('could not get scoped user token for user ' + _username + ' by ' + (err?.message ?? 'unknown'));
382
+ dbglogging_1.default.elog(error.message);
383
+ _callback(error, null);
384
+ return;
385
+ }
386
+ //r3logger.dlog('get user scoped token jsonres=\n' + JSON.stringify(jsonres));
387
+ const token_seed = k2hr3apiutil_1.default.isSafeString(jsonres.token_seed) ? jsonres.token_seed : null;
388
+ if (!rawSetUserToken(_username, _tenant_name, jsonres.token, jsonres.expire, jsonres.region, token_seed)) {
389
+ const error = new Error('failed to set unscoped/scoped user token');
390
+ dbglogging_1.default.elog(error.message);
391
+ _callback(error, null);
392
+ return;
393
+ }
394
+ // succeed
395
+ _callback(null, jsonres.token);
396
+ return;
397
+ });
398
+ });
399
+ };
400
+ //---------------------------------------------------------
401
+ // Get User Token
402
+ //---------------------------------------------------------
403
+ //
404
+ // Get scoped/unscoped user token from keystone
405
+ //
406
+ const rawGetUserToken = (user, passwd, tenant, callback) => {
407
+ const _callback = callback;
408
+ if (!k2hr3apiutil_1.default.isSafeString(user)) {
409
+ const error = new Error('user parameter is wrong');
410
+ dbglogging_1.default.elog(error.message);
411
+ _callback(error, null);
412
+ return;
413
+ }
414
+ const _tenant = k2hr3apiutil_1.default.getSafeString(tenant).toLowerCase();
415
+ let _user = user;
416
+ const _passwd = k2hr3apiutil_1.default.getSafeString(passwd);
417
+ // get unscoped token
418
+ rawGetUserUnscopedTokenWrap(_user, _passwd, (err, jsonres) => {
419
+ if (null !== err || null === jsonres) {
420
+ const error = new Error('could not get user access token by ' + (err?.message ?? 'unknown'));
421
+ dbglogging_1.default.elog(error.message);
422
+ _callback(error, null);
423
+ return;
424
+ }
425
+ // save to local val
426
+ _user = jsonres.user; // over write
427
+ const _userid = jsonres.userid;
428
+ const _username = jsonres.user;
429
+ const _unscopedtoken = jsonres.token;
430
+ //const _tokenexpire = jsonres.expire;
431
+ //const _region = jsonres.region;
432
+ // break when unscoped token
433
+ if (!k2hr3apiutil_1.default.isSafeString(_tenant)) {
434
+ _callback(null, _unscopedtoken);
435
+ return;
436
+ }
437
+ // get scoped user token
438
+ return rawGetScopedUserToken(_unscopedtoken, _username, _userid, _tenant, _callback);
439
+ });
440
+ };
441
+ //---------------------------------------------------------
442
+ // get user unscoped token from token issued by another authentication system
443
+ //---------------------------------------------------------
444
+ //
445
+ // Get user token from token issued by another authentication system
446
+ //
447
+ // result: null or resTypeUserToken
448
+ // {
449
+ // user: user name(if existed, from parameter)
450
+ // userid: user id(if existed, from "yrn:yahoo::::user:<user name>:id")
451
+ // scoped: false(always false)
452
+ // token: token string(id)
453
+ // expire: expire string(if existed, null)
454
+ // region: region string
455
+ // }
456
+ //
457
+ // [NOTE]
458
+ // This function is wrapper for osapi.getUserUnscopedTokenByToken().
459
+ // This function checks existing unscoped token before call it.
460
+ //
461
+ const rawGetUserUnscopedTokenbyTokenWrap = (token, callback) => {
462
+ const _orgtoken = token;
463
+ const _callback = callback;
464
+ if (!k2hr3apiutil_1.default.isSafeEntity(osapi)) {
465
+ const error = new Error('could not load osapi file(object)');
466
+ dbglogging_1.default.elog(error.message);
467
+ _callback(error, null);
468
+ return;
469
+ }
470
+ // get unscoped token
471
+ osapi.getUserUnscopedTokenByToken(_orgtoken, (err, jsonres) => {
472
+ if (null !== err || null === jsonres) {
473
+ const error = new Error('could not get user access token by ' + (err?.message ?? 'unknown'));
474
+ dbglogging_1.default.elog(error.message);
475
+ _callback(error, null);
476
+ return;
477
+ }
478
+ // init user
479
+ const resobj = k2hr3dkc_1.default.initUser(jsonres.user, jsonres.userid, jsonres.user, null);
480
+ if (!resobj.result) {
481
+ const error = new Error(resobj.message ?? '');
482
+ dbglogging_1.default.elog(error.message);
483
+ _callback(error, null);
484
+ return;
485
+ }
486
+ // set unscoped token
487
+ const token_seed = k2hr3apiutil_1.default.isSafeString(jsonres.token_seed) ? jsonres.token_seed : null;
488
+ if (!rawSetUserToken(jsonres.user, null, jsonres.token, jsonres.expire, jsonres.region, token_seed)) {
489
+ const error = new Error('failed to set unscoped/scoped user token');
490
+ dbglogging_1.default.elog(error.message);
491
+ _callback(error, null);
492
+ return;
493
+ }
494
+ // succeed
495
+ _callback(null, jsonres);
496
+ return;
497
+ });
498
+ };
499
+ //---------------------------------------------------------
500
+ // Get User Token from token issued by another authentication system
501
+ //---------------------------------------------------------
502
+ //
503
+ // Get scoped/unscoped user token from token issued by another authentication system
504
+ // (ex. openstack identity token which is not registered in k2hr3 yet.)
505
+ //
506
+ const rawGetUserTokenByToken = (token, tenant, callback) => {
507
+ const _callback = callback;
508
+ if (!k2hr3apiutil_1.default.isSafeString(token)) {
509
+ const error = new Error('token parameter is wrong');
510
+ dbglogging_1.default.elog(error.message);
511
+ _callback(error, null);
512
+ return;
513
+ }
514
+ const _tenant = k2hr3apiutil_1.default.getSafeString(tenant).toLowerCase();
515
+ const _orgtoken = token;
516
+ // get unscoped token
517
+ rawGetUserUnscopedTokenbyTokenWrap(_orgtoken, (err, jsonres) => {
518
+ if (null !== err || null === jsonres) {
519
+ const error = new Error('could not get user access token by ' + (err?.message ?? 'unknown'));
520
+ dbglogging_1.default.elog(error.message);
521
+ _callback(error, null);
522
+ return;
523
+ }
524
+ // save to local val
525
+ const _userid = jsonres.userid;
526
+ const _username = jsonres.user;
527
+ const _unscopedtoken = jsonres.token;
528
+ //const _tokenexpire = jsonres.expire; // eslint-disable-line no-unused-vars
529
+ //const _region = jsonres.region; // eslint-disable-line no-unused-vars
530
+ // break when unscoped token
531
+ if (!k2hr3apiutil_1.default.isSafeString(_tenant)) {
532
+ _callback(null, _unscopedtoken);
533
+ return;
534
+ }
535
+ // get scoped user token
536
+ return rawGetScopedUserToken(_unscopedtoken, _username, _userid, _tenant, _callback);
537
+ });
538
+ };
539
+ //
540
+ // Get scoped user token from unscoped user token
541
+ //
542
+ const rawGetScopedUserTokenByUnscoped = (unscopedtoken, username, tenant, callback) => {
543
+ if (!k2hr3apiutil_1.default.isSafeString(unscopedtoken) || !k2hr3apiutil_1.default.isSafeString(username) || !k2hr3apiutil_1.default.isSafeString(tenant)) {
544
+ const error = new Error('unscopedtoken or username or tenant parameters are wrong');
545
+ dbglogging_1.default.elog(error.message);
546
+ callback(error, null);
547
+ return;
548
+ }
549
+ // user id from user name
550
+ const _tenant = tenant.toLowerCase();
551
+ const user_info = k2hr3dkc_1.default.getUserId(username); // user id from user name
552
+ if (null === user_info || !k2hr3apiutil_1.default.isSafeEntity(user_info.name) || !k2hr3apiutil_1.default.isSafeEntity(user_info.id)) {
553
+ const error = new Error('could not find username(' + username + ') from unscoped token in k2hdkc.');
554
+ dbglogging_1.default.elog(error.message);
555
+ callback(error, null);
556
+ return;
557
+ }
558
+ // get scoped user token
559
+ return rawGetScopedUserToken(unscopedtoken, user_info.name, user_info.id, _tenant, callback);
560
+ };
561
+ //---------------------------------------------------------
562
+ // cleanup user/tenant by token
563
+ //---------------------------------------------------------
564
+ // utility local function
565
+ //
566
+ // [NOTE]
567
+ // This process can be time consuming when subkey list is too many.
568
+ // In that case, there is a possibility that the consistency of the subkey will be lost.
569
+ // If a new token is added to the subkey list during processing with this function, that
570
+ // token subkey will be overwritten(lost) when this function completes processing.
571
+ // Originally, this subkey list of "yrn:yahoo::::token:user" key has no direct use, so this
572
+ // is not a problem. Because it normally reads the sub key(token key) directly.
573
+ // Please do not read subkey(token key) from the subkey list of "yrn:yahoo::::token:user" key.
574
+ // This subkeys are only useful for "notes".
575
+ //
576
+ const rawCleanupUserToken = (callback) => {
577
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
578
+ if (!k2hr3apiutil_1.default.isPlainObject(dkcobj)) {
579
+ callback(false);
580
+ return;
581
+ }
582
+ const keys = r3keys();
583
+ let subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.TOKEN_USER_TOP_KEY, true)); // get subkeys under "yrn:yahoo::::token:user"
584
+ const retrive_skeys = new Array(0);
585
+ for (let cnt = 0; cnt < subkeylist.length; ++cnt) {
586
+ const user_token_key = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(subkeylist[cnt], null, true, null));
587
+ if (!k2hr3apiutil_1.default.isSafeString(user_token_key)) {
588
+ // value is not existed, so this key should be removing
589
+ retrive_skeys.push(subkeylist[cnt]);
590
+ }
591
+ else {
592
+ //
593
+ // user_token_key => "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>"
594
+ //
595
+ const value = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(user_token_key, null, true, null));
596
+ if (!k2hr3apiutil_1.default.isSafeString(value)) {
597
+ // user_token_key is not existed or expired.
598
+ retrive_skeys.push(subkeylist[cnt]);
599
+ // try remove user_token_key from "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token" subkey list
600
+ const parent_user_key = k2hr3apiutil_1.default.getParentPath(user_token_key);
601
+ if (k2hr3apiutil_1.default.isSafeString(parent_user_key)) {
602
+ const user_skeys = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(parent_user_key, true)); // get subkeys under "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token"
603
+ if (k2hr3apiutil_1.default.removeStringFromArray(user_skeys, user_token_key)) {
604
+ if (!dkcobj.setSubkeys(parent_user_key, user_skeys)) { // update subkey -> "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token"
605
+ dbglogging_1.default.wlog('could not update subkey under ' + parent_user_key + ' key, but continue...');
606
+ }
607
+ }
608
+ }
609
+ else {
610
+ dbglogging_1.default.wlog('could not get parent key from ' + user_token_key + ' key, but skip it and continue...');
611
+ }
612
+ }
613
+ }
614
+ }
615
+ if (0 < retrive_skeys.length) {
616
+ // need to remove keys from subkey list
617
+ let is_update = false;
618
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.TOKEN_USER_TOP_KEY, true)); // re-get subkeys under "yrn:yahoo::::token:user"
619
+ for (let cnt = 0; cnt < retrive_skeys.length; ++cnt) {
620
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, retrive_skeys[cnt])) {
621
+ is_update = true;
622
+ }
623
+ }
624
+ if (is_update) {
625
+ if (!dkcobj.setSubkeys(keys.TOKEN_USER_TOP_KEY, subkeylist)) { // update subkey -> "yrn:yahoo::::token:user"
626
+ dbglogging_1.default.elog('could not update subkey under ' + keys.TOKEN_USER_TOP_KEY + ' key, but continue...');
627
+ dkcobj.clean();
628
+ callback(false);
629
+ return;
630
+ }
631
+ }
632
+ }
633
+ dkcobj.clean();
634
+ callback(true);
635
+ };
636
+ //---------------------------------------------------------
637
+ // get tenant list by token
638
+ //---------------------------------------------------------
639
+ // result: resTypeUserTenantInfo = {
640
+ // user: xxx,
641
+ // tenant: xxxx,
642
+ // region: xxxxx
643
+ // }
644
+ //
645
+ // [NOTE] Must initialize User/Tenant before calling this function.
646
+ //
647
+ const rawGetUserTenantByToken = (token) => {
648
+ if (!k2hr3apiutil_1.default.isSafeString(token)) {
649
+ dbglogging_1.default.elog('token parameters are wrong : token=' + JSON.stringify(token));
650
+ return null;
651
+ }
652
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
653
+ if (!k2hr3apiutil_1.default.isPlainObject(dkcobj)) {
654
+ return null;
655
+ }
656
+ //
657
+ // Get subkeys under token top key
658
+ //
659
+ const keys = r3keys();
660
+ const token_value_key = keys.TOKEN_USER_TOP_KEY + '/' + token; // "yrn:yahoo::::token:user/<token>"
661
+ // get token key under user key
662
+ const user_token_key = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(token_value_key, null, true, null)); // "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>"
663
+ if (!k2hr3apiutil_1.default.isSafeString(user_token_key)) {
664
+ dbglogging_1.default.dlog('token key(' + token_value_key + ') for token(' + token + ') is not existed.');
665
+ dkcobj.clean();
666
+ //
667
+ // check and remove old token under token top key("yrn:yahoo::::token:user" and "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>")
668
+ // if old token is expired
669
+ //
670
+ // [NOTE]
671
+ // This processing is taking time, so it runs asynchronously.
672
+ // And for notes on this processing, refer to NOTE of rawCleanupUserToken function.
673
+ //
674
+ rawCleanupUserToken((result) => {
675
+ if (!result) {
676
+ dbglogging_1.default.wlog('Failed to cleanup expired user tokens under ' + keys.TOKEN_USER_TOP_KEY + ' key, but continue...');
677
+ }
678
+ });
679
+ return null;
680
+ }
681
+ // get user token key's value which is region
682
+ const region = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(user_token_key, null, true, null)); // "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>" value is region
683
+ if (!k2hr3apiutil_1.default.isSafeString(region)) {
684
+ dbglogging_1.default.dlog('token key(' + user_token_key + ') for token(' + token + ') is not existed.');
685
+ dkcobj.clean();
686
+ //
687
+ // check and remove old token under token top key("yrn:yahoo::::token:user" and "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>")
688
+ // if old token is expired
689
+ //
690
+ // [NOTE] look forwards
691
+ //
692
+ rawCleanupUserToken((result) => {
693
+ if (!result) {
694
+ dbglogging_1.default.wlog('Failed to cleanup expired user tokens under ' + keys.TOKEN_USER_TOP_KEY + ' key, but continue...');
695
+ }
696
+ });
697
+ return null;
698
+ }
699
+ // user_token_key format is "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>"
700
+ const pattern = new RegExp('^' + keys.MATCH_ANY_USER_TOKEN); // regex = /^yrn:yahoo::::user:(.*):tenant/(.*)/token/(.*)/
701
+ const matches = user_token_key.match(pattern); // reverse to user/tenant names
702
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(matches) || matches.length < 4 || '' === k2hr3apiutil_1.default.getSafeString(matches[1])) {
703
+ dbglogging_1.default.elog('token key(' + token_value_key + ') for token(' + token + ') has wrong format value(' + user_token_key + ')');
704
+ dkcobj.clean();
705
+ return null;
706
+ }
707
+ const user_name = k2hr3apiutil_1.default.getSafeString(matches[1]);
708
+ let tenant_name = k2hr3apiutil_1.default.getSafeString(matches[2]);
709
+ let tenant_display = null;
710
+ let tenant_id = null;
711
+ let tenant_desc = null;
712
+ if ('' === tenant_name) {
713
+ tenant_name = null;
714
+ }
715
+ else {
716
+ const tenant_keys = r3keys(user_name, tenant_name);
717
+ tenant_display = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(tenant_keys.TENANT_DISP_KEY, null, true, null));
718
+ tenant_id = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(tenant_keys.TENANT_ID_KEY, null, true, null));
719
+ tenant_desc = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(tenant_keys.TENANT_DESC_KEY, null, true, null));
720
+ }
721
+ // if token has seed, need to check seed
722
+ const user_token_seed_key = user_token_key + '/' + keys.SEED_KW; // "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>/seed"
723
+ const token_seed = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(user_token_seed_key, null, true, null));
724
+ if (k2hr3apiutil_1.default.isSafeString(token_seed)) {
725
+ // token has seed, then we need to check manually.
726
+ //
727
+ //r3logger.dlog('token key(' + user_token_key + ') has seed.');
728
+ if (!k2hr3apiutil_1.default.isSafeEntity(osapi)) {
729
+ dbglogging_1.default.elog('could not load osapi file(object)');
730
+ dkcobj.clean();
731
+ return null;
732
+ }
733
+ const vres = osapi.verifyUserToken(dkcobj, user_name, tenant_name, token, token_seed);
734
+ if (!vres.result) {
735
+ dbglogging_1.default.elog('failed to verify token(' + token + ') with seed by ' + (vres?.message ?? ''));
736
+ dkcobj.clean();
737
+ return null;
738
+ }
739
+ }
740
+ dkcobj.clean();
741
+ const result = {
742
+ user: user_name,
743
+ tenant: tenant_name,
744
+ display: tenant_display,
745
+ id: tenant_id,
746
+ description: tenant_desc,
747
+ region: region
748
+ };
749
+ return result;
750
+ };
751
+ //---------------------------------------------------------
752
+ // Check User Token
753
+ //---------------------------------------------------------
754
+ //
755
+ // Check User Token
756
+ //
757
+ // result : null or token information
758
+ // {
759
+ // role: role name
760
+ // user: user name
761
+ // hostname: always null
762
+ // ip: always null
763
+ // port: always 0
764
+ // cuk: always null
765
+ // extra: always null
766
+ // tenant: tenant name
767
+ // display: display alias name for tenant
768
+ // id: tenant id string
769
+ // description: description for tenant
770
+ // scoped: role token is always scoped(true)
771
+ // region: when user token, the creator region name of the token
772
+ // }
773
+ //
774
+ const rawCheckUserToken = (token) => {
775
+ if (!k2hr3apiutil_1.default.isSafeString(token)) {
776
+ dbglogging_1.default.elog('token parameter is wrong');
777
+ return null;
778
+ }
779
+ // get user/tenant from token
780
+ const tenant_info = rawGetUserTenantByToken(token);
781
+ if (null === tenant_info || !k2hr3apiutil_1.default.isSafeEntity(tenant_info.user)) {
782
+ dbglogging_1.default.elog('token is not any user/tenant(expired or wrong token)');
783
+ return null;
784
+ }
785
+ // check scoped flag
786
+ let scoped = false;
787
+ if (k2hr3apiutil_1.default.isSafeEntity(tenant_info.tenant)) {
788
+ scoped = true;
789
+ }
790
+ const token_info = {
791
+ role: null,
792
+ user: tenant_info.user ?? null,
793
+ hostname: null,
794
+ ip: null,
795
+ port: 0,
796
+ cuk: null,
797
+ extra: null,
798
+ tenant: tenant_info.tenant ?? null,
799
+ display: tenant_info.display ?? null,
800
+ id: tenant_info.id ?? null,
801
+ description: tenant_info.description ?? null,
802
+ region: tenant_info.region ?? null,
803
+ scoped: scoped
804
+ };
805
+ return token_info;
806
+ };
807
+ //---------------------------------------------------------
808
+ // remove scoped user token
809
+ //---------------------------------------------------------
810
+ //
811
+ // token scoped user token
812
+ //
813
+ // [NOTE] This removes(force expire) scoped user token for
814
+ // using ACR API.
815
+ // The token used by ACR must be removed after checking
816
+ // it, because this case allows using token one time.
817
+ //
818
+ const rawRemoveScopedUserToken = (token) => {
819
+ if (!k2hr3apiutil_1.default.isSafeString(token)) {
820
+ dbglogging_1.default.elog('parameter is wrong : token=' + JSON.stringify(token));
821
+ return false;
822
+ }
823
+ //
824
+ // Check token
825
+ //
826
+ if (0 === token.indexOf('R=')) {
827
+ dbglogging_1.default.elog('token(' + JSON.stringify(token) + ') is role token.');
828
+ return false;
829
+ }
830
+ else if (0 === token.indexOf('U=')) {
831
+ token = token.substr(2); // cut 'U='
832
+ }
833
+ const token_info = rawCheckUserToken(token);
834
+ if (null === token_info ||
835
+ !k2hr3apiutil_1.default.isSafeString(token_info.user) ||
836
+ !k2hr3apiutil_1.default.isSafeString(token_info.tenant) ||
837
+ !k2hr3apiutil_1.default.isSafeEntity(token_info.scoped) ||
838
+ !k2hr3apiutil_1.default.isBoolean(token_info.scoped) ||
839
+ true !== token_info.scoped) {
840
+ dbglogging_1.default.elog('token(' + JSON.stringify(token) + ') is something wrong.');
841
+ return false;
842
+ }
843
+ //
844
+ // Remove token
845
+ //
846
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
847
+ let errmsg = '';
848
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
849
+ return false;
850
+ }
851
+ //
852
+ // Keys
853
+ //
854
+ const keys = r3keys(token_info.user, token_info.tenant);
855
+ const token_top_key = keys.TOKEN_USER_TOP_KEY; // "yrn:yahoo::::token:user"
856
+ const token_value_key = keys.TOKEN_USER_TOP_KEY + '/' + token; // "yrn:yahoo::::token:user/<token>"
857
+ const utoken_top_key = keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY; // "yrn:yahoo::::user:<user>:tenant/<tenant>/token"
858
+ const utoken_token_key = keys.USER_TENANT_AMBIGUOUS_TOKEN_KEY + '/' + token; // "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>"
859
+ const utoken_seed_key = utoken_token_key + '/' + keys.SEED_KW; // "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>/seed"
860
+ //
861
+ // check under token top
862
+ //
863
+ let subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(token_top_key, true));
864
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, token_value_key)) { // remove subkeys "yrn:yahoo::::token:user/<token>" -> "yrn:yahoo::::token:user"
865
+ if (!dkcobj.setSubkeys(token_top_key, subkeylist)) {
866
+ errmsg += 'could not remove ' + token_value_key + ' subkey under ' + token_top_key + ' key, ';
867
+ }
868
+ }
869
+ if (!dkcobj.remove(token_value_key, false)) { // remove key "yrn:yahoo::::token:user/<token>"
870
+ errmsg += 'could not remove ' + token_value_key + 'key, probably it is not existed, ';
871
+ }
872
+ //
873
+ // check under user top
874
+ //
875
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(utoken_top_key, true));
876
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, utoken_token_key)) { // remove subkeys "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>" -> "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token"
877
+ if (!dkcobj.setSubkeys(utoken_top_key, subkeylist)) {
878
+ errmsg += 'could not remove ' + utoken_token_key + ' subkey under ' + utoken_top_key + ' key, ';
879
+ }
880
+ }
881
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(utoken_token_key, true));
882
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, utoken_seed_key)) { // remove subkeys "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>/seed" -> "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>"
883
+ if (!dkcobj.setSubkeys(utoken_token_key, subkeylist)) {
884
+ errmsg += 'could not remove ' + utoken_seed_key + ' subkey under ' + utoken_token_key + ' key, ';
885
+ }
886
+ }
887
+ if (!dkcobj.remove(utoken_seed_key, false)) { // remove key "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>/seed"
888
+ errmsg += 'could not remove ' + utoken_seed_key + 'key, probably it is not existed, ';
889
+ }
890
+ if (!dkcobj.remove(utoken_token_key, false)) { // remove key "yrn:yahoo::::user:<user>:tenant/{<tenant>}/token/<token>"
891
+ errmsg += 'could not remove ' + utoken_token_key + 'key, probably it is not existed, ';
892
+ }
893
+ if (k2hr3apiutil_1.default.isSafeString(errmsg)) {
894
+ dbglogging_1.default.elog(errmsg);
895
+ }
896
+ dkcobj.clean();
897
+ return true; // Returns true even if there is an error in deletion processing
898
+ };
899
+ //---------------------------------------------------------
900
+ // [Role Token]
901
+ //---------------------------------------------------------
902
+ //
903
+ // Token: Token Id(################)
904
+ // X-Auth-Token: R=Token Id
905
+ // Token Id: The "Token Id" is a unique hex number string for 128bit.
906
+ // "Token Id" = "(<base id(64bit:8byte)> ^ <crypt id(64bit:8byte)>)" + "(<role id(64bit:8byte)> ^ <crypt id(64bit:8byte)>)"
907
+ // Role Token Key: "yrn:yahoo::::token:role/<Token Id>"
908
+ // Role Token Value: = dkcTypeRoleTokenValue {
909
+ // role: "role full yrn"
910
+ // date: "UTC ISO 8601 time at create"
911
+ // expire: "UTC ISO 8601 time at expire"
912
+ // creator: "Host full yrn" or "User full yrn"
913
+ // base: "id from host" or "last 64bit string in UserToken"
914
+ // user: "user name", if creator is user, this value is user name.(if not, this is null)
915
+ // ip: "ip address", if creator is host, this value is ip address.(if not, this is null)
916
+ // hostname: "hostname", if creator is host, this value is hostname.(if not, this is null)
917
+ // port: "port number", if creator is host, this value is port number.(if not, this is 0)
918
+ // cuk: "cuk", if creator is host on iaas, this value is cuk.(allowed null)
919
+ // extra: "extra", if creator is host on iaas, this value is extra.(allowed null)
920
+ // tenant: "tenant name" for this role token(this mean token is scoped)
921
+ // verify: "random 64bit id for verify token"
922
+ // }
923
+ //
924
+ // [NOTE]
925
+ // "role id" which is in "Token Id" is included from role key(yrn:yahoo:<Tenant>:::role:<role name>/id).
926
+ // This value is secret, any API could not get this value directly.
927
+ //
928
+ //---------------------------------------------------------
929
+ // Get Role Token From user(token)
930
+ //---------------------------------------------------------
931
+ //
932
+ // user : this value is parsed from user token
933
+ // tenant : this value is parsed from user token
934
+ // role : target role name(full yrn or only role name)
935
+ // expire_limit : specify expire second(default 24H = 24 * 60 * 60 sec, 0 means no expire time.)
936
+ //
937
+ // result : resTypeGetRoleToken = {
938
+ // result: true/false
939
+ // message: null or error message string
940
+ // token: undefined(error) or role token string
941
+ // }
942
+ //
943
+ // [NOTE]
944
+ // set role token value is following:
945
+ // dkcTypeRoleTokenValue = {
946
+ // role: token's role yrn("yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}")
947
+ // date: create date(UTC ISO 8601)
948
+ // expire: expire date(UTC ISO 8601)
949
+ // creator: creator yrn("yrn:yahoo::::user:<user>" or "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/hosts/ip/<ip:port>")
950
+ // user: if creator is user, this value is user name.
951
+ // hostname: always null
952
+ // ip: always null
953
+ // port: if creator is host, this value is port number.(if not, this is 0)
954
+ // cuk: if creator is host on iaas, this value is cuk.(allowed null)
955
+ // extra: if creator is host on iaas, this value is extra.(allowed null)
956
+ // tenant: tenant name for this role token(this mean token is scoped)
957
+ // base: 32bytes hex string
958
+ // }
959
+ //
960
+ const rawGetRoleTokenByUser = (user, tenant, role, expire_limit) => {
961
+ const resobj = { result: true, message: null };
962
+ if (!k2hr3apiutil_1.default.isSafeString(user) || !k2hr3apiutil_1.default.isSafeString(tenant) || !k2hr3apiutil_1.default.isSafeString(role)) { // allow other argument is empty
963
+ resobj.result = false;
964
+ resobj.message = 'some parameters are wrong : user=' + JSON.stringify(user) + ', tenant=' + JSON.stringify(tenant) + ', role=' + JSON.stringify(role);
965
+ dbglogging_1.default.elog(resobj.message);
966
+ return resobj;
967
+ }
968
+ if (!k2hr3apiutil_1.default.isSafeNumber(expire_limit)) { // expire_limit must be number or null(undefined)
969
+ expire_limit = expire_rtoken; // default 24H
970
+ }
971
+ else {
972
+ if (0 == expire_limit) {
973
+ // [NOTE]
974
+ // If 0, set the maximum value to 10 years.
975
+ // Disable expire by setting a period of time within which this
976
+ // application is guaranteed not to survive, as permitted by ISO8601.
977
+ //
978
+ expire_limit = expire_reg_rtoken;
979
+ }
980
+ }
981
+ // check role name is only name or full yrn path
982
+ const keys = r3keys(user, tenant);
983
+ role = role.toLowerCase();
984
+ let roleptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
985
+ const rolematchs = role.match(roleptn);
986
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(rolematchs) || rolematchs.length < 4) {
987
+ // role is not matched role(maybe not full yrn), then we need check it is another yrn path
988
+ roleptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
989
+ if (role.match(roleptn)) {
990
+ resobj.result = false;
991
+ resobj.message = 'role(' + role + ') is not role yrn path)';
992
+ dbglogging_1.default.elog(resobj.message);
993
+ return resobj;
994
+ }
995
+ // role is only role name, then we do not modify it.
996
+ }
997
+ else {
998
+ // check tenant name
999
+ if (tenant !== rolematchs[2]) {
1000
+ resobj.result = false;
1001
+ resobj.message = 'role(' + role + ') yrn has tenant(' + rolematchs[2] + '), but it is not specified tenant(' + tenant + ')';
1002
+ dbglogging_1.default.elog(resobj.message);
1003
+ return resobj;
1004
+ }
1005
+ // role is set only role name
1006
+ role = rolematchs[3];
1007
+ }
1008
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
1009
+ let subkeylist;
1010
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
1011
+ resobj.result = false;
1012
+ resobj.message = 'Not initialize yet.';
1013
+ dbglogging_1.default.elog(resobj.message);
1014
+ return resobj;
1015
+ }
1016
+ //
1017
+ // keys
1018
+ //
1019
+ const role_key = keys.ROLE_TOP_KEY + ':' + role; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}"
1020
+ const role_id_key = role_key + '/' + keys.ID_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/id"
1021
+ const role_tokens_key = role_key + '/' + keys.ROLE_TOKEN_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens"
1022
+ // user id
1023
+ const user_id = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(keys.USER_ID_KEY, null, true, null)); // get user id from "yrn:yahoo::::user:<user name>:id"
1024
+ if (!k2hr3apiutil_1.default.isSafeString(user_id)) {
1025
+ resobj.result = false;
1026
+ resobj.message = 'could not get user id(' + keys.USER_ID_KEY + ') value, or it is wrong value(' + JSON.stringify(user_id) + ').';
1027
+ dbglogging_1.default.elog(resobj.message);
1028
+ dkcobj.clean();
1029
+ return resobj;
1030
+ }
1031
+ // role id
1032
+ let role_id = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(role_id_key, null, true, null));
1033
+ if (!k2hr3apiutil_1.default.isSafeStrUuid4(role_id)) {
1034
+ let isError = false;
1035
+ const old_role_id = k2hr3apiutil_1.default.parseJSON(role_id);
1036
+ if (k2hr3apiutil_1.default.isNotEmptyArray(old_role_id) && 4 == old_role_id.length) {
1037
+ // old version id, so reset new valus(UUID4) here.
1038
+ role_id = k2hr3apiutil_1.default.getStrUuid4();
1039
+ if (!dkcobj.setValue(role_id_key, role_id)) { // set value -> yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/id
1040
+ isError = true;
1041
+ resobj.message = 'could not get role id(' + role_id_key + ') value, because failed to reset new role id instead of old id.';
1042
+ }
1043
+ }
1044
+ else {
1045
+ isError = true;
1046
+ resobj.message = 'could not get role id(' + role_id_key + ') value, or it is wrong value(' + JSON.stringify(role_id) + ').';
1047
+ }
1048
+ if (isError) {
1049
+ resobj.result = false;
1050
+ dbglogging_1.default.elog(resobj.message);
1051
+ dkcobj.clean();
1052
+ return resobj;
1053
+ }
1054
+ }
1055
+ // make token value
1056
+ const now_unixtime = k2hr3apiutil_1.default.getUnixtime();
1057
+ const token_value = {
1058
+ role: role_key, // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}"
1059
+ date: (new Date(now_unixtime * 1000)).toISOString(), // now date(UTC ISO 8601)
1060
+ expire: (new Date((now_unixtime + expire_limit) * 1000)).toISOString(), // expire date(UTC ISO 8601)
1061
+ creator: keys.USER_KEY, // "yrn:yahoo::::user:<user>"
1062
+ user: user, // user(creator)
1063
+ hostname: null, // hostname(creator)
1064
+ ip: null, // ip(creator)
1065
+ port: 0, // port(creator)
1066
+ cuk: null, // cuk(creator)
1067
+ extra: null, // extra(creator)
1068
+ tenant: tenant // tenant(scope)
1069
+ };
1070
+ // role token and yrn key
1071
+ let role_token = '';
1072
+ let token_role_key = null;
1073
+ // create key
1074
+ for (let is_loop = true; is_loop;) { // for eslint
1075
+ // make role token
1076
+ const token_elements = k2hr3apiutil_1.default.makeStringToken256(user_id, role_id);
1077
+ if (!k2hr3apiutil_1.default.isSafeEntity(token_elements)) {
1078
+ resobj.result = false;
1079
+ resobj.message = 'could not make token from ' + JSON.stringify(user_id) + ' and ' + JSON.stringify(role_id);
1080
+ dbglogging_1.default.elog(resobj.message);
1081
+ dkcobj.clean();
1082
+ return resobj;
1083
+ }
1084
+ role_token = token_elements.str_token;
1085
+ token_value.base = token_elements.str_base; // token base
1086
+ // role token key
1087
+ token_role_key = keys.TOKEN_ROLE_TOP_KEY + '/' + role_token; // "yrn:yahoo::::token:role/<role token>"
1088
+ // get role token for existing check
1089
+ const value = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(token_role_key, null, true, null));
1090
+ if (!k2hr3apiutil_1.default.isSafeString(value)) {
1091
+ // set value to role token
1092
+ if (!dkcobj.setValue(token_role_key, JSON.stringify(token_value), null, null, expire_limit)) { // set token value -> yrn:yahoo::::token:role/<role token>
1093
+ resobj.result = false;
1094
+ resobj.message = 'could not set ' + JSON.stringify(token_value) + ' value to ' + token_role_key + ' key';
1095
+ dbglogging_1.default.elog(resobj.message);
1096
+ dkcobj.clean();
1097
+ return resobj;
1098
+ }
1099
+ break;
1100
+ }
1101
+ else {
1102
+ dbglogging_1.default.dlog('conflict role token(' + role_token + ') which already is used, so remake token for uniq.');
1103
+ }
1104
+ }
1105
+ // Add token to role token top key's subkey list
1106
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.TOKEN_ROLE_TOP_KEY, true));
1107
+ if (k2hr3apiutil_1.default.isSafeString(token_role_key) && k2hr3apiutil_1.default.tryAddStringToArray(subkeylist, token_role_key)) {
1108
+ if (!dkcobj.setSubkeys(keys.TOKEN_ROLE_TOP_KEY, subkeylist)) { // add subkey yrn:yahoo::::token:role/<role token> -> yrn:yahoo::::token:role
1109
+ resobj.result = false;
1110
+ resobj.message = 'could not add ' + token_role_key + ' subkey under ' + keys.TOKEN_ROLE_TOP_KEY + ' key';
1111
+ dbglogging_1.default.elog(resobj.message);
1112
+ dkcobj.clean();
1113
+ return resobj;
1114
+ }
1115
+ }
1116
+ // Add token to role tokens key's subkey list
1117
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(role_tokens_key, true));
1118
+ if (k2hr3apiutil_1.default.isSafeString(token_role_key) && k2hr3apiutil_1.default.tryAddStringToArray(subkeylist, token_role_key)) {
1119
+ if (!dkcobj.setSubkeys(role_tokens_key, subkeylist)) { // add subkey yrn:yahoo::::token:role/<role token> -> yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens
1120
+ resobj.result = false;
1121
+ resobj.message = 'could not add ' + token_role_key + ' subkey under ' + role_tokens_key + ' key';
1122
+ dbglogging_1.default.elog(resobj.message);
1123
+ dkcobj.clean();
1124
+ return resobj;
1125
+ }
1126
+ }
1127
+ // Add role token into result object.
1128
+ resobj.token = role_token;
1129
+ dkcobj.clean();
1130
+ return resobj;
1131
+ };
1132
+ //---------------------------------------------------------
1133
+ // Get Role Token From ip address
1134
+ //---------------------------------------------------------
1135
+ // ip : ip address
1136
+ // port : port number(0, undefined, null means any port)
1137
+ // cuk : container unique key(undefined, null means any)
1138
+ // tenant : tenant name
1139
+ // role : target role name(full yrn or only role name)
1140
+ // expire_limit : specify expire second(default 24H = 24 * 60 * 60 sec)
1141
+ //
1142
+ // result : resTypeGetRoleToken = {
1143
+ // result: true/false
1144
+ // message: null or error message string
1145
+ // token: undefined(error) or role token string
1146
+ // }
1147
+ //
1148
+ // [NOTE]
1149
+ // set role token value is following:
1150
+ // dkcTypeRoleTokenValue = {
1151
+ // role: token's role yrn("yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}")
1152
+ // date: create date(UTC ISO 8601)
1153
+ // expire: expire date(UTC ISO 8601)
1154
+ // creator: creator yrn("yrn:yahoo::::user:<user>" or "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/hosts/ip/<ip:port>")
1155
+ // user: always null
1156
+ // hostname: always null
1157
+ // ip: if creator is host, this value is ip address.
1158
+ // port: if creator is host, this value is port number.(if not, this is 0)
1159
+ // cuk: if creator is host on iaas, this value is cuk.(allowed null)
1160
+ // extra: if creator is host on iaas, this value is extra.(allowed null)
1161
+ // tenant: tenant name for this role token(this mean token is scoped)
1162
+ // base: 32bytes hex string
1163
+ // }
1164
+ //
1165
+ // The role token which is built by host is made by only IP address.
1166
+ // Hostname can not build a role token, because it is not secure.(= Hostname can easily be disguised.)
1167
+ // Then only IP address can build a role token without UserToken.
1168
+ //
1169
+ const rawGetRoleTokenByIP = (ip, port, cuk, tenant, role, expire_limit) => {
1170
+ const resobj = { result: true, message: null };
1171
+ if (!k2hr3apiutil_1.default.isSafeString(tenant) || !k2hr3apiutil_1.default.isSafeString(role) || !k2hr3apiutil_1.default.isSafeString(ip)) { // allow other argument is empty
1172
+ resobj.result = false;
1173
+ resobj.message = 'some parameters are wrong : tenant=' + JSON.stringify(tenant) + ', role=' + JSON.stringify(role) + ', ip' + JSON.stringify(ip);
1174
+ dbglogging_1.default.elog(resobj.message);
1175
+ return resobj;
1176
+ }
1177
+ if (!k2hr3apiutil_1.default.isSafeNumber(port)) { // port must be number or null(undefined)
1178
+ port = 0; // force set port 0(any).
1179
+ }
1180
+ if (!k2hr3apiutil_1.default.isSafeString(cuk)) { // cuk is string if spacified
1181
+ cuk = null; // force set null.
1182
+ }
1183
+ if (!k2hr3apiutil_1.default.isSafeNumber(expire_limit)) { // expire_limit must be number or null(undefined)
1184
+ expire_limit = expire_rtoken; // default 24H
1185
+ }
1186
+ // check role name is only name or full yrn path
1187
+ const keys = r3keys(null, tenant);
1188
+ role = role.toLowerCase();
1189
+ let roleptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
1190
+ const rolematchs = role.match(roleptn);
1191
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(rolematchs) || rolematchs.length < 4) {
1192
+ // role is not matched role(maybe not full yrn), then we need check it is another yrn path
1193
+ roleptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
1194
+ if (role.match(roleptn)) {
1195
+ resobj.result = false;
1196
+ resobj.message = 'role(' + role + ') is not role yrn path)';
1197
+ dbglogging_1.default.elog(resobj.message);
1198
+ return resobj;
1199
+ }
1200
+ // role is only role name, then we do not modify it.
1201
+ }
1202
+ else {
1203
+ // check tenant name
1204
+ if (tenant !== rolematchs[2]) {
1205
+ resobj.result = false;
1206
+ resobj.message = 'role(' + role + ') yrn has tenant(' + rolematchs[2] + '), but it is not specified tenant(' + tenant + ')';
1207
+ dbglogging_1.default.elog(resobj.message);
1208
+ return resobj;
1209
+ }
1210
+ // role is set only role name
1211
+ role = rolematchs[3];
1212
+ }
1213
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
1214
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
1215
+ resobj.result = false;
1216
+ resobj.message = 'Not initialize yet.';
1217
+ dbglogging_1.default.elog(resobj.message);
1218
+ return resobj;
1219
+ }
1220
+ //
1221
+ // keys
1222
+ //
1223
+ const role_key = keys.ROLE_TOP_KEY + ':' + role; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}"
1224
+ const role_id_key = role_key + '/' + keys.ID_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/id"
1225
+ const role_tokens_key = role_key + '/' + keys.ROLE_TOKEN_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens"
1226
+ // find host key and get host id for base id
1227
+ const host_info = k2hr3dkc_1.default.findRoleHost(dkcobj, role_key, null, ip, port, cuk);
1228
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(host_info)) {
1229
+ resobj.result = false;
1230
+ resobj.message = 'Not found ip(' + ip + ') with port(' + String(port) + ') and cuk(' + JSON.stringify(cuk) + ') in tenant(' + tenant + ') + role(' + role + ')';
1231
+ dbglogging_1.default.elog(resobj.message);
1232
+ dkcobj.clean();
1233
+ return resobj;
1234
+ }
1235
+ let host_value = null;
1236
+ for (let pos = 0; pos < host_info.length; ++pos) {
1237
+ const host_info_tmp = host_info[pos];
1238
+ if (!k2hr3apiutil_1.default.isPlainObject(host_info_tmp) || !k2hr3apiutil_1.default.isSafeString(host_info_tmp.key)) {
1239
+ dbglogging_1.default.dlog('Found ip(' + ip + ') with port(' + String(port) + ') in tenant(' + tenant + ') + role(' + role + '), but this host info(' + JSON.stringify(host_info_tmp) + ') is something wrong, skip it');
1240
+ continue;
1241
+ }
1242
+ const host_value_tmp = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(host_info_tmp.key, null, true, null));
1243
+ host_value = k2hr3apiutil_1.default.parseJSON(host_value_tmp);
1244
+ if (!k2hr3apiutil_1.default.isPlainObject(host_value) ||
1245
+ (!k2hr3apiutil_1.default.isSafeString(host_value.hostname) && !k2hr3apiutil_1.default.isSafeString(host_value.ip)) || // hostname or ip is existed
1246
+ !k2hr3apiutil_1.default.isSafeEntity(host_value.port) ||
1247
+ !k2hr3apiutil_1.default.isSafeString(host_value[keys.ID_KW])) {
1248
+ dbglogging_1.default.dlog('Found ip(' + ip + ') with port(' + String(port) + ') in tenant(' + tenant + ') + role(' + role + '), but this host value(' + JSON.stringify(host_value) + ') is something wrong, skip it');
1249
+ }
1250
+ else {
1251
+ // found safe host info, we use this.
1252
+ host_value.key = host_info_tmp.key;
1253
+ host_value.cuk = host_info_tmp.cuk;
1254
+ host_value.extra = host_info_tmp.extra;
1255
+ break;
1256
+ }
1257
+ host_value = null;
1258
+ }
1259
+ if (!k2hr3apiutil_1.default.isPlainObject(host_value)) {
1260
+ resobj.result = false;
1261
+ resobj.message = 'Found ip(' + ip + ') with port(' + String(port) + ') in tenant(' + tenant + ') + role(' + role + '), but there is not safe any host info';
1262
+ dbglogging_1.default.elog(resobj.message);
1263
+ dkcobj.clean();
1264
+ return resobj;
1265
+ }
1266
+ // role id
1267
+ let role_id = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(role_id_key, null, true, null));
1268
+ if (!k2hr3apiutil_1.default.isSafeStrUuid4(role_id)) {
1269
+ let isError = false;
1270
+ const old_role_id = k2hr3apiutil_1.default.parseJSON(role_id);
1271
+ if (k2hr3apiutil_1.default.isNotEmptyArray(old_role_id) && 4 == old_role_id.length) {
1272
+ // old version id, so reset new valus(UUID4) here.
1273
+ role_id = k2hr3apiutil_1.default.getStrUuid4();
1274
+ if (!dkcobj.setValue(role_id_key, role_id)) { // set value -> yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/id
1275
+ isError = true;
1276
+ resobj.message = 'could not get role id(' + role_id_key + ') value, because failed to reset new role id instead of old id.';
1277
+ }
1278
+ }
1279
+ else {
1280
+ isError = true;
1281
+ resobj.message = 'could not get role id(' + role_id_key + ') value, or it is wrong value(' + JSON.stringify(role_id) + ').';
1282
+ }
1283
+ if (isError) {
1284
+ resobj.result = false;
1285
+ dbglogging_1.default.elog(resobj.message);
1286
+ dkcobj.clean();
1287
+ return resobj;
1288
+ }
1289
+ }
1290
+ // make token value
1291
+ const now_unixtime = k2hr3apiutil_1.default.getUnixtime();
1292
+ const tmp_date = (new Date(now_unixtime * 1000)).toISOString();
1293
+ const tmp_expire = (new Date((now_unixtime + expire_limit) * 1000)).toISOString();
1294
+ const tmp_creator = k2hr3apiutil_1.default.getSafeString(host_value.key);
1295
+ const tmp_ip = k2hr3apiutil_1.default.isSafeString(host_value.ip) ? host_value.ip : null;
1296
+ const tmp_port = k2hr3apiutil_1.default.cvtToNumber(host_value.port) ?? 0;
1297
+ const tmp_cuk = k2hr3apiutil_1.default.isSafeString(host_value.cuk) ? host_value.cuk : null;
1298
+ const tmp_extra = k2hr3apiutil_1.default.isSafeString(host_value.extra) ? host_value.extra : null;
1299
+ const token_value = {
1300
+ role: role_key, // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}"
1301
+ date: tmp_date, // now date(UTC ISO 8601)
1302
+ expire: tmp_expire, // expire date(UTC ISO 8601)
1303
+ creator: tmp_creator, // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/hosts/ip/<ip:port>"
1304
+ user: null, // user(creator)
1305
+ hostname: null, // hostname(null)
1306
+ ip: tmp_ip, // ip(creator)
1307
+ port: tmp_port, // port(creator)
1308
+ cuk: tmp_cuk, // cuk(creator)
1309
+ extra: tmp_extra, // extra(creator)
1310
+ tenant: tenant, // tenant(scope)
1311
+ };
1312
+ // role token and yrn key
1313
+ let role_token = '';
1314
+ let token_role_key = null;
1315
+ // create key
1316
+ for (let is_loop = true; is_loop;) { // for eslint
1317
+ // make role token
1318
+ const token_elements = k2hr3apiutil_1.default.makeStringToken256(host_value[keys.ID_KW], role_id);
1319
+ if (!k2hr3apiutil_1.default.isSafeEntity(token_elements)) {
1320
+ resobj.result = false;
1321
+ resobj.message = 'could not make token from ' + JSON.stringify(host_value[keys.ID_KW]) + ' and ' + JSON.stringify(role_id);
1322
+ dbglogging_1.default.elog(resobj.message);
1323
+ dkcobj.clean();
1324
+ return resobj;
1325
+ }
1326
+ role_token = token_elements.str_token;
1327
+ token_value.base = token_elements.str_base; // token base
1328
+ // role token key
1329
+ token_role_key = keys.TOKEN_ROLE_TOP_KEY + '/' + role_token; // "yrn:yahoo::::token:role/<role token>"
1330
+ // get role token for existing check
1331
+ const value = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(token_role_key, null, true, null));
1332
+ if (!k2hr3apiutil_1.default.isSafeString(value)) {
1333
+ // set value to role token
1334
+ if (!dkcobj.setValue(token_role_key, JSON.stringify(token_value), null, null, expire_limit)) { // set token value -> yrn:yahoo::::token:role/<role token>
1335
+ resobj.result = false;
1336
+ resobj.message = 'could not set ' + JSON.stringify(token_value) + ' value to ' + token_role_key + ' key';
1337
+ dbglogging_1.default.elog(resobj.message);
1338
+ dkcobj.clean();
1339
+ return resobj;
1340
+ }
1341
+ break;
1342
+ }
1343
+ else {
1344
+ dbglogging_1.default.dlog('conflict role token(' + role_token + ') which already is used, so remake token for uniq.');
1345
+ }
1346
+ }
1347
+ // Add token to role token top key's subkey list
1348
+ let subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.TOKEN_ROLE_TOP_KEY, true));
1349
+ if (k2hr3apiutil_1.default.isSafeString(token_role_key) && k2hr3apiutil_1.default.tryAddStringToArray(subkeylist, token_role_key)) {
1350
+ if (!dkcobj.setSubkeys(keys.TOKEN_ROLE_TOP_KEY, subkeylist)) { // add subkey yrn:yahoo::::token:role/<role token> -> yrn:yahoo::::token:role
1351
+ dbglogging_1.default.elog('could not add ' + token_role_key + ' subkey under ' + keys.TOKEN_ROLE_TOP_KEY + ' key');
1352
+ dkcobj.clean();
1353
+ return resobj;
1354
+ }
1355
+ }
1356
+ // Add token to role tokens key's subkey list
1357
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(role_tokens_key, true));
1358
+ if (k2hr3apiutil_1.default.isSafeString(token_role_key) && k2hr3apiutil_1.default.tryAddStringToArray(subkeylist, token_role_key)) {
1359
+ if (!dkcobj.setSubkeys(role_tokens_key, subkeylist)) { // add subkey yrn:yahoo::::token:role/<role token> -> yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens
1360
+ resobj.result = false;
1361
+ resobj.message = 'could not add ' + token_role_key + ' subkey under ' + role_tokens_key + ' key';
1362
+ dbglogging_1.default.elog(resobj.message);
1363
+ dkcobj.clean();
1364
+ return resobj;
1365
+ }
1366
+ }
1367
+ // Add role token into result object.
1368
+ resobj.token = role_token;
1369
+ dkcobj.clean();
1370
+ return resobj;
1371
+ };
1372
+ //---------------------------------------------------------
1373
+ // cleanup role by token
1374
+ //---------------------------------------------------------
1375
+ // utility local function
1376
+ //
1377
+ // [NOTE]
1378
+ // This process can be time consuming when subkey list is too many.
1379
+ // In that case, there is a possibility that the consistency of the subkey will be lost.
1380
+ // If a new token is added to the subkey list during processing with this function, that
1381
+ // token subkey will be overwritten(lost) when this function completes processing.
1382
+ // Originally, this subkey list of "yrn:yahoo::::token:role" key has no direct use, so this
1383
+ // is not a problem. Because it normally reads the sub key(token key) directly.
1384
+ // Please do not read subkey(token key) from the subkey list of "yrn:yahoo::::token:role" key.
1385
+ // This subkeys are only useful for "notes".
1386
+ //
1387
+ const rawCleanupRoleToken = (callback) => {
1388
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
1389
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
1390
+ callback(false);
1391
+ return;
1392
+ }
1393
+ const keys = r3keys();
1394
+ const subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.TOKEN_ROLE_TOP_KEY, true)); // get subkeys under "yrn:yahoo::::token:role"
1395
+ let is_changed = false;
1396
+ const newsubkeylist = new Array(0);
1397
+ for (let cnt = 0; cnt < subkeylist.length; ++cnt) {
1398
+ let role_tokens_key;
1399
+ // not use attributes for getting role path
1400
+ const value_tmp = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(subkeylist[cnt], null, false, null));
1401
+ let value = k2hr3apiutil_1.default.parseJSON(value_tmp);
1402
+ if (k2hr3apiutil_1.default.isPlainObject(value) && k2hr3apiutil_1.default.isSafeString(value.role)) {
1403
+ role_tokens_key = value.role + '/' + keys.ROLE_TOKEN_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens"
1404
+ }
1405
+ else {
1406
+ role_tokens_key = null;
1407
+ }
1408
+ // use attributes for getting role path
1409
+ value = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(subkeylist[cnt], null, true, null));
1410
+ if (!k2hr3apiutil_1.default.isSafeString(value)) {
1411
+ is_changed = true;
1412
+ // remove role token from role's tokens subkey
1413
+ if (null !== role_tokens_key) {
1414
+ const tokenlist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(role_tokens_key, true));
1415
+ if (k2hr3apiutil_1.default.removeStringFromArray(tokenlist, subkeylist[cnt])) {
1416
+ if (!dkcobj.setSubkeys(role_tokens_key, tokenlist)) { // update subkey -> yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens
1417
+ dbglogging_1.default.elog('could not update subkey under ' + role_tokens_key + ' key, but continue...');
1418
+ }
1419
+ }
1420
+ }
1421
+ }
1422
+ else {
1423
+ newsubkeylist.push(subkeylist[cnt]);
1424
+ }
1425
+ }
1426
+ if (false === is_changed) {
1427
+ dkcobj.clean();
1428
+ callback(true);
1429
+ return;
1430
+ }
1431
+ if (!dkcobj.setSubkeys(keys.TOKEN_ROLE_TOP_KEY, newsubkeylist)) { // add subkeys -> yrn:yahoo::::token:role
1432
+ dbglogging_1.default.elog('could not update subkeys(tokens) under ' + keys.TOKEN_ROLE_TOP_KEY + ' key');
1433
+ dkcobj.clean();
1434
+ callback(false);
1435
+ return;
1436
+ }
1437
+ dkcobj.clean();
1438
+ callback(true);
1439
+ };
1440
+ //---------------------------------------------------------
1441
+ // Remove Role Token by User/IP
1442
+ //---------------------------------------------------------
1443
+ // token : role token
1444
+ // user : this value is parsed from user token(or null)
1445
+ // tenant : this value is parsed from user token(or null)
1446
+ // ip : client ip address(or null)
1447
+ // port : port number when ip address parameter exists
1448
+ // cuk : cuk value when ip address parameter exists
1449
+ //
1450
+ // result : {
1451
+ // result: true/false
1452
+ // message: null or error message string
1453
+ // }
1454
+ //
1455
+ const rawRemoveRoleToken = (token, user, tenant, ip, port, cuk) => {
1456
+ const resobj = { result: true, message: null };
1457
+ if (!k2hr3apiutil_1.default.isSafeString(token)) { // allow other argument is empty
1458
+ resobj.result = false;
1459
+ resobj.message = 'token parameter is empty';
1460
+ dbglogging_1.default.elog(resobj.message);
1461
+ return resobj;
1462
+ }
1463
+ if ((k2hr3apiutil_1.default.isSafeString(ip) && (k2hr3apiutil_1.default.isSafeString(user) || k2hr3apiutil_1.default.isSafeString(tenant))) ||
1464
+ (!k2hr3apiutil_1.default.isSafeString(ip) && (!k2hr3apiutil_1.default.isSafeString(user) || !k2hr3apiutil_1.default.isSafeString(tenant)))) {
1465
+ resobj.result = false;
1466
+ resobj.message = 'tenant(' + JSON.stringify(tenant) + '), user(' + JSON.stringify(user) + '), ip(' + JSON.stringify(ip) + ') parameters are wrong pattern.';
1467
+ dbglogging_1.default.elog(resobj.message);
1468
+ return resobj;
1469
+ }
1470
+ let dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
1471
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
1472
+ resobj.result = false;
1473
+ resobj.message = 'Not initialize yet.';
1474
+ dbglogging_1.default.elog(resobj.message);
1475
+ return resobj;
1476
+ }
1477
+ //
1478
+ // keys
1479
+ //
1480
+ const keys = (k2hr3apiutil_1.default.isSafeString(ip) ? r3keys() : r3keys(user, tenant));
1481
+ const role_token_key = keys.TOKEN_ROLE_TOP_KEY + '/' + token; // "yrn:yahoo::::token:role/<role token>"
1482
+ // get role token value
1483
+ const value_tmp = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(role_token_key, null, true, null));
1484
+ const value = k2hr3apiutil_1.default.parseJSON(value_tmp);
1485
+ if (!k2hr3apiutil_1.default.isPlainObject(value)) {
1486
+ // already role token is removed or expired.
1487
+ dbglogging_1.default.dlog('could not get role token(' + role_token_key + ') value, or it is wrong value(' + JSON.stringify(value) + '). We check all role token for expire here.');
1488
+ dkcobj.clean();
1489
+ //
1490
+ // check and remove old role token under token top key("yrn:yahoo::::token:role") if old token is expired
1491
+ //
1492
+ // [NOTE]
1493
+ // This processing is taking time, so it runs asynchronously.
1494
+ // And for notes on this processing, refer to NOTE of rawCleanupRoleToken function.
1495
+ //
1496
+ rawCleanupRoleToken((result) => {
1497
+ if (!result) {
1498
+ dbglogging_1.default.wlog('Failed to cleanup expired role tokens under ' + keys.TOKEN_ROLE_TOP_KEY + ' key, but continue...');
1499
+ }
1500
+ });
1501
+ // return success
1502
+ return resobj;
1503
+ }
1504
+ // check token value
1505
+ if (!k2hr3apiutil_1.default.isSafeString(value.role) ||
1506
+ !k2hr3apiutil_1.default.isSafeString(value.date) ||
1507
+ !k2hr3apiutil_1.default.isSafeString(value.expire) ||
1508
+ !k2hr3apiutil_1.default.isSafeString(value.creator) ||
1509
+ (!k2hr3apiutil_1.default.isSafeString(value.user) && !k2hr3apiutil_1.default.isSafeString(value.hostname) && !k2hr3apiutil_1.default.isSafeString(value.ip)) ||
1510
+ !k2hr3apiutil_1.default.isSafeNumber(value.port) ||
1511
+ !k2hr3apiutil_1.default.isSafeString(value.tenant) ||
1512
+ !k2hr3apiutil_1.default.isSafeString(value.base)) {
1513
+ //
1514
+ // Not check expired token and ip address is empty here.
1515
+ //
1516
+ resobj.result = false;
1517
+ resobj.message = 'could not get role token(' + role_token_key + ') value, or it is wrong value(' + JSON.stringify(value) + ').';
1518
+ dbglogging_1.default.elog(resobj.message);
1519
+ dkcobj.clean();
1520
+ return resobj;
1521
+ }
1522
+ // check expire
1523
+ if (k2hr3apiutil_1.default.isExpired(value.expire)) {
1524
+ resobj.result = false;
1525
+ resobj.message = 'role token(' + role_token_key + ') is expired by expire date(' + value.expire + ').';
1526
+ dbglogging_1.default.elog(resobj.message);
1527
+ dkcobj.clean();
1528
+ return resobj;
1529
+ }
1530
+ // keep role tokens key for removing key in its subkey list.
1531
+ const role_tokens_key = value.role + '/' + keys.ROLE_TOKEN_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens"
1532
+ // check requester
1533
+ if (k2hr3apiutil_1.default.isSafeString(ip)) {
1534
+ // check ip address bases
1535
+ //
1536
+ // port
1537
+ if (!k2hr3apiutil_1.default.isSafeNumber(port)) {
1538
+ port = 0;
1539
+ }
1540
+ // cuk
1541
+ cuk = k2hr3apiutil_1.default.getSafeString(cuk).trim();
1542
+ if (!k2hr3apiutil_1.default.isSafeString(cuk)) {
1543
+ cuk = null;
1544
+ }
1545
+ // check
1546
+ if (value.port != port ||
1547
+ k2hr3apiutil_1.default.isSafeString(value.cuk) != k2hr3apiutil_1.default.isSafeString(cuk) ||
1548
+ k2hr3apiutil_1.default.getSafeString(value.cuk) != k2hr3apiutil_1.default.getSafeString(cuk)) {
1549
+ resobj.result = false;
1550
+ resobj.message = 'could not remove role token(' + token + '), because port(' + JSON.stringify(port) + ' vs ' + JSON.stringify(value.port) + ')/cuk(' + JSON.stringify(cuk) + ' vs ' + JSON.stringify(value.cuk) + ') value is not same.';
1551
+ dbglogging_1.default.elog(resobj.message);
1552
+ dkcobj.clean();
1553
+ return resobj;
1554
+ }
1555
+ // [NOTE]
1556
+ // findHost() is creating k2hdkc object in it, thus we close dkc object here.
1557
+ // and re-create dkc object after returning that function.
1558
+ //
1559
+ dkcobj.clean();
1560
+ const find_result = k2hr3dkc_1.default.findHost(value.tenant, value.role, null, ip, port, cuk, false); // not strict checking
1561
+ if (!find_result.result || !k2hr3apiutil_1.default.isNotEmptyArray(find_result.host_info)) {
1562
+ // ip address is not member of role
1563
+ resobj.result = false;
1564
+ resobj.message = 'could not remove role token(' + token + '), because ip(' + ip + ') is not role host member.';
1565
+ dbglogging_1.default.elog(resobj.message);
1566
+ return resobj;
1567
+ }
1568
+ dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // re-creating permanent object(need to clean)
1569
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
1570
+ resobj.result = false;
1571
+ resobj.message = 'Failed to re-initialize.';
1572
+ dbglogging_1.default.elog(resobj.message);
1573
+ return resobj;
1574
+ }
1575
+ }
1576
+ else {
1577
+ // check tenant name
1578
+ if (0 !== value.role.indexOf(keys.ROLE_TOP_KEY)) {
1579
+ // not same tenant name
1580
+ resobj.result = false;
1581
+ resobj.message = 'could not remove role token(' + token + '), because user(' + JSON.stringify(user) + ')/tenant(' + JSON.stringify(tenant) + ') is not role member.';
1582
+ dbglogging_1.default.elog(resobj.message);
1583
+ dkcobj.clean();
1584
+ return resobj;
1585
+ }
1586
+ }
1587
+ // remove token
1588
+ if (!dkcobj.remove(role_token_key, false)) { // remove yrn:yahoo::::token:role/<role token>
1589
+ resobj.result = false;
1590
+ resobj.message = 'could not remove role token(' + token + '), probably it is not existed.';
1591
+ dbglogging_1.default.elog(resobj.message);
1592
+ dkcobj.clean();
1593
+ return resobj;
1594
+ }
1595
+ let subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.TOKEN_ROLE_TOP_KEY, true));
1596
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, role_token_key)) {
1597
+ if (!dkcobj.setSubkeys(keys.TOKEN_ROLE_TOP_KEY, subkeylist)) { // update subkey -> yrn:yahoo::::token:role
1598
+ resobj.result = false;
1599
+ resobj.message = 'could not update subkey under ' + keys.TOKEN_ROLE_TOP_KEY + ' key';
1600
+ dbglogging_1.default.elog(resobj.message);
1601
+ dkcobj.clean();
1602
+ return resobj;
1603
+ }
1604
+ }
1605
+ // remove token key from role's tokens subkey.
1606
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(role_tokens_key, true));
1607
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, role_token_key)) {
1608
+ if (!dkcobj.setSubkeys(role_tokens_key, subkeylist)) { // update subkey -> yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens
1609
+ resobj.result = false;
1610
+ resobj.message = 'could not update subkey under ' + role_tokens_key + ' key';
1611
+ dbglogging_1.default.elog(resobj.message);
1612
+ dkcobj.clean();
1613
+ return resobj;
1614
+ }
1615
+ }
1616
+ dkcobj.clean();
1617
+ return resobj;
1618
+ };
1619
+ //---------------------------------------------------------
1620
+ // Remove Role Tokens Directly
1621
+ //---------------------------------------------------------
1622
+ // dkcobj_permanent : dkcobj object
1623
+ // tokens : array to role token yrn path
1624
+ //
1625
+ // result : true/false
1626
+ //
1627
+ const rawDirectRemoveRoleTokens = (dkcobj_permanent, tokens) => {
1628
+ if (!(dkcobj_permanent instanceof Object) || !dkcobj_permanent.isPermanent()) {
1629
+ dbglogging_1.default.elog('dkcobj_parameters are wrong : dkcobj_permanent=' + JSON.stringify(dkcobj_permanent));
1630
+ return false;
1631
+ }
1632
+ if (k2hr3apiutil_1.default.isSafeString(tokens)) {
1633
+ tokens = [tokens];
1634
+ }
1635
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(tokens)) {
1636
+ dbglogging_1.default.dlog('tokens(' + JSON.stringify(tokens) + ') is empty or not array');
1637
+ return true;
1638
+ }
1639
+ //
1640
+ // Keys
1641
+ //
1642
+ const keys = r3keys();
1643
+ const subkeylist = dkcobj_permanent.getSubkeys(keys.TOKEN_ROLE_TOP_KEY, true); // get subkeys under "yrn:yahoo::::token:role"
1644
+ const matchptn = keys.TOKEN_ROLE_TOP_KEY + '/'; // matching pattern "yrn:yahoo::::token:role/"
1645
+ let needupdate = false;
1646
+ // remove each token
1647
+ for (let cnt = 0; cnt < tokens.length; ++cnt) {
1648
+ if (!k2hr3apiutil_1.default.isSafeString(tokens[cnt])) {
1649
+ dbglogging_1.default.elog('token(' + JSON.stringify(tokens[cnt]) + ') yrn path is not string, but continue...');
1650
+ continue;
1651
+ }
1652
+ if (0 !== tokens[cnt].indexOf(matchptn)) {
1653
+ dbglogging_1.default.elog('token(' + JSON.stringify(tokens[cnt]) + ') is not full yrn path, but continue...');
1654
+ continue;
1655
+ }
1656
+ // remove token
1657
+ if (!dkcobj_permanent.remove(tokens[cnt], false)) { // remove yrn:yahoo::::token:role/<role token>
1658
+ dbglogging_1.default.elog('failed to remove token(' + JSON.stringify(tokens[cnt]) + '), but continue...');
1659
+ }
1660
+ else {
1661
+ // remove token from subkeys(token top key)
1662
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, tokens[cnt])) {
1663
+ needupdate = true;
1664
+ }
1665
+ }
1666
+ }
1667
+ if (needupdate) {
1668
+ if (!dkcobj_permanent.setSubkeys(keys.TOKEN_ROLE_TOP_KEY, subkeylist)) { // update subkey -> yrn:yahoo::::token:role
1669
+ dbglogging_1.default.elog('failed to reset role token subkeys to ' + keys.TOKEN_ROLE_TOP_KEY + ' top key, but continue...');
1670
+ }
1671
+ }
1672
+ return true;
1673
+ };
1674
+ //---------------------------------------------------------
1675
+ // Remove Role Token with checking tenant
1676
+ //---------------------------------------------------------
1677
+ // token_string : role token string
1678
+ // tenant : tenant name
1679
+ //
1680
+ // result : true/false
1681
+ //
1682
+ const rawRemoveRoleTokenByPath = (token_string, tenant) => {
1683
+ if (!k2hr3apiutil_1.default.isSafeString(token_string) || !k2hr3apiutil_1.default.isSafeString(tenant)) {
1684
+ dbglogging_1.default.elog('token_string(' + JSON.stringify(token_string) + ') or tenant(' + JSON.stringify(tenant) + ') parameter is something wrong.');
1685
+ return false;
1686
+ }
1687
+ //
1688
+ // Keys
1689
+ //
1690
+ const keys = r3keys(null, tenant);
1691
+ const role_token_key = keys.TOKEN_ROLE_TOP_KEY + '/' + token_string; // role token path "yrn:yahoo::::token:role/<token>"
1692
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
1693
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
1694
+ dbglogging_1.default.elog('Not initialize yet.');
1695
+ return false;
1696
+ }
1697
+ // get token value
1698
+ const value_tmp = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(role_token_key, null, true, null));
1699
+ const value = k2hr3apiutil_1.default.parseJSON(value_tmp);
1700
+ if (!k2hr3apiutil_1.default.isPlainObject(value) ||
1701
+ !k2hr3apiutil_1.default.isSafeString(value.role) ||
1702
+ !k2hr3apiutil_1.default.isSafeString(value.date) ||
1703
+ !k2hr3apiutil_1.default.isSafeString(value.expire) ||
1704
+ !k2hr3apiutil_1.default.isSafeString(value.creator) ||
1705
+ (!k2hr3apiutil_1.default.isSafeString(value.user) && !k2hr3apiutil_1.default.isSafeString(value.hostname) && !k2hr3apiutil_1.default.isSafeString(value.ip)) ||
1706
+ !k2hr3apiutil_1.default.isSafeNumber(value.port) ||
1707
+ !k2hr3apiutil_1.default.isSafeString(value.tenant) ||
1708
+ !k2hr3apiutil_1.default.isSafeString(value.base)) {
1709
+ dbglogging_1.default.elog('could not get role role_token_key(' + role_token_key + ') value, or it is wrong value(' + JSON.stringify(value) + ') or already expired.');
1710
+ dkcobj.clean();
1711
+ return false;
1712
+ }
1713
+ // check tenant name
1714
+ const roleptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
1715
+ const rolematchs = value.role.match(roleptn);
1716
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(rolematchs) || rolematchs.length < 4) {
1717
+ // token's role is not matched role yrn
1718
+ dbglogging_1.default.elog('role path(' + JSON.stringify(value.role) + ') in role token(' + role_token_key + ') value is not role yrn full path.');
1719
+ dkcobj.clean();
1720
+ return false;
1721
+ }
1722
+ if (tenant !== rolematchs[2]) {
1723
+ // tenant name is not matched.
1724
+ dbglogging_1.default.elog('tenant name(' + JSON.stringify(rolematchs[2]) + ') in role token(' + role_token_key + ') value is not as same as specified tenant(' + JSON.stringify(tenant) + ').');
1725
+ dkcobj.clean();
1726
+ return false;
1727
+ }
1728
+ // remove token
1729
+ if (!dkcobj.remove(role_token_key, false)) { // remove yrn:yahoo::::token:role/<role token>
1730
+ dbglogging_1.default.elog('failed to remove token(' + JSON.stringify(role_token_key) + ').');
1731
+ dkcobj.clean();
1732
+ return false;
1733
+ }
1734
+ // remove token from subkeys(token top key)
1735
+ let subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(keys.TOKEN_ROLE_TOP_KEY, true)); // get subkeys under "yrn:yahoo::::token:role"
1736
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, role_token_key)) {
1737
+ // update subkey
1738
+ if (!dkcobj.setSubkeys(keys.TOKEN_ROLE_TOP_KEY, subkeylist)) { // update subkey -> yrn:yahoo::::token:role
1739
+ dbglogging_1.default.elog('failed to reset role token subkeys to ' + keys.TOKEN_ROLE_TOP_KEY + ' top key, but continue...');
1740
+ }
1741
+ }
1742
+ // remove token key from role's tokens subkey.
1743
+ const role_tokens_key = value.role + '/' + keys.ROLE_TOKEN_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens"
1744
+ subkeylist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(role_tokens_key, true));
1745
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, role_token_key)) {
1746
+ if (!dkcobj.setSubkeys(role_tokens_key, subkeylist)) { // update subkey -> yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens
1747
+ dbglogging_1.default.elog('could not update subkey under ' + role_tokens_key + ' key, but continue...');
1748
+ }
1749
+ }
1750
+ dkcobj.clean();
1751
+ return true;
1752
+ };
1753
+ //---------------------------------------------------------
1754
+ // Get Role Token Directly
1755
+ //---------------------------------------------------------
1756
+ // dkcobj_permanent : dkcobj object
1757
+ // tokens : array to role token yrn path
1758
+ //
1759
+ // result : {
1760
+ // "token": {
1761
+ // date: create date(UTC ISO 8601)
1762
+ // expire: expire date(UTC ISO 8601)
1763
+ // user: user name if user created this token
1764
+ // hostname: hostname if this token was created by host(name)
1765
+ // ip: ip address if this token was created by ip
1766
+ // port: port number, if specified port when created token
1767
+ // cuk: cuk, if specified cuk when created token
1768
+ // },
1769
+ // ...
1770
+ // }
1771
+ // or null(if error)
1772
+ //
1773
+ const rawGetDirectRoleTokenInfo = (dkcobj_permanent, tokens) => {
1774
+ if (!(dkcobj_permanent instanceof Object) || !dkcobj_permanent.isPermanent()) {
1775
+ dbglogging_1.default.elog('dkcobj_parameters are wrong : dkcobj_permanent=' + JSON.stringify(dkcobj_permanent));
1776
+ return null;
1777
+ }
1778
+ if (k2hr3apiutil_1.default.isSafeString(tokens)) {
1779
+ tokens = [tokens];
1780
+ }
1781
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(tokens)) {
1782
+ dbglogging_1.default.dlog('tokens(' + JSON.stringify(tokens) + ') is empty or not array');
1783
+ return null;
1784
+ }
1785
+ //
1786
+ // Keys
1787
+ //
1788
+ const keys = r3keys();
1789
+ const matchptn = keys.TOKEN_ROLE_TOP_KEY + '/'; // matching pattern "yrn:yahoo::::token:role/"
1790
+ const resobj = {};
1791
+ for (let cnt = 0; cnt < tokens.length; ++cnt) {
1792
+ // check role token path and split token string
1793
+ if (!k2hr3apiutil_1.default.isSafeString(tokens[cnt])) {
1794
+ dbglogging_1.default.elog('token(' + JSON.stringify(tokens[cnt]) + ') yrn path is not string, but continue...');
1795
+ continue;
1796
+ }
1797
+ if (0 !== tokens[cnt].indexOf(matchptn)) {
1798
+ dbglogging_1.default.elog('token(' + JSON.stringify(tokens[cnt]) + ') is not full yrn path, but continue...');
1799
+ continue;
1800
+ }
1801
+ const token_key = tokens[cnt].split(matchptn)[1];
1802
+ // get/check role token value
1803
+ const value_tmp = k2hr3apiutil_1.default.getSafeString(dkcobj_permanent.getValue(tokens[cnt], null, true, null));
1804
+ const value = k2hr3apiutil_1.default.parseJSON(value_tmp);
1805
+ if (!k2hr3apiutil_1.default.isPlainObject(value) ||
1806
+ !k2hr3apiutil_1.default.isSafeString(value.role) ||
1807
+ !k2hr3apiutil_1.default.isSafeString(value.date) ||
1808
+ !k2hr3apiutil_1.default.isSafeString(value.expire) ||
1809
+ !k2hr3apiutil_1.default.isSafeString(value.creator) ||
1810
+ (!k2hr3apiutil_1.default.isSafeString(value.user) && !k2hr3apiutil_1.default.isSafeString(value.hostname) && !k2hr3apiutil_1.default.isSafeString(value.ip)) ||
1811
+ !k2hr3apiutil_1.default.isSafeNumber(value.port) ||
1812
+ !k2hr3apiutil_1.default.isSafeString(value.tenant) ||
1813
+ !k2hr3apiutil_1.default.isSafeString(value.base) ||
1814
+ !k2hr3apiutil_1.default.isSafeString(value.expire)) {
1815
+ dbglogging_1.default.dlog('could not get role token(' + tokens[cnt] + ') value, or it is wrong value(' + JSON.stringify(value) + ') or expired, thus skip this.');
1816
+ continue;
1817
+ }
1818
+ // check expire by token value
1819
+ if (k2hr3apiutil_1.default.isExpired(value.expire)) {
1820
+ // expired
1821
+ continue;
1822
+ }
1823
+ // add result
1824
+ resobj[token_key] = {
1825
+ user: (k2hr3apiutil_1.default.isSafeString(value.user) ? value.user : null),
1826
+ hostname: (k2hr3apiutil_1.default.isSafeString(value.hostname) ? value.hostname : null),
1827
+ ip: (k2hr3apiutil_1.default.isSafeString(value.ip) ? value.ip : null),
1828
+ port: value.port,
1829
+ cuk: (k2hr3apiutil_1.default.isSafeString(value.cuk) ? value.cuk : null),
1830
+ date: value.date,
1831
+ expire: value.expire
1832
+ };
1833
+ }
1834
+ return resobj;
1835
+ };
1836
+ //---------------------------------------------------------
1837
+ // Get List of Role Tokens
1838
+ //---------------------------------------------------------
1839
+ // role : role yrn full path or role name(path)
1840
+ // tenant : for checking role full yrn path
1841
+ // expand : whether to expand token information(default false)
1842
+ //
1843
+ // result : not expand
1844
+ // {
1845
+ // result: true/false
1846
+ // message: null or error message string
1847
+ // tokens: [
1848
+ // "role token",
1849
+ // ....
1850
+ // ]
1851
+ // }
1852
+ //
1853
+ // result : expand
1854
+ // {
1855
+ // result: true/false
1856
+ // message: null or error message string
1857
+ // tokens: {
1858
+ // "token": {
1859
+ // date: create date(UTC ISO 8601)
1860
+ // expire: expire date(UTC ISO 8601)
1861
+ // user: user name if user created this token
1862
+ // hostname: hostname if this token was created by host(name)
1863
+ // ip: ip address if this token was created by ip
1864
+ // port: port number, if specified port when created token
1865
+ // cuk: cuk, if specified cuk when created token
1866
+ // },
1867
+ // ...
1868
+ // }
1869
+ // }
1870
+ //
1871
+ const rawGetListRoleTokens = (role, tenant, expand) => {
1872
+ const resobj = { result: true, message: null };
1873
+ if (!k2hr3apiutil_1.default.isSafeString(role) || !k2hr3apiutil_1.default.isSafeString(tenant)) {
1874
+ resobj.result = false;
1875
+ resobj.message = 'role(' + JSON.stringify(role) + '), tenant(' + JSON.stringify(tenant) + ') parameters are wrong.';
1876
+ dbglogging_1.default.elog(resobj.message);
1877
+ return resobj;
1878
+ }
1879
+ if (!k2hr3apiutil_1.default.isBoolean(expand)) {
1880
+ expand = false;
1881
+ }
1882
+ // check role is full yrn path and tenant
1883
+ const keys = r3keys(null, tenant);
1884
+ const roleptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
1885
+ const rolematchs = role.match(roleptn);
1886
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(rolematchs) || rolematchs.length < 4) {
1887
+ // role is not full yrn
1888
+ resobj.result = false;
1889
+ resobj.message = 'role(' + JSON.stringify(role) + ') is nor full yrn path.';
1890
+ dbglogging_1.default.elog(resobj.message);
1891
+ return resobj;
1892
+ }
1893
+ else {
1894
+ // role is full yrn to role
1895
+ if (!k2hr3apiutil_1.default.compareCaseString(rolematchs[2], tenant)) {
1896
+ resobj.result = false;
1897
+ resobj.message = 'tenant(' + tenant + ') is not as same as tenant in role(' + role + ') full yrn.';
1898
+ dbglogging_1.default.elog(resobj.message);
1899
+ return resobj;
1900
+ }
1901
+ }
1902
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
1903
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
1904
+ resobj.result = false;
1905
+ resobj.message = 'Not initialize yet.';
1906
+ dbglogging_1.default.elog(resobj.message);
1907
+ return resobj;
1908
+ }
1909
+ // check role path(check id key under role key)
1910
+ const id_key = role + '/' + keys.ID_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/id"
1911
+ const value = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(id_key, null, true, null));
1912
+ if (!k2hr3apiutil_1.default.isSafeString(value)) {
1913
+ resobj.result = false;
1914
+ resobj.message = 'role(' + JSON.stringify(role) + ') does not exist';
1915
+ dbglogging_1.default.elog(resobj.message);
1916
+ dkcobj.clean();
1917
+ return resobj;
1918
+ }
1919
+ // get all role tokens
1920
+ const tokens_key = role + '/' + keys.ROLE_TOKEN_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/tokens"
1921
+ let tokenlist = k2hr3apiutil_1.default.getSafeStringArray(dkcobj.getSubkeys(tokens_key, true));
1922
+ if (expand) {
1923
+ // get each token information
1924
+ const token_info = rawGetDirectRoleTokenInfo(dkcobj, tokenlist);
1925
+ if (null === token_info) {
1926
+ resobj.tokens = {};
1927
+ }
1928
+ else {
1929
+ resobj.tokens = token_info;
1930
+ }
1931
+ }
1932
+ else {
1933
+ // set token list
1934
+ const tokenptn = new RegExp('^' + keys.MATCH_ANY_ROLE_TOKEN); // regex = /^yrn:yahoo::::token:role\/(.*)/
1935
+ const token_info_list = [];
1936
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(tokenlist)) { // token list is full yrn path
1937
+ tokenlist = [];
1938
+ }
1939
+ for (let cnt = 0; cnt < tokenlist.length; ++cnt) {
1940
+ if (!k2hr3apiutil_1.default.isSafeString(tokenlist[cnt])) {
1941
+ dbglogging_1.default.wlog('Found wrong token string(' + JSON.stringify(tokenlist[cnt]) + ') in token list, skip this.');
1942
+ }
1943
+ else {
1944
+ const tokenmatches = tokenlist[cnt].match(tokenptn);
1945
+ if (k2hr3apiutil_1.default.isNotEmptyArray(tokenmatches) && 2 <= tokenmatches.length && k2hr3apiutil_1.default.isSafeString(tokenmatches[1])) {
1946
+ token_info_list.push(tokenmatches[1]);
1947
+ }
1948
+ else {
1949
+ dbglogging_1.default.wlog('Found wrong token string(' + JSON.stringify(tokenlist[cnt]) + ') in token list, skip this.');
1950
+ }
1951
+ }
1952
+ }
1953
+ resobj.tokens = token_info_list;
1954
+ }
1955
+ dkcobj.clean();
1956
+ return resobj;
1957
+ };
1958
+ //---------------------------------------------------------
1959
+ // Check Role Token
1960
+ //---------------------------------------------------------
1961
+ // token : role token
1962
+ // ip : client ip address
1963
+ // port : if is_strict is true, check port number
1964
+ // cuk : if is_strict is true, check cuk
1965
+ // is_strict : true means strict checking
1966
+ //
1967
+ // result : null or token information
1968
+ // {
1969
+ // role: role name
1970
+ // user: null or user name
1971
+ // hostname: null or host name
1972
+ // ip: null or ip address
1973
+ // port: port number(if host is existed), 0 means any
1974
+ // cuk: cuk(allowed null)
1975
+ // extra: extra(allowed null)
1976
+ // tenant: tenant name
1977
+ // display: display alias name for tenant
1978
+ // id: tenant id string
1979
+ // description: description for tenant
1980
+ // scoped: role token is always scoped(true)
1981
+ // region: role token is always null
1982
+ // }
1983
+ //
1984
+ const rawCheckRoleToken = (token, ip, port, cuk, is_strict) => {
1985
+ if (!k2hr3apiutil_1.default.isSafeString(token)) {
1986
+ dbglogging_1.default.elog('some parameters are wrong : token=' + JSON.stringify(token));
1987
+ return null;
1988
+ }
1989
+ if (!k2hr3apiutil_1.default.isSafeEntity(port)) {
1990
+ port = 0;
1991
+ }
1992
+ else if (!k2hr3apiutil_1.default.isSafeNumber(port)) {
1993
+ dbglogging_1.default.elog('port(' + JSON.stringify(port) + ') parameter is wrong.');
1994
+ return null;
1995
+ }
1996
+ if (!k2hr3apiutil_1.default.isSafeString(cuk)) {
1997
+ cuk = null;
1998
+ }
1999
+ if (!k2hr3apiutil_1.default.isBoolean(is_strict)) {
2000
+ is_strict = false;
2001
+ }
2002
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
2003
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
2004
+ return null;
2005
+ }
2006
+ //
2007
+ // keys
2008
+ //
2009
+ let keys = r3keys();
2010
+ const role_token_key = keys.TOKEN_ROLE_TOP_KEY + '/' + token; // "yrn:yahoo::::token:role/<role token>"
2011
+ // get role token value
2012
+ const value_tmp = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(role_token_key, null, true, null));
2013
+ const value = k2hr3apiutil_1.default.parseJSON(value_tmp);
2014
+ if (!k2hr3apiutil_1.default.isPlainObject(value)) {
2015
+ dbglogging_1.default.dlog('could not get role token(' + role_token_key + ') value, or it is wrong value(' + JSON.stringify(value) + '). We check all role token for expire here.');
2016
+ dkcobj.clean();
2017
+ //
2018
+ // check and remove old role token under token top key("yrn:yahoo::::token:role") if old token is expired
2019
+ //
2020
+ // [NOTE]
2021
+ // This processing is taking time, so it runs asynchronously.
2022
+ // And for notes on this processing, refer to NOTE of rawCleanupRoleToken function.
2023
+ //
2024
+ rawCleanupRoleToken((result) => {
2025
+ if (!result) {
2026
+ dbglogging_1.default.wlog('Failed to cleanup expired role tokens under ' + keys.TOKEN_ROLE_TOP_KEY + ' key, but continue...');
2027
+ }
2028
+ });
2029
+ return null;
2030
+ }
2031
+ if (!k2hr3apiutil_1.default.isSafeString(value.role) ||
2032
+ !k2hr3apiutil_1.default.isSafeString(value.date) ||
2033
+ !k2hr3apiutil_1.default.isSafeString(value.expire) ||
2034
+ !k2hr3apiutil_1.default.isSafeString(value.creator) ||
2035
+ (!k2hr3apiutil_1.default.isSafeString(value.user) && !k2hr3apiutil_1.default.isSafeString(value.hostname) && !k2hr3apiutil_1.default.isSafeString(value.ip)) ||
2036
+ !k2hr3apiutil_1.default.isSafeNumber(value.port) ||
2037
+ !k2hr3apiutil_1.default.isSafeString(value.tenant) ||
2038
+ !k2hr3apiutil_1.default.isSafeString(value.base) ||
2039
+ (null !== value.ip && undefined !== value.ip && !k2hr3apiutil_1.default.isSafeString(value.ip)) ||
2040
+ (null !== value.cuk && undefined !== value.cuk && !k2hr3apiutil_1.default.isSafeString(value.cuk)) ||
2041
+ (null !== value.extra && undefined !== value.extra && !k2hr3apiutil_1.default.isSafeString(value.extra))) {
2042
+ //
2043
+ // Not check expired token and ip address is empty here.
2044
+ //
2045
+ dbglogging_1.default.dlog('could not get role token(' + role_token_key + ') value, or it is wrong value(' + JSON.stringify(value) + ').');
2046
+ dkcobj.clean();
2047
+ return null;
2048
+ }
2049
+ const tmp_role = value.role;
2050
+ //const tmp_date = value.date;
2051
+ const tmp_expire = value.expire;
2052
+ //const tmp_creator = value.creator;
2053
+ const tmp_user = k2hr3apiutil_1.default.isSafeString(value.user) ? value.user : null;
2054
+ const tmp_hostname = k2hr3apiutil_1.default.isSafeString(value.hostname) ? value.hostname : null;
2055
+ const tmp_port = value.port;
2056
+ const tmp_tenant = value.tenant;
2057
+ const tmp_base = value.base;
2058
+ const tmp_ip = k2hr3apiutil_1.default.isSafeString(value.ip) ? value.ip : null;
2059
+ const tmp_cuk = k2hr3apiutil_1.default.isSafeString(value.cuk) ? value.cuk : null;
2060
+ const tmp_extra = k2hr3apiutil_1.default.isSafeString(value.extra) ? value.extra : null;
2061
+ // Get tenant information
2062
+ const tenant_keys = r3keys(null, value.tenant);
2063
+ const tmp_display = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(tenant_keys.TENANT_DISP_KEY, null, true, null));
2064
+ const tmp_id = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(tenant_keys.TENANT_ID_KEY, null, true, null));
2065
+ const tmp_description = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(tenant_keys.TENANT_DESC_KEY, null, true, null));
2066
+ // compare ip address, if they are specified and token is not created by user
2067
+ if (!k2hr3apiutil_1.default.isSafeString(tmp_user)) {
2068
+ if (!k2hr3apiutil_1.default.isSafeString(ip) || ip !== tmp_ip) {
2069
+ dbglogging_1.default.dlog('role token(' + role_token_key + ') has value(' + JSON.stringify(value) + '), but it is not same ip(' + ip + ').');
2070
+ dkcobj.clean();
2071
+ return null;
2072
+ }
2073
+ // strict checking
2074
+ if (is_strict) {
2075
+ if (tmp_port != port ||
2076
+ !k2hr3apiutil_1.default.isSafeString(tmp_cuk) != k2hr3apiutil_1.default.isSafeString(cuk) ||
2077
+ (k2hr3apiutil_1.default.isSafeString(tmp_cuk) && tmp_cuk != cuk)) {
2078
+ dbglogging_1.default.dlog('failed strictly checking role token(' + role_token_key + ').');
2079
+ dkcobj.clean();
2080
+ return null;
2081
+ }
2082
+ }
2083
+ }
2084
+ // check expire
2085
+ if (k2hr3apiutil_1.default.isExpired(tmp_expire)) {
2086
+ dbglogging_1.default.dlog('token(' + token + ') is expired.');
2087
+ dkcobj.clean();
2088
+ return null;
2089
+ }
2090
+ // get seed id(user id or host(ip) id)
2091
+ let seed_id;
2092
+ if (!k2hr3apiutil_1.default.isSafeString(tmp_user)) {
2093
+ // creator is host(ip), then get it's id
2094
+ const host_value_tmp = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(value.creator, null, true, null)); // get value from "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/hosts/ip/<ip:port>"
2095
+ const host_value = k2hr3apiutil_1.default.parseJSON(host_value_tmp);
2096
+ if (!k2hr3apiutil_1.default.isPlainObject(host_value) ||
2097
+ (!k2hr3apiutil_1.default.isSafeString(host_value.hostname) && !k2hr3apiutil_1.default.isSafeString(host_value.ip)) || // hostname or ip is existed
2098
+ !k2hr3apiutil_1.default.isSafeEntity(host_value.port) ||
2099
+ !k2hr3apiutil_1.default.isSafeString(host_value[keys.ID_KW])) {
2100
+ dbglogging_1.default.dlog('could not get host or ip(' + value.creator + ') value, or it is wrong value(' + JSON.stringify(host_value) + ').');
2101
+ dkcobj.clean();
2102
+ return null;
2103
+ }
2104
+ seed_id = k2hr3apiutil_1.default.getSafeString(host_value[keys.ID_KW]);
2105
+ }
2106
+ else {
2107
+ // creator is user, then get user's id
2108
+ const user_id_key = value.creator + ':' + keys.ID_KW; // "yrn:yahoo::::user:<user name>:id"
2109
+ seed_id = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(user_id_key, null, true, null));
2110
+ if (!k2hr3apiutil_1.default.isSafeString(seed_id)) {
2111
+ dbglogging_1.default.dlog('could not get user id(' + user_id_key + ') value, or it is wrong value(' + JSON.stringify(seed_id) + ').');
2112
+ dkcobj.clean();
2113
+ return null;
2114
+ }
2115
+ }
2116
+ // get role id for verify
2117
+ keys = r3keys(null, value.tenant); // remake keys
2118
+ const role_key = tmp_role; // role member is full yrn => "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}"
2119
+ const role_id_key = role_key + '/' + keys.ID_KW; // "yrn:yahoo:<service>::<tenant>:role:<role>{/<role>{...}}/id"
2120
+ const role_id = k2hr3apiutil_1.default.getSafeString(dkcobj.getValue(role_id_key, null, true, null));
2121
+ if (!k2hr3apiutil_1.default.isSafeStrUuid4(role_id)) {
2122
+ dbglogging_1.default.dlog('could not get role id(' + role_id_key + ') value, or it is wrong value(' + JSON.stringify(role_id) + '), maybe expired this token');
2123
+ dkcobj.clean();
2124
+ return null;
2125
+ }
2126
+ dkcobj.clean();
2127
+ // make verify token
2128
+ const token_elements = k2hr3apiutil_1.default.makeStringToken256(seed_id, role_id, tmp_base);
2129
+ if (!k2hr3apiutil_1.default.isSafeEntity(token_elements)) {
2130
+ dbglogging_1.default.dlog('could not make verify token from ' + JSON.stringify(seed_id) + ' and ' + JSON.stringify(role_id) + ' and ' + JSON.stringify(value));
2131
+ dkcobj.clean();
2132
+ return null;
2133
+ }
2134
+ if (token !== token_elements.str_token) {
2135
+ dbglogging_1.default.elog('token(' + token + ') verify is failure, verify token is ' + token_elements.str_token + '.');
2136
+ dkcobj.clean();
2137
+ return null;
2138
+ }
2139
+ // make result
2140
+ const token_info = {
2141
+ role: tmp_role,
2142
+ user: tmp_user,
2143
+ hostname: tmp_hostname, // hostname
2144
+ ip: tmp_ip,
2145
+ port: tmp_port,
2146
+ cuk: tmp_cuk,
2147
+ extra: tmp_extra,
2148
+ tenant: tmp_tenant,
2149
+ display: tmp_display,
2150
+ id: tmp_id,
2151
+ description: tmp_description,
2152
+ scoped: true, // role token is always scoped
2153
+ region: null
2154
+ };
2155
+ return token_info;
2156
+ };
2157
+ //---------------------------------------------------------
2158
+ // get tenant list by user(with DKC)
2159
+ //---------------------------------------------------------
2160
+ // result [
2161
+ // {
2162
+ // name: "tenant name", => tenant name which is "key" in k2hdkc
2163
+ // display: "display tenant name" => display alias name for tenant
2164
+ // id: "tenant id" => tenant id string
2165
+ // description: "tenant description" => description for tenant
2166
+ // },
2167
+ // ...
2168
+ // ]
2169
+ //
2170
+ // [NOTE] Must initialize User/Tenant before calling this function.
2171
+ //
2172
+ const rawGetTenantListByUserWithDkc = (dkcobj_permanent, user) => {
2173
+ if (!(dkcobj_permanent instanceof Object) || !dkcobj_permanent.isPermanent()) {
2174
+ dbglogging_1.default.elog('dkcobj_parameters are wrong : dkcobj_permanent=' + JSON.stringify(dkcobj_permanent));
2175
+ return null;
2176
+ }
2177
+ if (!k2hr3apiutil_1.default.isSafeString(user)) {
2178
+ dbglogging_1.default.elog('user parameters are wrong : user=' + JSON.stringify(user));
2179
+ return null;
2180
+ }
2181
+ //
2182
+ // Get subkeys under token top key
2183
+ //
2184
+ const keys = r3keys(user);
2185
+ const subkeylist = dkcobj_permanent.getSubkeys(keys.USER_TENANT_TOP_KEY, true); // get subkeys from "yrn:yahoo::::user:<user>:tenant"
2186
+ // remove no tenant key in tenant subkey list
2187
+ if (k2hr3apiutil_1.default.removeStringFromArray(subkeylist, keys.USER_TENANT_COMMON_KEY)) { // remove "yrn:yahoo::::user:<user>:tenant/"
2188
+ dbglogging_1.default.dlog('found ' + keys.USER_TENANT_COMMON_KEY + ' subkey in ' + keys.USER_TENANT_TOP_KEY + ' = user(' + user + ') tenant top key');
2189
+ }
2190
+ else {
2191
+ dbglogging_1.default.dlog('not found ' + keys.USER_TENANT_COMMON_KEY + ' subkey in ' + keys.USER_TENANT_TOP_KEY + ' = user(' + user + ') tenant top key');
2192
+ }
2193
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(subkeylist)) {
2194
+ dbglogging_1.default.wlog('There is no tenant for user(' + user + ')');
2195
+ return null;
2196
+ }
2197
+ // modify tenant name from yrn full path to only tenant name
2198
+ const pattern = new RegExp('^' + keys.USER_TENANT_COMMON_KEY + '(.*)'); // regex = /^yrn:yahoo::::user:<user>\:tenant\/(.*)/
2199
+ const name_list = [];
2200
+ for (let cnt = 0; cnt < subkeylist.length; ++cnt) {
2201
+ const tenant_matches = subkeylist[cnt].match(pattern); // reverse to tenant name
2202
+ if (k2hr3apiutil_1.default.isNotEmptyArray(tenant_matches) && 2 <= tenant_matches.length && '' !== k2hr3apiutil_1.default.getSafeString(tenant_matches[1])) {
2203
+ name_list.push(k2hr3apiutil_1.default.getSafeString(tenant_matches[1]));
2204
+ }
2205
+ }
2206
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(name_list)) {
2207
+ dbglogging_1.default.wlog('There is no tenant for user(' + user + ')');
2208
+ return null;
2209
+ }
2210
+ // get display name for each tenant
2211
+ const tenant_list = [];
2212
+ for (let cnt = 0; cnt < name_list.length; ++cnt) {
2213
+ const tenant_keys = r3keys(user, name_list[cnt]);
2214
+ const tenant_display = k2hr3apiutil_1.default.getSafeString(dkcobj_permanent.getValue(tenant_keys.TENANT_DISP_KEY, null, true, null));
2215
+ const tenant_id = k2hr3apiutil_1.default.getSafeString(dkcobj_permanent.getValue(tenant_keys.TENANT_ID_KEY, null, true, null));
2216
+ const tenant_desc = k2hr3apiutil_1.default.getSafeString(dkcobj_permanent.getValue(tenant_keys.TENANT_DESC_KEY, null, true, null));
2217
+ tenant_list.push({
2218
+ name: name_list[cnt],
2219
+ display: tenant_display,
2220
+ id: tenant_id,
2221
+ description: tenant_desc
2222
+ });
2223
+ }
2224
+ return tenant_list;
2225
+ };
2226
+ //---------------------------------------------------------
2227
+ // get tenant list by user
2228
+ //---------------------------------------------------------
2229
+ // result [
2230
+ // {
2231
+ // name: "tenant name", => tenant name which is "key" in k2hdkc
2232
+ // display: "display tenant name" => display alias name for tenant
2233
+ // id: "tenant id" => tenant id string
2234
+ // description: "tenant description" => description for tenant
2235
+ // },
2236
+ // ...
2237
+ // ]
2238
+ //
2239
+ // [NOTE] Must initialize User/Tenant before calling this function.
2240
+ //
2241
+ const rawGetTenantListByUser = (user) => {
2242
+ const dkcobj = k2hr3dkc_1.default.getK2hdkc(true, false); // use permanent object(need to clean)
2243
+ if (!k2hr3apiutil_1.default.isSafeEntity(dkcobj)) {
2244
+ return null;
2245
+ }
2246
+ const result = rawGetTenantListByUserWithDkc(dkcobj, user);
2247
+ dkcobj.clean();
2248
+ return result;
2249
+ };
2250
+ //---------------------------------------------------------
2251
+ // Initialize tenant list
2252
+ //---------------------------------------------------------
2253
+ const rawInitializeTenantListByToken = (unscopedtoken, username, userid, callback) => {
2254
+ const _callback = callback;
2255
+ if (!k2hr3apiutil_1.default.isSafeEntity(osapi)) {
2256
+ const error = new Error('could not load osapi file(object)');
2257
+ dbglogging_1.default.elog(error.message);
2258
+ _callback(error, null);
2259
+ return;
2260
+ }
2261
+ if (!k2hr3apiutil_1.default.isSafeString(unscopedtoken) || !k2hr3apiutil_1.default.isSafeString(username) || !k2hr3apiutil_1.default.isSafeString(userid)) {
2262
+ const error = new Error('unscopedtoken or username or userid parameters are wrong');
2263
+ dbglogging_1.default.elog(error.message);
2264
+ _callback(error, null);
2265
+ return;
2266
+ }
2267
+ const _unscopedtoken = unscopedtoken;
2268
+ const _username = username;
2269
+ const _userid = userid;
2270
+ // get tenant list for check
2271
+ osapi.getUserTenantList(_unscopedtoken, _userid, (err, jsonres) => {
2272
+ if (null !== err || null === jsonres) {
2273
+ const error = new Error('could not get tenant list for user ' + _username + '(token=' + _unscopedtoken + ') by ' + (err?.message ?? 'unknown'));
2274
+ dbglogging_1.default.elog(error.message);
2275
+ _callback(error, null);
2276
+ return;
2277
+ }
2278
+ //r3logger.dlog('get user tenant list jsonres=\n' + JSON.stringify(jsonres));
2279
+ // check tenants(and initialize tenants)
2280
+ const _name_list = [];
2281
+ const _tenant_list = [];
2282
+ for (let cnt = 0; cnt < jsonres.length; ++cnt) {
2283
+ if (!k2hr3apiutil_1.default.isSafeEntity(jsonres[cnt])) {
2284
+ continue;
2285
+ }
2286
+ // over write
2287
+ const resobj = k2hr3dkc_1.default.initUserTenant(_username, _userid, _username, jsonres[cnt].name, jsonres[cnt].id, jsonres[cnt].description, jsonres[cnt].display);
2288
+ if (!resobj.result) {
2289
+ const error = new Error(resobj.message ?? '');
2290
+ dbglogging_1.default.elog(error.message);
2291
+ _callback(error, null);
2292
+ return;
2293
+ }
2294
+ _name_list.push(jsonres[cnt].name);
2295
+ _tenant_list.push({
2296
+ name: jsonres[cnt].name,
2297
+ display: k2hr3apiutil_1.default.getSafeString(jsonres[cnt].display)
2298
+ });
2299
+ }
2300
+ // get and add local tenants
2301
+ const tmpresobj = k2hr3dkc_1.default.listLocalTenant(_username, true);
2302
+ if (!k2hr3apiutil_1.default.isPlainObject(tmpresobj) || !k2hr3apiutil_1.default.isSafeEntity(tmpresobj.result) || false === tmpresobj.result || !k2hr3apiutil_1.default.isSafeEntity(tmpresobj.tenants)) {
2303
+ if (k2hr3apiutil_1.default.isPlainObject(tmpresobj) && k2hr3apiutil_1.default.isSafeString(tmpresobj.message)) {
2304
+ dbglogging_1.default.wlog('failed to get local tenant list by ' + tmpresobj.message);
2305
+ }
2306
+ else {
2307
+ dbglogging_1.default.wlog('failed to get local tenant list.');
2308
+ }
2309
+ }
2310
+ else {
2311
+ if (k2hr3apiutil_1.default.isNotEmptyArray(tmpresobj.tenants)) {
2312
+ for (let cnt2 = 0; cnt2 < tmpresobj.tenants.length; ++cnt2) {
2313
+ const tmpTenatInfo = tmpresobj.tenants[cnt2];
2314
+ if (k2hr3dkc_1.default.isDkcTypeTenantInfo(tmpTenatInfo)) {
2315
+ _name_list.push(tmpTenatInfo.name);
2316
+ _tenant_list.push({
2317
+ name: tmpTenatInfo.name,
2318
+ display: k2hr3apiutil_1.default.getSafeString(tmpTenatInfo.display)
2319
+ });
2320
+ }
2321
+ else if (k2hr3apiutil_1.default.isStringArray(tmpTenatInfo)) {
2322
+ _name_list.push(tmpTenatInfo);
2323
+ _tenant_list.push({
2324
+ name: tmpTenatInfo,
2325
+ display: ''
2326
+ });
2327
+ }
2328
+ }
2329
+ }
2330
+ }
2331
+ // check and remove old tenant for user
2332
+ if (!k2hr3dkc_1.default.removeComprehensionByNewTenants(_username, _name_list)) {
2333
+ dbglogging_1.default.elog('failed to remove some tenant for user, but continue...');
2334
+ }
2335
+ // succeed
2336
+ _callback(null, _tenant_list);
2337
+ return;
2338
+ });
2339
+ };
2340
+ //---------------------------------------------------------
2341
+ // Initialize tenant list by unscoped user token
2342
+ //---------------------------------------------------------
2343
+ const rawInitializeTenantListByUnscoped = (unscopedtoken, username, callback) => {
2344
+ if (!k2hr3apiutil_1.default.isSafeString(unscopedtoken) || !k2hr3apiutil_1.default.isSafeString(username)) {
2345
+ const error = new Error('unscopedtoken or username parameters are wrong');
2346
+ dbglogging_1.default.elog(error.message);
2347
+ callback(error, null);
2348
+ return;
2349
+ }
2350
+ // user id from user name
2351
+ const user_info = k2hr3dkc_1.default.getUserId(username); // user id from user name
2352
+ if (null === user_info || !k2hr3apiutil_1.default.isSafeEntity(user_info.name) || !k2hr3apiutil_1.default.isSafeEntity(user_info.id)) {
2353
+ const error = new Error('could not find username(' + username + ') from unscoped token in k2hdkc.');
2354
+ dbglogging_1.default.elog(error.message);
2355
+ callback(error, null);
2356
+ return;
2357
+ }
2358
+ // get scoped user token
2359
+ return rawInitializeTenantListByToken(unscopedtoken, user_info.name, user_info.id, callback);
2360
+ };
2361
+ const rawCheckTenantInTenantList = (tenants, tenant) => {
2362
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(tenants) || !k2hr3apiutil_1.default.isSafeString(tenant)) {
2363
+ return false;
2364
+ }
2365
+ for (let cnt = 0; cnt < tenants.length; ++cnt) {
2366
+ if (!k2hr3apiutil_1.default.isSafeString(tenants[cnt].name)) {
2367
+ continue;
2368
+ }
2369
+ if (String(tenants[cnt].name).trim().toLowerCase() === String(tenant).trim().toLowerCase()) {
2370
+ // found
2371
+ return true;
2372
+ }
2373
+ }
2374
+ return false;
2375
+ };
2376
+ //---------------------------------------------------------
2377
+ // Check Token Automatically
2378
+ //---------------------------------------------------------
2379
+ // req : request from http(s)
2380
+ // is_scoped : check scoped token(default not scoped check)
2381
+ // is_user : = true : token must be user token
2382
+ // = false : token must be role token
2383
+ // = other : both token type is allowed, automatically checking.
2384
+ //
2385
+ // result : {
2386
+ // result: true/false
2387
+ // message: null or error message string
2388
+ // status: status code
2389
+ // token: undefined(error) or token string
2390
+ // token_type; undefined(error) or "user" or "role"
2391
+ // token_info: undefined(error) or token information object
2392
+ // }
2393
+ //
2394
+ // token is following:
2395
+ // {
2396
+ // role: role name
2397
+ // user: null or user name
2398
+ // hostname: null or host name
2399
+ // ip: null or host ip address
2400
+ // port: port number(if host is existed), 0 means any
2401
+ // cuk: cuk(allowed null)
2402
+ // extra: extra(allowed null)
2403
+ // tenant: tenant name
2404
+ // display: display alias name for tenant
2405
+ // id: tenant id string
2406
+ // description: description for tenant
2407
+ // scoped: role token is always scoped(true)
2408
+ // region: role token is always null / user token is the creator region name of the token
2409
+ // }
2410
+ const rawCheckToken = (req, is_scoped, is_user) => {
2411
+ const resobj = { result: true, status: 200, message: null };
2412
+ if (!k2hr3apiutil_1.default.isPlainObject(req)) {
2413
+ resobj.result = false;
2414
+ resobj.message = 'POST body does not have policy data';
2415
+ resobj.status = 400; // 400: Bad Request
2416
+ dbglogging_1.default.elog(resobj.message);
2417
+ return resobj;
2418
+ }
2419
+ if (!k2hr3apiutil_1.default.isBoolean(is_scoped)) {
2420
+ is_scoped = false; // default no scope check
2421
+ }
2422
+ let user_type = true;
2423
+ let role_type = true;
2424
+ if (k2hr3apiutil_1.default.isBoolean(is_user)) {
2425
+ if (is_user) {
2426
+ role_type = false;
2427
+ }
2428
+ else {
2429
+ user_type = false;
2430
+ }
2431
+ }
2432
+ //------------------------------
2433
+ // check token
2434
+ //------------------------------
2435
+ let token;
2436
+ let token_type;
2437
+ let token_info;
2438
+ if (rawIsRoleAuthToken(req)) {
2439
+ // Get IP address
2440
+ const ip = k2hr3apiutil_1.default.getClientIpAddress(req);
2441
+ if (!k2hr3apiutil_1.default.isSafeString(ip)) {
2442
+ resobj.result = false;
2443
+ resobj.message = 'Could not get client ip address from request';
2444
+ resobj.status = 401; // 401: Unauthorized
2445
+ dbglogging_1.default.elog(resobj.message);
2446
+ return resobj;
2447
+ }
2448
+ // Token is ROLE
2449
+ if (!role_type) {
2450
+ resobj.result = false;
2451
+ resobj.message = 'x-auth-token header token is not role token';
2452
+ resobj.status = 400; // 400: Bad Request
2453
+ dbglogging_1.default.elog(resobj.message);
2454
+ return resobj;
2455
+ }
2456
+ // get token
2457
+ token = rawGetAuthTokenHeader(req, true);
2458
+ if (null === token) {
2459
+ resobj.result = false;
2460
+ resobj.message = 'There is no x-auth-token header';
2461
+ resobj.status = 400; // 400: Bad Request
2462
+ dbglogging_1.default.elog(resobj.message);
2463
+ return resobj;
2464
+ }
2465
+ // get token information
2466
+ //
2467
+ // [NOTE]
2468
+ // we set always ip address to token(and role/hosts) value now.
2469
+ // then we do not need to convert ip to hostname here.
2470
+ //
2471
+ token_info = rawCheckRoleToken(token, ip); // not strictly checking
2472
+ if (null === token_info || !k2hr3apiutil_1.default.isSafeEntity(token_info.role)) {
2473
+ resobj.result = false;
2474
+ resobj.message = 'token(' + token + ') is not existed, because it is expired or not set yet.';
2475
+ resobj.status = 401; // 401: Unauthorized
2476
+ dbglogging_1.default.elog(resobj.message);
2477
+ return resobj;
2478
+ }
2479
+ else if (is_scoped && !token_info.scoped) {
2480
+ resobj.result = false;
2481
+ resobj.message = 'token(' + token + ') is not scoped.';
2482
+ resobj.status = 401; // 401: Unauthorized
2483
+ dbglogging_1.default.elog(resobj.message);
2484
+ return resobj;
2485
+ }
2486
+ token_type = 'role';
2487
+ }
2488
+ else {
2489
+ // Token is USER
2490
+ if (!user_type) {
2491
+ resobj.result = false;
2492
+ resobj.message = 'x-auth-token header token is not user token';
2493
+ resobj.status = 400; // 400: Bad Request
2494
+ dbglogging_1.default.elog(resobj.message);
2495
+ return resobj;
2496
+ }
2497
+ // get token
2498
+ token = rawGetAuthTokenHeader(req, false);
2499
+ if (null === token) {
2500
+ resobj.result = false;
2501
+ resobj.message = 'There is no x-auth-token header';
2502
+ resobj.status = 400; // 400: Bad Request
2503
+ dbglogging_1.default.elog(resobj.message);
2504
+ return resobj;
2505
+ }
2506
+ // get token information
2507
+ token_info = rawCheckUserToken(token);
2508
+ if (null === token_info || !k2hr3apiutil_1.default.isSafeEntity(token_info.user)) {
2509
+ resobj.result = false;
2510
+ resobj.message = 'token(' + token + ') is not existed, because it is expired or not set yet.';
2511
+ resobj.status = 401; // 401: Unauthorized
2512
+ dbglogging_1.default.elog(resobj.message);
2513
+ return resobj;
2514
+ }
2515
+ else if (is_scoped && !token_info.scoped) {
2516
+ resobj.result = false;
2517
+ resobj.message = 'token(' + token + ') is not scoped.';
2518
+ resobj.status = 401; // 401: Unauthorized
2519
+ dbglogging_1.default.elog(resobj.message);
2520
+ return resobj;
2521
+ }
2522
+ token_type = 'user';
2523
+ }
2524
+ resobj.token = token;
2525
+ resobj.token_type = token_type;
2526
+ resobj.token_info = token_info;
2527
+ return resobj;
2528
+ };
2529
+ //---------------------------------------------------------
2530
+ // Parse Token from X-Auth-Token header in request
2531
+ //---------------------------------------------------------
2532
+ const rawHasAuthTokenHeader = (req) => {
2533
+ if (k2hr3apiutil_1.default.isPlainObject(req) &&
2534
+ k2hr3apiutil_1.default.isPlainObject(req.headers) &&
2535
+ k2hr3apiutil_1.default.isSafeString(req.headers['x-auth-token'])) {
2536
+ return true;
2537
+ }
2538
+ return false;
2539
+ };
2540
+ const rawGetAuthTokenHeader = (req, is_role) => {
2541
+ if (!k2hr3apiutil_1.default.isBoolean(is_role)) {
2542
+ is_role = false;
2543
+ }
2544
+ if (k2hr3apiutil_1.default.isPlainObject(req) &&
2545
+ k2hr3apiutil_1.default.isPlainObject(req.headers) &&
2546
+ k2hr3apiutil_1.default.isSafeString(req.headers['x-auth-token'])) {
2547
+ let token = req.headers['x-auth-token'];
2548
+ if (!k2hr3apiutil_1.default.isString(token)) {
2549
+ return null;
2550
+ }
2551
+ if (is_role) {
2552
+ if (0 !== token.indexOf('R=')) {
2553
+ return null;
2554
+ }
2555
+ token = token.substr(2); // cut 'R='
2556
+ }
2557
+ else {
2558
+ if (0 === token.indexOf('U=')) {
2559
+ token = token.substr(2); // cut 'U='
2560
+ }
2561
+ }
2562
+ return token;
2563
+ }
2564
+ return null;
2565
+ };
2566
+ const rawIsUserAuthToken = (req) => {
2567
+ if (k2hr3apiutil_1.default.isPlainObject(req) &&
2568
+ k2hr3apiutil_1.default.isPlainObject(req.headers) &&
2569
+ k2hr3apiutil_1.default.isSafeString(req.headers['x-auth-token'])) {
2570
+ const token = req.headers['x-auth-token'];
2571
+ if (!k2hr3apiutil_1.default.isString(token)) {
2572
+ return false;
2573
+ }
2574
+ if (-1 === token.indexOf('U=')) { // user token has 'U='
2575
+ return true;
2576
+ }
2577
+ else if (-1 === token.indexOf('R=')) {
2578
+ return true; // user token does not have any prefix
2579
+ }
2580
+ }
2581
+ return false;
2582
+ };
2583
+ const rawIsRoleAuthToken = (req) => {
2584
+ if (k2hr3apiutil_1.default.isPlainObject(req) &&
2585
+ k2hr3apiutil_1.default.isPlainObject(req.headers) &&
2586
+ k2hr3apiutil_1.default.isSafeString(req.headers['x-auth-token'])) {
2587
+ const token = req.headers['x-auth-token'];
2588
+ if (!k2hr3apiutil_1.default.isString(token)) {
2589
+ return false;
2590
+ }
2591
+ if (0 === token.indexOf('R=')) {
2592
+ return true; // role token has 'R='
2593
+ }
2594
+ }
2595
+ return false;
2596
+ };
2597
+ //---------------------------------------------------------
2598
+ // Exports
2599
+ //---------------------------------------------------------
2600
+ exports.k2hr3tokens = {
2601
+ isDkcTypeSourceUserHostInfo: rawIsDkcTypeSourceUserHostInfo,
2602
+ isValTypeUserTenantInfo: rawIsValTypeUserTenantInfo,
2603
+ isDkcTypeBaseRoleToken: rawIsDkcTypeBaseRoleToken,
2604
+ isResTypeObjRoleTokens: rawIsResTypeObjRoleTokens,
2605
+ isResTypeCheckKindToken: rawIsResTypeCheckKindToken,
2606
+ isResTypeCheckUserToken: rawIsResTypeCheckUserToken,
2607
+ isResTypeCheckRoleToken: rawIsResTypeCheckRoleToken,
2608
+ getUserToken: rawGetUserToken,
2609
+ getUserTokenByToken: rawGetUserTokenByToken,
2610
+ getScopedUserToken: rawGetScopedUserTokenByUnscoped,
2611
+ removeScopedUserToken: rawRemoveScopedUserToken,
2612
+ checkUserToken: rawCheckUserToken,
2613
+ getRoleTokenByUser: rawGetRoleTokenByUser,
2614
+ getRoleTokenByIP: rawGetRoleTokenByIP,
2615
+ removeRoleTokenByUser: (token, user, tenant) => rawRemoveRoleToken(token, user, tenant, null, 0, null),
2616
+ directRemoveRoleTokens: rawDirectRemoveRoleTokens,
2617
+ removeRoleTokenByPath: rawRemoveRoleTokenByPath,
2618
+ getListRoleTokens: rawGetListRoleTokens,
2619
+ getDirectRoleTokenInfo: rawGetDirectRoleTokenInfo,
2620
+ removeRoleTokenByIP: (token, ip, port, cuk) => rawRemoveRoleToken(token, null, null, ip, port, cuk),
2621
+ checkRoleToken: rawCheckRoleToken,
2622
+ getTenantListWithDkc: rawGetTenantListByUserWithDkc,
2623
+ getTenantList: rawGetTenantListByUser,
2624
+ initializeTenantList: rawInitializeTenantListByUnscoped,
2625
+ checkTenantInTenantList: rawCheckTenantInTenantList,
2626
+ hasAuthTokenHeader: rawHasAuthTokenHeader,
2627
+ getAuthTokenHeader: rawGetAuthTokenHeader,
2628
+ isUserAuthToken: rawIsUserAuthToken,
2629
+ isRoleAuthToken: rawIsRoleAuthToken,
2630
+ checkToken: rawCheckToken
2631
+ };
2632
+ //
2633
+ // Default
2634
+ //
2635
+ exports.default = exports.k2hr3tokens;
2636
+ /*
2637
+ * Local variables:
2638
+ * tab-width: 4
2639
+ * c-basic-offset: 4
2640
+ * End:
2641
+ * vim600: noexpandtab sw=4 ts=4 fdm=marker
2642
+ * vim<600: noexpandtab sw=4 ts=4
2643
+ */