Skip to content

Commit

Permalink
Restructure user profile for granular app privs (elastic#23750)
Browse files Browse the repository at this point in the history
merging to feature branch for further development
  • Loading branch information
legrego committed Nov 26, 2018
1 parent 60a2e70 commit 2e7bbd1
Show file tree
Hide file tree
Showing 23 changed files with 399 additions and 5 deletions.
32 changes: 32 additions & 0 deletions src/core_plugins/kibana/public/discover/discover_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { uiModules } from 'ui/modules';

uiModules.get('kibana')
.provider('discoverConfig', () => {
return {
$get() {
return {
getHideWriteControls() {
return false;
}
};
}
};
});
1 change: 1 addition & 0 deletions src/core_plugins/kibana/public/discover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/

import './discover_config';
import './saved_searches/saved_searches';
import './directives';
import 'ui/collapsible_sidebar';
Expand Down
34 changes: 34 additions & 0 deletions src/ui/public/chrome/api/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { uiModules } from '../../modules';

export function initConfig() {
uiModules.get('kibana')
.provider('chromeConfig', () => {
return {
$get() {
return {
shouldHideNavLink() {
return false;
}
};
}
};
});
}
2 changes: 2 additions & 0 deletions src/ui/public/chrome/chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { initChromeNavApi } from './api/nav';
import { initBreadcrumbsApi } from './api/breadcrumbs';
import templateApi from './api/template';
import { initChromeThemeApi } from './api/theme';
import { initConfig } from './api/config';
import { initChromeXsrfApi } from './api/xsrf';
import { initUiSettingsApi } from './api/ui_settings';
import { initLoadingCountApi } from './api/loading_count';
Expand All @@ -61,6 +62,7 @@ const internals = _.defaults(
}
);

initConfig();
initUiSettingsApi(chrome);
initSavedObjectClient(chrome);
appsApi(chrome, internals);
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/security/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { createAuthorizationService, registerPrivilegesWithCluster } from './ser
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 { capabilityDecorator } from './server/lib/capability_decorator';
import { registerUserProfileCapabilityDecorator } from '../xpack_main/server/lib/user_profile';

export const security = (kibana) => new kibana.Plugin({
id: 'security',
Expand Down Expand Up @@ -127,6 +129,8 @@ export const security = (kibana) => new kibana.Plugin({
}
});

registerUserProfileCapabilityDecorator(Number.MIN_SAFE_INTEGER, capabilityDecorator);

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

savedObjects.setScopedSavedObjectsClientFactory(({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { KibanaPrivilege } from '../../../../../../../../security/common/model/kibana_privilege';
import { UserProfile } from '../../../../../../../../xpack_main/common/user_profile';
import { RoleValidator } from '../../../lib/validate_role';
import { KibanaPrivileges } from './kibana_privileges';
import { SimplePrivilegeForm } from './simple_privilege_form';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ routes.when(`${EDIT_ROLES_PATH}/:name?`, {
}
},
controllerAs: 'editRole',
controller($injector, $scope, $http, enableSpaceAwarePrivileges) {
controller($injector, $scope, $http, enableSpaceAwarePrivileges, userProfile) {
const $route = $injector.get('$route');
const Private = $injector.get('Private');

Expand Down
10 changes: 7 additions & 3 deletions x-pack/plugins/spaces/public/views/management/page_routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
// @ts-ignore
import routes from 'ui/routes';
import { UserProfile } from '../../../../xpack_main/common/user_profile';
import { SpacesManager } from '../../lib/spaces_manager';
import { ManageSpacePage } from './edit_space';
import { SpacesGridPage } from './spaces_grid';
Expand All @@ -27,7 +28,8 @@ routes.when('/management/spaces/list', {
$http: any,
chrome: any,
spacesNavState: SpacesNavState,
spaceSelectorURL: string
spaceSelectorURL: string,
userProfile: UserProfile
) {
$scope.$$postDigest(() => {
const domNode = document.getElementById(reactRootNodeId);
Expand Down Expand Up @@ -58,7 +60,8 @@ routes.when('/management/spaces/create', {
$http: any,
chrome: any,
spacesNavState: SpacesNavState,
spaceSelectorURL: string
spaceSelectorURL: string,
userProfile: UserProfile
) {
$scope.$$postDigest(() => {
const domNode = document.getElementById(reactRootNodeId);
Expand Down Expand Up @@ -95,7 +98,8 @@ routes.when('/management/spaces/edit/:spaceId', {
chrome: any,
Private: any,
spacesNavState: SpacesNavState,
spaceSelectorURL: string
spaceSelectorURL: string,
userProfile: UserProfile
) {
$scope.$$postDigest(() => {
const domNode = document.getElementById(reactRootNodeId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { uiModules } from 'ui/modules';
import { chromeHeaderNavControlsRegistry } from 'ui/registry/chrome_header_nav_controls';
// @ts-ignore
import { chromeNavControlsRegistry } from 'ui/registry/chrome_nav_controls';
import { UserProfile } from '../../../../xpack_main/common/user_profile';
import { Space } from '../../../common/model/space';
import { SpacesGlobalNavButton } from './components/spaces_global_nav_button';
import { SpacesHeaderNavButton } from './components/spaces_header_nav_button';
Expand Down Expand Up @@ -93,7 +94,7 @@ module.service('spacesNavState', (activeSpace: any) => {
});

chromeHeaderNavControlsRegistry.register(
($http: any, chrome: any, Private: any, activeSpace: any) => ({
($http: any, chrome: any, Private: any, activeSpace: any, userProfile: UserProfile) => ({
name: 'spaces',
order: 1000,
side: NavControlSide.Left,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { mount, shallow } from 'enzyme';
import React from 'react';
import { UserProfile } from '../../../../xpack_main/common/user_profile';
import { SpaceAvatar } from '../../components';
import { SpacesManager } from '../../lib/spaces_manager';
import { SpacesGlobalNavButton } from './components/spaces_global_nav_button';
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/xpack_main/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* 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.
*/

export { Capabilities, UserProfile } from './user_profile';
9 changes: 9 additions & 0 deletions x-pack/plugins/xpack_main/common/user_profile/capabilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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.
*/

export interface Capabilities {
[capability: string]: boolean;
}
7 changes: 7 additions & 0 deletions x-pack/plugins/xpack_main/common/user_profile/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* 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.
*/
export { Capabilities } from './capabilities';
export { UserProfile } from './user_profile';
38 changes: 38 additions & 0 deletions x-pack/plugins/xpack_main/common/user_profile/user_profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 { Capabilities } from './capabilities';

export class UserProfile {
private capabilities: Capabilities;
constructor(profileData: Capabilities = {}) {
this.capabilities = {
...profileData,
};
}

public hasCapability(capability: string, defaultValue: boolean = true): boolean {
return capability in this.capabilities ? this.capabilities[capability] : defaultValue;
}

public canAccessFeature(feature: string, defaultValue: boolean = true): boolean {
return this.hasCapability(`ui:${feature}/read`, defaultValue);
}

public canReadSavedObject(savedObjectType: string, defaultValue: boolean = true): boolean {
return this.hasCapability(`saved_objects/${savedObjectType}/get`, defaultValue);
}

public canWriteSavedObject(savedObjectType: string, defaultValue: boolean = true): boolean {
return this.hasCapability(`saved_objects/${savedObjectType}/create`, defaultValue);
}

public toJSON() {
return {
...this.capabilities,
};
}
}
5 changes: 5 additions & 0 deletions x-pack/plugins/xpack_main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
CONFIG_TELEMETRY_DESC,
} from './common/constants';
import { settingsRoute } from './server/routes/api/v1/settings';
import { userProfileMixin } from './server/lib/user_profile';
import mappings from './mappings.json';

export { callClusterFactory } from './server/lib/call_cluster_factory';
Expand Down Expand Up @@ -102,6 +103,8 @@ export const xpackMain = (kibana) => {
'plugins/xpack_main/hacks/check_xpack_info_change',
'plugins/xpack_main/hacks/telemetry_opt_in',
'plugins/xpack_main/hacks/telemetry_trigger',
'plugins/xpack_main/hacks/user_profile',
'plugins/xpack_main/hacks/user_profile_config_decorators',
],
replaceInjectedVars,
__webpackPluginProvider__(webpack) {
Expand All @@ -122,6 +125,8 @@ export const xpackMain = (kibana) => {
setupXPackMain(server);
registerOssFeatures();

userProfileMixin(this.kbnServer, server);

// register routes
xpackInfoRoute(server);
telemetryRoute(server);
Expand Down
17 changes: 17 additions & 0 deletions x-pack/plugins/xpack_main/public/hacks/user_profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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 chrome from 'ui/chrome';
// @ts-ignore
import { uiModules } from 'ui/modules';
import { UserProfile } from '../../common';

uiModules.get('userProfile').provider('userProfile', function userProfileProvider() {
// @ts-ignore
this.$get = () => {
return new UserProfile(chrome.getInjected('userProfileData'));
};
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 { uiModules } from 'ui/modules';

uiModules.get('kibana')
.config(($provide, $injector) => {
if ($injector.has('dashboardConfig')) {
$provide.decorator('dashboardConfig', function ($delegate, userProfile) {
return {
getHideWriteControls() {
if (!userProfile.canWriteSavedObject('dashboard')) {
return true;
}

return $delegate.getHideWriteControls();
}
};
});
}

if ($injector.has('discoverConfig')) {
$provide.decorator('discoverConfig', function ($delegate, userProfile) {
return {
getHideWriteControls() {
if (!userProfile.canWriteSavedObject('search')) {
return true;
}

return $delegate.getHideWriteControls();
}
};
});
}

if ($injector.has('chromeConfig')) {
$provide.decorator('chromeConfig', function ($delegate, userProfile) {
return {
shouldHideNavLink(navLink) {
if (!userProfile.canAccessFeature(navLink.id)) {
return true;
}

return $delegate.shouldHideNavLink(navLink);
}
};
});
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const buildRequest = (telemetryOptedIn = null, path = '/app/kibana') => {

return {
path,
getUserProfile: async () => ({
toJSON: () => ({})
}),
getSavedObjectsClient: () => {
return {
get,
Expand Down
Loading

0 comments on commit 2e7bbd1

Please sign in to comment.