From 4886bf9e4eeaa5ccc8611301899582a4a2d7c597 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Thu, 17 Sep 2015 18:33:30 -0700 Subject: [PATCH 1/5] Expose authHandler and createClient helper functions --- src/plugins/elasticsearch/index.js | 2 + .../elasticsearch/lib/expose_auth_handler.js | 20 +++++ .../elasticsearch/lib/expose_client.js | 87 +++++++++++-------- 3 files changed, 74 insertions(+), 35 deletions(-) create mode 100644 src/plugins/elasticsearch/lib/expose_auth_handler.js diff --git a/src/plugins/elasticsearch/index.js b/src/plugins/elasticsearch/index.js index e193e30cec45..65742c7ca0fb 100644 --- a/src/plugins/elasticsearch/index.js +++ b/src/plugins/elasticsearch/index.js @@ -1,6 +1,7 @@ module.exports = function (kibana) { var healthCheck = require('./lib/health_check'); var exposeClient = require('./lib/expose_client'); + var exposeAuthHandler = require('./lib/expose_auth_handler'); var createProxy = require('./lib/create_proxy'); return new kibana.Plugin({ @@ -33,6 +34,7 @@ module.exports = function (kibana) { // Expose the client to the server exposeClient(server); + exposeAuthHandler(server); createProxy(server, 'GET', '/{paths*}'); createProxy(server, 'POST', '/_mget'); createProxy(server, 'POST', '/{index}/_search'); diff --git a/src/plugins/elasticsearch/lib/expose_auth_handler.js b/src/plugins/elasticsearch/lib/expose_auth_handler.js new file mode 100644 index 000000000000..038a679b8e97 --- /dev/null +++ b/src/plugins/elasticsearch/lib/expose_auth_handler.js @@ -0,0 +1,20 @@ +module.exports = (server) => { + + function authHandler(fn) { + return function (req, reply) { + return fn(req, reply) + .then(reply) + .catch(function (err) { + if (err.status === 401) { + return reply(err.body) + .header('WWW-Authenticate', 'Basic realm="Authorization Required"') + .code(401); + } + reply(err); + }); + }; + } + + server.expose('authHandler', authHandler); + +}; diff --git a/src/plugins/elasticsearch/lib/expose_client.js b/src/plugins/elasticsearch/lib/expose_client.js index c0a4972ee35c..ce9875bf5e5b 100644 --- a/src/plugins/elasticsearch/lib/expose_client.js +++ b/src/plugins/elasticsearch/lib/expose_client.js @@ -6,48 +6,65 @@ var url = require('url'); module.exports = function (server) { var config = server.config(); - var uri = url.parse(config.get('elasticsearch.url')); - var username = config.get('elasticsearch.username'); - var password = config.get('elasticsearch.password'); - var verifySsl = config.get('elasticsearch.ssl.verify'); - var clientCrt = config.get('elasticsearch.ssl.cert'); - var clientKey = config.get('elasticsearch.ssl.key'); - var ca = config.get('elasticsearch.ssl.ca'); - var apiVersion = config.get('elasticsearch.apiVersion'); - if (username && password) { - uri.auth = util.format('%s:%s', username, password); - } + function createClient(options) { + options = _.defaults(options || {}, { + url: config.get('elasticsearch.url'), + username: config.get('elasticsearch.username'), + password: config.get('elasticsearch.password'), + verifySsl: config.get('elasticsearch.ssl.verify'), + clientCrt: config.get('elasticsearch.ssl.cert'), + clientKey: config.get('elasticsearch.ssl.key'), + ca: config.get('elasticsearch.ssl.ca'), + apiVersion: config.get('elasticsearch.apiVersion'), + keepAlive: true + }); - var ssl = { rejectUnauthorized: verifySsl }; - if (clientCrt && clientKey) { - ssl.cert = fs.readFileSync(clientCrt, 'utf8'); - ssl.key = fs.readFileSync(clientKey, 'utf8'); - } - if (ca) { - ssl.ca = fs.readFileSync(ca, 'utf8'); - } + var uri = url.parse(options.url); - var client = new elasticsearch.Client({ - host: url.format(uri), - ssl: ssl, - apiVersion: apiVersion, - log: function () { - this.error = function (err) { - server.log(['error', 'elasticsearch'], err); - }; - this.warning = function (message) { - server.log(['warning', 'elasticsearch'], message); - }; - this.info = _.noop; - this.debug = _.noop; - this.trace = _.noop; - this.close = _.noop; + var authorization; + if (options.req) { + if (_.get(options.req, 'headers.authorization')) { + authorization = _.get(options.req, 'headers.authorization').replace('Basic ', ''); + uri.auth = new Buffer(authorization, 'base64').toString('utf8'); + } + } else if (options.username && options.password) { + uri.auth = util.format('%s:%s', options.username, options.password); } - }); + var ssl = { rejectUnauthorized: options.verifySsl }; + if (options.clientCrt && options.clientKey) { + ssl.cert = fs.readFileSync(options.clientCrt, 'utf8'); + ssl.key = fs.readFileSync(options.clientKey, 'utf8'); + } + if (options.ca) { + ssl.ca = fs.readFileSync(options.ca, 'utf8'); + } + + return new elasticsearch.Client({ + host: url.format(uri), + ssl: ssl, + apiVersion: options.apiVersion, + keepAlive: options.keepAlive, + log: function () { + this.error = function (err) { + server.log(['error', 'elasticsearch'], err); + }; + this.warning = function (message) { + server.log(['warning', 'elasticsearch'], message); + }; + this.info = _.noop; + this.debug = _.noop; + this.trace = _.noop; + this.close = _.noop; + } + }); + } + + var client = createClient(); server.on('close', _.bindKey(client, 'close')); server.expose('client', client); + server.expose('createClient', createClient); return client; From bdd0dc23b50654d71454c8a290d27fefc63d1174 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Fri, 18 Sep 2015 14:26:09 -0700 Subject: [PATCH 2/5] Changing to callWithRequest - Remove auth handler - Add callWithRequest - Create noAuthClient --- src/plugins/elasticsearch/index.js | 2 -- .../elasticsearch/lib/call_with_request.js | 19 ++++++++++++++++++ .../elasticsearch/lib/expose_auth_handler.js | 20 ------------------- .../elasticsearch/lib/expose_client.js | 16 ++++++++------- 4 files changed, 28 insertions(+), 29 deletions(-) create mode 100644 src/plugins/elasticsearch/lib/call_with_request.js delete mode 100644 src/plugins/elasticsearch/lib/expose_auth_handler.js diff --git a/src/plugins/elasticsearch/index.js b/src/plugins/elasticsearch/index.js index 65742c7ca0fb..e193e30cec45 100644 --- a/src/plugins/elasticsearch/index.js +++ b/src/plugins/elasticsearch/index.js @@ -1,7 +1,6 @@ module.exports = function (kibana) { var healthCheck = require('./lib/health_check'); var exposeClient = require('./lib/expose_client'); - var exposeAuthHandler = require('./lib/expose_auth_handler'); var createProxy = require('./lib/create_proxy'); return new kibana.Plugin({ @@ -34,7 +33,6 @@ module.exports = function (kibana) { // Expose the client to the server exposeClient(server); - exposeAuthHandler(server); createProxy(server, 'GET', '/{paths*}'); createProxy(server, 'POST', '/_mget'); createProxy(server, 'POST', '/{index}/_search'); diff --git a/src/plugins/elasticsearch/lib/call_with_request.js b/src/plugins/elasticsearch/lib/call_with_request.js new file mode 100644 index 000000000000..b4e1e01383ed --- /dev/null +++ b/src/plugins/elasticsearch/lib/call_with_request.js @@ -0,0 +1,19 @@ +const _ = require('lodash'); +const Promise = require('bluebird'); +const Boom = require('boom'); +module.exports = (client) => { + return (req, endpoint, params = {}) => { + if (req.headers.authorization) { + _.set(params, 'headers.authorization', req.headers.authorization); + } + const api = _.get(client, endpoint).bind(client); + console.log(params); + return api(params).catch((err) => { + if (err.status === 401) { + const options = { realm: 'Authorization Required' }; + return Promise.reject(Boom.unauthorized(err.body, 'Basic', options)); + } + return Promise.reject(err); + }); + }; +}; diff --git a/src/plugins/elasticsearch/lib/expose_auth_handler.js b/src/plugins/elasticsearch/lib/expose_auth_handler.js deleted file mode 100644 index 038a679b8e97..000000000000 --- a/src/plugins/elasticsearch/lib/expose_auth_handler.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = (server) => { - - function authHandler(fn) { - return function (req, reply) { - return fn(req, reply) - .then(reply) - .catch(function (err) { - if (err.status === 401) { - return reply(err.body) - .header('WWW-Authenticate', 'Basic realm="Authorization Required"') - .code(401); - } - reply(err); - }); - }; - } - - server.expose('authHandler', authHandler); - -}; diff --git a/src/plugins/elasticsearch/lib/expose_client.js b/src/plugins/elasticsearch/lib/expose_client.js index ce9875bf5e5b..c5b683ea19f7 100644 --- a/src/plugins/elasticsearch/lib/expose_client.js +++ b/src/plugins/elasticsearch/lib/expose_client.js @@ -3,6 +3,7 @@ var _ = require('lodash'); var fs = require('fs'); var util = require('util'); var url = require('url'); +var callWithRequest = require('./call_with_request'); module.exports = function (server) { var config = server.config(); @@ -17,18 +18,14 @@ module.exports = function (server) { clientKey: config.get('elasticsearch.ssl.key'), ca: config.get('elasticsearch.ssl.ca'), apiVersion: config.get('elasticsearch.apiVersion'), - keepAlive: true + keepAlive: true, + auth: true }); var uri = url.parse(options.url); var authorization; - if (options.req) { - if (_.get(options.req, 'headers.authorization')) { - authorization = _.get(options.req, 'headers.authorization').replace('Basic ', ''); - uri.auth = new Buffer(authorization, 'base64').toString('utf8'); - } - } else if (options.username && options.password) { + if (options.auth && options.username && options.password) { uri.auth = util.format('%s:%s', options.username, options.password); } @@ -63,8 +60,13 @@ module.exports = function (server) { var client = createClient(); server.on('close', _.bindKey(client, 'close')); + + var noAuthClient = createClient({ auth: false }); + server.on('close', _.bindKey(noAuthClient, 'close')); + server.expose('client', client); server.expose('createClient', createClient); + server.expose('callWithRequest', callWithRequest(noAuthClient)); return client; From 2367934ab5406f54700211925be54d019bb03768 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Fri, 18 Sep 2015 14:45:22 -0700 Subject: [PATCH 3/5] removing console.log --- src/plugins/elasticsearch/lib/call_with_request.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/elasticsearch/lib/call_with_request.js b/src/plugins/elasticsearch/lib/call_with_request.js index b4e1e01383ed..7b43dc79d600 100644 --- a/src/plugins/elasticsearch/lib/call_with_request.js +++ b/src/plugins/elasticsearch/lib/call_with_request.js @@ -7,7 +7,6 @@ module.exports = (client) => { _.set(params, 'headers.authorization', req.headers.authorization); } const api = _.get(client, endpoint).bind(client); - console.log(params); return api(params).catch((err) => { if (err.status === 401) { const options = { realm: 'Authorization Required' }; From a52895bf3f5a81f31d6f49ed30aaa152cc76ed04 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Fri, 18 Sep 2015 15:43:26 -0700 Subject: [PATCH 4/5] Refactoring to use call instead of bind --- .../elasticsearch/lib/call_with_request.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/plugins/elasticsearch/lib/call_with_request.js b/src/plugins/elasticsearch/lib/call_with_request.js index 7b43dc79d600..6abf865c67d3 100644 --- a/src/plugins/elasticsearch/lib/call_with_request.js +++ b/src/plugins/elasticsearch/lib/call_with_request.js @@ -6,13 +6,14 @@ module.exports = (client) => { if (req.headers.authorization) { _.set(params, 'headers.authorization', req.headers.authorization); } - const api = _.get(client, endpoint).bind(client); - return api(params).catch((err) => { - if (err.status === 401) { - const options = { realm: 'Authorization Required' }; - return Promise.reject(Boom.unauthorized(err.body, 'Basic', options)); - } - return Promise.reject(err); - }); + return _.get(client, endpoint) + .call(client, params) + .catch((err) => { + if (err.status === 401) { + const options = { realm: 'Authorization Required' }; + return Promise.reject(Boom.unauthorized(err.body, 'Basic', options)); + } + return Promise.reject(err); + }); }; }; From b2e83dcf5d7e27e5ea767ad587a6c87e6c8183e1 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Fri, 18 Sep 2015 16:14:56 -0700 Subject: [PATCH 5/5] Adding endpoint missing exception --- src/plugins/elasticsearch/lib/call_with_request.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/elasticsearch/lib/call_with_request.js b/src/plugins/elasticsearch/lib/call_with_request.js index 6abf865c67d3..5df624faea93 100644 --- a/src/plugins/elasticsearch/lib/call_with_request.js +++ b/src/plugins/elasticsearch/lib/call_with_request.js @@ -6,8 +6,9 @@ module.exports = (client) => { if (req.headers.authorization) { _.set(params, 'headers.authorization', req.headers.authorization); } - return _.get(client, endpoint) - .call(client, params) + const api = _.get(client, endpoint); + if (!api) throw new Error(`callWithRequest called with an invalid endpoint: ${endpoint}`); + return api.call(client, params) .catch((err) => { if (err.status === 401) { const options = { realm: 'Authorization Required' };