Revert "Add Multi-Tenancy for keystone plugin"
Problem with stability.
Problem with `yar` dependencies.
This reverts commit aab355dae6
.
Change-Id: Iba1b6be9d3608a951544a79bfd4859ca64a7c15f
This commit is contained in:
parent
aab355dae6
commit
4752d35777
25
index.js
25
index.js
@ -12,12 +12,11 @@
|
|||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import session from './server/session';
|
module.exports = (kibana) => {
|
||||||
import binding from './server/binding';
|
|
||||||
import healthCheck from './server/healthcheck';
|
|
||||||
|
|
||||||
export default (kibana) => {
|
const session = require('./server/session');
|
||||||
const COOKIE_PASSWORD_SIZE = 32;
|
const proxy = require('./server/proxy');
|
||||||
|
const healthCheck = require('./server/healthcheck');
|
||||||
|
|
||||||
return new kibana.Plugin({
|
return new kibana.Plugin({
|
||||||
require: ['elasticsearch'],
|
require: ['elasticsearch'],
|
||||||
@ -28,19 +27,17 @@ export default (kibana) => {
|
|||||||
function config(Joi) {
|
function config(Joi) {
|
||||||
|
|
||||||
const cookie = Joi.object({
|
const cookie = Joi.object({
|
||||||
name : Joi.string()
|
|
||||||
.default('keystone'),
|
|
||||||
password : Joi.string()
|
password : Joi.string()
|
||||||
.min(COOKIE_PASSWORD_SIZE)
|
.min(16)
|
||||||
.default(require('crypto').randomBytes(COOKIE_PASSWORD_SIZE).toString('hex')),
|
.default(require('crypto').randomBytes(16).toString('hex')),
|
||||||
isSecure : Joi.boolean()
|
isSecure : Joi.boolean()
|
||||||
.default(process.env.NODE_ENV !== 'development'),
|
.default(false),
|
||||||
ignoreErrors: Joi.boolean()
|
ignoreErrors: Joi.boolean()
|
||||||
.default(true),
|
.default(true),
|
||||||
expiresIn : Joi.number()
|
expiresIn : Joi.number()
|
||||||
.positive()
|
.positive()
|
||||||
.integer()
|
.integer()
|
||||||
.default(60 * 60 * 1000) // 1 hour
|
.default(24 * 60 * 60 * 1000) // 1 day
|
||||||
}).default();
|
}).default();
|
||||||
|
|
||||||
return Joi.object({
|
return Joi.object({
|
||||||
@ -54,11 +51,9 @@ export default (kibana) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init(server) {
|
function init(server) {
|
||||||
server.log(['status', 'debug', 'keystone'], 'Initializing keystone plugin');
|
session(server);
|
||||||
binding(server).start();
|
proxy(server);
|
||||||
session(server).start();
|
|
||||||
healthCheck(this, server).start();
|
healthCheck(this, server).start();
|
||||||
server.log(['status', 'debug', 'keystone'], 'Initialized keystone plugin');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
17
package.json
17
package.json
@ -1,14 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "fts-keystone",
|
"name": "fts-keystone",
|
||||||
"version": "0.0.2",
|
"version": "0.0.1",
|
||||||
"description": "Keystone authentication & multitenancy support for Kibana 4.4.x",
|
"description": "Keystone authentication support for Kibana 4.4.x",
|
||||||
"author": "Fujitsu Enabling Software Technology GmbH",
|
"author": "Fujitsu Enabling Software Technology GmbH",
|
||||||
"license": "Apache-2.0",
|
"licenses": "Apache-2.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"kibana",
|
"kibana",
|
||||||
"authentication",
|
"authentication",
|
||||||
"keystone",
|
"keystone",
|
||||||
"multitenancy",
|
|
||||||
"plugin"
|
"plugin"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -23,9 +22,8 @@
|
|||||||
},
|
},
|
||||||
"main": "gulpfile.js",
|
"main": "gulpfile.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hoek": "^4.0.1",
|
"yar": "^4.2.0",
|
||||||
"keystone-v3-client": "^0.0.7",
|
"keystone-v3-client": "^0.0.7"
|
||||||
"yar": "^7.x.x"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -45,14 +43,11 @@
|
|||||||
"gulp-mocha": "^2.2.0",
|
"gulp-mocha": "^2.2.0",
|
||||||
"gulp-tar": "^1.8.0",
|
"gulp-tar": "^1.8.0",
|
||||||
"gulp-util": "^3.0.7",
|
"gulp-util": "^3.0.7",
|
||||||
"joi": "^9.0.4",
|
|
||||||
"lodash": "^4.2.1",
|
"lodash": "^4.2.1",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"proxyquire": "^1.7.4",
|
"proxyquire": "^1.7.4",
|
||||||
"rimraf": "^2.5.1",
|
"rimraf": "^2.5.1",
|
||||||
"rsync": "^0.4.0",
|
"rsync": "^0.4.0",
|
||||||
"semver": "^5.3.0",
|
"sinon": "^1.17.3"
|
||||||
"sinon": "^1.17.3",
|
|
||||||
"wreck": "^8.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const sinon = require('sinon');
|
|
||||||
const chai = require('chai');
|
|
||||||
const proxyRequire = require('proxyquire');
|
|
||||||
|
|
||||||
describe('fts-keystone', () => {
|
|
||||||
describe('binding', () => {
|
|
||||||
|
|
||||||
it('should expose tokens & users', () => {
|
|
||||||
|
|
||||||
let tokens = sinon.spy();
|
|
||||||
let users = sinon.spy();
|
|
||||||
|
|
||||||
let server = {
|
|
||||||
config: sinon.stub().returns({
|
|
||||||
get: sinon.spy()
|
|
||||||
}),
|
|
||||||
expose: sinon.spy()
|
|
||||||
};
|
|
||||||
|
|
||||||
proxyRequire('../binding', {
|
|
||||||
'keystone-v3-client/lib/keystone/tokens': tokens,
|
|
||||||
'keystone-v3-client/lib/keystone/users' : users
|
|
||||||
})(server).start();
|
|
||||||
|
|
||||||
chai.expect(server.expose.callCount).to.be.eq(2);
|
|
||||||
chai.expect(server.expose.calledWith('tokens', tokens));
|
|
||||||
chai.expect(server.expose.calledWith('users', users));
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -52,7 +52,6 @@ describe('plugins/fts-keystone', ()=> {
|
|||||||
|
|
||||||
server = {
|
server = {
|
||||||
log : sinon.stub(),
|
log : sinon.stub(),
|
||||||
on : sinon.stub(),
|
|
||||||
config: function () {
|
config: function () {
|
||||||
return {
|
return {
|
||||||
get: configGet
|
get: configGet
|
||||||
@ -64,7 +63,6 @@ describe('plugins/fts-keystone', ()=> {
|
|||||||
|
|
||||||
it('should set status to green if keystone available', (done)=> {
|
it('should set status to green if keystone available', (done)=> {
|
||||||
let expectedCode = 200;
|
let expectedCode = 200;
|
||||||
let expectedStatus = true;
|
|
||||||
let healthcheck = proxyRequire('../healthcheck', {
|
let healthcheck = proxyRequire('../healthcheck', {
|
||||||
'http': {
|
'http': {
|
||||||
request: (_, callback)=> {
|
request: (_, callback)=> {
|
||||||
@ -84,8 +82,8 @@ describe('plugins/fts-keystone', ()=> {
|
|||||||
|
|
||||||
check
|
check
|
||||||
.run()
|
.run()
|
||||||
.then((status) => {
|
.then((code) => {
|
||||||
chai.expect(expectedStatus).to.be.equal(status);
|
chai.expect(expectedCode).to.be.equal(code);
|
||||||
chai.expect(plugin.status.green.calledWith('Ready')).to.be.ok;
|
chai.expect(plugin.status.green.calledWith('Ready')).to.be.ok;
|
||||||
})
|
})
|
||||||
.finally(done);
|
.finally(done);
|
||||||
@ -94,7 +92,6 @@ describe('plugins/fts-keystone', ()=> {
|
|||||||
|
|
||||||
it('should set status to red if keystone not available', (done) => {
|
it('should set status to red if keystone not available', (done) => {
|
||||||
let expectedCode = 500;
|
let expectedCode = 500;
|
||||||
let expectedStatus = false;
|
|
||||||
let healthcheck = proxyRequire('../healthcheck', {
|
let healthcheck = proxyRequire('../healthcheck', {
|
||||||
'http': {
|
'http': {
|
||||||
request: (_, callback)=> {
|
request: (_, callback)=> {
|
||||||
@ -114,8 +111,8 @@ describe('plugins/fts-keystone', ()=> {
|
|||||||
|
|
||||||
check
|
check
|
||||||
.run()
|
.run()
|
||||||
.catch((status) => {
|
.catch((code) => {
|
||||||
chai.expect(expectedStatus).to.be.equal(status);
|
chai.expect(expectedCode).to.be.equal(code);
|
||||||
chai.expect(plugin.status.red.calledWith('Unavailable')).to.be.ok;
|
chai.expect(plugin.status.red.calledWith('Unavailable')).to.be.ok;
|
||||||
})
|
})
|
||||||
.finally(done);
|
.finally(done);
|
||||||
|
174
server/__tests__/proxy.spec.js
Normal file
174
server/__tests__/proxy.spec.js
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 FUJITSU LIMITED
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const proxyRequire = require('proxyquire');
|
||||||
|
const Promise = require('bluebird');
|
||||||
|
const sinon = require('sinon');
|
||||||
|
const chai = require('chai');
|
||||||
|
|
||||||
|
describe('plugins/fts-keystone', ()=> {
|
||||||
|
describe('proxy', ()=> {
|
||||||
|
describe('proxy_check', ()=> {
|
||||||
|
|
||||||
|
const keystoneUrl = 'http://localhost'; // mocking http
|
||||||
|
const keystonePort = 9000;
|
||||||
|
|
||||||
|
let server;
|
||||||
|
let configGet;
|
||||||
|
|
||||||
|
beforeEach(()=> {
|
||||||
|
configGet = sinon.stub();
|
||||||
|
configGet.withArgs('fts-keystone.url').returns(keystoneUrl);
|
||||||
|
configGet.withArgs('fts-keystone.port').returns(keystonePort);
|
||||||
|
|
||||||
|
server = {
|
||||||
|
log : sinon.stub(),
|
||||||
|
config: function () {
|
||||||
|
return {
|
||||||
|
get: configGet
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing if not /elasticsearch call', ()=> {
|
||||||
|
let checkSpy = sinon.spy();
|
||||||
|
let retrieveTokenSpy = sinon.spy();
|
||||||
|
let proxy = proxyRequire('../proxy/proxy', {
|
||||||
|
'keystone-v3-client/lib/keystone/tokens': () => {
|
||||||
|
return {check: checkSpy};
|
||||||
|
},
|
||||||
|
'./retrieveToken' : retrieveTokenSpy
|
||||||
|
})(server);
|
||||||
|
let request = {
|
||||||
|
url: {
|
||||||
|
path: '/bundles/styles.css'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = {
|
||||||
|
'continue': sinon.spy()
|
||||||
|
};
|
||||||
|
|
||||||
|
proxy(request, reply);
|
||||||
|
|
||||||
|
chai.expect(reply.continue.calledOnce).to.be.ok;
|
||||||
|
chai.expect(checkSpy.called).to.not.be.ok;
|
||||||
|
chai.expect(retrieveTokenSpy.called).to.not.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should authenticate with keystone', (done)=> {
|
||||||
|
|
||||||
|
let token = '1234567890';
|
||||||
|
let checkStub = sinon.stub().returns(Promise.resolve());
|
||||||
|
let retrieveTokenStub = sinon.stub().returns(token);
|
||||||
|
|
||||||
|
let proxy = proxyRequire('../proxy/proxy', {
|
||||||
|
'keystone-v3-client/lib/keystone/tokens': () => {
|
||||||
|
return {check: checkStub};
|
||||||
|
},
|
||||||
|
'./retrieveToken' : retrieveTokenStub
|
||||||
|
})(server);
|
||||||
|
let request = {
|
||||||
|
session: {
|
||||||
|
'get' : sinon.stub(),
|
||||||
|
'set' : sinon.stub()
|
||||||
|
},
|
||||||
|
url : {
|
||||||
|
path: '/elasticsearch/.kibana'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let reply = {
|
||||||
|
'continue': sinon.spy()
|
||||||
|
};
|
||||||
|
let replyCall;
|
||||||
|
|
||||||
|
proxy(request, reply)
|
||||||
|
.finally(verifyStubs)
|
||||||
|
.done(done);
|
||||||
|
|
||||||
|
function verifyStubs() {
|
||||||
|
chai.expect(reply.continue.calledOnce).to.be.ok;
|
||||||
|
replyCall = reply.continue.firstCall.args;
|
||||||
|
|
||||||
|
chai.expect(replyCall).to.be.empty;
|
||||||
|
|
||||||
|
// other stubs
|
||||||
|
chai.expect(checkStub.calledOnce).to.be.ok;
|
||||||
|
chai.expect(checkStub.calledWithExactly({
|
||||||
|
headers: {
|
||||||
|
'X-Auth-Token' : token,
|
||||||
|
'X-Subject-Token': token
|
||||||
|
}
|
||||||
|
})).to.be.ok;
|
||||||
|
|
||||||
|
chai.expect(retrieveTokenStub.calledOnce).to.be.ok;
|
||||||
|
chai.expect(retrieveTokenStub.calledWithExactly(server, request))
|
||||||
|
.to.be.ok;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not authenticate with keystone', (done)=> {
|
||||||
|
let token = '1234567890';
|
||||||
|
let checkStub = sinon.stub().returns(Promise.reject({
|
||||||
|
statusCode: 666
|
||||||
|
}));
|
||||||
|
let retrieveTokenStub = sinon.stub().returns(token);
|
||||||
|
let proxy = proxyRequire('../proxy/proxy', {
|
||||||
|
'keystone-v3-client/lib/keystone/tokens': () => {
|
||||||
|
return {check: checkStub};
|
||||||
|
},
|
||||||
|
'./retrieveToken' : retrieveTokenStub
|
||||||
|
})(server);
|
||||||
|
let request = {
|
||||||
|
session: {
|
||||||
|
'get' : sinon.stub(),
|
||||||
|
'set' : sinon.stub()
|
||||||
|
},
|
||||||
|
url : {
|
||||||
|
path: '/elasticsearch/.kibana'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = sinon.spy();
|
||||||
|
let replyCall;
|
||||||
|
|
||||||
|
proxy(request, reply)
|
||||||
|
.finally(verifyStubs)
|
||||||
|
.done(done);
|
||||||
|
|
||||||
|
function verifyStubs() {
|
||||||
|
chai.expect(reply.calledOnce).to.be.ok;
|
||||||
|
replyCall = reply.firstCall.args[0];
|
||||||
|
|
||||||
|
chai.expect(replyCall.isBoom).to.be.ok;
|
||||||
|
|
||||||
|
// other stubs
|
||||||
|
chai.expect(checkStub.calledOnce).to.be.ok;
|
||||||
|
chai.expect(checkStub.calledWithExactly({
|
||||||
|
headers: {
|
||||||
|
'X-Auth-Token' : token,
|
||||||
|
'X-Subject-Token': token
|
||||||
|
}
|
||||||
|
})).to.be.ok;
|
||||||
|
|
||||||
|
chai.expect(retrieveTokenStub.calledOnce).to.be.ok;
|
||||||
|
chai.expect(retrieveTokenStub.calledWithExactly(server, request))
|
||||||
|
.to.be.ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -15,176 +15,157 @@
|
|||||||
const sinon = require('sinon');
|
const sinon = require('sinon');
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
|
|
||||||
const retrieveToken = require('../mt/auth/token');
|
const retrieveToken = require('../proxy/retrieveToken');
|
||||||
const CONSTANTS = require('../const');
|
|
||||||
const RELOAD_SYMBOL = require('../mt/auth/reload');
|
|
||||||
|
|
||||||
describe('plugins/fts-keystone', ()=> {
|
describe('plugins/fts-keystone', ()=> {
|
||||||
describe('mt', ()=> {
|
describe('proxy', ()=> {
|
||||||
describe('auth', () => {
|
describe('retrieveToken', ()=> {
|
||||||
describe('token', ()=> {
|
|
||||||
|
|
||||||
let server;
|
let server;
|
||||||
|
|
||||||
beforeEach(()=> {
|
beforeEach(()=> {
|
||||||
server = {
|
server = {
|
||||||
log: sinon.stub()
|
log: sinon.stub()
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return isBoom if session not available', ()=> {
|
it('should return isBoom if session not available', ()=> {
|
||||||
let request = {};
|
let request = {};
|
||||||
let errMsg = /Session support is missing/;
|
let errMsg = /Session support is missing/;
|
||||||
|
|
||||||
chai.expect(()=> {
|
chai.expect(()=> {
|
||||||
retrieveToken(server, request);
|
retrieveToken(server, request);
|
||||||
}).to.throw(errMsg);
|
}).to.throw(errMsg);
|
||||||
|
|
||||||
request = {
|
request = {
|
||||||
yar: undefined
|
session: undefined
|
||||||
};
|
};
|
||||||
chai.expect(()=> {
|
chai.expect(()=> {
|
||||||
retrieveToken(server, request);
|
retrieveToken(server, request);
|
||||||
}).to.throw(errMsg);
|
}).to.throw(errMsg);
|
||||||
|
|
||||||
request = {
|
request = {
|
||||||
session: null
|
session: null
|
||||||
};
|
};
|
||||||
chai.expect(()=> {
|
chai.expect(()=> {
|
||||||
retrieveToken(server, request);
|
retrieveToken(server, request);
|
||||||
}).to.throw(errMsg);
|
}).to.throw(errMsg);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should Boom with unauthorized if token not in header or session', function () {
|
it('should Boom with unauthorized if token not in header or session', function () {
|
||||||
let expectedMsg = 'You\'re not logged into the OpenStack. Please login via Horizon Dashboard';
|
let expectedMsg = 'You\'re not logged into the OpenStack. Please login via Horizon Dashboard';
|
||||||
let request = {
|
let request = {
|
||||||
yar : {
|
session: {
|
||||||
'get': sinon
|
'get': sinon
|
||||||
.stub()
|
|
||||||
.withArgs(CONSTANTS.SESSION_TOKEN_KEY)
|
|
||||||
.returns(undefined)
|
|
||||||
},
|
|
||||||
headers: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = retrieveToken(server, request);
|
|
||||||
chai.expect(result.isBoom).to.be.true;
|
|
||||||
chai.expect(result.output.payload.message).to.be.eq(expectedMsg);
|
|
||||||
chai.expect(result.output.statusCode).to.be.eq(401);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use session token if requested does not have it', () => {
|
|
||||||
let expectedToken = 'SOME_RANDOM_TOKEN';
|
|
||||||
let yar = {
|
|
||||||
'reset': sinon.spy(),
|
|
||||||
'set' : sinon.spy(),
|
|
||||||
'get' : sinon.stub()
|
|
||||||
};
|
|
||||||
let request = {
|
|
||||||
yar : yar,
|
|
||||||
headers: {}
|
|
||||||
};
|
|
||||||
let token;
|
|
||||||
|
|
||||||
yar.get.returns(expectedToken);
|
|
||||||
|
|
||||||
token = retrieveToken(server, request);
|
|
||||||
chai.expect(token).not.to.be.undefined;
|
|
||||||
chai.expect(token).to.be.eql(expectedToken);
|
|
||||||
|
|
||||||
console.log(yar.get.callCount);
|
|
||||||
|
|
||||||
chai.expect(yar.get.callCount).to.be.eq(2);
|
|
||||||
chai.expect(yar.set.calledOnce).not.to.be.ok;
|
|
||||||
chai.expect(
|
|
||||||
yar.set.calledWithExactly(CONSTANTS.SESSION_TOKEN_KEY, expectedToken)
|
|
||||||
).not.to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set token in session if not there and request has it', () => {
|
|
||||||
let expectedToken = 'SOME_RANDOM_TOKEN';
|
|
||||||
let yar = {
|
|
||||||
'reset': sinon.spy(),
|
|
||||||
'set' : sinon.spy(),
|
|
||||||
'get' : sinon.stub()
|
|
||||||
};
|
|
||||||
let request = {
|
|
||||||
yar : yar,
|
|
||||||
headers: {
|
|
||||||
'x-auth-token': expectedToken
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let token;
|
|
||||||
|
|
||||||
yar.get
|
|
||||||
.withArgs(CONSTANTS.SESSION_TOKEN_KEY)
|
|
||||||
.onCall(0).returns(undefined)
|
|
||||||
.onCall(1).returns(expectedToken);
|
|
||||||
|
|
||||||
token = retrieveToken(server, request);
|
|
||||||
chai.expect(token).to.not.be.undefined;
|
|
||||||
chai.expect(token).to.be.eql(expectedToken);
|
|
||||||
|
|
||||||
chai.expect(yar.get.callCount).to.be.eq(2);
|
|
||||||
chai.expect(yar.set.calledOnce).to.be.ok;
|
|
||||||
|
|
||||||
chai.expect(
|
|
||||||
yar.set.calledWithExactly(
|
|
||||||
CONSTANTS.SESSION_TOKEN_KEY,
|
|
||||||
expectedToken
|
|
||||||
)
|
|
||||||
).to.be.ok;
|
|
||||||
chai.expect(
|
|
||||||
yar.set.calledWithExactly(
|
|
||||||
CONSTANTS.SESSION_TOKEN_CHANGED,
|
|
||||||
CONSTANTS.TOKEN_CHANGED_VALUE
|
|
||||||
)
|
|
||||||
).to.not.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update token in session if request\'s token is different', ()=> {
|
|
||||||
let expectedToken = 'SOME_RANDOM_TOKEN';
|
|
||||||
let oldToken = 'OLD_TOKEN';
|
|
||||||
|
|
||||||
let headers = {
|
|
||||||
'x-auth-token': expectedToken
|
|
||||||
};
|
|
||||||
let yar = {
|
|
||||||
'reset': sinon.stub(),
|
|
||||||
'get' : sinon
|
|
||||||
.stub()
|
.stub()
|
||||||
.withArgs(CONSTANTS.SESSION_TOKEN_KEY)
|
.withArgs('keystone_token')
|
||||||
.returns(oldToken),
|
.returns(undefined)
|
||||||
'set' : sinon.spy()
|
},
|
||||||
};
|
headers: {}
|
||||||
let token;
|
};
|
||||||
let request = {
|
|
||||||
yar : yar,
|
|
||||||
headers: headers
|
|
||||||
};
|
|
||||||
|
|
||||||
token = retrieveToken(server, request);
|
let result = retrieveToken(server, request);
|
||||||
chai.expect(token).to.not.be.undefined;
|
chai.expect(result.isBoom).to.be.true;
|
||||||
chai.expect(token).to.be.eql(RELOAD_SYMBOL);
|
chai.expect(result.output.payload.message).to.be.eq(expectedMsg);
|
||||||
|
chai.expect(result.output.statusCode).to.be.eq(401);
|
||||||
|
});
|
||||||
|
|
||||||
chai.expect(yar.reset.calledOnce).to.be.ok;
|
it('should use session token if requested does not have it', () => {
|
||||||
chai.expect(yar.get.calledOnce).to.be.ok;
|
let expectedToken = 'SOME_RANDOM_TOKEN';
|
||||||
|
let yar = {
|
||||||
|
'set': sinon
|
||||||
|
.spy(),
|
||||||
|
'get': sinon
|
||||||
|
.stub()
|
||||||
|
.withArgs('keystone_token')
|
||||||
|
.returns(expectedToken)
|
||||||
|
};
|
||||||
|
let request = {
|
||||||
|
session: yar,
|
||||||
|
headers: {}
|
||||||
|
};
|
||||||
|
let token;
|
||||||
|
|
||||||
chai.expect(yar.set.callCount).to.be.eq(2);
|
token = retrieveToken(server, request);
|
||||||
chai.expect(
|
chai.expect(token).not.to.be.undefined;
|
||||||
yar.set.calledWithExactly(
|
chai.expect(token).to.be.eql(expectedToken);
|
||||||
CONSTANTS.SESSION_TOKEN_KEY,
|
|
||||||
expectedToken
|
|
||||||
)
|
|
||||||
).to.be.ok;
|
|
||||||
chai.expect(
|
|
||||||
yar.set.calledWithExactly(
|
|
||||||
CONSTANTS.SESSION_TOKEN_CHANGED,
|
|
||||||
CONSTANTS.TOKEN_CHANGED_VALUE
|
|
||||||
)
|
|
||||||
).to.be.ok;
|
|
||||||
|
|
||||||
});
|
chai.expect(
|
||||||
|
yar.get.calledOnce
|
||||||
|
).to.be.ok;
|
||||||
|
chai.expect(
|
||||||
|
yar.set.calledOnce
|
||||||
|
).not.to.be.ok;
|
||||||
|
chai.expect(
|
||||||
|
yar.set.calledWithExactly('keystone_token', expectedToken)
|
||||||
|
).not.to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set token in session if not there and request has it', () => {
|
||||||
|
let expectedToken = 'SOME_RANDOM_TOKEN';
|
||||||
|
let yar = {
|
||||||
|
'set': sinon
|
||||||
|
.spy(),
|
||||||
|
'get': sinon
|
||||||
|
.stub()
|
||||||
|
.withArgs('keystone_token')
|
||||||
|
.returns(undefined)
|
||||||
|
};
|
||||||
|
let request = {
|
||||||
|
session: yar,
|
||||||
|
headers: {
|
||||||
|
'x-auth-token': expectedToken
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let token;
|
||||||
|
|
||||||
|
token = retrieveToken(server, request);
|
||||||
|
chai.expect(token).to.not.be.undefined;
|
||||||
|
chai.expect(token).to.be.eql(expectedToken);
|
||||||
|
|
||||||
|
chai.expect(
|
||||||
|
yar.get.calledOnce
|
||||||
|
).to.be.ok;
|
||||||
|
chai.expect(
|
||||||
|
yar.set.calledOnce
|
||||||
|
).to.be.ok;
|
||||||
|
chai.expect(
|
||||||
|
yar.set.calledWithExactly('keystone_token', expectedToken)
|
||||||
|
).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update token in session if request\'s token is different', ()=> {
|
||||||
|
let expectedToken = 'SOME_RANDOM_TOKEN';
|
||||||
|
let headers = {
|
||||||
|
'x-auth-token': expectedToken
|
||||||
|
};
|
||||||
|
let yar = {
|
||||||
|
'get': sinon
|
||||||
|
.stub()
|
||||||
|
.withArgs('keystone_token')
|
||||||
|
.returns('SOME_OLD_TOKEN'),
|
||||||
|
'set': sinon
|
||||||
|
.spy()
|
||||||
|
};
|
||||||
|
let token;
|
||||||
|
let request = {
|
||||||
|
session: yar,
|
||||||
|
headers: headers
|
||||||
|
};
|
||||||
|
|
||||||
|
token = retrieveToken(server, request);
|
||||||
|
chai.expect(token).to.not.be.undefined;
|
||||||
|
chai.expect(token).to.be.eql(expectedToken);
|
||||||
|
|
||||||
|
chai.expect(
|
||||||
|
yar.get.calledOnce
|
||||||
|
).to.be.ok;
|
||||||
|
chai.expect(
|
||||||
|
yar.set.calledOnce
|
||||||
|
).to.be.ok;
|
||||||
|
chai.expect(
|
||||||
|
yar.set.calledWithExactly('keystone_token', expectedToken)
|
||||||
|
).to.be.ok;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const sinon = require('sinon');
|
|
||||||
const chai = require('chai');
|
|
||||||
const proxyRequire = require('proxyquire');
|
|
||||||
|
|
||||||
describe('plugins/fts-keystone', () => {
|
|
||||||
describe('mt', () => {
|
|
||||||
describe('routing', () => {
|
|
||||||
describe('createProxy', () => {
|
|
||||||
const kibanaIndex = '.kibana';
|
|
||||||
const server = {
|
|
||||||
log : sinon.spy(),
|
|
||||||
config: sinon.stub().returns({
|
|
||||||
get: sinon.stub().withArgs('kibana.index').returns(kibanaIndex)
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let mgetHandler;
|
|
||||||
let pathsHandler;
|
|
||||||
let kibanaIndexHandler;
|
|
||||||
let defaultHandler;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mgetHandler = sinon.stub().returns({});
|
|
||||||
pathsHandler = sinon.stub().returns({});
|
|
||||||
kibanaIndexHandler = sinon.stub().returns({});
|
|
||||||
defaultHandler = sinon.stub().returns({});
|
|
||||||
|
|
||||||
server.route = sinon.spy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should load mget handler if that is the route', () => {
|
|
||||||
const route = '/_mget';
|
|
||||||
const method = sinon.spy();
|
|
||||||
|
|
||||||
proxyRequire('../mt/routing/_create_proxy', {
|
|
||||||
'./routes/mget' : mgetHandler,
|
|
||||||
'./routes/paths' : pathsHandler,
|
|
||||||
'./routes/kibana_index': kibanaIndexHandler,
|
|
||||||
'./routes/default' : defaultHandler
|
|
||||||
})(server, method, route);
|
|
||||||
|
|
||||||
chai.expect(mgetHandler.calledOnce).to.be.ok;
|
|
||||||
chai.expect(mgetHandler.calledWith(server, method, sinon.match.string)).to.be.ok;
|
|
||||||
|
|
||||||
chai.expect(pathsHandler.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(kibanaIndexHandler.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(defaultHandler.calledOnce).to.not.be.ok;
|
|
||||||
|
|
||||||
chai.expect(server.route.calledWith(sinon.match.object)).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should load paths handler if that is the route', () => {
|
|
||||||
const route = '/{paths*}';
|
|
||||||
const method = sinon.spy();
|
|
||||||
|
|
||||||
proxyRequire('../mt/routing/_create_proxy', {
|
|
||||||
'./routes/mget' : mgetHandler,
|
|
||||||
'./routes/paths' : pathsHandler,
|
|
||||||
'./routes/kibana_index': kibanaIndexHandler,
|
|
||||||
'./routes/default' : defaultHandler
|
|
||||||
})(server, method, route);
|
|
||||||
|
|
||||||
chai.expect(pathsHandler.calledOnce).to.be.ok;
|
|
||||||
chai.expect(pathsHandler.calledWith(server, method, sinon.match.string)).to.be.ok;
|
|
||||||
|
|
||||||
chai.expect(mgetHandler.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(kibanaIndexHandler.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(defaultHandler.calledOnce).to.not.be.ok;
|
|
||||||
|
|
||||||
chai.expect(server.route.calledWith(sinon.match.object)).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should load default handler if that is the route', () => {
|
|
||||||
const route = '/other';
|
|
||||||
const method = sinon.spy();
|
|
||||||
|
|
||||||
proxyRequire('../mt/routing/_create_proxy', {
|
|
||||||
'./routes/mget' : mgetHandler,
|
|
||||||
'./routes/paths' : pathsHandler,
|
|
||||||
'./routes/kibana_index': kibanaIndexHandler,
|
|
||||||
'./routes/default' : defaultHandler
|
|
||||||
})(server, method, route);
|
|
||||||
|
|
||||||
chai.expect(defaultHandler.calledOnce).to.be.ok;
|
|
||||||
chai.expect(defaultHandler.calledWith(server, method, sinon.match.string)).to.be.ok;
|
|
||||||
|
|
||||||
chai.expect(mgetHandler.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(kibanaIndexHandler.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(pathsHandler.calledOnce).to.not.be.ok;
|
|
||||||
|
|
||||||
chai.expect(server.route.calledWith(sinon.match.object)).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should load kibana handler if that is the route', () => {
|
|
||||||
const route = `/${kibanaIndex}/{paths*}`;
|
|
||||||
const method = sinon.spy();
|
|
||||||
|
|
||||||
proxyRequire('../mt/routing/_create_proxy', {
|
|
||||||
'./routes/mget' : mgetHandler,
|
|
||||||
'./routes/paths' : pathsHandler,
|
|
||||||
'./routes/kibana_index': kibanaIndexHandler,
|
|
||||||
'./routes/default' : defaultHandler
|
|
||||||
})(server, method, route);
|
|
||||||
|
|
||||||
chai.expect(kibanaIndexHandler.calledOnce).to.be.ok;
|
|
||||||
chai.expect(kibanaIndexHandler.calledWith(server, method, sinon.match.string)).to.be.ok;
|
|
||||||
|
|
||||||
chai.expect(mgetHandler.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(defaultHandler.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(pathsHandler.calledOnce).to.not.be.ok;
|
|
||||||
|
|
||||||
chai.expect(server.route.calledWith(sinon.match.object)).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const sinon = require('sinon');
|
|
||||||
const chai = require('chai');
|
|
||||||
const proxyRequire = require('proxyquire');
|
|
||||||
|
|
||||||
describe('plugins/fts-keystone', () => {
|
|
||||||
describe('mt', () => {
|
|
||||||
describe('routing', () => {
|
|
||||||
describe('reRoute', () => {
|
|
||||||
const prefix = '/test';
|
|
||||||
const server = {
|
|
||||||
log: sinon.spy()
|
|
||||||
};
|
|
||||||
|
|
||||||
it('should re-route ElasticSearch request', () => {
|
|
||||||
const requestPath = '/elasticsearch/something/a/b/c';
|
|
||||||
|
|
||||||
let request = {
|
|
||||||
setUrl: sinon.spy()
|
|
||||||
};
|
|
||||||
let reply = {
|
|
||||||
continue: sinon.spy()
|
|
||||||
};
|
|
||||||
let utils = {
|
|
||||||
requestPath: sinon.stub().withArgs(request).returns(requestPath),
|
|
||||||
isESRequest: sinon.stub().withArgs(request).returns(true)
|
|
||||||
};
|
|
||||||
|
|
||||||
proxyRequire('../mt/routing/_re_route', {
|
|
||||||
'../../util': utils,
|
|
||||||
'./_utils' : {
|
|
||||||
PREFIX: prefix
|
|
||||||
}
|
|
||||||
})(server)(request, reply);
|
|
||||||
|
|
||||||
chai.expect(request.setUrl.calledOnce).to.be.ok;
|
|
||||||
chai.expect(request.setUrl.calledWith(`${prefix}${requestPath}`)).to.be.ok;
|
|
||||||
chai.expect(reply.continue.calledOnce).to.be.ok;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not re-route non-ElasticSearch request', () => {
|
|
||||||
const requestPath = '/resources/cool.ico';
|
|
||||||
|
|
||||||
let request = {
|
|
||||||
setUrl: sinon.spy()
|
|
||||||
};
|
|
||||||
let reply = {
|
|
||||||
continue: sinon.spy()
|
|
||||||
};
|
|
||||||
let utils = {
|
|
||||||
requestPath: sinon.stub().withArgs(request).returns(requestPath),
|
|
||||||
isESRequest: sinon.stub().withArgs(request).returns(false)
|
|
||||||
};
|
|
||||||
|
|
||||||
proxyRequire('../mt/routing/_re_route', {
|
|
||||||
'../../util': utils,
|
|
||||||
'./_utils' : {
|
|
||||||
PREFIX: prefix
|
|
||||||
}
|
|
||||||
})(server)(request, reply);
|
|
||||||
|
|
||||||
chai.expect(request.setUrl.calledOnce).to.not.be.ok;
|
|
||||||
chai.expect(request.setUrl.calledWith(`${prefix}${requestPath}`)).to.not.be.ok;
|
|
||||||
chai.expect(reply.continue.calledOnce).to.be.ok;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const sinon = require('sinon');
|
|
||||||
const chai = require('chai');
|
|
||||||
const proxyRequire = require('proxyquire');
|
|
||||||
|
|
||||||
describe('plugins/fts-keystone', ()=> {
|
|
||||||
describe('mt', ()=> {
|
|
||||||
describe('routing', () => {
|
|
||||||
|
|
||||||
const createProxy = sinon.spy();
|
|
||||||
const serverLog = sinon.spy();
|
|
||||||
|
|
||||||
let serverExt;
|
|
||||||
let server;
|
|
||||||
let reRoute;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
serverExt = sinon.spy();
|
|
||||||
server = {
|
|
||||||
log: serverLog,
|
|
||||||
ext: serverExt
|
|
||||||
};
|
|
||||||
reRoute = sinon.spy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should load re-route logic', (done) => {
|
|
||||||
|
|
||||||
proxyRequire('../mt/routing', {
|
|
||||||
'./_create_proxy': createProxy,
|
|
||||||
'./_re_route' : reRoute
|
|
||||||
})(server).then(verify);
|
|
||||||
|
|
||||||
function verify(route) {
|
|
||||||
chai.expect(serverExt.calledOnce).to.be.ok;
|
|
||||||
chai.expect(serverExt.calledWith('onRequest', reRoute));
|
|
||||||
chai.expect(createProxy).to.be.eq(route);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const sinon = require('sinon');
|
|
||||||
const chai = require('chai');
|
|
||||||
const proxyRequire = require('proxyquire');
|
|
||||||
|
|
||||||
const CONSTANTS = require('../const');
|
|
||||||
|
|
||||||
describe('plugins/fts-keystone', ()=> {
|
|
||||||
describe('mt', ()=> {
|
|
||||||
describe('verify', () => {
|
|
||||||
|
|
||||||
it('should skip if session not available', () => {
|
|
||||||
let server = {
|
|
||||||
log: sinon.spy()
|
|
||||||
};
|
|
||||||
let request = {
|
|
||||||
yar: {
|
|
||||||
_store: undefined
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let reply = {
|
|
||||||
continue: sinon.spy()
|
|
||||||
};
|
|
||||||
|
|
||||||
require('../mt/verify')(server)(request, reply);
|
|
||||||
chai.expect(reply.continue.calledOnce).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should skip if session available but user object not found', () => {
|
|
||||||
let server = {
|
|
||||||
log: sinon.spy()
|
|
||||||
};
|
|
||||||
let request = {
|
|
||||||
yar: {
|
|
||||||
_store: {
|
|
||||||
'1': 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let reply = {
|
|
||||||
continue: sinon.spy()
|
|
||||||
};
|
|
||||||
|
|
||||||
require('../mt/verify')(server)(request, reply);
|
|
||||||
chai.expect(reply.continue.calledOnce).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should skip non ElasticSearch requests', () => {
|
|
||||||
let store = {};
|
|
||||||
|
|
||||||
store[CONSTANTS.SESSION_USER_KEY] = {'id': 1};
|
|
||||||
|
|
||||||
let server = {
|
|
||||||
log: sinon.spy()
|
|
||||||
};
|
|
||||||
let request = {
|
|
||||||
url : {
|
|
||||||
path: '/some/other/path'
|
|
||||||
},
|
|
||||||
yar: {
|
|
||||||
_store: store
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let reply = {
|
|
||||||
continue: sinon.spy()
|
|
||||||
};
|
|
||||||
|
|
||||||
require('../mt/verify')(server)(request, reply);
|
|
||||||
chai.expect(reply.continue.calledOnce).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call verify indexPattern', () => {
|
|
||||||
let store = {};
|
|
||||||
let indexPattern = '*';
|
|
||||||
|
|
||||||
store[CONSTANTS.SESSION_USER_KEY] = {'id': 1};
|
|
||||||
|
|
||||||
let server = {
|
|
||||||
log: sinon.spy()
|
|
||||||
};
|
|
||||||
let request = {
|
|
||||||
method: 'GET',
|
|
||||||
url : {
|
|
||||||
path: `/elasticsearch/${indexPattern}/_mapping/field/`
|
|
||||||
},
|
|
||||||
yar: {
|
|
||||||
_store: store
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let verifyIndexPattern = sinon.spy();
|
|
||||||
|
|
||||||
proxyRequire('../mt/verify', {
|
|
||||||
'./_verify_index_pattern': verifyIndexPattern
|
|
||||||
})(server)(request);
|
|
||||||
|
|
||||||
chai.expect(verifyIndexPattern.calledOnce).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const sinon = require('sinon');
|
|
||||||
const chai = require('chai');
|
|
||||||
|
|
||||||
const CONSTANTS = require('../const');
|
|
||||||
const verifyIndexPattern = require('../mt/verify/_verify_index_pattern');
|
|
||||||
|
|
||||||
describe('plugins/fts-keystone', ()=> {
|
|
||||||
describe('mt', ()=> {
|
|
||||||
describe('verify', () => {
|
|
||||||
describe('verify_index_pattern', () => {
|
|
||||||
|
|
||||||
it('should reject * as index-pattern', () => {
|
|
||||||
let indexPattern = '*';
|
|
||||||
let request = {
|
|
||||||
url: {
|
|
||||||
path: `/a/${indexPattern}/`
|
|
||||||
},
|
|
||||||
yar: {
|
|
||||||
_store: {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
verifyIndexPattern(request, (result) => {
|
|
||||||
chai.expect(result.isBoom)
|
|
||||||
.to.be.true;
|
|
||||||
chai.expect(result.output.payload.message)
|
|
||||||
.to.be.eq('* as pattern is not supported at the moment');
|
|
||||||
chai.expect(result.output.statusCode)
|
|
||||||
.to.be.eq(422);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reject index-pattern if it does not match user`s projects', () => {
|
|
||||||
let projects = [
|
|
||||||
{ id: 'project_1'}, { id: 'project_2' }, {id: 'project_3'}
|
|
||||||
];
|
|
||||||
let indexPattern = 'test';
|
|
||||||
let store = {};
|
|
||||||
|
|
||||||
store[CONSTANTS.SESSION_PROJECTS_KEY] = projects;
|
|
||||||
|
|
||||||
let request = {
|
|
||||||
url: {
|
|
||||||
path: `/a/${indexPattern}/`
|
|
||||||
},
|
|
||||||
yar: {
|
|
||||||
_store: store
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let reply = sinon.spy();
|
|
||||||
|
|
||||||
verifyIndexPattern(request, (result) => {
|
|
||||||
chai.expect(result.isBoom)
|
|
||||||
.to.be.true;
|
|
||||||
chai.expect(result.output.payload.message)
|
|
||||||
.to.be.eq(`${indexPattern} do not match any project of current user`);
|
|
||||||
chai.expect(result.output.statusCode)
|
|
||||||
.to.be.eq(422);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should accept index-pattern it it constaint project id', () => {
|
|
||||||
let projects = [
|
|
||||||
{ id: 'project_1'}, { id: 'project_2' }, {id: 'project_3'}
|
|
||||||
];
|
|
||||||
let indexPattern = projects[1].id;
|
|
||||||
let store = {};
|
|
||||||
|
|
||||||
store[CONSTANTS.SESSION_PROJECTS_KEY] = projects;
|
|
||||||
|
|
||||||
let request = {
|
|
||||||
url: {
|
|
||||||
path: `/a/${indexPattern}/`
|
|
||||||
},
|
|
||||||
yar: {
|
|
||||||
_store: store
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let reply = {
|
|
||||||
continue: sinon.spy()
|
|
||||||
};
|
|
||||||
|
|
||||||
verifyIndexPattern(request, reply);
|
|
||||||
chai.expect(reply.continue.calledOnce).to.be.ok;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import TokensApi from 'keystone-v3-client/lib/keystone/tokens';
|
|
||||||
import UsersApi from 'keystone-v3-client/lib/keystone/users';
|
|
||||||
|
|
||||||
module.exports = function binding(server) {
|
|
||||||
const config = server.config();
|
|
||||||
const keystoneCfg = {
|
|
||||||
url: `${config.get('fts-keystone.url')}:${config.get('fts-keystone.port')}`
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
start: () => {
|
|
||||||
server.expose('tokens', new TokensApi(keystoneCfg));
|
|
||||||
server.expose('users', new UsersApi(keystoneCfg));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const NOW_TIME = (new Date().valueOf() / 1000);
|
|
||||||
|
|
||||||
export const SESSION_USER_KEY = `fts-keystone-user-${NOW_TIME}`;
|
|
||||||
export const SESSION_TOKEN_KEY = `fts-keystone-token-${NOW_TIME}`;
|
|
||||||
export const SESSION_PROJECTS_KEY = `fts-keystone-projects-${NOW_TIME}`;
|
|
||||||
export const SESSION_TOKEN_CHANGED = `fts-keystone-token-changed-${NOW_TIME}`;
|
|
||||||
|
|
||||||
export const TOKEN_CHANGED_VALUE = Symbol('token-changed');
|
|
@ -12,19 +12,18 @@
|
|||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import url from 'url';
|
const Promise = require('bluebird');
|
||||||
import Promise from 'bluebird';
|
const url = require('url');
|
||||||
|
|
||||||
import util from '../util';
|
const util = require('../util/');
|
||||||
|
|
||||||
|
module.exports = function (plugin, server) {
|
||||||
|
let timeoutId;
|
||||||
|
|
||||||
module.exports = function healthcheck(plugin, server) {
|
|
||||||
const config = server.config();
|
const config = server.config();
|
||||||
const keystoneUrl = config.get('fts-keystone.url');
|
const keystoneUrl = config.get('fts-keystone.url');
|
||||||
const keystonePort = config.get('fts-keystone.port');
|
const keystonePort = config.get('fts-keystone.port');
|
||||||
const request = getRequest();
|
const request = getRequest();
|
||||||
|
|
||||||
let timeoutId;
|
|
||||||
|
|
||||||
const service = {
|
const service = {
|
||||||
run : check,
|
run : check,
|
||||||
start : start,
|
start : start,
|
||||||
@ -34,12 +33,22 @@ module.exports = function healthcheck(plugin, server) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
server.on('stop', stop);
|
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
||||||
|
function getRequest() {
|
||||||
|
let required;
|
||||||
|
if (util.startsWith(keystoneUrl, 'https')) {
|
||||||
|
required = require('https');
|
||||||
|
} else {
|
||||||
|
required = require('http');
|
||||||
|
}
|
||||||
|
return required.request;
|
||||||
|
}
|
||||||
|
|
||||||
function check() {
|
function check() {
|
||||||
|
|
||||||
return new Promise((resolve, reject)=> {
|
return new Promise((resolve, reject)=> {
|
||||||
|
|
||||||
const req = request({
|
const req = request({
|
||||||
hostname: getHostname(),
|
hostname: getHostname(),
|
||||||
port : keystonePort,
|
port : keystonePort,
|
||||||
@ -48,13 +57,12 @@ module.exports = function healthcheck(plugin, server) {
|
|||||||
const statusCode = res.statusCode;
|
const statusCode = res.statusCode;
|
||||||
if (statusCode >= 400) {
|
if (statusCode >= 400) {
|
||||||
plugin.status.red('Unavailable');
|
plugin.status.red('Unavailable');
|
||||||
reject(false);
|
reject(statusCode);
|
||||||
} else {
|
} else {
|
||||||
plugin.status.green('Ready');
|
plugin.status.green('Ready');
|
||||||
resolve(true);
|
resolve(statusCode);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
req.on('error', (error)=> {
|
req.on('error', (error)=> {
|
||||||
plugin.status.red('Unavailable: Failed to communicate with Keystone');
|
plugin.status.red('Unavailable: Failed to communicate with Keystone');
|
||||||
server.log(['keystone', 'healthcheck', 'error'], `${error.message}`);
|
server.log(['keystone', 'healthcheck', 'error'], `${error.message}`);
|
||||||
@ -62,9 +70,14 @@ module.exports = function healthcheck(plugin, server) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
req.end();
|
req.end();
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getHostname() {
|
||||||
|
return url.parse(keystoneUrl).hostname;
|
||||||
|
}
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
scheduleCheck(service.stop() ? 10000 : 1);
|
scheduleCheck(service.stop() ? 10000 : 1);
|
||||||
}
|
}
|
||||||
@ -96,18 +109,4 @@ module.exports = function healthcheck(plugin, server) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHostname() {
|
|
||||||
return url.parse(keystoneUrl).hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRequest() {
|
|
||||||
let required;
|
|
||||||
if (util.startsWith(keystoneUrl, 'https')) {
|
|
||||||
required = require('https');
|
|
||||||
} else {
|
|
||||||
required = require('http');
|
|
||||||
}
|
|
||||||
return required.request;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Boom from 'boom';
|
|
||||||
import Joi from 'joi';
|
|
||||||
|
|
||||||
import { SESSION_USER_KEY } from '../../const';
|
|
||||||
import lookupToken from './token';
|
|
||||||
import RELOAD from './reload';
|
|
||||||
|
|
||||||
const RELOAD_MARKUP = `<html>
|
|
||||||
<head><script type="text/javascript">window.location.reload();</script></head>
|
|
||||||
<body>reloading...</body>
|
|
||||||
</html>`;
|
|
||||||
const NOOP = ()=> {
|
|
||||||
};
|
|
||||||
const SCHEMA = {
|
|
||||||
tokenOk : Joi.func().default(NOOP),
|
|
||||||
tokenBad: Joi.func().default(NOOP)
|
|
||||||
};
|
|
||||||
|
|
||||||
export default (server, opts) => {
|
|
||||||
Joi.assert(opts, SCHEMA, 'Invalid keystone auth options');
|
|
||||||
|
|
||||||
const tokensApi = server.plugins['fts-keystone'].tokens;
|
|
||||||
const callbackOk = opts.tokenOk;
|
|
||||||
const callbackBad = opts.tokenBad;
|
|
||||||
|
|
||||||
return (request, reply) => {
|
|
||||||
const token = lookupToken(server, request);
|
|
||||||
const session = request.yar;
|
|
||||||
|
|
||||||
let userObj = session.get(SESSION_USER_KEY);
|
|
||||||
|
|
||||||
if (token.isBoom) {
|
|
||||||
server.log(['status', 'debug', 'keystone'],
|
|
||||||
'Received error object from token lookup'
|
|
||||||
);
|
|
||||||
return reply(token);
|
|
||||||
} else if (token === RELOAD) {
|
|
||||||
server.log(['status', 'debug', 'keystone'],
|
|
||||||
'Received reload markup object from token lookup'
|
|
||||||
);
|
|
||||||
return reply(RELOAD_MARKUP).type('text/html');
|
|
||||||
} else if (userObj && 'project' in userObj) {
|
|
||||||
server.log(['status','info','keystone'], `${token} already authorized`);
|
|
||||||
return reply.continue({credentials:token});
|
|
||||||
}
|
|
||||||
|
|
||||||
server.log(['status', 'debug', 'keystone'],
|
|
||||||
'About to validate token with keystone'
|
|
||||||
);
|
|
||||||
|
|
||||||
return tokensApi
|
|
||||||
.validate({
|
|
||||||
headers: {
|
|
||||||
'X-Auth-Token' : token,
|
|
||||||
'X-Subject-Token': token
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(
|
|
||||||
(data) => {
|
|
||||||
userObj = data.data.token;
|
|
||||||
return callbackOk(token, userObj, session)
|
|
||||||
.then(()=> {
|
|
||||||
server.log(['status', 'debug', 'keystone'],
|
|
||||||
`Auth process completed for user ${userObj.user.id}`);
|
|
||||||
return reply.continue({credentials: token});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
return callbackBad(token, error, session)
|
|
||||||
.then((err)=> {
|
|
||||||
server.log(['status', 'error', 'keystone'], `Auth process did not complete for token ${token}`);
|
|
||||||
server.log(['status', 'error', 'keystone'], `${err}`);
|
|
||||||
return reply(Boom.wrap(err));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const RELOAD = Symbol('reload-me');
|
|
||||||
|
|
||||||
module.exports = RELOAD;
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Boom from 'boom';
|
|
||||||
import Promise from 'bluebird';
|
|
||||||
|
|
||||||
import kibanaIndex from '../kibana';
|
|
||||||
import userProjects from '../projects';
|
|
||||||
|
|
||||||
import {
|
|
||||||
SESSION_TOKEN_KEY,
|
|
||||||
SESSION_USER_KEY
|
|
||||||
} from '../../const';
|
|
||||||
|
|
||||||
export default (server) => {
|
|
||||||
|
|
||||||
return {
|
|
||||||
tokenOk : tokenOk,
|
|
||||||
tokenBad: tokenBad
|
|
||||||
};
|
|
||||||
|
|
||||||
function tokenOk(token, userObj, session) {
|
|
||||||
session.reset();
|
|
||||||
session.set(SESSION_TOKEN_KEY, token);
|
|
||||||
session.set(SESSION_USER_KEY, userObj);
|
|
||||||
|
|
||||||
return Promise
|
|
||||||
.all([
|
|
||||||
userProjects(server, session, userObj),
|
|
||||||
kibanaIndex(server, userObj)
|
|
||||||
])
|
|
||||||
.then(() => {
|
|
||||||
server.log(['status', 'info', 'keystone'], `User ${userObj.user.id} authorized with keystone`);
|
|
||||||
return token;
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
server.log(['status', 'info', 'keystone'],
|
|
||||||
`Error caught in process of authorization, err was ${err}`);
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function tokenBad(token, error, session) {
|
|
||||||
return new Promise((resolve)=> {
|
|
||||||
server.log(['keystone', 'error'], `Failed to authenticate token ${token} with keystone, error is ${error.statusCode}.`);
|
|
||||||
session.reset();
|
|
||||||
|
|
||||||
let err;
|
|
||||||
|
|
||||||
if (error.statusCode === 401) {
|
|
||||||
err = Boom.forbidden('\You\'re not logged in as a user who\'s authorized to access log information');
|
|
||||||
} else {
|
|
||||||
err = Boom.internal(
|
|
||||||
error.message || 'Unexpected error during Keystone communication',
|
|
||||||
{},
|
|
||||||
error.statusCode
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return resolve(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Boom from 'boom';
|
|
||||||
|
|
||||||
import {
|
|
||||||
SESSION_PROJECTS_KEY,
|
|
||||||
SESSION_USER_KEY,
|
|
||||||
SESSION_TOKEN_CHANGED,
|
|
||||||
TOKEN_CHANGED_VALUE
|
|
||||||
} from '../../const';
|
|
||||||
import reload from './reload';
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return (request, reply) => {
|
|
||||||
|
|
||||||
let session = request.yar;
|
|
||||||
let userObj = session.get(SESSION_USER_KEY);
|
|
||||||
let tokenChanged = session.get(SESSION_TOKEN_CHANGED);
|
|
||||||
|
|
||||||
if (tokenChanged === TOKEN_CHANGED_VALUE) {
|
|
||||||
request.log(['status', 'info', 'keystone'],
|
|
||||||
'Detected that token has been changed, replaying the request'
|
|
||||||
);
|
|
||||||
session.clear(SESSION_TOKEN_CHANGED);
|
|
||||||
return reply(reload.markup).type('text/html');
|
|
||||||
} else if (userObj) {
|
|
||||||
let expiresAt = new Date(userObj.expires_at).valueOf();
|
|
||||||
let now = new Date().valueOf();
|
|
||||||
let diff = now - expiresAt;
|
|
||||||
|
|
||||||
if (diff >= 0) {
|
|
||||||
session.reset();
|
|
||||||
return reply(Boom.unauthorized('User token has expired')).takeover();
|
|
||||||
} else {
|
|
||||||
return reply.continue({
|
|
||||||
credentials: userObj,
|
|
||||||
artifacts : {
|
|
||||||
projects: session.get(SESSION_PROJECTS_KEY)
|
|
||||||
},
|
|
||||||
log : {
|
|
||||||
tags: 'keystone ok'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(trebskit) should actually throw error here I guess
|
|
||||||
return reply.continue();
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default {
|
|
||||||
bind: (server) => {
|
|
||||||
server.log(['status', 'info', 'keystone'], 'Registering keystone-auth schema');
|
|
||||||
return Promise.all([
|
|
||||||
bindAuthScheme(server),
|
|
||||||
bindExt(server),
|
|
||||||
bindRouting(server)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function bindRouting(server) {
|
|
||||||
const kibanaIndex = server.config().get('kibana.index');
|
|
||||||
return require('./routing')(server)
|
|
||||||
.then((route)=> {
|
|
||||||
route(server, 'GET', '/{paths*}');
|
|
||||||
route(server, 'POST', '/_mget');
|
|
||||||
route(server, 'POST', '/{index}/_search');
|
|
||||||
route(server, 'POST', '/{index}/_field_stats');
|
|
||||||
route(server, 'POST', '/_msearch');
|
|
||||||
route(server, 'POST', '/_search/scroll');
|
|
||||||
route(server, ['PUT', 'POST', 'DELETE'], '/' + kibanaIndex + '/{paths*}');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindAuthScheme(server) {
|
|
||||||
return Promise.all([
|
|
||||||
server.auth.scheme(
|
|
||||||
'keystone-token',
|
|
||||||
require('./auth/scheme')
|
|
||||||
),
|
|
||||||
server.auth.strategy(
|
|
||||||
'session',
|
|
||||||
'keystone-token',
|
|
||||||
true,
|
|
||||||
require('./auth/strategy')(server)
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindExt(server) {
|
|
||||||
return Promise.all([
|
|
||||||
server.ext(
|
|
||||||
'onPreAuth',
|
|
||||||
require('./auth/verify')(server),
|
|
||||||
{after: ['yar']}
|
|
||||||
),
|
|
||||||
server.ext('onRequest', require('./verify')(server))
|
|
||||||
]);
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import semver from 'semver';
|
|
||||||
|
|
||||||
const VERSION_REGEX = /(\d+\.\d+\.\d+)\-rc(\d+)/i;
|
|
||||||
|
|
||||||
export default (server, doc) => {
|
|
||||||
const config = server.config();
|
|
||||||
|
|
||||||
if (/beta|snapshot/i.test(doc._id)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!doc._id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (doc._id === config.get('pkg.version')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let packageRcRelease = Infinity;
|
|
||||||
let rcRelease = Infinity;
|
|
||||||
let packageVersion = config.get('pkg.version');
|
|
||||||
let version = doc._id;
|
|
||||||
let matches = doc._id.match(VERSION_REGEX);
|
|
||||||
let packageMatches = config.get('pkg.version').match(VERSION_REGEX);
|
|
||||||
|
|
||||||
if (matches) {
|
|
||||||
version = matches[1];
|
|
||||||
rcRelease = parseInt(matches[2], 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packageMatches) {
|
|
||||||
packageVersion = packageMatches[1];
|
|
||||||
packageRcRelease = parseInt(packageMatches[2], 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (semver.gte(version, packageVersion) && rcRelease >= packageRcRelease) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { find } from 'lodash';
|
|
||||||
import Promise from 'bluebird';
|
|
||||||
|
|
||||||
import canUpgradeConfig from './_can_upgrade';
|
|
||||||
|
|
||||||
export default (server, indexName) => {
|
|
||||||
const config = server.config();
|
|
||||||
const client = server.plugins.elasticsearch.client;
|
|
||||||
const options = {
|
|
||||||
index: indexName,
|
|
||||||
type : 'config',
|
|
||||||
body : {
|
|
||||||
size: 1000,
|
|
||||||
sort: [
|
|
||||||
{
|
|
||||||
buildNum: {
|
|
||||||
order : 'desc',
|
|
||||||
ignore_unmapped: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
server.log(['status', 'debug', 'keystone'], `Configuring index ${indexName}`);
|
|
||||||
|
|
||||||
return client
|
|
||||||
.search(options)
|
|
||||||
.then(upgradeConfig(server, indexName))
|
|
||||||
.then(()=>{
|
|
||||||
return Promise
|
|
||||||
.delay(666)
|
|
||||||
.then(() => {
|
|
||||||
server.log(['status', 'debug', 'keystone'], `Index ${indexName} has been configured`);
|
|
||||||
return indexName;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((err)=> {
|
|
||||||
throw new Error(`Configuring ${indexName} failed, error is ${err}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
function upgradeConfig(server, indexName) {
|
|
||||||
const client = server.plugins.elasticsearch.client;
|
|
||||||
const config = server.config();
|
|
||||||
|
|
||||||
return (response) => {
|
|
||||||
if (response.hits.hits.length === 0) {
|
|
||||||
return client.create({
|
|
||||||
index: indexName,
|
|
||||||
type : 'config',
|
|
||||||
body : {
|
|
||||||
buildNum: config.get('pkg.buildNum')
|
|
||||||
},
|
|
||||||
id : config.get('pkg.version')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we already have a the current version in the index then we need to stop
|
|
||||||
var devConfig = find(response.hits.hits, function currentVersion(hit) {
|
|
||||||
return hit._id !== '@@version' && hit._id === config.get('pkg.version');
|
|
||||||
});
|
|
||||||
|
|
||||||
if (devConfig) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for upgradeable configs. If none of them are upgradeable
|
|
||||||
// then resolve with null.
|
|
||||||
let body = find(response.hits.hits, canUpgradeConfig.bind(null, server));
|
|
||||||
if (!body) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the build number is still the template string (which it wil be in development)
|
|
||||||
// then we need to set it to the max interger. Otherwise we will set it to the build num
|
|
||||||
body._source.buildNum = config.get('pkg.buildNum');
|
|
||||||
|
|
||||||
server.log(['plugin', 'elasticsearch'], {
|
|
||||||
tmpl : 'Upgrade config from <%= prevVersion %> to <%= newVersion %>',
|
|
||||||
prevVersion: body._id,
|
|
||||||
newVersion : config.get('pkg.version')
|
|
||||||
});
|
|
||||||
|
|
||||||
return client.create({
|
|
||||||
index: indexName,
|
|
||||||
type : 'config',
|
|
||||||
body : body._source,
|
|
||||||
id : config.get('pkg.version')
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Boom from 'boom';
|
|
||||||
|
|
||||||
import { exists as indexExists } from './_exists';
|
|
||||||
|
|
||||||
export default (server, indexName) => {
|
|
||||||
const client = server.plugins.elasticsearch.client;
|
|
||||||
|
|
||||||
server.log(['status', 'info', 'keystone'], `Creating user index ${indexName}`);
|
|
||||||
|
|
||||||
return client.indices
|
|
||||||
.create({
|
|
||||||
index: indexName,
|
|
||||||
body : {
|
|
||||||
settings: {
|
|
||||||
number_of_shards: 1
|
|
||||||
},
|
|
||||||
mappings: {
|
|
||||||
config: {
|
|
||||||
properties: {
|
|
||||||
buildNum: {
|
|
||||||
type : 'string',
|
|
||||||
index: 'not_analyzed'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err)=> {
|
|
||||||
throw Boom.wrap(err, 500,
|
|
||||||
`Failed to create index ${indexName}`);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
return indexExists(server, indexName, 'yellow')
|
|
||||||
.catch((err)=> {
|
|
||||||
throw Boom.wrap(err, 500,
|
|
||||||
`Waiting for index ${indexName} to come online failed`);
|
|
||||||
})
|
|
||||||
.then(()=> {
|
|
||||||
server.log(['status', 'info', 'keystone'],
|
|
||||||
`Index ${indexName} has been created`);
|
|
||||||
return Promise.resolve(indexName);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import kibanaIndex from './kibanaIndex';
|
|
||||||
|
|
||||||
export default (server, userObj) => {
|
|
||||||
const indexName = kibanaIndex(server, userObj);
|
|
||||||
return exists(server, indexName)
|
|
||||||
.then((resp) => {
|
|
||||||
return {indexName, resp};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export function exists(server, indexName, status) {
|
|
||||||
const es = server.plugins.elasticsearch.client;
|
|
||||||
const opts = {
|
|
||||||
timeout : '5s',
|
|
||||||
index : indexName,
|
|
||||||
ignore : [408],
|
|
||||||
waitForActiveShards: 1
|
|
||||||
};
|
|
||||||
if (status) {
|
|
||||||
opts.status = status;
|
|
||||||
}
|
|
||||||
return es.cluster.health(opts);
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import indexExists from './_exists';
|
|
||||||
import createIndex from './_create';
|
|
||||||
import configureIndex from './_configure';
|
|
||||||
|
|
||||||
export default (server, userObj) => {
|
|
||||||
return doCheck();
|
|
||||||
|
|
||||||
function doCheck() {
|
|
||||||
return indexExists(server, userObj)
|
|
||||||
.then(({indexName, resp}) => {
|
|
||||||
if (!resp || resp.timed_out) {
|
|
||||||
server.log(['status', 'warning', 'keystone'], `Index ${indexName} does not exists`);
|
|
||||||
return createIndex(server, indexName);
|
|
||||||
}
|
|
||||||
if (resp.status === 'red') {
|
|
||||||
server.log(['status', 'warning', 'keystone'], `Shards not ready for index ${indexName}`);
|
|
||||||
return Promise.delay(2500).then(doCheck);
|
|
||||||
}
|
|
||||||
return Promise.resolve(indexName);
|
|
||||||
})
|
|
||||||
.then((indexName)=> {
|
|
||||||
return configureIndex(server, indexName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns tenant/project-aware kibana index
|
|
||||||
*
|
|
||||||
* @param server server object
|
|
||||||
* @param userObj user details as retrieved from keystone
|
|
||||||
* @returns {string} project aware kibana index
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export default (server, userObj) => {
|
|
||||||
return `${server.config().get('kibana.index')}-${getProjectId(userObj)}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
function getProjectId(userObj) {
|
|
||||||
return userObj.project.id;
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Promise from 'bluebird';
|
|
||||||
import { pick, sortBy } from 'lodash';
|
|
||||||
|
|
||||||
import { SESSION_PROJECTS_KEY, SESSION_TOKEN_KEY } from '../../const';
|
|
||||||
|
|
||||||
export default (server, session, userObj) => {
|
|
||||||
|
|
||||||
const usersApi = server.plugins['fts-keystone'].users;
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
return usersApi
|
|
||||||
.allProjects({
|
|
||||||
params : {
|
|
||||||
user_id: userObj.user.id
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'X-Auth-Token' : session.get(SESSION_TOKEN_KEY),
|
|
||||||
'X-Subject-Token': session.get(SESSION_TOKEN_KEY)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
const data = response.data;
|
|
||||||
const projects = data.projects;
|
|
||||||
|
|
||||||
return sortBy(
|
|
||||||
projects.map(
|
|
||||||
project=>pick(project, ['id', 'name', 'description', 'domain_id'])
|
|
||||||
),
|
|
||||||
'name'
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.then((projects) => {
|
|
||||||
session.set(SESSION_PROJECTS_KEY, projects);
|
|
||||||
return resolve(projects);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
This file was copied and modified for this plugin needs.
|
|
||||||
Original file can be found here => https://github.com/elastic/kibana/blob/4.4/src/plugins/elasticsearch/lib/create_agent.js
|
|
||||||
*/
|
|
||||||
|
|
||||||
import url from 'url';
|
|
||||||
import {memoize, size} from 'lodash';
|
|
||||||
import fs from 'fs';
|
|
||||||
import http from 'http';
|
|
||||||
import https from 'https';
|
|
||||||
|
|
||||||
const readFile = (file) => fs.readFileSync(file, 'utf8');
|
|
||||||
|
|
||||||
module.exports = memoize(function (server) {
|
|
||||||
const config = server.config();
|
|
||||||
const target = url.parse(config.get('elasticsearch.url'));
|
|
||||||
|
|
||||||
if (!/^https/.test(target.protocol)) {
|
|
||||||
return new http.Agent();
|
|
||||||
}
|
|
||||||
|
|
||||||
const agentOptions = {
|
|
||||||
rejectUnauthorized: config.get('elasticsearch.ssl.verify')
|
|
||||||
};
|
|
||||||
|
|
||||||
if (size(config.get('elasticsearch.ssl.ca'))) {
|
|
||||||
agentOptions.ca = config.get('elasticsearch.ssl.ca').map(readFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasSSLEnabled()) {
|
|
||||||
agentOptions.cert = readFile(config.get('elasticsearch.ssl.cert'));
|
|
||||||
agentOptions.key = readFile(config.get('elasticsearch.ssl.key'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new https.Agent(agentOptions);
|
|
||||||
|
|
||||||
function hasSSLEnabled() {
|
|
||||||
return config.get('elasticsearch.ssl.cert')
|
|
||||||
&& config.get('elasticsearch.ssl.key');
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.cache = new Map();
|
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { PREFIX } from './_utils';
|
|
||||||
|
|
||||||
module.exports = (server, method, route) => {
|
|
||||||
|
|
||||||
const serverConfig = server.config();
|
|
||||||
const pre = '/elasticsearch';
|
|
||||||
const sep = route[0] === '/' ? '' : '/';
|
|
||||||
const path = `${PREFIX}${pre}${sep}${route}`;
|
|
||||||
|
|
||||||
let options;
|
|
||||||
|
|
||||||
switch (route) {
|
|
||||||
case '/_mget':
|
|
||||||
options = require('./routes/mget')(server, method, path);
|
|
||||||
break;
|
|
||||||
case '/{paths*}':
|
|
||||||
options = require('./routes/paths')(server, method, path);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (route === `/${serverConfig.get('kibana.index')}/{paths*}`) {
|
|
||||||
options = require('./routes/kibana_index')(server, method, path);
|
|
||||||
} else {
|
|
||||||
options = require('./routes/default')(server, method, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.route(options);
|
|
||||||
};
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
This file was copied and modified for this plugin needs.
|
|
||||||
Original file can be found here => https://github.com/elastic/kibana/blob/4.4/src/plugins/elasticsearch/lib/map_uri.js
|
|
||||||
*/
|
|
||||||
|
|
||||||
import querystring from 'querystring';
|
|
||||||
|
|
||||||
import { PREFIX } from './_utils';
|
|
||||||
|
|
||||||
export default (server, request) => {
|
|
||||||
const config = server.config();
|
|
||||||
const path = request.path.replace(`${PREFIX}/elasticsearch`, '');
|
|
||||||
const query = querystring.stringify(request.query);
|
|
||||||
|
|
||||||
let url = config.get('elasticsearch.url');
|
|
||||||
|
|
||||||
if (path) {
|
|
||||||
if (/\/$/.test(url)) {
|
|
||||||
url = url.substring(0, url.length - 1);
|
|
||||||
}
|
|
||||||
url += path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query) {
|
|
||||||
url += '?' + query;
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
};
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import utils from '../../util';
|
|
||||||
import { PREFIX } from './_utils';
|
|
||||||
|
|
||||||
module.exports = function reRoute(server) {
|
|
||||||
return (request, reply) => {
|
|
||||||
const requestPath = utils.requestPath(request);
|
|
||||||
if (utils.isESRequest(request)) {
|
|
||||||
server.log(['status', 'debug', 'keystone'], `Routing ${requestPath} onto ${PREFIX}${requestPath}`);
|
|
||||||
request.setUrl(`${PREFIX}${requestPath}`);
|
|
||||||
}
|
|
||||||
return reply.continue();
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import createAgent from './_create_agent';
|
|
||||||
|
|
||||||
export const PREFIX = '/mt';
|
|
||||||
|
|
||||||
export function getOpts(server, request, url, payload) {
|
|
||||||
|
|
||||||
let options = {
|
|
||||||
headers : {},
|
|
||||||
redirects : true,
|
|
||||||
passThrough : true,
|
|
||||||
xforward : true,
|
|
||||||
timeout : 1000 * 60 * 3,
|
|
||||||
localStatePassThrough: false,
|
|
||||||
agent : createAgent(server),
|
|
||||||
};
|
|
||||||
let protocol = url.split(':', 1)[0];
|
|
||||||
|
|
||||||
if (payload) {
|
|
||||||
options.payload = JSON.stringify(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.passThrough) {
|
|
||||||
options.headers = require('hoek').clone(request.headers);
|
|
||||||
delete options.headers.host;
|
|
||||||
if (options.acceptEncoding === false) {
|
|
||||||
delete options.headers['accept-encoding'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.xforward &&
|
|
||||||
request.info.remoteAddress &&
|
|
||||||
request.info.remotePort) {
|
|
||||||
|
|
||||||
options.headers['x-forwarded-for'] = (options.headers['x-forwarded-for'] ?
|
|
||||||
options.headers['x-forwarded-for'] + ',' : '') + request.info.remoteAddress;
|
|
||||||
options.headers['x-forwarded-port'] = (options.headers['x-forwarded-port'] ?
|
|
||||||
options.headers['x-forwarded-port'] + ',' : '') + request.info.remotePort;
|
|
||||||
options.headers['x-forwarded-proto'] = (options.headers['x-forwarded-proto'] ?
|
|
||||||
options.headers['x-forwarded-proto'] + ',' : '') + protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
const contentType = request.headers['content-type'];
|
|
||||||
if (contentType) {
|
|
||||||
options.headers['content-type'] = contentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parsePayload(request) {
|
|
||||||
let payload = request.payload;
|
|
||||||
if (!payload || payload.length <= 0) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return JSON.parse(payload.toString('utf-8'));
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Promise from 'bluebird';
|
|
||||||
import reRoute from './_re_route';
|
|
||||||
|
|
||||||
module.exports = function routing(server) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
server.ext('onRequest', reRoute(server));
|
|
||||||
resolve(require('./_create_proxy'));
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import mapUri from '../_map_uri';
|
|
||||||
import createAgent from '../_create_agent';
|
|
||||||
|
|
||||||
module.exports = function defaultHandler(server, method, path) {
|
|
||||||
return {
|
|
||||||
method : method,
|
|
||||||
path : path,
|
|
||||||
handler: {
|
|
||||||
proxy: {
|
|
||||||
mapUri : (request, done) => {
|
|
||||||
server.log(['status', 'debug', 'keystone'],
|
|
||||||
`mapUri for path ${request.path}`);
|
|
||||||
done(null, mapUri(server, request));
|
|
||||||
},
|
|
||||||
agent : createAgent(server),
|
|
||||||
passThrough: true,
|
|
||||||
xforward : true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Wreck from 'wreck';
|
|
||||||
|
|
||||||
import { SESSION_USER_KEY } from '../../../const';
|
|
||||||
import { getOpts, parsePayload } from '../_utils';
|
|
||||||
import kibanaIndex from '../../kibana/kibanaIndex';
|
|
||||||
import mapUri from '../_map_uri';
|
|
||||||
|
|
||||||
export default function (server, method, path) {
|
|
||||||
|
|
||||||
const defaultKibanaIndex = server.config().get('kibana.index');
|
|
||||||
|
|
||||||
return {
|
|
||||||
method : method,
|
|
||||||
path : path,
|
|
||||||
config : {
|
|
||||||
auth : false,
|
|
||||||
payload: {
|
|
||||||
output: 'data',
|
|
||||||
parse : false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handler: handler
|
|
||||||
};
|
|
||||||
|
|
||||||
function handler(request, reply) {
|
|
||||||
const url = getUrl(request);
|
|
||||||
const opts = getOpts(server, request, url, parsePayload(request));
|
|
||||||
return Wreck.request(request.method, url, opts, (err, res) => {
|
|
||||||
return reply(res).code(res.statusCode).passThrough(!!opts.passThrough);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUrl(request) {
|
|
||||||
const session = request.yar._store;
|
|
||||||
|
|
||||||
let url = mapUri(server, request).split('/');
|
|
||||||
let indexPos = url.findIndex((item) => item === defaultKibanaIndex);
|
|
||||||
|
|
||||||
url[indexPos] = kibanaIndex(server, session[SESSION_USER_KEY]);
|
|
||||||
|
|
||||||
return url.join('/');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Boom from 'boom';
|
|
||||||
import Wreck from 'wreck';
|
|
||||||
|
|
||||||
import { SESSION_USER_KEY } from '../../../const';
|
|
||||||
import { getOpts, parsePayload } from '../_utils';
|
|
||||||
import kibanaIndex from '../../kibana/kibanaIndex';
|
|
||||||
import mapUri from '../_map_uri';
|
|
||||||
|
|
||||||
export default function (server, method, path) {
|
|
||||||
|
|
||||||
return {
|
|
||||||
method : method,
|
|
||||||
path : path,
|
|
||||||
config : {
|
|
||||||
auth : false,
|
|
||||||
payload: {
|
|
||||||
output: 'data',
|
|
||||||
parse : false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handler: handler
|
|
||||||
};
|
|
||||||
|
|
||||||
function handler(request, reply) {
|
|
||||||
const url = mapUri(server, request);
|
|
||||||
const session = request.yar._store;
|
|
||||||
const payload = parsePayload(request);
|
|
||||||
|
|
||||||
payload.docs.forEach((doc) => {
|
|
||||||
doc._index = kibanaIndex(server, session[SESSION_USER_KEY]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const opts = getOpts(server, request, url, payload);
|
|
||||||
return Wreck.request(request.method, url, opts, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
server.log(
|
|
||||||
['status', 'error', 'keystone'],
|
|
||||||
`Failed to request ${url}, error is ${err}`);
|
|
||||||
return reply(Boom.wrap(err));
|
|
||||||
}
|
|
||||||
return Wreck.read(res, {json: true}, (err, body)=> {
|
|
||||||
if (err) {
|
|
||||||
server.log(
|
|
||||||
['status', 'error', 'keystone'],
|
|
||||||
`Failed to read response from ${url}, error is ${err}`);
|
|
||||||
return reply(Boom.wrap(err));
|
|
||||||
}
|
|
||||||
|
|
||||||
return reply(body)
|
|
||||||
.code(res.statusCode)
|
|
||||||
.passThrough(!!opts.passThrough);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Wreck from 'wreck';
|
|
||||||
|
|
||||||
import { SESSION_USER_KEY } from '../../../const';
|
|
||||||
import { getOpts } from '../_utils';
|
|
||||||
import kibanaIndex from '../../kibana/kibanaIndex';
|
|
||||||
import mapUri from '../_map_uri';
|
|
||||||
|
|
||||||
export default function (server, method, path) {
|
|
||||||
const defaultKibanaIndex = defaultKibanaIndex;
|
|
||||||
|
|
||||||
return {
|
|
||||||
method : method,
|
|
||||||
path : path,
|
|
||||||
config : {
|
|
||||||
tags: ['elasticsearch', 'multitenancy'],
|
|
||||||
auth: false
|
|
||||||
},
|
|
||||||
handler: handler
|
|
||||||
};
|
|
||||||
|
|
||||||
function handler(request, reply) {
|
|
||||||
const session = request.yar._store;
|
|
||||||
|
|
||||||
let url = mapUri(server, request).split('/');
|
|
||||||
let kibanaIndexRequest = false;
|
|
||||||
|
|
||||||
let indexPos = url.findIndex((item) => item === defaultKibanaIndex);
|
|
||||||
if (indexPos > -1) {
|
|
||||||
url[indexPos] = kibanaIndex(server, session[SESSION_USER_KEY]);
|
|
||||||
kibanaIndexRequest = true;
|
|
||||||
}
|
|
||||||
url = url.join('/');
|
|
||||||
|
|
||||||
const opts = getOpts(server, request, url);
|
|
||||||
return Wreck.request(request.method, url, opts, (err, res) => {
|
|
||||||
return Wreck.read(res, {json: true}, (err, body)=> {
|
|
||||||
let newData = {};
|
|
||||||
|
|
||||||
if (kibanaIndexRequest) {
|
|
||||||
let tenantAwareIndex = Object.keys(body)[0];
|
|
||||||
newData[defaultKibanaIndex] = body[tenantAwareIndex];
|
|
||||||
} else {
|
|
||||||
newData = body;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reply(newData)
|
|
||||||
.code(res.statusCode)
|
|
||||||
.passThrough(!!opts.passThrough);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Boom from 'boom';
|
|
||||||
|
|
||||||
import { SESSION_PROJECTS_KEY } from '../../const';
|
|
||||||
import util from '../../util';
|
|
||||||
|
|
||||||
const INDEX_PATTER_POS = 2;
|
|
||||||
|
|
||||||
module.exports = (request, reply) => {
|
|
||||||
const session = request.yar._store;
|
|
||||||
const requestPath = util.requestPath(request);
|
|
||||||
const splittedPath = requestPath.split('/');
|
|
||||||
|
|
||||||
let pattern = splittedPath[INDEX_PATTER_POS];
|
|
||||||
let projects = session[SESSION_PROJECTS_KEY];
|
|
||||||
|
|
||||||
if ('*' === pattern) {
|
|
||||||
return reply(Boom.badData('* as pattern is not supported at the moment'));
|
|
||||||
} else if (projects.filter(filter).length === 0) {
|
|
||||||
return reply(Boom.badData(`${pattern} do not match any project of current user`));
|
|
||||||
}
|
|
||||||
|
|
||||||
return reply.continue();
|
|
||||||
|
|
||||||
function filter(project) {
|
|
||||||
return new RegExp(`${project.id}.*`, 'gi').test(pattern);
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 FUJITSU LIMITED
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
||||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { SESSION_USER_KEY } from '../../const';
|
|
||||||
import util from '../../util';
|
|
||||||
|
|
||||||
module.exports = (server) => {
|
|
||||||
|
|
||||||
return (request, reply) => {
|
|
||||||
const session = request.yar._store;
|
|
||||||
if (!(session && (SESSION_USER_KEY in session))) {
|
|
||||||
server.log(['status', 'warning', 'keystone'], 'Session not yet available');
|
|
||||||
return reply.continue();
|
|
||||||
}
|
|
||||||
|
|
||||||
let requestPath = util.requestPath(request);
|
|
||||||
let requestMethod = request.method;
|
|
||||||
|
|
||||||
if (util.isESRequest(request)) {
|
|
||||||
let handler;
|
|
||||||
if (isIndexPatternLookup()) {
|
|
||||||
handler = require('./_verify_index_pattern');
|
|
||||||
}
|
|
||||||
if (handler) {
|
|
||||||
return handler(request, reply);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reply.continue();
|
|
||||||
|
|
||||||
function isIndexPatternLookup() {
|
|
||||||
let regExp = /\/elasticsearch\/.*\/_mapping\/field\/.*/;
|
|
||||||
return regExp.test(requestPath) && requestMethod.toLowerCase() === 'get';
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
@ -12,10 +12,14 @@
|
|||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import authenticateFactory from './_authenticate';
|
const proxy = require('./proxy');
|
||||||
|
|
||||||
export default (server, opts) => {
|
module.exports = function createProxy(server) {
|
||||||
return {
|
server.ext(
|
||||||
authenticate: authenticateFactory(server, opts)
|
'onPreAuth',
|
||||||
};
|
proxy(server),
|
||||||
|
{
|
||||||
|
after: ['yar']
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
93
server/proxy/proxy.js
Normal file
93
server/proxy/proxy.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 FUJITSU LIMITED
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||||
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||||
|
* or implied. See the License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Boom = require('boom');
|
||||||
|
const retrieveToken = require('./retrieveToken');
|
||||||
|
const TokensApi = require('keystone-v3-client/lib/keystone/tokens');
|
||||||
|
|
||||||
|
const util = require('../util/');
|
||||||
|
|
||||||
|
module.exports = function (server) {
|
||||||
|
const config = server.config();
|
||||||
|
const tokensApi = new TokensApi({
|
||||||
|
url: `${config.get('fts-keystone.url')}:${config.get('fts-keystone.port')}`
|
||||||
|
});
|
||||||
|
|
||||||
|
return (request, reply) => {
|
||||||
|
const requestPath = getRequestPath(request);
|
||||||
|
let token;
|
||||||
|
|
||||||
|
if (shouldCallKeystone(requestPath)) {
|
||||||
|
server.log(
|
||||||
|
['keystone', 'debug'],
|
||||||
|
`Call for ${requestPath} detected, authenticating with keystone`
|
||||||
|
);
|
||||||
|
|
||||||
|
token = retrieveToken(server, request);
|
||||||
|
if (token.isBoom) {
|
||||||
|
return reply(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokensApi
|
||||||
|
.check({
|
||||||
|
headers: {
|
||||||
|
'X-Auth-Token' : token,
|
||||||
|
'X-Subject-Token': token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(onFulfilled, onFailed);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply.continue();
|
||||||
|
|
||||||
|
function onFulfilled() {
|
||||||
|
reply.continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFailed(error) {
|
||||||
|
|
||||||
|
server.log(
|
||||||
|
['keystone', 'error'],
|
||||||
|
`Failed to authenticate token ${token} with keystone,
|
||||||
|
error is ${error.statusCode}.`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error.statusCode === 401) {
|
||||||
|
request.session.clear('keystone_token');
|
||||||
|
reply(Boom.forbidden(
|
||||||
|
`
|
||||||
|
You\'re not logged in as a
|
||||||
|
user who\'s authenticated to access log information
|
||||||
|
`
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
reply(Boom.internal(
|
||||||
|
error.message || 'Unexpected error during Keystone communication',
|
||||||
|
{},
|
||||||
|
error.statusCode
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function getRequestPath(request) {
|
||||||
|
return request.url.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldCallKeystone(path) {
|
||||||
|
return util.startsWith(path, '/elasticsearch');
|
||||||
|
}
|
@ -12,15 +12,10 @@
|
|||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Boom from 'boom';
|
const Boom = require('boom');
|
||||||
import {
|
|
||||||
SESSION_TOKEN_KEY,
|
|
||||||
SESSION_TOKEN_CHANGED,
|
|
||||||
TOKEN_CHANGED_VALUE
|
|
||||||
} from '../../../const';
|
|
||||||
import RELOAD_SYMBOL from '../reload';
|
|
||||||
|
|
||||||
const HEADER_NAME = 'x-auth-token';
|
/** @module */
|
||||||
|
module.exports = retrieveToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves token from the response header using key <b>X-Keystone-Token</b>.
|
* Retrieves token from the response header using key <b>X-Keystone-Token</b>.
|
||||||
@ -36,21 +31,21 @@ const HEADER_NAME = 'x-auth-token';
|
|||||||
*
|
*
|
||||||
* @returns {string} current token value
|
* @returns {string} current token value
|
||||||
*/
|
*/
|
||||||
module.exports = (server, request) => {
|
|
||||||
|
|
||||||
if (!request.yar || request.yar === null) {
|
const HEADER_NAME = 'x-auth-token';
|
||||||
server.log(['status', 'keystone', 'error'], 'Session is not enabled');
|
|
||||||
|
function retrieveToken(server, request) {
|
||||||
|
|
||||||
|
if (!request.session || request.session === null) {
|
||||||
|
server.log(['keystone', 'error'], 'Session is not enabled');
|
||||||
throw new Error('Session support is missing');
|
throw new Error('Session support is missing');
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEV PURPOSE ONLY
|
let tokenFromSession = request.session.get('keystone_token');
|
||||||
// request.yar.set(SESSION_TOKEN_KEY, 'a60e832483c34526a0c2bc3c6f8fa320');
|
|
||||||
|
|
||||||
let tokenFromSession = request.yar.get(SESSION_TOKEN_KEY);
|
|
||||||
let token = request.headers[HEADER_NAME];
|
let token = request.headers[HEADER_NAME];
|
||||||
|
|
||||||
if (!token && !tokenFromSession) {
|
if (!token && !tokenFromSession) {
|
||||||
server.log(['status', 'keystone', 'error'],
|
server.log(['keystone', 'error'],
|
||||||
'Token hasn\'t been located, looked in headers and session');
|
'Token hasn\'t been located, looked in headers and session');
|
||||||
return Boom.unauthorized(
|
return Boom.unauthorized(
|
||||||
'You\'re not logged into the OpenStack. Please login via Horizon Dashboard'
|
'You\'re not logged into the OpenStack. Please login via Horizon Dashboard'
|
||||||
@ -59,28 +54,15 @@ module.exports = (server, request) => {
|
|||||||
|
|
||||||
if (!token && tokenFromSession) {
|
if (!token && tokenFromSession) {
|
||||||
token = tokenFromSession;
|
token = tokenFromSession;
|
||||||
server.log(['status', 'debug', 'keystone'],
|
server.log(['keystone', 'debug'],
|
||||||
'Token lookup status: Found token in session'
|
'Token lookup status: Found token in session'
|
||||||
);
|
);
|
||||||
} else if ((token && !tokenFromSession) || (token !== tokenFromSession)) {
|
} else if ((token && !tokenFromSession) || (token !== tokenFromSession)) {
|
||||||
server.log(['status', 'debug', 'keystone'],
|
server.log(['keystone', 'debug'],
|
||||||
'Token lookup status: Token located in header/session or token changed'
|
'Token lookup status: Token located in header/session or token changed'
|
||||||
);
|
);
|
||||||
|
request.session.set('keystone_token', token);
|
||||||
if ((token !== tokenFromSession) && (token && tokenFromSession)) {
|
|
||||||
server.log(['status', 'info', 'keystone'],
|
|
||||||
'Reseting session because token has changed'
|
|
||||||
);
|
|
||||||
request.yar.reset();
|
|
||||||
|
|
||||||
request.yar.set(SESSION_TOKEN_CHANGED, TOKEN_CHANGED_VALUE);
|
|
||||||
request.yar.set(SESSION_TOKEN_KEY, token);
|
|
||||||
|
|
||||||
return RELOAD_SYMBOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
request.yar.set(SESSION_TOKEN_KEY, token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.yar.get(SESSION_TOKEN_KEY);
|
return token;
|
||||||
};
|
}
|
@ -12,39 +12,34 @@
|
|||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import yarCookie from 'yar';
|
module.exports = function initSession(server) {
|
||||||
import multiTenancy from '../mt';
|
|
||||||
|
|
||||||
export default (server) => {
|
|
||||||
const config = server.config();
|
const config = server.config();
|
||||||
return {
|
const registerOpts = {
|
||||||
start: ()=> {
|
register: require('yar'),
|
||||||
server.register({
|
options : {
|
||||||
register: yarCookie,
|
name : 'kibana_session',
|
||||||
options : {
|
storeBlank : false,
|
||||||
maxCookieSize: 4096,
|
cache : {
|
||||||
name : config.get('fts-keystone.cookie.name'),
|
expiresIn: config.get('fts-keystone.cookie.expiresIn')
|
||||||
storeBlank : false,
|
},
|
||||||
cache : {
|
cookieOptions: {
|
||||||
expiresIn: config.get('fts-keystone.cookie.expiresIn')
|
password : config.get('fts-keystone.cookie.password'),
|
||||||
},
|
isSecure : config.get('fts-keystone.cookie.isSecure'),
|
||||||
cookieOptions: {
|
ignoreErrors: config.get('fts-keystone.cookie.ignoreErrors'),
|
||||||
password : config.get('fts-keystone.cookie.password'),
|
clearInvalid: true
|
||||||
isSecure : config.get('fts-keystone.cookie.isSecure'),
|
}
|
||||||
ignoreErrors: config.get('fts-keystone.cookie.ignoreErrors'),
|
|
||||||
clearInvalid: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, (error) => {
|
|
||||||
if (!error) {
|
|
||||||
server.log(['status', 'info', 'keystone'], 'Session registered');
|
|
||||||
multiTenancy.bind(server);
|
|
||||||
} else {
|
|
||||||
server.log(['status', 'error', 'keystone'], error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const callback = (error) => {
|
||||||
|
if (!error) {
|
||||||
|
server.log(['session', 'debug'], 'Session registered');
|
||||||
|
} else {
|
||||||
|
server.log(['session', 'error'], error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
server.register(registerOpts, callback);
|
||||||
};
|
};
|
||||||
|
@ -13,9 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
startsWith: startsWith,
|
startsWith: startsWith
|
||||||
requestPath: getRequestPath,
|
|
||||||
isESRequest: isESRequest
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function startsWith(str) {
|
function startsWith(str) {
|
||||||
@ -27,11 +25,3 @@ function startsWith(str) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRequestPath(request) {
|
|
||||||
return request.url.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isESRequest(request) {
|
|
||||||
return startsWith(getRequestPath(request), '/elasticsearch');
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user