"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.calculateRouteAuthz = void 0; exports.checkSecurityEnabled = checkSecurityEnabled; exports.checkSuperuser = checkSuperuser; exports.doesNotHaveRequiredFleetAuthz = void 0; exports.getAuthzFromRequest = getAuthzFromRequest; var _lodash = require("lodash"); var _plugin = require("../../../common/constants/plugin"); var _common = require("../../../common"); var _authz = require("../../../common/authz"); var _2 = require(".."); var _constants = require("../../constants"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ function checkSecurityEnabled() { return _2.appContextService.getSecurityLicense().isEnabled(); } function checkSuperuser(req) { if (!checkSecurityEnabled()) { return false; } const security = _2.appContextService.getSecurity(); const user = security.authc.getCurrentUser(req); if (!user) { return false; } const userRoles = user.roles || []; if (!userRoles.includes('superuser')) { return false; } return true; } function getAuthorizationFromPrivileges(kibanaPrivileges, searchPrivilege) { const privilege = kibanaPrivileges.find(p => p.privilege.includes(searchPrivilege)); return privilege ? privilege.authorized : false; } async function getAuthzFromRequest(req) { const security = _2.appContextService.getSecurity(); if (security.authz.mode.useRbacForRequest(req)) { const checkPrivileges = security.authz.checkPrivilegesDynamicallyWithRequest(req); const endpointPrivileges = Object.entries(_constants.ENDPOINT_PRIVILEGES).map(([_, { appId, privilegeType, privilegeName }]) => { if (privilegeType === 'ui') { return security.authz.actions[privilegeType].get(`${appId}`, `${privilegeName}`); } return security.authz.actions[privilegeType].get(`${appId}-${privilegeName}`); }); const { privileges } = await checkPrivileges({ kibana: [security.authz.actions.api.get(`${_constants.PLUGIN_ID}-all`), security.authz.actions.api.get(`${_constants.PLUGIN_ID}-setup`), security.authz.actions.api.get(`${_common.INTEGRATIONS_PLUGIN_ID}-all`), security.authz.actions.api.get(`${_common.INTEGRATIONS_PLUGIN_ID}-read`), security.authz.actions.api.get(`${_plugin.TRANSFORM_PLUGIN_ID}-all`), security.authz.actions.api.get(`${_plugin.TRANSFORM_PLUGIN_ID}-admin`), security.authz.actions.api.get(`${_plugin.TRANSFORM_PLUGIN_ID}-read`), ...endpointPrivileges] }); const fleetAllAuth = getAuthorizationFromPrivileges(privileges.kibana, `${_constants.PLUGIN_ID}-all`); const intAllAuth = getAuthorizationFromPrivileges(privileges.kibana, `${_common.INTEGRATIONS_PLUGIN_ID}-all`); const intReadAuth = getAuthorizationFromPrivileges(privileges.kibana, `${_common.INTEGRATIONS_PLUGIN_ID}-read`); const fleetSetupAuth = getAuthorizationFromPrivileges(privileges.kibana, 'fleet-setup'); const authz = { ...(0, _authz.calculateAuthz)({ fleet: { all: fleetAllAuth, setup: fleetSetupAuth }, integrations: { all: intAllAuth, read: intReadAuth }, isSuperuser: checkSuperuser(req) }), packagePrivileges: (0, _authz.calculatePackagePrivilegesFromKibanaPrivileges)(privileges.kibana) }; return authz; } return (0, _authz.calculateAuthz)({ fleet: { all: false, setup: false }, integrations: { all: false, read: false }, isSuperuser: false }); } /** * Calculates Authz information for a Route, including: * 1. Is access granted * 2. was access granted based on Fleet and/or Integration privileges, and * 3. a list of package names for which access was granted (only set if access was granted by package privileges) * * @param fleetAuthz * @param requiredAuthz */ const calculateRouteAuthz = (fleetAuthz, requiredAuthz) => { const response = { granted: false, grantedByFleetPrivileges: false, scopeDataToPackages: undefined }; const fleetAuthzFlatten = flatten(fleetAuthz); const isPrivilegeGranted = flattenPrivilegeKey => fleetAuthzFlatten[flattenPrivilegeKey] === true; if (typeof requiredAuthz === 'undefined') { return response; } if (requiredAuthz.all) { response.granted = Object.keys(flatten(requiredAuthz.all)).every(isPrivilegeGranted); if (response.granted) { if (requiredAuthz.all.fleet || requiredAuthz.all.integrations) { response.grantedByFleetPrivileges = true; } return response; } } if (requiredAuthz.any) { response.granted = Object.keys(flatten(requiredAuthz.any)).some(isPrivilegeGranted); if (response.granted) { // Figure out if authz was granted via Fleet privileges if (requiredAuthz.any.fleet || requiredAuthz.any.integrations) { const fleetAnyPrivileges = (0, _lodash.pick)(requiredAuthz.any, ['fleet', 'integrations']); response.grantedByFleetPrivileges = Object.keys(flatten(fleetAnyPrivileges)).some(isPrivilegeGranted); } // If access was NOT granted via Fleet Authz, then retrieve a list of Package names that were // granted access to their respective data. if (!response.grantedByFleetPrivileges && requiredAuthz.any.packagePrivileges) { for (const [packageName, packageRequiredAuthz] of Object.entries(requiredAuthz.any.packagePrivileges)) { const packageRequiredAuthzKeys = Object.keys(flatten({ packagePrivileges: { [packageName]: packageRequiredAuthz } })); if (packageRequiredAuthzKeys.some(isPrivilegeGranted)) { if (!response.scopeDataToPackages) { response.scopeDataToPackages = []; } response.scopeDataToPackages.push(packageName); } } } return response; } } return response; }; /** * Utility to flatten an object's key all the way down to the last value. * @param source */ exports.calculateRouteAuthz = calculateRouteAuthz; function flatten(source) { const response = {}; const processKeys = (prefix, value) => { if (typeof value === 'object' && value !== null) { const objectKeys = Object.keys(value); for (const key of objectKeys) { processKeys(`${prefix}${prefix ? '.' : ''}${key}`, value[key]); } } else if (Array.isArray(value)) { value.forEach((subValue, key) => { processKeys(`${prefix}${prefix ? '.' : ''}${key}`, subValue); }); } else { response[prefix] = value; } }; processKeys('', source); return response; } /** * Utility to determine if a user has the required Fleet Authz based on user privileges * and route required authz structure. * @param authz * @param fleetRequiredAuthz * @returns boolean */ const doesNotHaveRequiredFleetAuthz = (authz, fleetRequiredAuthz) => { return !!fleetRequiredAuthz && (typeof fleetRequiredAuthz === 'function' && !fleetRequiredAuthz(authz) || typeof fleetRequiredAuthz !== 'function' && !calculateRouteAuthz(authz, { all: fleetRequiredAuthz }).granted); }; exports.doesNotHaveRequiredFleetAuthz = doesNotHaveRequiredFleetAuthz;