mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
241 lines
9 KiB
JavaScript
241 lines
9 KiB
JavaScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the Elastic License;
|
|
* you may not use this file except in compliance with the Elastic License.
|
|
*/
|
|
|
|
import { resolve } from 'path';
|
|
import { getUserProvider } from './server/lib/get_user';
|
|
import { initAuthenticateApi } from './server/routes/api/v1/authenticate';
|
|
import { initUsersApi } from './server/routes/api/v1/users';
|
|
import { initPublicRolesApi } from './server/routes/api/public/roles';
|
|
import { initPrivilegesApi } from './server/routes/api/public/privileges';
|
|
import { initIndicesApi } from './server/routes/api/v1/indices';
|
|
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 { validateConfig } from './server/lib/validate_config';
|
|
import { authenticateFactory } from './server/lib/auth_redirect';
|
|
import { checkLicense } from './server/lib/check_license';
|
|
import { initAuthenticator } from './server/lib/authentication/authenticator';
|
|
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';
|
|
|
|
export const security = (kibana) => new kibana.Plugin({
|
|
id: 'security',
|
|
configPrefix: 'xpack.security',
|
|
publicDir: resolve(__dirname, 'public'),
|
|
require: ['kibana', 'elasticsearch', 'xpack_main'],
|
|
|
|
config(Joi) {
|
|
return Joi.object({
|
|
authProviders: Joi.array().items(Joi.string()).default(['basic']),
|
|
enabled: Joi.boolean().default(true),
|
|
cookieName: Joi.string().default('sid'),
|
|
encryptionKey: Joi.string(),
|
|
sessionTimeout: Joi.number().allow(null).default(null),
|
|
secureCookies: Joi.boolean().default(false),
|
|
public: Joi.object({
|
|
protocol: Joi.string().valid(['http', 'https']),
|
|
hostname: Joi.string().hostname(),
|
|
port: Joi.number().integer().min(0).max(65535)
|
|
}).default(),
|
|
authorization: Joi.object({
|
|
legacyFallback: Joi.object({
|
|
enabled: Joi.boolean().default(true) // deprecated
|
|
}).default()
|
|
}).default(),
|
|
audit: Joi.object({
|
|
enabled: Joi.boolean().default(false)
|
|
}).default(),
|
|
}).default();
|
|
},
|
|
|
|
deprecations: function ({ unused }) {
|
|
return [
|
|
unused('authorization.legacyFallback.enabled'),
|
|
];
|
|
},
|
|
|
|
uiExports: {
|
|
chromeNavControls: ['plugins/security/views/nav_control'],
|
|
managementSections: ['plugins/security/views/management'],
|
|
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
|
apps: [{
|
|
id: 'login',
|
|
title: 'Login',
|
|
main: 'plugins/security/views/login',
|
|
hidden: true,
|
|
}, {
|
|
id: 'overwritten_session',
|
|
title: 'Overwritten Session',
|
|
main: 'plugins/security/views/overwritten_session',
|
|
description: 'The view is shown when user had an active session previously, but logged in as a different user.',
|
|
hidden: true,
|
|
}, {
|
|
id: 'logout',
|
|
title: 'Logout',
|
|
main: 'plugins/security/views/logout',
|
|
hidden: true
|
|
}, {
|
|
id: 'logged_out',
|
|
title: 'Logged out',
|
|
main: 'plugins/security/views/logged_out',
|
|
hidden: true
|
|
}],
|
|
hacks: [
|
|
'plugins/security/hacks/on_session_timeout',
|
|
'plugins/security/hacks/on_unauthorized_response'
|
|
],
|
|
home: ['plugins/security/register_feature'],
|
|
injectDefaultVars: function (server) {
|
|
const config = server.config();
|
|
|
|
return {
|
|
secureCookies: config.get('xpack.security.secureCookies'),
|
|
sessionTimeout: config.get('xpack.security.sessionTimeout'),
|
|
enableSpaceAwarePrivileges: config.get('xpack.spaces.enabled'),
|
|
};
|
|
}
|
|
},
|
|
|
|
async postInit(server) {
|
|
const plugin = this;
|
|
|
|
const xpackMainPlugin = server.plugins.xpack_main;
|
|
|
|
watchStatusAndLicenseToInitialize(xpackMainPlugin, plugin, async (license) => {
|
|
if (license.allowRbac) {
|
|
const { security } = server.plugins;
|
|
await validateFeaturePrivileges(security.authorization.actions, xpackMainPlugin.getFeatures());
|
|
await registerPrivilegesWithCluster(server);
|
|
}
|
|
});
|
|
},
|
|
|
|
async init(server) {
|
|
const plugin = this;
|
|
|
|
const config = server.config();
|
|
const xpackMainPlugin = server.plugins.xpack_main;
|
|
const xpackInfo = xpackMainPlugin.info;
|
|
|
|
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);
|
|
|
|
validateConfig(config, message => server.log(['security', 'warning'], message));
|
|
|
|
// Create a Hapi auth scheme that should be applied to each request.
|
|
server.auth.scheme('login', () => ({ authenticate: authenticateFactory(server) }));
|
|
|
|
server.auth.strategy('session', 'login');
|
|
|
|
// The default means that the `session` strategy that is based on `login` schema defined above will be
|
|
// automatically assigned to all routes that don't contain an auth config.
|
|
server.auth.default('session');
|
|
|
|
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.MIN_SAFE_INTEGER, ({ client, request }) => {
|
|
if (authorization.mode.useRbacForRequest(request)) {
|
|
return new SecureSavedObjectsClientWrapper({
|
|
actions: authorization.actions,
|
|
auditLogger,
|
|
baseClient: client,
|
|
checkPrivilegesDynamicallyWithRequest: authorization.checkPrivilegesDynamicallyWithRequest,
|
|
errors: savedObjects.SavedObjectsClient.errors,
|
|
request,
|
|
savedObjectTypes: savedObjects.types,
|
|
});
|
|
}
|
|
|
|
return client;
|
|
});
|
|
|
|
getUserProvider(server);
|
|
|
|
await initAuthenticator(server);
|
|
initAuthenticateApi(server);
|
|
initAPIAuthorization(server, authorization);
|
|
initAppAuthorization(server, xpackMainPlugin, authorization);
|
|
initUsersApi(server);
|
|
initPublicRolesApi(server);
|
|
initIndicesApi(server);
|
|
initPrivilegesApi(server);
|
|
initLoginView(server, xpackMainPlugin);
|
|
initLogoutView(server);
|
|
initLoggedOutView(server);
|
|
initOverwrittenSessionView(server);
|
|
|
|
server.injectUiAppVars('login', () => {
|
|
|
|
const { showLogin, loginMessage, allowLogin, layout = 'form' } = xpackInfo.feature(plugin.id).getLicenseCheckResults() || {};
|
|
|
|
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);
|
|
});
|
|
}
|
|
});
|