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:
Brandon Kobel 2018-10-29 15:54:45 -07:00 committed by GitHub
parent 0429a54c28
commit 9f1cdac12b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 484 additions and 854 deletions

View file

@ -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);
});
});
});

View file

@ -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'
});
});
});
});

View file

@ -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 {

View file

@ -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);
}
/**