UNPKG

k2hr3-api

Version:

K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules

533 lines (532 loc) 22.9 kB
"use strict"; /* * K2HR3 REST API * * Copyright 2017 Yahoo Japan Corporation. * * K2HR3 is K2hdkc based Resource and Roles and policy Rules, gathers * common management information for the cloud. * K2HR3 can dynamically manage information as "who", "what", "operate". * These are stored as roles, resources, policies in K2hdkc, and the * client system can dynamically read and modify these information. * * For the full copyright and license information, please view * the license file that was distributed with this source code. * * AUTHOR: Takeshi Nakatani * CREATE: Fri Oct 27 2017 * REVISION: * */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.k2hr3acrutil = void 0; const https = __importStar(require("https")); const http = __importStar(require("http")); const k2hr3tokens_1 = __importDefault(require("./k2hr3tokens")); const k2hr3apiutil_1 = __importDefault(require("./k2hr3apiutil")); const dbglogging_1 = __importDefault(require("./dbglogging")); const cacerts_1 = require("./cacerts"); // // Type chekcer // const rawIsResTypeACRVerifyResponseKeys = (val) => { if (!k2hr3apiutil_1.default.isPlainObject(val)) { return false; } for (const [, value] of Object.entries(val)) { if (null !== value && !k2hr3apiutil_1.default.isString(value)) { return false; } } return true; }; const rawIsDkcTypeACRVerifyOneResponseBodyData = (val) => { if (!k2hr3apiutil_1.default.isPlainObject(val)) { return false; } const _obj = val; const _isName = (key) => k2hr3apiutil_1.default.isString(_obj[key]); const _isExpire = (key) => 'undefined' === typeof _obj[key] || k2hr3apiutil_1.default.isSafeNumber(_obj[key]); const _isType = (key) => null === _obj[key] || k2hr3apiutil_1.default.isString(_obj[key]); const _isData = (key) => 'undefined' === typeof _obj[key] || k2hr3apiutil_1.default.isValTypeAll(_obj[key]); const _isKeys = (key) => 'undefined' === typeof _obj[key] || rawIsResTypeACRVerifyResponseKeys(_obj[key]); return (_isName('name') && _isExpire('expire') && _isType('data') && _isData('type') && _isKeys('keys')); }; //--------------------------------------------------------- // Common send verify request //--------------------------------------------------------- // // Send and Get response from verify URL // // Inputs // scopedtoken : scoped user token // urlobj : url object built by apiutil.parseUrl() // callback(error, response) : callback function received response data // // Response : following formatted array // // Ex.) Response format from verify url // // response body = [ : undefined/null or resource array(if one element, allows only it not array) // dkcTypeACRVerifyOneResponseBodyData = { // name : resource name which is key name(path) for resource // expire : undefined/null or integer // type : resource data type(string or object), if date is null or '', this value must be string. // data : resource data which must be string or object or null/undefined. // keys = { : resource has keys(associative array), or null/undefined. // 'foo': bar, : any value is allowed // ... : // } : // }, // ... // ] // const rawACRSendVerifyEx = (scopedtoken, urlobj, callback) => { if (!k2hr3apiutil_1.default.isFunction(callback)) { dbglogging_1.default.elog('callback parameter is wrong : callback=' + JSON.stringify(callback)); return; } const _callback = callback; if (!k2hr3apiutil_1.default.isSafeString(scopedtoken) || !k2hr3apiutil_1.default.isSafeEntity(urlobj)) { const error = new Error('some parameters are wrong : scopedtoken=' + JSON.stringify(scopedtoken) + ', urlobj=' + JSON.stringify(urlobj)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } const headers = { 'Content-Type': 'application/json', 'Content-Length': 0, 'X-Auth-Token': scopedtoken ?? undefined // [NOTE] this token string does not have 'U=' prefix. }; const caCert = (urlobj && urlobj.https) ? (0, cacerts_1.ca)() : null; const options = { 'host': k2hr3apiutil_1.default.getSafeString(urlobj.host), 'port': urlobj.port, 'path': k2hr3apiutil_1.default.getSafeString(urlobj.path), 'method': 'GET', 'headers': headers, 'ca': caCert ?? undefined }; const agent = (urlobj && urlobj.https) ? https : http; dbglogging_1.default.dlog('request options = ' + JSON.stringify({ ...options, ca: options.ca ? '[Buffer]' : undefined })); dbglogging_1.default.dlog('request headers = ' + JSON.stringify(headers)); // send request const req = agent.request(options, (res) => { let _body = ''; const _status = res.statusCode; const _headers = res.headers; dbglogging_1.default.dlog('verify response status: ' + _status); dbglogging_1.default.dlog('verify response header: ' + JSON.stringify(_headers)); res.setEncoding('utf8'); res.on('data', (chunk) => { //r3logger.dlog('verify response chunk: ' + chunk); _body += chunk; }); res.on('end', () => { let _error = null; let resobj = []; if (300 <= (_status ?? 500)) { _error = new Error('got error response for verify request by status=' + String(_status ?? 0)); dbglogging_1.default.elog(_error.message); _callback(_error, null); return; } //r3logger.dlog('response body: ' + _body); // check response body if (!k2hr3apiutil_1.default.isSafeString(_body)) { _error = new Error('verify resource is not json string : response(json) =' + JSON.stringify(_body)); } else { // check response string(json) if (k2hr3apiutil_1.default.checkSimpleJSON(_body)) { const tmp_resobj = JSON.parse(_body); if (k2hr3apiutil_1.default.isArray(tmp_resobj)) { if (tmp_resobj.every((element) => rawIsDkcTypeACRVerifyOneResponseBodyData(element))) { resobj = tmp_resobj; } } } else if (k2hr3apiutil_1.default.isArray(_body)) { if (_body.every((element) => rawIsDkcTypeACRVerifyOneResponseBodyData(element))) { resobj = _body; } } else if (rawIsDkcTypeACRVerifyOneResponseBodyData(_body)) { // This format is not officially permitted (maybe it should be removed) resobj = [_body]; } if (!k2hr3apiutil_1.default.isArray(resobj)) { _error = new Error('verify resource is not array : response(object) =' + JSON.stringify(resobj)); } else { // check each object in array const namemap = {}; for (let cnt = 0; cnt < resobj.length; ++cnt) { // check name field if (!k2hr3apiutil_1.default.isSafeString(resobj[cnt].name)) { _error = new Error('empty resource name in verify response is found : response pos=' + cnt); break; } if (k2hr3apiutil_1.default.isSafeEntity(namemap[resobj[cnt].name])) { _error = new Error('same resource name in verify response is found : response pos=' + cnt + ', name=' + JSON.stringify(resobj[cnt].name)); break; } namemap[resobj[cnt].name] = true; // set any value. // check expire field if (!k2hr3apiutil_1.default.isSafeEntity(resobj[cnt].expire)) { resobj[cnt].expire = -1; // set no expire } else if (!k2hr3apiutil_1.default.isSafeNumber(resobj[cnt].expire)) { _error = new Error('wrong expire value in verify response is found : response pos=' + cnt + ', expire=' + JSON.stringify(resobj[cnt].expire)); break; } } } } if (null !== _error) { dbglogging_1.default.elog(_error.message); _callback(_error, null); return; } // return response _callback(null, resobj); return; }); }); req.on('error', (exception) => { dbglogging_1.default.elog('problem with verify request: ' + exception.message); _callback(exception, null); return; }); req.end(); }; //--------------------------------------------------------- // Send verify request //--------------------------------------------------------- // // Send and Get response from verify URL // // Inputs // user : user name // passwd : pass phrase for user // tenant : tenant name for scoped // verifyurl : verify url(allow not url string, it means static value formatted JSON) // callback(error, response) : callback function received response data // // Response : see rawACRSendVerifyEx() // const rawACRSendVerifyByUser = (user, passwd, tenant, verifyurl, callback) => { if (!k2hr3apiutil_1.default.isFunction(callback)) { dbglogging_1.default.elog('callback parameter is wrong : callback=' + JSON.stringify(callback)); return; } const _callback = callback; if (!k2hr3apiutil_1.default.isSafeString(verifyurl)) { const error = new Error('parameter is wrong : verifyurl=' + JSON.stringify(verifyurl)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } if (k2hr3apiutil_1.default.checkSimpleJSON(verifyurl)) { // verifyurl is formatted by JSON, it means static value. _callback(null, JSON.parse(verifyurl)); return; } const urlobj = k2hr3apiutil_1.default.parseUrl(verifyurl); // parse verify url string to url obejct. if (null === urlobj) { const error = new Error('parameter is wrong : verifyurl=' + JSON.stringify(verifyurl)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } if (!k2hr3apiutil_1.default.isSafeString(user) || !k2hr3apiutil_1.default.isSafeString(tenant)) { const error = new Error('some parameters are wrong : user=' + JSON.stringify(user) + ', tenant=' + JSON.stringify(tenant)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } const _user = user; const _tenant = tenant; const _passwd = passwd; // get scoped token directly. k2hr3tokens_1.default.getUserToken(_user, _passwd, _tenant, (err, token) => { if (null !== err) { const error = new Error('could not get scoped user token for user=' + _user + ', tenant=' + _tenant + ' by ' + k2hr3apiutil_1.default.getSafeString(err.message)); dbglogging_1.default.elog(error.message); _callback(error, null); } dbglogging_1.default.dlog('get user token jsonres = ' + JSON.stringify(token)); // call verify url rawACRSendVerifyEx(token, urlobj, _callback); }); }; //--------------------------------------------------------- // Send verify request //--------------------------------------------------------- // // Send and Get response from verify URL // // Inputs // unscopedtoken : unscoped user token // user : user name // tenant : tenant name for scoped // verifyurl : verify url(allow not url string, it means static value formatted JSON) // callback(error, response) : callback function received response data // // Response : see rawACRSendVerifyEx() // const rawACRSendVerifyByUnscopedToken = (unscopedtoken, user, tenant, verifyurl, callback) => { if (!k2hr3apiutil_1.default.isFunction(callback)) { dbglogging_1.default.elog('callback parameter is wrong : callback=' + JSON.stringify(callback)); return; } const _callback = callback; if (!k2hr3apiutil_1.default.isSafeString(verifyurl)) { const error = new Error('parameter is wrong : verifyurl=' + JSON.stringify(verifyurl)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } if (k2hr3apiutil_1.default.checkSimpleJSON(verifyurl)) { // verifyurl is formatted by JSON, it means static value. _callback(null, JSON.parse(verifyurl)); return; } const urlobj = k2hr3apiutil_1.default.parseUrl(verifyurl); if (null === urlobj) { const error = new Error('parameter is wrong : verifyurl=' + JSON.stringify(verifyurl)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } if (!k2hr3apiutil_1.default.isSafeString(unscopedtoken) || !k2hr3apiutil_1.default.isSafeString(user) || !k2hr3apiutil_1.default.isSafeString(tenant)) { const error = new Error('some parameters are wrong : unscopedtoken=' + JSON.stringify(unscopedtoken) + ', user=' + JSON.stringify(user) + ', tenant=' + JSON.stringify(tenant)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } const _unscopedtoken = unscopedtoken; const _user = user; const _tenant = tenant; // get scoped token from unscoped token k2hr3tokens_1.default.getScopedUserToken(_unscopedtoken, _user, _tenant, (err, token) => { if (null !== err) { const error = new Error('could not get scoped user token for user=' + _user + ', tenant=' + _tenant + ' by ' + k2hr3apiutil_1.default.getSafeString(err.message)); dbglogging_1.default.elog(error.message); _callback(error, null); } dbglogging_1.default.dlog('get user token jsonres = ' + JSON.stringify(token)); // call verify url rawACRSendVerifyEx(token, urlobj, _callback); }); }; //--------------------------------------------------------- // Send verify request //--------------------------------------------------------- // // Send and Get response from verify URL // // Inputs // scopedtoken : scoped user token // verifyurl : verify url(allow not url string, it means static value formatted JSON) // callback(error, response) : callback function received response data // // Response : see rawACRSendVerifyEx() // const rawACRSendVerifyByScopedToken = (scopedtoken, verifyurl, callback) => { if (!k2hr3apiutil_1.default.isFunction(callback)) { dbglogging_1.default.elog('callback parameter is wrong : callback=' + JSON.stringify(callback)); return; } const _callback = callback; if (!k2hr3apiutil_1.default.isSafeString(verifyurl)) { const error = new Error('parameter is wrong : verifyurl=' + JSON.stringify(verifyurl)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } if (k2hr3apiutil_1.default.checkSimpleJSON(verifyurl)) { // verifyurl is formatted by JSON, it means static value. _callback(null, JSON.parse(verifyurl)); return; } const urlobj = k2hr3apiutil_1.default.parseUrl(verifyurl); if (null === urlobj) { const error = new Error('parameter is wrong : verifyurl=' + JSON.stringify(verifyurl)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } if (!k2hr3apiutil_1.default.isSafeString(scopedtoken)) { const error = new Error('parameter is wrong : scopedtoken=' + JSON.stringify(scopedtoken)); dbglogging_1.default.elog(error.message); _callback(error, null); return; } const _scopedtoken = scopedtoken; // parse token to get user/tenant const _token_res = k2hr3tokens_1.default.checkUserToken(_scopedtoken); if (null === _token_res || !k2hr3apiutil_1.default.isSafeString(_token_res.user) || !k2hr3apiutil_1.default.isSafeString(_token_res.tenant) || !k2hr3apiutil_1.default.isSafeEntity(_token_res.scoped) || !k2hr3apiutil_1.default.isBoolean(_token_res.scoped) || true !== _token_res.scoped) { const error = new Error('parameter scopedtoken(' + _scopedtoken + ' -> ' + JSON.stringify(_token_res) + ') is something wrong,'); dbglogging_1.default.elog(error.message); _callback(error, null); return; } // get scoped token from unscoped token // // [NOTE] // getScopedUserToken is allowed scoped token when is has as same as tenant name specified. // k2hr3tokens_1.default.getScopedUserToken(_scopedtoken, _token_res.user, _token_res.tenant, (err, token) => { if (null !== err) { const error = new Error('could not get scoped user token for user=' + _token_res.user + ', tenant=' + _token_res.tenant + ' by ' + k2hr3apiutil_1.default.getSafeString(err.message)); dbglogging_1.default.elog(error.message); _callback(error, null); } dbglogging_1.default.dlog('get user token jsonres = ' + JSON.stringify(token)); // call verify url rawACRSendVerifyEx(token, urlobj, _callback); }); }; //--------------------------------------------------------- // Send verify request for all pattern //--------------------------------------------------------- // // Send and Get response from verify URL // // Inputs // unscopedtoken : unscoped user token // user : user name // passwd : pass phrase for user // token : (un)scoped user token // tenant : tenant name for scoped // verifyurl : verify url(allow not url string, it means static value formatted JSON) // callback(error, response) : callback function received response data // // Response : see rawACRSendVerifyEx() // // [NOTE] // This function automatically decides raw functions by parameters. // // 1) no token // Both user and passwd parameters must be specified, and token must be null(undefined). // 2) unscoped token // Both user and token parameters must be specified, and passwd must be null(undefined). // The token parameter should be "unscoped" user token. // 3) scoped token // token parameter must be specified, and both user and passwd must be null(undefined). // The token parameter should be "scoped" user token. // const rawACRSendVerify = (token, user, passwd, tenant, verifyurl, callback) => { if (!k2hr3apiutil_1.default.isFunction(callback)) { dbglogging_1.default.elog('callback parameter is wrong : callback=' + JSON.stringify(callback)); return; } const _callback = callback; let error = null; // check pattern if (k2hr3apiutil_1.default.isSafeString(user)) { if (k2hr3apiutil_1.default.isSafeString(token)) { if (k2hr3apiutil_1.default.isSafeEntity(passwd)) { error = new Error('all parameters user(' + JSON.stringify(user) + ') and token(' + JSON.stringify(token) + ') and passwd(xxxxx) are specified.'); } else { // case : user + unscoped token rawACRSendVerifyByUser(user, passwd, tenant, verifyurl, _callback); } } else { token = null; if (k2hr3apiutil_1.default.isSafeEntity(passwd)) { // case : user + passwd } else { // case : user + passwd(null) // // [NOTE] // This case is not error pattern, because empty passwd is allowed by some authorizing system. } rawACRSendVerifyByUnscopedToken(token, user, tenant, verifyurl, _callback); } } else { if (k2hr3apiutil_1.default.isSafeString(token)) { if (k2hr3apiutil_1.default.isSafeEntity(passwd)) { error = new Error('user parameter is empty, but passwd(xxxx) is specified.'); } else { // case : scoped token rawACRSendVerifyByScopedToken(token, verifyurl, _callback); } } else { error = new Error('user parameter is empty, but scoped token is not specified.'); } } if (null !== error) { dbglogging_1.default.elog(error.message); _callback(error, null); } }; //--------------------------------------------------------- // Export types //--------------------------------------------------------- exports.k2hr3acrutil = { getACRVerifyByUser: rawACRSendVerifyByUser, getACRVerifyByUnscopedToken: rawACRSendVerifyByUnscopedToken, getACRVerifyByScopedToken: rawACRSendVerifyByScopedToken, getACRSendVerify: rawACRSendVerify }; exports.default = exports.k2hr3acrutil; /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noexpandtab sw=4 ts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 */