Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] Check auth status via security plugin on our privileges endpoint (#61334) #61383

Merged
merged 1 commit into from
Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ export const updateActionResult = (): ActionResult => ({
config: {},
});

export const getMockPrivileges = () => ({
export const getMockPrivilegesResult = () => ({
username: 'test-space',
has_all_requested: false,
cluster: {
Expand Down Expand Up @@ -565,8 +565,6 @@ export const getMockPrivileges = () => ({
},
},
application: {},
is_authenticated: false,
has_encryption_key: true,
});

export const getFindResultStatusEmpty = (): SavedObjectsFindResponse<IRuleSavedAttributesSavedObjectAttributes> => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { securityMock } from '../../../../../../../../plugins/security/server/mocks';
import { readPrivilegesRoute } from './read_privileges_route';
import { serverMock, requestContextMock } from '../__mocks__';
import { getPrivilegeRequest, getMockPrivileges } from '../__mocks__/request_responses';
import { getPrivilegeRequest, getMockPrivilegesResult } from '../__mocks__/request_responses';

describe('read_privileges', () => {
describe('read_privileges route', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
let mockSecurity: ReturnType<typeof securityMock.createSetup>;

beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

clients.clusterClient.callAsCurrentUser.mockResolvedValue(getMockPrivileges());
readPrivilegesRoute(server.router, false);
mockSecurity = securityMock.createSetup();
mockSecurity.authc.isAuthenticated.mockReturnValue(false);
clients.clusterClient.callAsCurrentUser.mockResolvedValue(getMockPrivilegesResult());
readPrivilegesRoute(server.router, mockSecurity, false);
});

describe('normal status codes', () => {
Expand All @@ -26,10 +30,28 @@ describe('read_privileges', () => {
expect(response.status).toEqual(200);
});

test.skip('returns the payload when doing a normal request', async () => {
test('returns the payload when doing a normal request', async () => {
const response = await server.inject(getPrivilegeRequest(), context);
const expectedBody = {
...getMockPrivilegesResult(),
is_authenticated: false,
has_encryption_key: true,
};
expect(response.status).toEqual(200);
expect(response.body).toEqual(getMockPrivileges());
expect(response.body).toEqual(expectedBody);
});

test('is authenticated when security says so', async () => {
mockSecurity.authc.isAuthenticated.mockReturnValue(true);
const expectedBody = {
...getMockPrivilegesResult(),
is_authenticated: true,
has_encryption_key: true,
};

const response = await server.inject(getPrivilegeRequest(), context);
expect(response.status).toEqual(200);
expect(response.body).toEqual(expectedBody);
});

test('returns 500 when bad response from cluster', async () => {
Expand All @@ -41,4 +63,26 @@ describe('read_privileges', () => {
expect(response.body).toEqual({ message: 'Test error', status_code: 500 });
});
});

describe('when security plugin is disabled', () => {
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

clients.clusterClient.callAsCurrentUser.mockResolvedValue(getMockPrivilegesResult());
readPrivilegesRoute(server.router, undefined, false);
});

it('returns unauthenticated', async () => {
const expectedBody = {
...getMockPrivilegesResult(),
is_authenticated: false,
has_encryption_key: true,
};

const response = await server.inject(getPrivilegeRequest(), context);
expect(response.status).toEqual(200);
expect(response.body).toEqual(expectedBody);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ import { merge } from 'lodash/fp';

import { IRouter } from '../../../../../../../../../src/core/server';
import { DETECTION_ENGINE_PRIVILEGES_URL } from '../../../../../common/constants';
import { SetupPlugins } from '../../../../plugin';
import { buildSiemResponse, transformError } from '../utils';
import { readPrivileges } from '../../privileges/read_privileges';

export const readPrivilegesRoute = (router: IRouter, usingEphemeralEncryptionKey: boolean) => {
export const readPrivilegesRoute = (
router: IRouter,
security: SetupPlugins['security'],
usingEphemeralEncryptionKey: boolean
) => {
router.get(
{
path: DETECTION_ENGINE_PRIVILEGES_URL,
Expand All @@ -29,7 +34,7 @@ export const readPrivilegesRoute = (router: IRouter, usingEphemeralEncryptionKey
const index = siemClient.signalsIndex;
const clusterPrivileges = await readPrivileges(clusterClient.callAsCurrentUser, index);
const privileges = merge(clusterPrivileges, {
is_authenticated: true, // until we support optional auth: https://github.com/elastic/kibana/pull/55327#issuecomment-577159911
is_authenticated: security?.authc.isAuthenticated(request) ?? false,
has_encryption_key: !usingEphemeralEncryptionKey,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class KibanaBackendFrameworkAdapter implements FrameworkAdapter {

private async getCurrentUserInfo(request: KibanaRequest): Promise<AuthenticatedUser | null> {
try {
const user = await this.security.authc.getCurrentUser(request);
const user = (await this.security?.authc.getCurrentUser(request)) ?? null;
return user;
} catch {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ import {

import { IRouter } from '../../../../../../../../src/core/server';
import { TIMELINE_IMPORT_URL } from '../../../../common/constants';
import { SetupPlugins } from '../../../plugin';
import { importTimelinesPayloadSchema } from './schemas/import_timelines_schema';
import { importRulesSchema } from '../../detection_engine/routes/schemas/response/import_rules_schema';
import { LegacyServices } from '../../../types';

import { Timeline } from '../saved_object';
import { validate } from '../../detection_engine/routes/rules/validate';
import { FrameworkRequest } from '../../framework';
import { SecurityPluginSetup } from '../../../../../../../plugins/security/server';

const CHUNK_PARSED_OBJECT_SIZE = 10;

Expand All @@ -46,7 +46,7 @@ const timelineLib = new Timeline();
export const importTimelinesRoute = (
router: IRouter,
config: LegacyServices['config'],
securityPluginSetup: SecurityPluginSetup
security: SetupPlugins['security']
) => {
router.post(
{
Expand Down Expand Up @@ -96,7 +96,7 @@ export const importTimelinesRoute = (
const chunkParseObjects = chunk(CHUNK_PARSED_OBJECT_SIZE, uniqueParsedObjects);
let importTimelineResponse: ImportTimelineResponse[] = [];

const user = await securityPluginSetup.authc.getCurrentUser(request);
const user = await security?.authc.getCurrentUser(request);
let frameworkRequest = set('context.core.savedObjects.client', savedObjectsClient, request);
frameworkRequest = set('user', user, frameworkRequest);

Expand Down
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/siem/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export interface SetupPlugins {
encryptedSavedObjects: EncryptedSavedObjectsSetup;
features: FeaturesSetup;
licensing: LicensingPluginSetup;
security: SecuritySetup;
security?: SecuritySetup;
spaces?: SpacesSetup;
}

Expand Down
6 changes: 3 additions & 3 deletions x-pack/legacy/plugins/siem/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ import { findRulesStatusesRoute } from '../lib/detection_engine/routes/rules/fin
import { getPrepackagedRulesStatusRoute } from '../lib/detection_engine/routes/rules/get_prepackaged_rules_status_route';
import { importTimelinesRoute } from '../lib/timeline/routes/import_timelines_route';
import { exportTimelinesRoute } from '../lib/timeline/routes/export_timelines_route';
import { SecurityPluginSetup } from '../../../../../plugins/security/server/';
import { SetupPlugins } from '../plugin';

export const initRoutes = (
router: IRouter,
config: LegacyServices['config'],
usingEphemeralEncryptionKey: boolean,
security: SecurityPluginSetup
security: SetupPlugins['security']
) => {
// Detection Engine Rule routes that have the REST endpoints of /api/detection_engine/rules
// All REST rule creation, deletion, updating, etc......
Expand Down Expand Up @@ -79,5 +79,5 @@ export const initRoutes = (
readTagsRoute(router);

// Privileges API to get the generic user privileges
readPrivilegesRoute(router, usingEphemeralEncryptionKey);
readPrivilegesRoute(router, security, usingEphemeralEncryptionKey);
};