k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
841 lines (840 loc) • 41.4 kB
JavaScript
"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: Wed Jun 8 2017
* REVISION:
*
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const k2hr3apiutil_1 = __importDefault(require("../lib/k2hr3apiutil"));
const k2hr3resutil_1 = __importDefault(require("../lib/k2hr3resutil"));
const k2hr3tokens_1 = __importDefault(require("../lib/k2hr3tokens"));
const k2hr3dkc_1 = __importDefault(require("../lib/k2hr3dkc"));
const dbglogging_1 = __importDefault(require("../lib/dbglogging"));
const express_1 = __importDefault(require("express"));
const k2hr3keys_1 = require("../lib/k2hr3keys");
const r3keys = k2hr3keys_1.getK2hr3Keys;
const router = express_1.default.Router();
// Mountpath : '/v1/policy'
// POST '/v1/policy' : post policy on version 1
// response body : result => true/false
// message => messages
// body :
// {
// "policy": {
// "name": <policy name> => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>"
// "effect": "allow" or "deny" => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>/effect"
// if null or undefined is specified, not update this member in policy when this policy exists.
// if '' or zero array, this member in policy is set default(default deny)..
// "action": [<action yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>/action"
// specify "yrn:yahoo::::action:read" or "yrn:yahoo::::action:write"
// if null or undefined is specified, not update this member in policy when this policy exists.
// if '' or zero array, this member in policy is set empty array.
// "resource": [<resource yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>/resource"
// specify "yrn:yahoo:<service>::<tenant>:resource:<resource>{/<resource>{...}}"
// if null or undefined is specified, not update this member in policy when this policy exists.
// if '' or zero array, this member in policy is set empty array.
// "condition": null or undefined => this member is reserved on v1, must be null or undefined.
// "alias": [<policy yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>/@"
// specify another policy as "yrn:yahoo:<service>::<tenant>:policy:<policy>"
// if null or undefined is specified, not update this member in policy when this policy exists.
// if '' or zero array, this member in policy is set empty array.
// }
// }
//
router.post('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url);
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isPlainObject(req.body) ||
!k2hr3apiutil_1.default.isPlainObject(req.body.policy)) {
const result = {
result: false,
message: 'POST body does not have policy data'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check arguments
//------------------------------
if (!k2hr3apiutil_1.default.isSafeString(req.body.policy.name)) {
const result = {
result: false,
message: 'policy:name field is wrong : ' + JSON.stringify(req.body.policy.name)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const keys = r3keys(token_info.user, token_info.tenant);
let name = k2hr3apiutil_1.default.getSafeString(req.body.policy.name).toLowerCase();
// policy name is only name or full yrn path
let nameptn = new RegExp('^' + keys.POLICY_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:policy:(.*)/
const namematchs = name.match(nameptn);
if (k2hr3apiutil_1.default.isStringArray(namematchs) && k2hr3apiutil_1.default.isNotEmptyArray(namematchs) && 2 <= namematchs.length) {
name = namematchs[1];
}
// check token's tenant(if same tenant, name is not full yrn)
nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
if (name.match(nameptn)) {
const result = {
result: false,
message: 'POST request url has wrong yrn full path to policy'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
let effect;
if (!k2hr3apiutil_1.default.isSafeEntity(req.body.policy.effect)) {
effect = null; // = not update if policy exists
}
else if (k2hr3apiutil_1.default.isString(req.body.policy.effect) && '' === req.body.policy.effect) {
effect = false; // = deny
}
else if (k2hr3apiutil_1.default.isString(req.body.policy.effect) && k2hr3apiutil_1.default.compareCaseString(req.body.policy.effect, keys.VALUE_ALLOW)) {
effect = true; // = allow
}
else if (k2hr3apiutil_1.default.isString(req.body.policy.effect) && k2hr3apiutil_1.default.compareCaseString(req.body.policy.effect, keys.VALUE_DENY)) {
effect = false; // = deny
}
else {
const result = {
result: false,
message: 'policy:effect field is wrong : ' + JSON.stringify(req.body.policy.effect)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const actptns = [keys.ACTION_READ_KEY, keys.ACTION_WRITE_KEY]; // allow string as read/write yrn full path
const actpram = k2hr3apiutil_1.default.getNormalizeParameter(req.body.policy.action, null, actptns);
if (false === actpram.result) {
const result = {
result: false,
message: 'policy:action field is wrong : ' + JSON.stringify(req.body.policy.action)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const actions = actpram.parameter;
const resptn = new RegExp('^' + keys.RESOURCE_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:resource:(.*)/
const respram = k2hr3apiutil_1.default.getNormalizeParameter(req.body.policy.resource, resptn, null);
if (false === respram.result) {
const result = {
result: false,
message: 'policy:resource field is wrong : ' + JSON.stringify(req.body.policy.resource)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const resources = respram.parameter;
const condition = null; // now reserved this field
if (null !== req.body.policy.condition && undefined !== req.body.policy.condition && !k2hr3apiutil_1.default.isSafeString(req.body.policy.condition)) {
const result = {
result: false,
message: 'policy:condition field is wrong : ' + JSON.stringify(req.body.policy.condition)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const aliasptn = new RegExp('^' + keys.POLICY_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:policy:(.*)/
const aliaspram = k2hr3apiutil_1.default.getNormalizeParameter(req.body.policy.alias, aliasptn, null);
if (false === aliaspram.result) {
const result = {
result: false,
message: 'policy:alias field is wrong : ' + JSON.stringify(req.body.policy.alias)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const aliases = aliaspram.parameter;
//------------------------------
// set all field to policy
//------------------------------
const pol_result = k2hr3dkc_1.default.setPolicyAll(token_info.user, token_info.tenant, name, effect, actions, resources, condition, aliases);
if (!k2hr3apiutil_1.default.isPlainObject(pol_result) || !k2hr3apiutil_1.default.isBoolean(pol_result.result) || false === pol_result.result) {
if (!k2hr3apiutil_1.default.isPlainObject(pol_result)) {
const result = {
result: false,
message: 'Could not get response from setPolicyAll'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
else {
const result = {
result: k2hr3apiutil_1.default.isBoolean(pol_result.result) ? pol_result.result : false,
message: k2hr3apiutil_1.default.isString(pol_result.message) ? pol_result.message : 'Could not get error message in response from setPolicyAll'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
return;
}
dbglogging_1.default.dlog('succeed : ' + pol_result.message);
res.status(201); // 201: Created
res.send(JSON.stringify(pol_result));
});
// Mountpath : '/v1/policy'
// PUT '/v1/policy' : put policy on version 1
// response body : result => true/false
// message => messages
// url argument
// "name" : <policy name> => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>"
// "effect" : "allow" or "deny" => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>/effect"
// if null or undefined is specified, not update this member in policy when this policy exists.
// if '' or zero array, this member in policy is set default(default deny)..
// "action" : [<action yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>/action"
// specify "yrn:yahoo::::action:read" or "yrn:yahoo::::action:write"
// if null or undefined is specified, not update this member in policy when this policy exists.
// if '' or zero array, this member in policy is set empty array.
// "resource" : [<resource yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>/resource"
// specify "yrn:yahoo:<service>::<tenant>:resource:<resource>{/<resource>{...}}"
// if null or undefined is specified, not update this member in policy when this policy exists.
// if '' or zero array, this member in policy is set empty array.
// "condition" : null or undefined => this member is reserved on v1, must be null or undefined.
// "alias" : [<policy yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:policy:<policy>/@"
// specify another policy as "yrn:yahoo:<service>::<tenant>:policy:<policy>"
// if null or undefined is specified, not update this member in policy when this policy exists.
// if '' or zero array, this member in policy is set empty array.
//
router.put('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url);
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeEntity(req.query)) {
const result = {
result: false,
message: 'PUT argument does not have any data'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check arguments
//------------------------------
if (!k2hr3apiutil_1.default.isSafeString(req.query.name)) {
const result = {
result: false,
message: 'policy:name field is wrong : ' + JSON.stringify(req.query.name)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const keys = r3keys(token_info.user, token_info.tenant);
let name = k2hr3apiutil_1.default.getSafeString(req.query.name).toLowerCase();
// policy name is only name or full yrn path
let nameptn = new RegExp('^' + keys.POLICY_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:policy:(.*)/
const namematchs = name.match(nameptn);
if (k2hr3apiutil_1.default.isStringArray(namematchs) && k2hr3apiutil_1.default.isNotEmptyArray(namematchs) && 2 <= namematchs.length) {
name = namematchs[1];
}
// check token's tenant(if same tenant, name is not full yrn)
nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
if (name.match(nameptn)) {
const result = {
result: false,
message: 'PUT request url has wrong yrn full path to policy'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
let effect;
if (!k2hr3apiutil_1.default.isString(req.query.effect)) {
effect = null; // = not update if policy exists
}
else if (!k2hr3apiutil_1.default.isSafeString(req.query.effect)) {
effect = false; // = deny
}
else if (k2hr3apiutil_1.default.compareCaseString(req.query.effect, keys.VALUE_ALLOW)) {
effect = true; // = allow
}
else if (k2hr3apiutil_1.default.compareCaseString(req.query.effect, keys.VALUE_DENY)) {
effect = false; // = deny
}
else {
const result = {
result: false,
message: 'policy:effect field is wrong : ' + JSON.stringify(req.query.effect)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const actptns = [keys.ACTION_READ_KEY, keys.ACTION_WRITE_KEY]; // allow string as read/write yrn full path
const actpram = k2hr3apiutil_1.default.getNormalizeParameter(req.query.action, null, actptns);
if (false === actpram.result) {
const result = {
result: false,
message: 'policy:action field is wrong : ' + JSON.stringify(req.query.action)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const actions = actpram.parameter;
const resptn = new RegExp('^' + keys.RESOURCE_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:resource:(.*)/
const respram = k2hr3apiutil_1.default.getNormalizeParameter(req.query.resource, resptn, null);
if (false === respram.result) {
const result = {
result: false,
message: 'policy:resource field is wrong : ' + JSON.stringify(req.query.resource)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const resources = respram.parameter;
const condition = null; // now reserved this field
if (null !== req.query.condition && undefined !== req.query.condition && !k2hr3apiutil_1.default.isSafeString(req.query.condition)) {
const result = {
result: false,
message: 'policy:condition field is wrong : ' + JSON.stringify(req.query.condition)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const aliasptn = new RegExp('^' + keys.POLICY_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:policy:(.*)/
const aliaspram = k2hr3apiutil_1.default.getNormalizeParameter(req.query.alias, aliasptn, null);
if (false === aliaspram.result) {
const result = {
result: false,
message: 'policy:alias field is wrong : ' + JSON.stringify(req.query.alias)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const aliases = aliaspram.parameter;
//------------------------------
// set all field to policy
//------------------------------
const pol_result = k2hr3dkc_1.default.setPolicyAll(token_info.user, token_info.tenant, name, effect, actions, resources, condition, aliases);
if (!k2hr3apiutil_1.default.isPlainObject(pol_result) || !k2hr3apiutil_1.default.isBoolean(pol_result.result) || false === pol_result.result) {
if (!k2hr3apiutil_1.default.isPlainObject(pol_result)) {
const result = {
result: false,
message: 'Could not get response from setPolicyAll'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
else {
const result = {
result: k2hr3apiutil_1.default.isBoolean(pol_result.result) ? pol_result.result : false,
message: k2hr3apiutil_1.default.isString(pol_result.message) ? pol_result.message : 'Could not get error message in response from setPolicyAll'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
return;
}
dbglogging_1.default.dlog('succeed : ' + pol_result.message);
res.status(201); // 201: Created
res.send(JSON.stringify(pol_result));
});
// Mountpath : '/v1/policy/*'
// GET '/v1/policy/name' : get policy on version 1(name is allowed full yrn path)
// URL arguments : service => undefined or service name
// response body : result => true/false
// message => error message
// policy => object
// policy object
// {
// "name": <policy name>
// "effect": "allow" or "deny"
// "action": [<action yrn full path>, ...]
// "resource": [<resource yrn full path>, ...]
// "condition": null or undefined
// "alias": [<policy yrn full path>, ...]
// }
//
router.get('/', (req, res, next) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
if ('GET' !== req.method) {
// HEAD request comes here, so it should be routed to head function.
next();
return;
}
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
const result = {
result: false,
message: 'GET request or url is wrong'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// service name
//------------------------------
let service = null;
if (k2hr3apiutil_1.default.isPlainObject(req.query) && k2hr3apiutil_1.default.isSafeString(req.query.service)) {
service = k2hr3apiutil_1.default.getSafeString(req.query.service).toLowerCase();
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const keys = r3keys(token_info.user, token_info.tenant, service);
//------------------------------
// check policy name
//------------------------------
const requestptn = new RegExp('^/v1/policy/(.*)'); // regex = /^\/v1\/policy\/(.*)/
const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
const result = {
result: false,
message: 'GET request url does not have policy name'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
let name = reqmatchs[1].toLowerCase();
//
// make policy name from policy yrn
//
let nameptn = new RegExp('^' + keys.MATCH_ANY_TENANT_POLICY); // regex = /^yrn:yahoo:(.*)::(.*):policy:(.*)/
const namematchs = name.match(nameptn);
if (!k2hr3apiutil_1.default.isStringArray(namematchs) || !k2hr3apiutil_1.default.isNotEmptyArray(namematchs) || namematchs.length < 4) {
// name is not full yrn to policy, then check wrong policy name
nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
if (name.match(nameptn)) {
const result = {
result: false,
message: 'Request query has wrong yrn full path to policy'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
// no token need full yrn to policy(other token has tenant name)
if (!k2hr3apiutil_1.default.isString(token_result.token_type)) {
const result = {
result: false,
message: 'Request query does not have yrn full path to policy'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
// no problem, name is policy name
}
else {
// name is full yrn to policy, then need to check tenant name
if (k2hr3apiutil_1.default.isString(token_result.token_type) && !k2hr3apiutil_1.default.compareCaseString(namematchs[2], token_info.tenant)) {
const result = {
result: false,
message: 'Request query has wrong yrn full path(tenant=' + namematchs[2] + ') to policy(tenant=' + k2hr3apiutil_1.default.getSafeString(token_info.tenant) + ')'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
// check service name
if (k2hr3apiutil_1.default.isSafeString(service)) {
if (!k2hr3apiutil_1.default.compareCaseString(service, namematchs[1])) {
const result = {
result: false,
message: 'Request query has service name(' + (service ?? '') + ') and path has service name(' + namematchs[1] + '), but both are not same service name.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
}
else if (k2hr3apiutil_1.default.isSafeString(namematchs[1])) {
// set service name
service = k2hr3apiutil_1.default.getSafeString(namematchs[1]).trim().toLowerCase();
//keys = r3keys(token_info.user, token_info.tenant, service);
}
// set name
name = namematchs[3].toLowerCase();
}
//------------------------------
// get all policy
//------------------------------
const pol_result = k2hr3dkc_1.default.getPolicyAll(token_info.user, token_info.tenant, service, name);
if (!k2hr3apiutil_1.default.isPlainObject(pol_result) || !k2hr3apiutil_1.default.isBoolean(pol_result.result) || false === pol_result.result) {
if (!k2hr3apiutil_1.default.isPlainObject(pol_result)) {
const result = {
result: false,
message: 'Could not get response from getPolicyAll'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
else {
const result = {
result: k2hr3apiutil_1.default.isBoolean(pol_result.result) ? pol_result.result : false,
message: k2hr3apiutil_1.default.isString(pol_result.message) ? pol_result.message : 'Could not get error message in response from getPolicyAll'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
return;
}
dbglogging_1.default.dlog('succeed : ' + pol_result.message);
res.status(200); // 200: OK
res.send(JSON.stringify(pol_result));
});
// Mountpath : '/v1/policy/*'
// HEAD '/v1/policy/name' : head policy on version 1(name is allowed full yrn path)
// Url arguments
// tenant : optional for policy/resource not full yrn
// resource : resource to full yrn(or name)
// action : action(read/write)
// service : undefined or service name
//
router.head('/', (req, res, next) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
if ('HEAD' !== req.method) {
// If other method request comes here, so it should be routed another function.
next();
return;
}
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl) ||
!k2hr3apiutil_1.default.isPlainObject(req.query)) {
dbglogging_1.default.elog('HEAD request or url or query is wrong');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// check arguments
//------------------------------
// first tenant name
let tenant = null;
if (req.query.tenant && k2hr3apiutil_1.default.isSafeString(req.query.tenant)) {
tenant = k2hr3apiutil_1.default.getSafeString(req.query.tenant).trim().toLowerCase();
}
// service name
let service = null;
if (k2hr3apiutil_1.default.isSafeString(req.query.service)) {
service = k2hr3apiutil_1.default.getSafeString(req.query.service).trim().toLowerCase();
}
// keys
let keys = r3keys(null, tenant, service);
// policy name from path
const requestptn = new RegExp('^/v1/policy/(.*)'); // regex = /^\/v1\/policy\/(.*)/
const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
dbglogging_1.default.elog('HEAD request url does not have policy name');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
// check policy name is only name or full yrn path
let name = reqmatchs[1].toLowerCase();
//
// make policy name and full yrn path
//
let policy_yrn;
let nameptn = new RegExp('^' + keys.MATCH_ANY_TENANT_POLICY); // regex = /^yrn:yahoo:(.*)::(.*):policy:(.*)/
const namematchs = name.match(nameptn);
if (!k2hr3apiutil_1.default.isStringArray(namematchs) || !k2hr3apiutil_1.default.isNotEmptyArray(namematchs) || namematchs.length < 4) {
// name is not full yrn to policy, then check wrong policy name
nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
if (name.match(nameptn)) {
dbglogging_1.default.elog('Request query has wrong yrn full path to policy');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
// no token need full yrn to policy(other token has tenant name)
if (!k2hr3apiutil_1.default.isSafeString(tenant)) {
dbglogging_1.default.elog('Request query does not have yrn full path to policy');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
// no problem, name is policy name
policy_yrn = keys.POLICY_TOP_KEY + ':' + name;
}
else {
// name is full yrn to policy, then need to check tenant name
if (k2hr3apiutil_1.default.isSafeString(tenant) && !k2hr3apiutil_1.default.compareCaseString(namematchs[2], tenant)) {
dbglogging_1.default.elog('Request query has wrong yrn full path(tenant=' + namematchs[2] + ') to policy(tenant=' + k2hr3apiutil_1.default.getSafeString(tenant) + ')');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
// check service name
if (k2hr3apiutil_1.default.isSafeString(service)) {
if (!k2hr3apiutil_1.default.compareCaseString(service, namematchs[1])) {
dbglogging_1.default.elog('Request query has service name(' + k2hr3apiutil_1.default.getSafeString(service) + ') and path has service name(' + namematchs[1] + '), but both are not same service name.');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
}
else if (k2hr3apiutil_1.default.isSafeString(namematchs[1])) {
// set service name
service = k2hr3apiutil_1.default.getSafeString(namematchs[1]).trim().toLowerCase();
keys = r3keys(null, tenant, service);
}
// set name
name = namematchs[3].toLowerCase();
policy_yrn = keys.POLICY_TOP_KEY + ':' + name;
}
// resource
if (!k2hr3apiutil_1.default.isSafeString(req.query.resource)) {
dbglogging_1.default.elog('HEAD request argument does not have resource parameter');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
// check resource is only resource name or full yrn path
let resource = k2hr3apiutil_1.default.getSafeString(req.query.resource);
let resourceptn = new RegExp('^' + keys.MATCH_ANY_TENANT_RESOURCE); // regex = /^yrn:yahoo:(.*)::(.*):resource:(.*)/
const resourcematchs = resource.match(resourceptn);
if (!k2hr3apiutil_1.default.isStringArray(resourcematchs) || !k2hr3apiutil_1.default.isNotEmptyArray(resourcematchs) || resourcematchs.length < 4) {
// resource is not matched resource(maybe not full yrn), thus we need tenant parameter
if (!k2hr3apiutil_1.default.isSafeString(tenant)) {
dbglogging_1.default.elog('HEAD request query does not have resource by full yrn(if you want to set only resource name, you must specify tenant url argument)');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
// if resource is yrn full path, then it is wrong policy resource
resourceptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
if (resource.match(resourceptn)) {
dbglogging_1.default.elog('HEAD request query has wrong yrn full path to resource');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
// make full yrn for policy resource
resource = keys.RESOURCE_TOP_KEY + ':' + resource;
}
// action
if (!k2hr3apiutil_1.default.isSafeString(req.query.action)) {
dbglogging_1.default.elog('HEAD request argument does not have action parameter');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
// check action is only action name or full yrn path
let action = k2hr3apiutil_1.default.getSafeString(req.query.action);
if (keys.VALUE_READ === action) {
action = keys.ACTION_READ_KEY;
}
else if (keys.VALUE_WRITE === action) {
action = keys.ACTION_WRITE_KEY;
}
else if (keys.ACTION_READ_KEY !== action && keys.ACTION_WRITE_KEY !== action) {
dbglogging_1.default.elog('HEAD request query has wrong action value');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// check policy
//------------------------------
const result = k2hr3dkc_1.default.checkPolicy(policy_yrn, resource, action);
if (!result.result) {
dbglogging_1.default.dlog('action(' + JSON.stringify(action) + ') to resource(' + JSON.stringify(resource) + ') is not allowed by policy(' + JSON.stringify(name) + ') : message=' + k2hr3apiutil_1.default.getSafeString(result.message));
k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
return;
}
dbglogging_1.default.dlog('action(' + JSON.stringify(action) + ') to resource(' + JSON.stringify(resource) + ') is allowed by policy(' + JSON.stringify(name) + ')');
res.status(204); // 204: No Content
res.send();
});
//
// Mountpath : '/v1/policy/*'
// DELETE '/v1/policy/name' : delete policy on version 1
//
router.delete('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
dbglogging_1.default.elog('DELETE request or url or query is wrong');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const keys = r3keys(token_info.user, token_info.tenant);
//------------------------------
// check policy name
//------------------------------
const requestptn = new RegExp('^/v1/policy/(.*)'); // regex = /^\/v1\/policy\/(.*)/
const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
const result = {
result: false,
message: 'GET request url does not have policy name'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
let name = reqmatchs[1].toLowerCase();
// policy name is only name or full yrn path
let nameptn = new RegExp('^' + keys.POLICY_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:policy:(.*)/
const namematchs = name.match(nameptn);
if (k2hr3apiutil_1.default.isStringArray(namematchs) && k2hr3apiutil_1.default.isNotEmptyArray(namematchs) && 2 <= namematchs.length) {
name = namematchs[1];
}
// check yrn full path(it is NG)
nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
if (name.match(nameptn)) {
const result = {
result: false,
message: 'DELETE request url has wrong yrn full path to policy'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// delete policy
//------------------------------
const pol_result = k2hr3dkc_1.default.removePolicy(token_info.user, token_info.tenant, name);
if (!k2hr3apiutil_1.default.isPlainObject(pol_result) || !k2hr3apiutil_1.default.isBoolean(pol_result.result) || false === pol_result.result) {
if (!k2hr3apiutil_1.default.isPlainObject(pol_result)) {
const result = {
result: false,
message: 'Could not get response from removePolicy'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden(is this status OK?)
}
else {
const result = {
result: k2hr3apiutil_1.default.isBoolean(pol_result.result) ? pol_result.result : false,
message: k2hr3apiutil_1.default.isString(pol_result.message) ? pol_result.message : 'Could not get error message in response from removePolicy'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden(is this status OK?)
}
return;
}
dbglogging_1.default.dlog('succeed : ' + pol_result.message);
res.status(204); // 204: No Content
res.send();
});
//---------------------------------------------------------
// Exports
//---------------------------------------------------------
//
// Functions
//
exports.default = router;
/*
* 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
*/