Skip to content

Commit

Permalink
Changes in Security plugin.
Browse files Browse the repository at this point in the history
  • Loading branch information
azasypkin committed Oct 28, 2019
1 parent 418be5b commit 5e6a836
Show file tree
Hide file tree
Showing 97 changed files with 5,539 additions and 5,351 deletions.
1 change: 0 additions & 1 deletion x-pack/legacy/plugins/security/common/login_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ export type LoginLayout = 'form' | 'error-es-unavailable' | 'error-xpack-unavail
export interface LoginState {
layout: LoginLayout;
allowLogin: boolean;
loginMessage: string;
}
2 changes: 0 additions & 2 deletions x-pack/legacy/plugins/security/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@

import { Legacy } from 'kibana';
import { AuthenticatedUser } from './common/model';
import { AuthorizationService } from './server/lib/authorization/service';

/**
* Public interface of the security plugin.
*/
export interface SecurityPlugin {
authorization: Readonly<AuthorizationService>;
getUser: (request: Legacy.Request) => Promise<AuthenticatedUser>;
}
129 changes: 24 additions & 105 deletions x-pack/legacy/plugins/security/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,13 @@ import { resolve } from 'path';
import { initAuthenticateApi } from './server/routes/api/v1/authenticate';
import { initUsersApi } from './server/routes/api/v1/users';
import { initApiKeysApi } from './server/routes/api/v1/api_keys';
import { initExternalRolesApi } from './server/routes/api/external/roles';
import { initPrivilegesApi } from './server/routes/api/external/privileges';
import { initIndicesApi } from './server/routes/api/v1/indices';
import { initGetBuiltinPrivilegesApi } from './server/routes/api/v1/builtin_privileges';
import { initOverwrittenSessionView } from './server/routes/views/overwritten_session';
import { initLoginView } from './server/routes/views/login';
import { initLogoutView } from './server/routes/views/logout';
import { initLoggedOutView } from './server/routes/views/logged_out';
import { checkLicense } from './server/lib/check_license';
import { SecurityAuditLogger } from './server/lib/audit_logger';
import { AuditLogger } from '../../server/lib/audit_logger';
import {
createAuthorizationService,
disableUICapabilitesFactory,
initAPIAuthorization,
initAppAuthorization,
registerPrivilegesWithCluster,
validateFeaturePrivileges
} from './server/lib/authorization';
import { watchStatusAndLicenseToInitialize } from '../../server/lib/watch_status_and_license_to_initialize';
import { SecureSavedObjectsClientWrapper } from './server/lib/saved_objects_client/secure_saved_objects_client_wrapper';
import { deepFreeze } from './server/lib/deep_freeze';
import { createOptionalPlugin } from '../../server/lib/optional_plugin';
import { KibanaRequest } from '../../../../src/core/server';
import { createCSPRuleString } from '../../../../src/legacy/server/csp';

Expand Down Expand Up @@ -103,23 +87,22 @@ export const security = (kibana) => new kibana.Plugin({
}

return {
secureCookies: securityPlugin.config.secureCookies,
sessionTimeout: securityPlugin.config.sessionTimeout,
secureCookies: securityPlugin.__legacyCompat.config.secureCookies,
sessionTimeout: securityPlugin.__legacyCompat.config.sessionTimeout,
enableSpaceAwarePrivileges: server.config().get('xpack.spaces.enabled'),
};
},
},

async postInit(server) {
const plugin = this;

const xpackMainPlugin = server.plugins.xpack_main;
const securityPlugin = server.newPlatform.setup.plugins.security;
if (!securityPlugin) {
throw new Error('New Platform XPack Security plugin is not available.');
}

watchStatusAndLicenseToInitialize(xpackMainPlugin, plugin, async (license) => {
if (license.allowRbac) {
const { security } = server.plugins;
await validateFeaturePrivileges(security.authorization.actions, xpackMainPlugin.getFeatures());
await registerPrivilegesWithCluster(server);
watchStatusAndLicenseToInitialize(server.plugins.xpack_main, this, async () => {
if (securityPlugin.__legacyCompat.license.getFeatures().allowRbac) {
await securityPlugin.__legacyCompat.registerPrivilegesWithCluster();
}
});
},
Expand All @@ -131,110 +114,46 @@ export const security = (kibana) => new kibana.Plugin({
}

const config = server.config();
const xpackMainPlugin = server.plugins.xpack_main;
const xpackInfo = xpackMainPlugin.info;
securityPlugin.registerLegacyAPI({
xpackInfo,
const xpackInfo = server.plugins.xpack_main.info;
securityPlugin.__legacyCompat.registerLegacyAPI({
savedObjects: server.savedObjects,
auditLogger: new AuditLogger(server, 'security', config, xpackInfo),
isSystemAPIRequest: server.plugins.kibana.systemApi.isSystemApiRequest.bind(
server.plugins.kibana.systemApi
),
capabilities: { registerCapabilitiesModifier: server.registerCapabilitiesModifier },
cspRules: createCSPRuleString(config.get('csp.rules')),
kibanaIndexName: config.get('kibana.index'),
});

const plugin = this;
const xpackInfoFeature = xpackInfo.feature(plugin.id);

// Register a function that is called whenever the xpack info changes,
// to re-compute the license check results for this plugin
xpackInfoFeature.registerLicenseCheckResultsGenerator(checkLicense);
// Legacy xPack Info endpoint returns whatever we return in a callback for `registerLicenseCheckResultsGenerator`
// and the result is consumed by the legacy plugins all over the place, so we should keep it here for now. We assume
// that when legacy callback is called license has been already propagated to the new platform security plugin and
// features are up to date.
xpackInfo.feature(this.id).registerLicenseCheckResultsGenerator(
() => securityPlugin.__legacyCompat.license.getFeatures()
);

server.expose({ getUser: request => securityPlugin.authc.getCurrentUser(KibanaRequest.from(request)) });

const { savedObjects } = server;

const spaces = createOptionalPlugin(config, 'xpack.spaces', server.plugins, 'spaces');

// exposes server.plugins.security.authorization
const authorization = createAuthorizationService(server, xpackInfoFeature, xpackMainPlugin, spaces);
server.expose('authorization', deepFreeze(authorization));

const auditLogger = new SecurityAuditLogger(new AuditLogger(server, 'security', server.config(), xpackInfo));

savedObjects.setScopedSavedObjectsClientFactory(({
request,
}) => {
const adminCluster = server.plugins.elasticsearch.getCluster('admin');
const { callWithRequest, callWithInternalUser } = adminCluster;
const callCluster = (...args) => callWithRequest(request, ...args);

if (authorization.mode.useRbacForRequest(request)) {
const internalRepository = savedObjects.getSavedObjectsRepository(callWithInternalUser);
return new savedObjects.SavedObjectsClient(internalRepository);
}

const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster);
return new savedObjects.SavedObjectsClient(callWithRequestRepository);
});

savedObjects.addScopedSavedObjectsClientWrapperFactory(Number.MAX_SAFE_INTEGER - 1, 'security', ({ client, request }) => {
if (authorization.mode.useRbacForRequest(request)) {
return new SecureSavedObjectsClientWrapper({
actions: authorization.actions,
auditLogger,
baseClient: client,
checkSavedObjectsPrivilegesWithRequest: authorization.checkSavedObjectsPrivilegesWithRequest,
errors: savedObjects.SavedObjectsClient.errors,
request,
savedObjectTypes: savedObjects.types,
});
}

return client;
});

initAuthenticateApi(securityPlugin, server);
initAPIAuthorization(server, authorization);
initAppAuthorization(server, xpackMainPlugin, authorization);
initUsersApi(securityPlugin, server);
initApiKeysApi(server);
initExternalRolesApi(server);
initIndicesApi(server);
initPrivilegesApi(server);
initGetBuiltinPrivilegesApi(server);
initLoginView(securityPlugin, server, xpackMainPlugin);
initLoginView(securityPlugin, server);
initLogoutView(server);
initLoggedOutView(securityPlugin, server);
initOverwrittenSessionView(server);

server.injectUiAppVars('login', () => {

const { showLogin, loginMessage, allowLogin, layout = 'form' } = xpackInfo.feature(plugin.id).getLicenseCheckResults() || {};

const { showLogin, allowLogin, layout = 'form' } = securityPlugin.__legacyCompat.license.getFeatures();
return {
loginState: {
showLogin,
allowLogin,
loginMessage,
layout,
}
};
});

server.registerCapabilitiesModifier((request, uiCapabilities) => {
// if we have a license which doesn't enable security, or we're a legacy user
// we shouldn't disable any ui capabilities
const { authorization } = server.plugins.security;
if (!authorization.mode.useRbacForRequest(request)) {
return uiCapabilities;
}

const disableUICapabilites = disableUICapabilitesFactory(server, request);
// if we're an anonymous route, we disable all ui capabilities
if (request.route.settings.auth === false) {
return disableUICapabilites.all(uiCapabilities);
}

return disableUICapabilites.usingPrivileges(uiCapabilities);
});
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const createLoginState = (options?: Partial<LoginState>) => {
return {
allowLogin: true,
layout: 'form',
loginMessage: '',
...options,
} as LoginState;
};
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const createLoginState = (options?: Partial<LoginState>) => {
return {
allowLogin: true,
layout: 'form',
loginMessage: '',
...options,
} as LoginState;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { UICapabilities } from 'ui/capabilities';
import { Space } from '../../../../../../spaces/common/model/space';
import { Feature } from '../../../../../../../../plugins/features/server';
import { Actions } from '../../../../../../../../plugins/security/server/authorization/actions';
import { privilegesFactory } from '../../../../../../../../plugins/security/server/authorization/privileges';
import { RawKibanaPrivileges, Role } from '../../../../../common/model';
import { actionsFactory } from '../../../../../server/lib/authorization/actions';
import { privilegesFactory } from '../../../../../server/lib/authorization/privileges';
import { EditRolePage } from './edit_role_page';
import { SimplePrivilegeSection } from './privileges/kibana/simple_privilege_section';
import { SpaceAwarePrivilegeSection } from './privileges/kibana/space_aware_privilege_section';
Expand Down Expand Up @@ -56,13 +56,9 @@ const buildFeatures = () => {
};

const buildRawKibanaPrivileges = () => {
const xpackMainPlugin = {
return privilegesFactory(new Actions('unit_test_version'), {
getFeatures: () => buildFeatures(),
};

const actions = actionsFactory({ get: jest.fn(() => 'unit_test_version') });

return privilegesFactory(actions, xpackMainPlugin as any).get();
}).get();
};

const buildBuiltinESPrivileges = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const routeDefinition = (action) => ({
return kfetch({ method: 'get', pathname: '/api/security/privileges', query: { includeActions: true } });
},
builtinESPrivileges() {
return kfetch({ method: 'get', pathname: '/api/security/v1/esPrivileges/builtin' });
return kfetch({ method: 'get', pathname: '/api/security/esPrivileges/builtin' });
},
features() {
return kfetch({ method: 'get', pathname: '/api/features' }).catch(e => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
const Boom = require('boom');

export function routePreCheckLicense(server) {
const xpackMainPlugin = server.plugins.xpack_main;
const pluginId = 'security';
return function forbidApiAccess() {
const licenseCheckResults = xpackMainPlugin.info.feature(pluginId).getLicenseCheckResults();
const licenseCheckResults = server.newPlatform.setup.plugins.security.__legacyCompat.license.getFeatures();
if (!licenseCheckResults.showLinks) {
throw Boom.forbidden(licenseCheckResults.linksMessage);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ export function initApiKeysApi(server) {
const callWithRequest = getClient(server).callWithRequest;
const routePreCheckLicenseFn = routePreCheckLicense(server);

const { authorization } = server.plugins.security;
const { application } = authorization;

initCheckPrivilegesApi(server, callWithRequest, routePreCheckLicenseFn, application);
initGetApiKeysApi(server, callWithRequest, routePreCheckLicenseFn, application);
initInvalidateApiKeysApi(server, callWithRequest, routePreCheckLicenseFn, application);
initCheckPrivilegesApi(server, callWithRequest, routePreCheckLicenseFn);
initGetApiKeysApi(server, callWithRequest, routePreCheckLicenseFn);
initInvalidateApiKeysApi(server, callWithRequest, routePreCheckLicenseFn);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { canRedirectRequest, wrapError, OIDCAuthenticationFlow } from '../../../
import { KibanaRequest } from '../../../../../../../../src/core/server';
import { createCSPRuleString } from '../../../../../../../../src/legacy/server/csp';

export function initAuthenticateApi({ authc: { login, logout }, config }, server) {
export function initAuthenticateApi({ authc: { login, logout }, __legacyCompat: { config } }, server) {
function prepareCustomResourceResponse(response, contentType) {
return response
.header('cache-control', 'private, no-cache, no-store')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { routePreCheckLicense } from '../../../lib/route_pre_check_license';
import { wrapError } from '../../../../../../../plugins/security/server';
import { KibanaRequest } from '../../../../../../../../src/core/server';

export function initUsersApi({ authc: { login }, config }, server) {
export function initUsersApi({ authc: { login }, __legacyCompat: { config } }, server) {
const callWithRequest = getClient(server).callWithRequest;
const routePreCheckLicenseFn = routePreCheckLicense(server);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

export function initLoggedOutView({ config: { cookieName } }, server) {
export function initLoggedOutView({ __legacyCompat: { config: { cookieName } } }, server) {
const config = server.config();
const loggedOut = server.getHiddenUiAppById('logged_out');

Expand Down
9 changes: 3 additions & 6 deletions x-pack/legacy/plugins/security/server/routes/views/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ import { get } from 'lodash';

import { parseNext } from '../../lib/parse_next';

export function initLoginView({ config: { cookieName } }, server, xpackMainPlugin) {
export function initLoginView({ __legacyCompat: { config: { cookieName }, license } }, server) {
const config = server.config();
const login = server.getHiddenUiAppById('login');

function shouldShowLogin() {
if (xpackMainPlugin && xpackMainPlugin.info) {
const licenseCheckResults = xpackMainPlugin.info.feature('security').getLicenseCheckResults();
if (licenseCheckResults) {
return Boolean(licenseCheckResults.showLogin);
}
if (license.isEnabled()) {
return Boolean(license.getFeatures().showLogin);
}

// default to true if xpack info isn't available or
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/security/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@
*/

export const GLOBAL_RESOURCE = '*';
export const IGNORED_TYPES = ['space'];
export const APPLICATION_PREFIX = 'kibana-';
export const RESERVED_PRIVILEGES_APPLICATION_WILDCARD = 'kibana-*';
1 change: 1 addition & 0 deletions x-pack/plugins/security/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "8.0.0",
"kibanaVersion": "kibana",
"configPath": ["xpack", "security"],
"requiredPlugins": ["features", "licensing"],
"server": true,
"ui": true
}
15 changes: 7 additions & 8 deletions x-pack/plugins/security/server/audit/audit_logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,21 @@ import { SecurityAuditLogger } from './audit_logger';

const createMockAuditLogger = () => {
return {
log: jest.fn()
log: jest.fn(),
};
};

describe(`#savedObjectsAuthorizationFailure`, () => {

test('logs via auditLogger', () => {
const auditLogger = createMockAuditLogger();
const securityAuditLogger = new SecurityAuditLogger(auditLogger);
const username = 'foo-user';
const action = 'foo-action';
const types = [ 'foo-type-1', 'foo-type-2' ];
const types = ['foo-type-1', 'foo-type-2'];
const missing = [`saved_object:${types[0]}/foo-action`, `saved_object:${types[1]}/foo-action`];
const args = {
'foo': 'bar',
'baz': 'quz',
foo: 'bar',
baz: 'quz',
};

securityAuditLogger.savedObjectsAuthorizationFailure(username, action, types, missing, args);
Expand All @@ -47,10 +46,10 @@ describe(`#savedObjectsAuthorizationSuccess`, () => {
const securityAuditLogger = new SecurityAuditLogger(auditLogger);
const username = 'foo-user';
const action = 'foo-action';
const types = [ 'foo-type-1', 'foo-type-2' ];
const types = ['foo-type-1', 'foo-type-2'];
const args = {
'foo': 'bar',
'baz': 'quz',
foo: 'bar',
baz: 'quz',
};

securityAuditLogger.savedObjectsAuthorizationSuccess(username, action, types, args);
Expand Down
Loading

0 comments on commit 5e6a836

Please sign in to comment.