mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Reporting cookies 2 (#24752)
* Revert "Reporting cookies (#24177)"
This reverts commit 9f4ec18000
.
* Take 2
* Adding comment
* Better escaping and encoding for use in eval
* Checking for an empty string also
* Fixing session test
This commit is contained in:
parent
0429a54c28
commit
9f1cdac12b
25 changed files with 484 additions and 854 deletions
|
@ -542,55 +542,4 @@ describe('Authenticator', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('`serializeSession` method', () => {
|
||||
let serializeSession;
|
||||
beforeEach(async () => {
|
||||
config.get.withArgs('xpack.security.authProviders').returns(['basic']);
|
||||
config.get.withArgs('server.basePath').returns('/base-path');
|
||||
|
||||
await initAuthenticator(server);
|
||||
|
||||
// Second argument will be a method we'd like to test.
|
||||
serializeSession = server.expose.withArgs('serializeSession').firstCall.args[1];
|
||||
});
|
||||
|
||||
it('fails if request is not provided.', async () => {
|
||||
try {
|
||||
await serializeSession();
|
||||
expect().fail('`serializeSession` should fail.');
|
||||
} catch(err) {
|
||||
expect(err).to.be.a(Error);
|
||||
expect(err.message).to.be('Request should be a valid object, was [undefined].');
|
||||
}
|
||||
});
|
||||
|
||||
it('calls session.serialize with request', async () => {
|
||||
const request = {};
|
||||
const expectedResult = Symbol();
|
||||
session.serialize.withArgs(request).returns(Promise.resolve(expectedResult));
|
||||
const actualResult = await serializeSession(request);
|
||||
expect(actualResult).to.be(expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('`getSessionCookieOptions` method', () => {
|
||||
let getSessionCookieOptions;
|
||||
beforeEach(async () => {
|
||||
config.get.withArgs('xpack.security.authProviders').returns(['basic']);
|
||||
config.get.withArgs('server.basePath').returns('/base-path');
|
||||
|
||||
await initAuthenticator(server);
|
||||
|
||||
// Second argument will be a method we'd like to test.
|
||||
getSessionCookieOptions = server.expose.withArgs('getSessionCookieOptions').firstCall.args[1];
|
||||
});
|
||||
|
||||
it('calls session.getCookieOptions', async () => {
|
||||
const expectedResult = Symbol();
|
||||
session.getCookieOptions.returns(Promise.resolve(expectedResult));
|
||||
const actualResult = await getSessionCookieOptions();
|
||||
expect(actualResult).to.be(expectedResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import expect from 'expect.js';
|
||||
import sinon from 'sinon';
|
||||
import iron from 'iron';
|
||||
|
||||
import { serverFixture } from '../../__tests__/__fixtures__/server';
|
||||
import { Session } from '../session';
|
||||
|
@ -189,87 +188,4 @@ describe('Session', () => {
|
|||
sinon.assert.calledOnce(request.cookieAuth.clear);
|
||||
});
|
||||
});
|
||||
|
||||
describe('`serialize` method', () => {
|
||||
let session;
|
||||
beforeEach(async () => {
|
||||
config.get.withArgs('xpack.security.cookieName').returns('cookie-name');
|
||||
config.get.withArgs('xpack.security.encryptionKey').returns('encryption-key');
|
||||
session = await Session.create(server);
|
||||
});
|
||||
|
||||
it('returns null if state is null', async () => {
|
||||
const request = {
|
||||
_states: {
|
||||
}
|
||||
};
|
||||
|
||||
const returnValue = await session.serialize(request);
|
||||
expect(returnValue).to.eql(null);
|
||||
});
|
||||
|
||||
it('uses iron to encrypt the state with the set password', async () => {
|
||||
const stateValue = {
|
||||
foo: 'bar'
|
||||
};
|
||||
const request = {
|
||||
_states: {
|
||||
'cookie-name': {
|
||||
value: stateValue,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sandbox.stub(iron, 'seal')
|
||||
.withArgs(stateValue, 'encryption-key', iron.defaults)
|
||||
.callsArgWith(3, null, 'serialized-value');
|
||||
|
||||
const returnValue = await session.serialize(request);
|
||||
expect(returnValue).to.eql('serialized-value');
|
||||
});
|
||||
|
||||
it(`rejects if iron can't seal the session`, async () => {
|
||||
const stateValue = {
|
||||
foo: 'bar'
|
||||
};
|
||||
const request = {
|
||||
_states: {
|
||||
'cookie-name': {
|
||||
value: stateValue,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sandbox.stub(iron, 'seal')
|
||||
.withArgs(stateValue, 'encryption-key', iron.defaults)
|
||||
.callsArgWith(3, new Error('IDK'), null);
|
||||
|
||||
try {
|
||||
await session.serialize(request);
|
||||
expect().fail('`serialize` should fail.');
|
||||
} catch(err) {
|
||||
expect(err).to.be.a(Error);
|
||||
expect(err.message).to.be('IDK');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('`getCookieOptions` method', () => {
|
||||
let session;
|
||||
beforeEach(async () => {
|
||||
config.get.withArgs('xpack.security.cookieName').returns('cookie-name');
|
||||
config.get.withArgs('xpack.security.secureCookies').returns('secure-cookies');
|
||||
config.get.withArgs('server.basePath').returns('base/path');
|
||||
session = await Session.create(server);
|
||||
});
|
||||
|
||||
it('returns cookie options', () => {
|
||||
expect(session.getCookieOptions()).to.eql({
|
||||
name: 'cookie-name',
|
||||
path: 'base/path/',
|
||||
httpOnly: true,
|
||||
secure: 'secure-cookies'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -213,25 +213,6 @@ class Authenticator {
|
|||
return DeauthenticationResult.notHandled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the request's session.
|
||||
* @param {Hapi.Request} request HapiJS request instance.
|
||||
* @returns {Promise.<string>}
|
||||
*/
|
||||
async serializeSession(request) {
|
||||
assertRequest(request);
|
||||
|
||||
return await this._session.serialize(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options that we're using for the session cookie
|
||||
* @returns {CookieOptions}
|
||||
*/
|
||||
getSessionCookieOptions() {
|
||||
return this._session.getCookieOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates authentication provider based on the provider key from config.
|
||||
* @param {string} providerType Provider type key.
|
||||
|
@ -300,8 +281,6 @@ export async function initAuthenticator(server, authorizationMode) {
|
|||
server.expose('authenticate', (request) => authenticator.authenticate(request));
|
||||
server.expose('deauthenticate', (request) => authenticator.deauthenticate(request));
|
||||
server.expose('registerAuthScopeGetter', (scopeExtender) => authScope.registerGetter(scopeExtender));
|
||||
server.expose('serializeSession', (request) => authenticator.serializeSession(request));
|
||||
server.expose('getSessionCookieOptions', () => authenticator.getSessionCookieOptions());
|
||||
|
||||
server.expose('isAuthenticated', async (request) => {
|
||||
try {
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
import hapiAuthCookie from 'hapi-auth-cookie';
|
||||
|
||||
import iron from 'iron';
|
||||
|
||||
const HAPI_STRATEGY_NAME = 'security-cookie';
|
||||
// Forbid applying of Hapi authentication strategies to routes automatically.
|
||||
const HAPI_STRATEGY_MODE = false;
|
||||
|
@ -18,16 +16,6 @@ function assertRequest(request) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CookieOptions
|
||||
* @typedef {Object} CookieOptions
|
||||
* @property {string} name - The name of the cookie
|
||||
* @property {string} password - The password that is used to encrypt the cookie
|
||||
* @property {string} path - The path that is set for the cookie
|
||||
* @property {boolean} secure - Whether the cookie should only be sent over HTTPS
|
||||
* @property {?number} ttl - Session duration in ms. If `null` session will stay active until the browser is closed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Manages Kibana user session.
|
||||
*/
|
||||
|
@ -40,20 +28,20 @@ export class Session {
|
|||
_server = null;
|
||||
|
||||
/**
|
||||
* Options for the cookie
|
||||
* @type {CookieOptions}
|
||||
* Session duration in ms. If `null` session will stay active until the browser is closed.
|
||||
* @type {?number}
|
||||
* @private
|
||||
*/
|
||||
_cookieOptions = null;
|
||||
_ttl = null;
|
||||
|
||||
/**
|
||||
* Instantiates Session. Constructor is not supposed to be used directly. To make sure that all
|
||||
* `Session` dependencies/plugins are properly initialized one should use static `Session.create` instead.
|
||||
* @param {Hapi.Server} server HapiJS Server instance.
|
||||
*/
|
||||
constructor(server, cookieOptions) {
|
||||
constructor(server) {
|
||||
this._server = server;
|
||||
this._cookieOptions = cookieOptions;
|
||||
this._ttl = this._server.config().get('xpack.security.sessionTimeout');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,7 +79,7 @@ export class Session {
|
|||
|
||||
request.cookieAuth.set({
|
||||
value,
|
||||
expires: this._cookieOptions.ttl && Date.now() + this._cookieOptions.ttl
|
||||
expires: this._ttl && Date.now() + this._ttl
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,43 +94,6 @@ export class Session {
|
|||
request.cookieAuth.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes current session.
|
||||
* @param {Hapi.Request} request HapiJS request instance.
|
||||
* @returns {Promise.<string>}
|
||||
*/
|
||||
async serialize(request) {
|
||||
const state = request._states[this._cookieOptions.name];
|
||||
if (!state) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const value = await new Promise((resolve, reject) => {
|
||||
iron.seal(state.value, this._cookieOptions.password, iron.defaults, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options that we're using for the session cookie
|
||||
* @returns {CookieOptions}
|
||||
*/
|
||||
getCookieOptions() {
|
||||
return {
|
||||
name: this._cookieOptions.name,
|
||||
path: this._cookieOptions.path,
|
||||
httpOnly: this._cookieOptions.httpOnly,
|
||||
secure: this._cookieOptions.secure,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares and creates a session instance.
|
||||
* @param {Hapi.Server} server HapiJS Server instance.
|
||||
|
@ -160,7 +111,6 @@ export class Session {
|
|||
const password = config.get('xpack.security.encryptionKey');
|
||||
const path = `${config.get('server.basePath')}/`;
|
||||
const secure = config.get('xpack.security.secureCookies');
|
||||
const ttl = config.get(`xpack.security.sessionTimeout`);
|
||||
|
||||
server.auth.strategy(HAPI_STRATEGY_NAME, 'cookie', {
|
||||
cookie: name,
|
||||
|
@ -180,14 +130,7 @@ export class Session {
|
|||
});
|
||||
}
|
||||
|
||||
return new Session(server, {
|
||||
httpOnly,
|
||||
name,
|
||||
password,
|
||||
path,
|
||||
secure,
|
||||
ttl,
|
||||
});
|
||||
return new Session(server);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue