Skip to content

Commit

Permalink
Register cluster privileges in Kibana Platform Security plugin.
Browse files Browse the repository at this point in the history
  • Loading branch information
azasypkin committed May 12, 2020
1 parent 304c7c1 commit d4c6f7b
Show file tree
Hide file tree
Showing 20 changed files with 224 additions and 176 deletions.
1 change: 1 addition & 0 deletions .sass-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ files:
- 'x-pack/plugins/cross_cluster_replication/**/*.s+(a|c)ss'
- 'x-pack/legacy/plugins/maps/**/*.s+(a|c)ss'
- 'x-pack/plugins/maps/**/*.s+(a|c)ss'
- 'x-pack/plugins/security/**/*.s+(a|c)ss'
ignore:
- 'x-pack/plugins/canvas/shareable_runtime/**/*.s+(a|c)ss'
rules:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import { Lifecycle, ResponseToolkit } from 'hapi';
import * as t from 'io-ts';
import { SecurityPluginSetup } from '../../../../../../../plugins/security/server';
import { LicenseType } from '../../../../common/constants/security';

export const internalAuthData = Symbol('internalAuthData');
Expand Down Expand Up @@ -39,6 +40,11 @@ export interface BackendFrameworkAdapter {
}

export interface KibanaLegacyServer {
newPlatform: {
setup: {
plugins: { security: SecurityPluginSetup };
};
};
plugins: {
xpack_main: {
status: {
Expand All @@ -53,9 +59,6 @@ export interface KibanaLegacyServer {
};
};
};
security: {
getUser: (request: KibanaServerRequest) => any;
};
elasticsearch: {
status: {
on: (status: 'green' | 'yellow' | 'red', callback: () => void) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ResponseToolkit } from 'hapi';
import { PathReporter } from 'io-ts/lib/PathReporter';
import { get } from 'lodash';
import { isLeft } from 'fp-ts/lib/Either';
import { KibanaRequest, LegacyRequest } from '../../../../../../../../src/core/server';
// @ts-ignore
import { mirrorPluginStatus } from '../../../../../../server/lib/mirror_plugin_status';
import {
Expand Down Expand Up @@ -128,13 +129,10 @@ export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter {
}

private async getUser(request: KibanaServerRequest): Promise<KibanaUser | null> {
let user;
try {
user = await this.server.plugins.security.getUser(request);
} catch (e) {
return null;
}
if (user === null) {
const user = this.server.newPlatform.setup.plugins.security?.authc.getCurrentUser(
KibanaRequest.from((request as unknown) as LegacyRequest)
);
if (!user) {
return null;
}
const assertKibanaUser = RuntimeKibanaUser.decode(user);
Expand Down
40 changes: 5 additions & 35 deletions x-pack/legacy/plugins/security/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,9 @@
import { Root } from 'joi';
import { resolve } from 'path';
import { Server } from 'src/legacy/server/kbn_server';
import { KibanaRequest, LegacyRequest } from '../../../../src/core/server';
// @ts-ignore
import { AuditLogger } from '../../server/lib/audit_logger';
// @ts-ignore
import { watchStatusAndLicenseToInitialize } from '../../server/lib/watch_status_and_license_to_initialize';
import { AuthenticatedUser, SecurityPluginSetup } from '../../../plugins/security/server';

/**
* Public interface of the security plugin.
*/
export interface SecurityPlugin {
getUser: (request: LegacyRequest) => Promise<AuthenticatedUser>;
}

function getSecurityPluginSetup(server: Server) {
const securityPlugin = server.newPlatform.setup.plugins.security as SecurityPluginSetup;
if (!securityPlugin) {
throw new Error('Kibana Platform Security plugin is not available.');
}

return securityPlugin;
}
import { SecurityPluginSetup } from '../../../plugins/security/server';

export const security = (kibana: Record<string, any>) =>
new kibana.Plugin({
Expand All @@ -55,17 +36,11 @@ export const security = (kibana: Record<string, any>) =>
},
},

async postInit(server: Server) {
watchStatusAndLicenseToInitialize(server.plugins.xpack_main, this, async () => {
const xpackInfo = server.plugins.xpack_main.info;
if (xpackInfo.isAvailable() && xpackInfo.feature('security').isEnabled()) {
await getSecurityPluginSetup(server).__legacyCompat.registerPrivilegesWithCluster();
}
});
},

async init(server: Server) {
const securityPlugin = getSecurityPluginSetup(server);
const securityPlugin = server.newPlatform.setup.plugins.security as SecurityPluginSetup;
if (!securityPlugin) {
throw new Error('Kibana Platform Security plugin is not available.');
}

const xpackInfo = server.plugins.xpack_main.info;
securityPlugin.__legacyCompat.registerLegacyAPI({
Expand All @@ -79,10 +54,5 @@ export const security = (kibana: Record<string, any>) =>
xpackInfo
.feature(this.id)
.registerLicenseCheckResultsGenerator(() => securityPlugin.license.getFeatures());

server.expose({
getUser: async (request: LegacyRequest) =>
securityPlugin.authc.getCurrentUser(KibanaRequest.from(request)),
});
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@
}

&:focus {
@include euiFocusRing;

border-color: transparent;
border-radius: $euiBorderRadius;
@include euiFocusRing;

.secLoginCard__title {
text-decoration: underline;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,20 @@ import { Feature } from '../../../../../features/public';
import { KibanaPrivileges } from '../model';
import { SecurityLicenseFeatures } from '../../..';

// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { featuresPluginMock } from '../../../../../features/server/mocks';

export const createRawKibanaPrivileges = (
features: Feature[],
{ allowSubFeaturePrivileges = true } = {}
) => {
const featuresService = {
getFeatures: () => features,
};

const licensingService = {
getFeatures: () => ({ allowSubFeaturePrivileges } as SecurityLicenseFeatures),
};

return privilegesFactory(
new Actions('unit_test_version'),
featuresService,
featuresPluginMock.createSetup(),
licensingService
).get();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { CoreSetup, Logger } from '../../../../../src/core/server';
import { Authorization } from '.';
import { HttpServiceSetup, Logger } from '../../../../../src/core/server';
import { AuthorizationServiceSetup } from '.';

export function initAPIAuthorization(
http: CoreSetup['http'],
{ actions, checkPrivilegesDynamicallyWithRequest, mode }: Authorization,
http: HttpServiceSetup,
{ actions, checkPrivilegesDynamicallyWithRequest, mode }: AuthorizationServiceSetup,
logger: Logger
) {
http.registerOnPostAuth(async (request, response, toolkit) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { CoreSetup, Logger } from '../../../../../src/core/server';
import { FeaturesService } from '../plugin';
import { Authorization } from '.';
import { HttpServiceSetup, Logger } from '../../../../../src/core/server';
import { PluginSetupContract as FeaturesPluginSetup } from '../../../features/server';
import { AuthorizationServiceSetup } from '.';

class ProtectedApplications {
private applications: Set<string> | null = null;
constructor(private readonly featuresService: FeaturesService) {}
constructor(private readonly featuresService: FeaturesPluginSetup) {}

public shouldProtect(appId: string) {
// Currently, once we get the list of features we essentially "lock" additional
Expand All @@ -30,14 +30,14 @@ class ProtectedApplications {
}

export function initAppAuthorization(
http: CoreSetup['http'],
http: HttpServiceSetup,
{
actions,
checkPrivilegesDynamicallyWithRequest,
mode,
}: Pick<Authorization, 'actions' | 'checkPrivilegesDynamicallyWithRequest' | 'mode'>,
}: Pick<AuthorizationServiceSetup, 'actions' | 'checkPrivilegesDynamicallyWithRequest' | 'mode'>,
logger: Logger,
featuresService: FeaturesService
featuresService: FeaturesPluginSetup
) {
const protectedApplications = new ProtectedApplications(featuresService);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@ import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges
import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges';
import { authorizationModeFactory } from './mode';
import { privilegesFactory } from './privileges';
import { setupAuthorization } from '.';
import { AuthorizationService } from '.';

import {
coreMock,
elasticsearchServiceMock,
loggingServiceMock,
} from '../../../../../src/core/server/mocks';
import { featuresPluginMock } from '../../../features/server/mocks';
import { licenseMock } from '../../common/licensing/index.mock';

test(`returns exposed services`, () => {
it(`returns exposed services`, () => {
const kibanaIndexName = '.a-kibana-index';
const application = `kibana-${kibanaIndexName}`;

Expand All @@ -52,17 +53,21 @@ test(`returns exposed services`, () => {
const mockGetSpacesService = jest
.fn()
.mockReturnValue({ getSpaceId: jest.fn(), namespaceToSpaceId: jest.fn() });
const mockFeaturesService = { getFeatures: () => [] };
const mockFeaturesSetup = featuresPluginMock.createSetup();
const mockLicense = licenseMock.create();
const mockCoreSetup = coreMock.createSetup();

const authz = setupAuthorization({
http: coreMock.createSetup().http,
const authorizationService = new AuthorizationService();
const authz = authorizationService.setup({
http: mockCoreSetup.http,
capabilities: mockCoreSetup.capabilities,
status: mockCoreSetup.status,
clusterClient: mockClusterClient,
license: mockLicense,
loggers: loggingServiceMock.create(),
kibanaIndexName,
packageVersion: 'some-version',
featuresService: mockFeaturesService,
features: mockFeaturesSetup,
getSpacesService: mockGetSpacesService,
});

Expand Down Expand Up @@ -93,7 +98,7 @@ test(`returns exposed services`, () => {
);

expect(authz.privileges).toBe(mockPrivilegesService);
expect(privilegesFactory).toHaveBeenCalledWith(authz.actions, mockFeaturesService, mockLicense);
expect(privilegesFactory).toHaveBeenCalledWith(authz.actions, mockFeaturesSetup, mockLicense);

expect(authz.mode).toBe(mockAuthorizationMode);
expect(authorizationModeFactory).toHaveBeenCalledWith(mockLicense);
Expand Down
Loading

0 comments on commit d4c6f7b

Please sign in to comment.