Skip to content

Commit

Permalink
[7.x] Security - remove auth scope provider (#36998) (#37339)
Browse files Browse the repository at this point in the history
* remove auth scope provider

* handle missing roles

* guard for unauthenticated calls

* update functional tests to not expect a scope property

* there's always money in the banana stand

* revert interceptor optimizations

* protect against missing roles

* address pr feedback

* remove scope as expected property on kerberos auth response
  • Loading branch information
legrego authored May 29, 2019
1 parent 38d74c4 commit 99c1741
Show file tree
Hide file tree
Showing 16 changed files with 53 additions and 420 deletions.
1 change: 0 additions & 1 deletion x-pack/plugins/dashboard_mode/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@
*/

export const CONFIG_DASHBOARD_ONLY_MODE_ROLES = 'xpackDashboardMode:roles';
export const AUTH_SCOPE_DASHBORD_ONLY_MODE = 'xpack:dashboardMode';
4 changes: 0 additions & 4 deletions x-pack/plugins/dashboard_mode/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
} from './common';

import {
getDashboardModeAuthScope,
createDashboardModeRequestInterceptor,
} from './server';

Expand Down Expand Up @@ -80,9 +79,6 @@ export function dashboardMode(kibana) {
));

if (server.plugins.security) {
// register auth getter with security plugin
server.plugins.security.registerAuthScopeGetter(getDashboardModeAuthScope);

// extend the server to intercept requests
const dashboardViewerApp = server.getHiddenUiAppById('dashboardViewer');
server.ext(createDashboardModeRequestInterceptor(dashboardViewerApp));
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,24 @@

import expect from '@kbn/expect';
import Hapi from 'hapi';
import Chance from 'chance';

import { createDashboardModeRequestInterceptor } from '../dashboard_mode_request_interceptor';
import * as constantsNS from '../../common/constants';

const chance = new Chance();
const DASHBOARD_ONLY_MODE_ROLE = 'test_dashboard_only_mode_role';

function setup() {
// randomize AUTH_SCOPE_DASHBORD_ONLY_MODE "constant" to ensure it's being used everywhere
const authScope = chance.word({ length: 12 });
Object.defineProperty(constantsNS, 'AUTH_SCOPE_DASHBORD_ONLY_MODE', {
value: authScope,
configurable: true,
});

const dashboardViewerApp = {
name: 'dashboardViewerApp'
};

const server = new Hapi.Server();

server.decorate('request', 'getUiSettingsService', () => {
return {
get: () => Promise.resolve([DASHBOARD_ONLY_MODE_ROLE])
};
});

// attach the extension
server.ext(createDashboardModeRequestInterceptor(dashboardViewerApp));

Expand All @@ -53,7 +50,7 @@ function setup() {
}
});

return { server, authScope };
return { server };
}

describe('DashboardOnlyModeRequestInterceptor', () => {
Expand All @@ -65,14 +62,14 @@ describe('DashboardOnlyModeRequestInterceptor', () => {
});
});

describe('request does not have `xpack:dashboardMode` scope', () => {
describe('request is not for dashboad-only user', () => {
describe('app route', () => {
it('lets the route render as normal', async () => {
const { server } = setup();
const response = await server.inject({
url: '/app/kibana',
credentials: {
scope: ['foo', 'bar']
roles: ['foo', 'bar']
}
});

Expand All @@ -91,7 +88,7 @@ describe('DashboardOnlyModeRequestInterceptor', () => {
const response = await server.inject({
url: '/foo/bar',
credentials: {
scope: ['foo', 'bar']
roles: ['foo', 'bar']
}
});

Expand All @@ -105,14 +102,14 @@ describe('DashboardOnlyModeRequestInterceptor', () => {
});
});

describe('request has correct auth scope scope', () => {
describe('request for dashboard-only user', () => {
describe('non-kibana app route', () => {
it('responds with 404', async () => {
const { server, authScope } = setup();
const { server } = setup();
const response = await server.inject({
url: '/app/foo',
credentials: {
scope: [authScope]
roles: [DASHBOARD_ONLY_MODE_ROLE]
}
});

Expand All @@ -124,11 +121,11 @@ describe('DashboardOnlyModeRequestInterceptor', () => {
function testRendersDashboardViewerApp(url) {
describe(`requests to url:"${url}"`, () => {
it('renders the dashboardViewerApp instead', async () => {
const { server, authScope } = setup();
const { server } = setup();
const response = await server.inject({
url: '/app/kibana',
credentials: {
scope: [authScope]
roles: [DASHBOARD_ONLY_MODE_ROLE]
}
});

Expand Down
39 changes: 0 additions & 39 deletions x-pack/plugins/dashboard_mode/server/dashboard_mode_auth_scope.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
import Boom from 'boom';

import {
AUTH_SCOPE_DASHBORD_ONLY_MODE
CONFIG_DASHBOARD_ONLY_MODE_ROLES,
} from '../common';

const superuserRole = 'superuser';

/**
* Intercept all requests after auth has completed and apply filtering
* logic to enforce `xpack:dashboardMode` scope
* logic to enforce dashboard only mode.
*
* @type {Hapi.RequestExtension}
*/
Expand All @@ -25,14 +27,34 @@ export function createDashboardModeRequestInterceptor(dashboardViewerApp) {
type: 'onPostAuth',
async method(request, h) {
const { auth, url } = request;
const user = auth.credentials;
const roles = user ? user.roles : [];

if (!user) {
return h.continue;
}

const isAppRequest = url.path.startsWith('/app/');

if (isAppRequest && auth.credentials.scope && auth.credentials.scope.includes(AUTH_SCOPE_DASHBORD_ONLY_MODE)) {
// The act of retrieving this setting ends up creating the config document if it doesn't already exist.
// Various functional tests have come to indirectly rely on this behavior, so changing this is non-trivial.
// This will be addressed once dashboard-only-mode is removed altogether.
const uiSettings = request.getUiSettingsService();
const dashboardOnlyModeRoles = await uiSettings.get(CONFIG_DASHBOARD_ONLY_MODE_ROLES);

if (!isAppRequest || !dashboardOnlyModeRoles || !roles || roles.length === 0) {
return h.continue;
}

const isDashboardOnlyModeUser = user.roles.find(role => dashboardOnlyModeRoles.includes(role));
const isSuperUser = user.roles.find(role => role === superuserRole);

const enforceDashboardOnlyMode = isDashboardOnlyModeUser && !isSuperUser;
if (enforceDashboardOnlyMode) {
if (url.path.startsWith('/app/kibana')) {
// If the user is in "Dashboard only mode" they should only be allowed to see
// that app and none others. Here we are intercepting all other routing and ensuring the viewer
// app is the only one ever rendered.
// Read more about Dashboard Only Mode here: https://github.com/elastic/x-pack-kibana/issues/180
const response = await h.renderApp(dashboardViewerApp);
return response.takeover();
}
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/dashboard_mode/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/

export { getDashboardModeAuthScope } from './dashboard_mode_auth_scope';
export { createDashboardModeRequestInterceptor } from './dashboard_mode_request_interceptor';
Loading

0 comments on commit 99c1741

Please sign in to comment.