k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
264 lines (241 loc) • 8.09 kB
JavaScript
/*
* 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: Mon Nov 6 2017
* REVISION:
*
*/
;
var express = require('express');
var router = express.Router();
var http = require('http');
var https = require('https');
var cacerts = require('../lib/cacerts');
var r3token = require('../lib/k2hr3tokens');
var apiutil = require('../lib/k2hr3apiutil');
var resutil = require('../lib/k2hr3resutil');
// Debug logging objects
var r3logger = require('../lib/dbglogging');
//
// Debug Verify URL
//
// This router is for debugging verify url for dummy service.
// This is called only on development environment.
//
// Mountpath : '/v1/debug/verify'
//
// GET '/v1/debug/verify' : get verify for debug on version 1
// URL argument
// service : service name(default testservice)
// HEADER : X-Auth-Token => Scoped User token(without 'U=' prefix)
// response body = [ : undefined/null or resource array(if one element, allows only it not array)
// {
// 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
// ... :
// } :
// },
// ]
//
router.get('/', function(req, res, next)
{
r3logger.dlog('CALL:', req.method, req.url);
var _req = req;
var _res = res;
var _next = next;
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');
//
// Check request
//
if( !apiutil.isSafeEntity(_req) ||
!apiutil.isSafeString(_req.baseUrl) ||
!apiutil.isSafeString(_req.method) ||
!apiutil.isSafeString(_req.protocol) ||
!apiutil.isSafeEntity(_req.query) ||
(!apiutil.isSafeString(_req.host) && !apiutil.isSafeString(_req.hostname)) ||
!apiutil.isSafeEntity(_req.headers) ||
!apiutil.isSafeEntity(_req.headers.host) )
{
r3logger.elog('GET request or url or token is wrong');
resutil.errResponse(_req, _res, 400); // 400: Bad Request
return;
}
//
// check token
//
var token_result = r3token.checkToken(req, true, true); // scoped, user token
if(!token_result.result){
r3logger.elog(token_result.message);
var _status = token_result.status;
delete token_result.status;
resutil.errResponse(req, res, _status, token_result);
return;
}
var _token_info = token_result.token_info;
//
// check arguments
//
var _service_name = 'testservice'; // [NOTE] default service name
if(apiutil.isSafeString(req.query.service) && apiutil.isSafeString(req.query.service.trim())){
_service_name = req.query.service.trim();
}
//
// Check localhost information for ACR API
//
var urlobj = apiutil.parseUrl(_req.protocol + '://' + _req.headers.host);
if(!urlobj.https){
if(!apiutil.compareCaseString(_req.protocol, 'http')){
r3logger.elog('Original request url method is not as same as request method');
resutil.errResponse(_req, _res, 400); // 400: Bad Request
return;
}
}else{
if(!apiutil.compareCaseString(_req.protocol, 'https')){
r3logger.elog('Original request url method is not as same as request method');
resutil.errResponse(_req, _res, 400); // 400: Bad Request
return;
}
}
if(urlobj.host !== apiutil.getSafeString(_req.host) && urlobj.host !== apiutil.getSafeString(_req.hostname)){
r3logger.elog('Original request url host is not as same as request host');
resutil.errResponse(_req, _res, 400); // 400: Bad Request
return;
}
//
// Make request data
//
var headers = {
'Content-Type': 'application/json',
'Content-Length': 0,
'X-Auth-Token': apiutil.getSafeString(_req.headers['x-auth-token']) // Transfer
};
var options = {
'host': urlobj.host,
'port': urlobj.port,
'path': '/v1/acr/' + _service_name,
'method': 'GET',
'headers': headers
};
var agent;
if(urlobj.https){
if(null !== cacerts.ca){
options.ca = cacerts.ca;
}
options.agent = new https.Agent(options);
agent = https;
}else{
options.agent = new http.Agent(options);
agent = http;
}
r3logger.dlog('request options = ' + JSON.stringify(options));
r3logger.dlog('request headers = ' + JSON.stringify(headers));
//
// Send request to localhost
//
var subreq = agent.request(options, function(subres)
{
var _body = '';
var _status = subres.statusCode;
var _headers= subres.headers;
r3logger.dlog('/v1/acr/testservice response status: ' + _status);
r3logger.dlog('/v1/acr/testservice response header: ' + JSON.stringify(_headers));
subres.setEncoding('utf8');
subres.on('data', function(chunk)
{
//r3logger.dlog('/v1/acr/testservice response chunk: ' + chunk);
_body += chunk;
});
subres.on('end', function(result) // eslint-disable-line no-unused-vars
{
var _error = null;
if(300 <= _status){
_error = new Error('got error response for verify request by status=' + String(_status));
r3logger.elog(_error.message);
resutil.errResponse(_req, _res, _status, _error.message); // 4xx, 5xx
return;
}
//r3logger.dlog('/v1/acr/testservice response body: ' + _body);
//
// Check response body
//
if(apiutil.checkSimpleJSON(_body)){
_body = JSON.parse(_body);
}
if( !apiutil.isSafeEntity(_body) ||
!apiutil.isSafeEntity(_body.tokeninfo) ||
!apiutil.isSafeString(_body.tokeninfo.service) ||
!apiutil.compareCaseString(_body.tokeninfo.service, _service_name) ||
!apiutil.isSafeString(_body.tokeninfo.user) ||
!apiutil.isSafeString(_body.tokeninfo.tenant) )
{
_error = new Error('/v1/acr/testservice response is something wrong(' + JSON.stringify(_body) + ').');
r3logger.elog(_error.message);
resutil.errResponse(_req, _res, 400, _error.message); // 400: Bad Request
return;
}
r3logger.dlog('Call Verify URL: verified user(' + _body.user + ') and tenant(' + _body.tenant + ')');
//
// Make response body for debug
//
var resobj = [
{
name: _service_name + '_resource', // resource name
expire: null, // no expire
type: 'string', // resource is string type
data: _service_name + ' resource data for debug', // resource data(string)
keys: {
'creator': apiutil.getSafeString(_token_info.user),
'owner_tenant': apiutil.getSafeString(_token_info.tenant),
'service_name': _service_name,
'token': 'sample_token_value',
'accesskey': 'sample_accesskey_value',
'secretkey': 'sample_secretkey_value',
'anykey': 'sample_value'
}
}
];
//
// Return response
//
r3logger.dlog('succeed : ' + JSON.stringify(resobj));
_res.status(200); // 200: OK
_res.send(JSON.stringify(resobj));
});
});
subreq.on('error', function(exception) {
r3logger.elog(exception.message);
resutil.errResponse(_req, _res, exception.code, exception.message); // 4xx, 5xx
return;
});
subreq.end();
});
module.exports = 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
*/