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.
- package/config/k2hr3-init.sh.templ +4 -4
- package/dist/.gitkeep +0 -0
- package/dist/src/app.js +262 -0
- package/{bin → dist/src/bin}/run.sh +1 -1
- package/dist/src/bin/watcher.js +113 -0
- package/dist/src/bin/www.js +217 -0
- package/dist/src/lib/basicipcheck.js +392 -0
- package/dist/src/lib/cacerts.js +106 -0
- package/dist/src/lib/dbglogging.js +190 -0
- package/dist/src/lib/dummyuserapi.js +719 -0
- package/dist/src/lib/ipwatch.js +354 -0
- package/dist/src/lib/k2hr3acrutil.js +532 -0
- package/dist/src/lib/k2hr3apiutil.js +1444 -0
- package/dist/src/lib/k2hr3cliutil.js +183 -0
- package/dist/src/lib/k2hr3config.js +832 -0
- package/dist/src/lib/k2hr3cryptutil.js +258 -0
- package/dist/src/lib/k2hr3dkc.js +12121 -0
- package/dist/src/lib/k2hr3extdata.js +198 -0
- package/dist/src/lib/k2hr3keys.js +207 -0
- package/dist/src/lib/k2hr3resutil.js +111 -0
- package/dist/src/lib/k2hr3template.js +6546 -0
- package/dist/src/lib/k2hr3tokens.js +2643 -0
- package/dist/src/lib/k2hr3userdata.js +296 -0
- package/dist/src/lib/k8soidc.js +1000 -0
- package/dist/src/lib/openstackapiv2.js +695 -0
- package/dist/src/lib/openstackapiv3.js +932 -0
- package/dist/src/lib/openstackep.js +667 -0
- package/{tests/auto_common.js → dist/src/lib/types.js} +4 -38
- package/dist/src/routes/acr.js +704 -0
- package/dist/src/routes/debugVerify.js +294 -0
- package/dist/src/routes/extdata.js +219 -0
- package/dist/src/routes/list.js +264 -0
- package/dist/src/routes/policy.js +840 -0
- package/dist/src/routes/resource.js +1489 -0
- package/dist/src/routes/role.js +2627 -0
- package/dist/src/routes/service.js +908 -0
- package/dist/src/routes/tenant.js +1141 -0
- package/dist/src/routes/userTokens.js +482 -0
- package/dist/src/routes/userdata.js +212 -0
- package/dist/src/routes/version.js +103 -0
- package/package.json +152 -121
- package/ChangeLog +0 -378
- package/app.js +0 -292
- package/bin/watcher +0 -122
- package/bin/www +0 -180
- package/eslint.config.mjs +0 -68
- package/lib/basicipcheck.js +0 -376
- package/lib/cacerts.js +0 -71
- package/lib/dbglogging.js +0 -151
- package/lib/dummyuserapi.js +0 -766
- package/lib/ipwatch.js +0 -379
- package/lib/k2hr3acrutil.js +0 -516
- package/lib/k2hr3apiutil.js +0 -1494
- package/lib/k2hr3cliutil.js +0 -191
- package/lib/k2hr3config.js +0 -826
- package/lib/k2hr3cryptutil.js +0 -254
- package/lib/k2hr3dkc.js +0 -12632
- package/lib/k2hr3extdata.js +0 -198
- package/lib/k2hr3keys.js +0 -234
- package/lib/k2hr3resutil.js +0 -100
- package/lib/k2hr3template.js +0 -6925
- package/lib/k2hr3tokens.js +0 -2799
- package/lib/k2hr3userdata.js +0 -312
- package/lib/k8soidc.js +0 -1012
- package/lib/openstackapiv2.js +0 -764
- package/lib/openstackapiv3.js +0 -1032
- package/lib/openstackep.js +0 -553
- package/routes/acr.js +0 -738
- package/routes/debugVerify.js +0 -263
- package/routes/extdata.js +0 -232
- package/routes/list.js +0 -270
- package/routes/policy.js +0 -869
- package/routes/resource.js +0 -1441
- package/routes/role.js +0 -2664
- package/routes/service.js +0 -894
- package/routes/tenant.js +0 -1095
- package/routes/userTokens.js +0 -511
- package/routes/userdata.js +0 -218
- package/routes/version.js +0 -108
- package/templ/Dockerfile.templ +0 -71
- package/tests/auto_acr.js +0 -1101
- package/tests/auto_acr_spec.js +0 -79
- package/tests/auto_all_spec.js +0 -142
- package/tests/auto_control_subprocess.sh +0 -243
- package/tests/auto_extdata.js +0 -220
- package/tests/auto_extdata_spec.js +0 -79
- package/tests/auto_init_config_json.sh +0 -275
- package/tests/auto_k2hdkc_server.ini +0 -109
- package/tests/auto_k2hdkc_slave.ini +0 -83
- package/tests/auto_list.js +0 -439
- package/tests/auto_list_spec.js +0 -79
- package/tests/auto_policy.js +0 -1579
- package/tests/auto_policy_spec.js +0 -79
- package/tests/auto_resource.js +0 -10956
- package/tests/auto_resource_spec.js +0 -79
- package/tests/auto_role.js +0 -6150
- package/tests/auto_role_spec.js +0 -79
- package/tests/auto_service.js +0 -770
- package/tests/auto_service_spec.js +0 -79
- package/tests/auto_subprocesses.js +0 -114
- package/tests/auto_template.sh +0 -126
- package/tests/auto_tenant.js +0 -1100
- package/tests/auto_tenant_spec.js +0 -79
- package/tests/auto_token_util.js +0 -219
- package/tests/auto_userdata.js +0 -292
- package/tests/auto_userdata_spec.js +0 -79
- package/tests/auto_usertokens.js +0 -565
- package/tests/auto_usertokens_spec.js +0 -79
- package/tests/auto_version.js +0 -127
- package/tests/auto_version_spec.js +0 -79
- package/tests/auto_watcher.js +0 -157
- package/tests/auto_watcher_spec.js +0 -79
- package/tests/k2hdkc_test.data +0 -986
- package/tests/k2hdkc_test_load.sh +0 -255
- package/tests/k2hr3template_test.js +0 -187
- package/tests/k2hr3template_test.sh +0 -339
- package/tests/k2hr3template_test_async.js +0 -216
- package/tests/k2hr3template_test_template.result +0 -7117
- package/tests/k2hr3template_test_template.txt +0 -3608
- package/tests/k2hr3template_test_vars.js +0 -194
- package/tests/manual_acr_delete.js +0 -143
- package/tests/manual_acr_get.js +0 -297
- package/tests/manual_acr_postput.js +0 -215
- package/tests/manual_allusertenant_get.js +0 -113
- package/tests/manual_extdata_get.js +0 -191
- package/tests/manual_k2hr3keys_get.js +0 -84
- package/tests/manual_list_gethead.js +0 -230
- package/tests/manual_policy_delete.js +0 -132
- package/tests/manual_policy_gethead.js +0 -275
- package/tests/manual_policy_postput.js +0 -297
- package/tests/manual_resource_delete.js +0 -433
- package/tests/manual_resource_gethead.js +0 -423
- package/tests/manual_resource_postput.js +0 -487
- package/tests/manual_role_delete.js +0 -404
- package/tests/manual_role_gethead.js +0 -547
- package/tests/manual_role_postput.js +0 -544
- package/tests/manual_service_delete.js +0 -153
- package/tests/manual_service_gethead.js +0 -178
- package/tests/manual_service_postput.js +0 -348
- package/tests/manual_tenant_delete.js +0 -186
- package/tests/manual_tenant_gethead.js +0 -268
- package/tests/manual_tenant_postput.js +0 -293
- package/tests/manual_test.sh +0 -352
- package/tests/manual_userdata_get.js +0 -173
- package/tests/manual_usertoken_gethead.js +0 -136
- package/tests/manual_usertoken_postput.js +0 -310
- package/tests/manual_version_get.js +0 -127
- package/tests/run_local_test_k2hdkc.sh +0 -174
- 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
|
+
*/
|