mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
210 lines
7.9 KiB
JavaScript
210 lines
7.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 { has } from 'lodash';
|
|
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 { initIndicesApi } from './server/routes/api/v1/indices';
|
|
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, registerPrivilegesWithCluster } 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';
|
|
|
|
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),
|
|
sameSiteCookies: Joi.string().valid(['Strict', 'Lax', 'None']).optional(),
|
|
loginAssistanceMessage: Joi.string(),
|
|
public: Joi.object({
|
|
protocol: Joi.string().valid(['http', 'https']),
|
|
hostname: Joi.string().hostname(),
|
|
port: Joi.number().integer().min(0).max(65535)
|
|
}).default(),
|
|
authc: Joi.object({})
|
|
.when('authProviders', {
|
|
is: Joi.array().items(Joi.string().valid('saml').required(), Joi.string()),
|
|
then: Joi.object({ saml: Joi.object({ useRelayStateDeepLink: Joi.boolean().default(false) }) }).default(),
|
|
otherwise: Joi.any().forbidden(),
|
|
}),
|
|
authorization: Joi.object({
|
|
legacyFallback: Joi.object({
|
|
enabled: Joi.boolean().default(true)
|
|
}).default()
|
|
}).default(),
|
|
audit: Joi.object({
|
|
enabled: Joi.boolean().default(false)
|
|
}).default(),
|
|
}).default();
|
|
},
|
|
|
|
deprecations() {
|
|
return [
|
|
(settings, log) => {
|
|
if (has(settings, 'authc.saml.useRelayStateDeepLink')) {
|
|
log('Config key "authc.saml.useRelayStateDeepLink" is deprecated and will be removed in the next major version.');
|
|
}
|
|
}
|
|
];
|
|
},
|
|
|
|
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: '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 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');
|
|
|
|
// exposes server.plugins.security.authorization
|
|
const authorization = createAuthorizationService(server, xpackInfoFeature);
|
|
server.expose('authorization', deepFreeze(authorization));
|
|
|
|
watchStatusAndLicenseToInitialize(xpackMainPlugin, plugin, async (license) => {
|
|
if (license.allowRbac) {
|
|
await registerPrivilegesWithCluster(server);
|
|
}
|
|
});
|
|
|
|
const auditLogger = new SecurityAuditLogger(new AuditLogger(server, 'security', server.config(), xpackInfo));
|
|
|
|
const { savedObjects } = server;
|
|
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_VALUE, ({ client, request }) => {
|
|
if (authorization.mode.useRbacForRequest(request)) {
|
|
const { spaces } = server.plugins;
|
|
|
|
return new SecureSavedObjectsClientWrapper({
|
|
actions: authorization.actions,
|
|
auditLogger,
|
|
baseClient: client,
|
|
checkPrivilegesWithRequest: authorization.checkPrivilegesWithRequest,
|
|
errors: savedObjects.SavedObjectsClient.errors,
|
|
request,
|
|
savedObjectTypes: savedObjects.types,
|
|
spaces,
|
|
});
|
|
}
|
|
|
|
return client;
|
|
});
|
|
|
|
getUserProvider(server);
|
|
|
|
await initAuthenticator(server, authorization.mode);
|
|
initAuthenticateApi(server);
|
|
initUsersApi(server);
|
|
initPublicRolesApi(server);
|
|
initIndicesApi(server);
|
|
initLoginView(server, xpackMainPlugin);
|
|
initLogoutView(server);
|
|
initLoggedOutView(server);
|
|
|
|
server.injectUiAppVars('login', () => {
|
|
|
|
const { showLogin, loginMessage, allowLogin, layout = 'form' } = xpackInfo.feature(plugin.id).getLicenseCheckResults() || {};
|
|
|
|
return {
|
|
loginAssistanceMessage: config.get('xpack.security.loginAssistanceMessage') || '',
|
|
loginState: {
|
|
showLogin,
|
|
allowLogin,
|
|
loginMessage,
|
|
layout,
|
|
}
|
|
};
|
|
});
|
|
}
|
|
});
|