Merge pull request #5 from srinandan/master
add debug statements for oauth
diff --git a/healthcheck/index.js b/healthcheck/index.js
new file mode 100644
index 0000000..cc2bcb9
--- /dev/null
+++ b/healthcheck/index.js
@@ -0,0 +1,30 @@
+'use strict';
+
+var toobusy = require('toobusy-js');
+var debug = require('debug')('gateway:healthcheck');
+
+const HEALTHCHECK_URL = '/healthcheck';
+
+module.exports.init = function(config, logger, stats) {
+ return {
+ onrequest: function(req, res, next) {
+ var healthcheck_url = config['healthcheck_url'] || HEALTHCHECK_URL
+ if(healthcheck_url == req.url) {
+ var statusCode = (this.toobusy() ? 503 : 200)
+ debug(statusCode)
+ var healthInfo = {
+ memoryUsage: process.memoryUsage(),
+ cpuUsage: process.cpuUsage(),
+ uptime: process.uptime(),
+ pid: process.pid
+ }
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' })
+ res.write(JSON.stringify(healthInfo))
+ res.end()
+ }
+ else {
+ next()
+ }
+ }
+ }
+}
diff --git a/healthcheck/package.json b/healthcheck/package.json
new file mode 100644
index 0000000..ae4a118
--- /dev/null
+++ b/healthcheck/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "edgemicro-healthcheck",
+ "version": "1.0.0",
+ "description": "A basic plugin for healthcheck",
+ "dependencies": {
+ "debug": "^2.2.0",
+ "toobusy-js": "^0.5.1"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/apigee/microgateway-plugins.git"
+ },
+ "author": "srinandan",
+ "license": "Apache 2.0",
+ "bugs": {
+ "url": "https://github.com/apigee/microgateway-plugins/issues"
+ },
+ "homepage": "https://github.com/apigee/microgateway-plugins#readme"
+}
diff --git a/json2xml/index.js b/json2xml/index.js
new file mode 100644
index 0000000..2b78e72
--- /dev/null
+++ b/json2xml/index.js
@@ -0,0 +1,194 @@
+'use strict';
+/**
+ * This plugin accumulates data chunks from the client into an array
+ * property on the request or response, concats them on end. Then
+ * transforms the request or response based on 'accept' or 'content-type'
+ * headers.
+ *
+ * If the HTTP verb is GET and the Accept type does not match the
+ * response type, the plugin will attempt to transform it (from
+ * xml to json or vice versa).
+ *
+ * If the HTTP verb is NOT GET then the content-type is used. If the
+ * content-type is set to 'json', then an attempt is made to transform to
+ * 'xml' and vice-versa.
+ *
+ * This plugin can be disabled by sending the 'x-apigee-json2xml' http
+ * header.
+ *
+ * Users should be aware that buffering large requests or responses in
+ * memory can cause Apigee Edge Microgateway to run out of memory under
+ * high load or with a large number of concurrent requests. So this plugin
+ * should only be used when it is known that request/response bodies are small.
+ */
+
+var debug = require('debug')('plugin:json2xml');
+//library to convert json to xml
+var js2xmlparser = require("js2xmlparser");
+//library to convert xml to json
+var parseString = require("xml2js").parseString;
+var util = require("util");
+
+module.exports.init = function (config, logger, stats) {
+
+ //initialize the variables to false
+
+ //variables to control whether request and/or response transformation should take place
+ var requestXML = false;
+ var requestJSON = false;
+ var responseJSON = false;
+ var responseXML = false;
+ //use these variables to determine the content type of response sent by target server
+ var responseIsXML = false;
+ var responseIsJSON = false;
+ //flag to control whether transfornation should take place
+ var disable = false;
+
+ //method to accumulate responses
+ function accumulateResponse(res, data) {
+ debug('plugin accumulateResponse');
+ if (!res._chunks) res._chunks = [];
+ res._chunks.push(data);
+ }
+
+ //method to accumulate requests
+ function accumulateRequest(req, data) {
+ debug('plugin accumulateRequest');
+ if (disable) return;
+ if (!req._chunks) req._chunks = [];
+ req._chunks.push(data);
+ }
+
+ return {
+
+ onrequest: function(req, res, next) {
+ debug('plugin onrequest');
+ var method = req.method.toLowerCase();
+ var acceptType = req.headers['accept'];
+ var contentType = req.headers['content-type'];
+
+ if (req.headers['x-apigee-json2xml-disable']) disable = true;
+
+ debug("accept header: " + acceptType);
+ debug("content-type header: " + contentType);
+
+ //if plugin is disabled don't process headers.
+ if (!disable) {
+ if (method === "get" && acceptType === "application/xml") {
+ responseXML = true;
+ } else if (method === "get" && acceptType === "application/json") {
+ responseJSON = true;
+ } else if (method !== "get" && contentType === "application/json") {
+ requestJSON = true;
+ responseJSON = true;
+ } else if (method !== "get" && contentType === "application/xml") {
+ requestXML = true;
+ responseXML = true;
+ }
+ }
+
+ debug("requestJSON flag is " + requestJSON);
+ debug("responseJSON flag is " + responseJSON);
+
+ debug("requestXML flag is " + requestXML);
+ debug("responseXML flag is " + responseXML);
+
+ debug("plugin disabled: " + disable);
+
+ next();
+ },
+ // indicates start of target response
+ // response headers and status code should be available at this time
+ onresponse: function(req, res, next) {
+ debug('plugin onresponse');
+ //nothing to do on response
+ next();
+ },
+ //
+ ondata_request: function(req, res, data, next) {
+ debug('plugin ondata_request');
+ if (data && data.length > 0 && disable == false) accumulateRequest(req, data);
+ next(null, null);
+ },
+ //
+ //
+ ondata_response: function(req, res, data, next) {
+ debug('plugin ondata_response');
+ if (data && data.length > 0 && disable == false) accumulateResponse(res, data);
+ next(null, null);
+ },
+ //
+ onend_request: function(req, res, data, next) {
+ debug('plugin onend_request');
+ if (data && data.length > 0 && disable == false) accumulateRequest(res, data);
+ var content = null;
+ if(req._chunks && req._chunks.length) {
+ content = Buffer.concat(req._chunks);
+ }
+ delete req._chunks;
+
+ //if pugin is disabled, don't do anything
+ if (!disable) {
+ if (requestJSON) {
+ //the request needs to be transformed to xml before sending to
+ //the target server.
+
+ //set request content type.
+ req.setHeader('Content-Type', 'application/xml');
+ next(null, js2xmlparser.parse("Root",JSON.parse(content)));
+ } else if (requestXML) {
+ //set request content type.
+ req.setHeader('Content-Type', 'application/json');
+ parseString(content.toString(), function(err, js){
+ if (err) next (err);
+ next(null, JSON.stringify(js));
+ });
+ } else { //do nothing
+ next(null, content);
+ }
+ } else {
+ next(null, content);
+ }
+ },
+ //
+ onend_response: function(req, res, data, next) {
+ debug('plugin onend_request');
+ if (data && data.length > 0 && disable == false) accumulateResponse(res, data);
+
+ var contentType = res.getHeader('content-type');
+ if (contentType === "application/xml") {
+ responseIsXML = true;
+ } else if (contentType === "application/json") {
+ responseIsJSON = true;
+ }
+
+ debug("responseIsJSON flag is " + responseIsJSON);
+ debug("responseIsXML flag is" + responseIsXML);
+
+
+ var content = null;
+ if(res._chunks && res._chunks.length) {
+ content = Buffer.concat(res._chunks);
+ }
+ delete res._chunks;
+
+ //if disabled don't do anything.
+ if (!disable) {
+ if (responseXML && responseIsJSON) {
+ res.setHeader('Content-Type', 'application/xml');
+ next(null, js2xmlparser.parse("Root",JSON.parse(content)));
+ } else if (responseJSON && responseIsXML) {
+ res.setHeader('Content-Type', 'application/json');
+ parseString(content.toString(), function(err, js){
+ if (err) next (err);
+ next(null, JSON.stringify(js));
+ });
+ } else {
+ next(null, content);
+ }
+ } else {
+ next(null, content);
+ }
+ }
+ };
+}
\ No newline at end of file
diff --git a/json2xml/package.json b/json2xml/package.json
new file mode 100644
index 0000000..52013ed
--- /dev/null
+++ b/json2xml/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "edgemicro-json2xml",
+ "version": "1.0.0",
+ "description": "This plugin transforms JSON to XML and vice versa based on the Accept and Content-Type http headers",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "srinandan",
+ "license": "Apache 2.0",
+ "dependencies": {
+ "debug": "^2.2.0",
+ "js2xmlparser": "^2.0.2",
+ "xml2js": "^0.4.17"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/apigee/microgateway-plugins.git"
+ },
+ "bugs": {
+ "url": "https://github.com/apigee/microgateway-plugins/issues"
+ },
+ "homepage": "https://github.com/apigee/microgateway-plugins#readme"
+}
diff --git a/oauth/index.js b/oauth/index.js
index 3a4ccc4..75d4ed0 100644
--- a/oauth/index.js
+++ b/oauth/index.js
@@ -32,11 +32,13 @@
} else if (config.allowNoAuthorization) {
return next();
} else {
+ debug('missing_authorization');
return sendError(req, res, next, logger, stats, 'missing_authorization', 'Missing Authorization header');
}
} else {
var header = authHeaderRegex.exec(req.headers[authHeaderName]);
if (!header || header.length < 2) {
+ debug('Invalid Authorization Header');
return sendError(req, res, next, logger, stats, 'invalid_request', 'Invalid Authorization header');
}
@@ -74,8 +76,14 @@
json: { 'apiKey': apiKey },
headers: { 'x-dna-api-key': apiKey }
}, function (err, response, body) {
- if (err) return sendError(req, res, next, logger, stats, 'gateway_timeout', err.message);
- if (response.statusCode !== 200) return sendError(req, res, next, logger, stats, 'access_denied', response.statusMessage);
+ if (err) {
+ debug('verify apikey gateway timeout');
+ return sendError(req, res, next, logger, stats, 'gateway_timeout', err.message);
+ }
+ if (response.statusCode !== 200) {
+ debug('verify apikey access_denied');
+ return sendError(req, res, next, logger, stats, 'access_denied', response.statusMessage);
+ }
verify(body, config, logger, stats, middleware, req, res, next, apiKey);
});
}
@@ -100,10 +108,12 @@
} else {
if (err.name === 'TokenExpiredError') {
+ debug('Token expired error');
return sendError(req, res, next, logger, stats, 'access_denied');
}
// todo: check other properties and/or give client more info?
+ debug('invalid token');
return sendError(req, res, next, logger, stats, 'invalid_token');
}
}
@@ -164,12 +174,12 @@
// then check if that proxy is one of the authorized proxies in bootstrap
const checkIfAuthorized = module.exports.checkIfAuthorized = function checkIfAuthorized(config, urlPath, proxy, decodedToken) {
- if (!decodedToken.api_product_list) { return false; }
+ if (!decodedToken.api_product_list) { debug('no api product list'); return false; }
return decodedToken.api_product_list.some(function (product) {
const validProxyNames = config.product_to_proxy[product];
- if (!validProxyNames) { return false; }
+ if (!validProxyNames) { debug('no proxies found for product'); return false; }
const apiproxies = config.product_to_api_resource[product];
var matchesProxyRules = false;
@@ -177,6 +187,7 @@
apiproxies.forEach(function (tempApiProxy) {
if(matchesProxyRules){
//found one
+ debug('found matching proxy rule');
return;
}
const apiproxy = tempApiProxy.includes(proxy.base_path)