mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Feature Controls - automatically grant access to short urls (#37532)
* automatically grant access to short urls * adds API integration tests * Update x-pack/test/api_integration/apis/short_urls/index.ts Co-Authored-By: Brandon Kobel <brandon.kobel@gmail.com>
This commit is contained in:
parent
227feeb243
commit
54af64d416
6 changed files with 150 additions and 14 deletions
|
@ -46,7 +46,7 @@ describe('FeatureRegistry', () => {
|
|||
app: ['app1'],
|
||||
savedObject: {
|
||||
all: ['space', 'etc', 'telemetry'],
|
||||
read: ['canvas', 'config'],
|
||||
read: ['canvas', 'config', 'url'],
|
||||
},
|
||||
api: ['someApiEndpointTag', 'anotherEndpointTag'],
|
||||
ui: ['allowsFoo', 'showBar', 'showBaz'],
|
||||
|
@ -62,7 +62,7 @@ describe('FeatureRegistry', () => {
|
|||
app: ['app1'],
|
||||
savedObject: {
|
||||
all: ['space', 'etc', 'telemetry'],
|
||||
read: ['canvas', 'config'],
|
||||
read: ['canvas', 'config', 'url'],
|
||||
},
|
||||
api: ['someApiEndpointTag', 'anotherEndpointTag'],
|
||||
ui: ['allowsFoo', 'showBar', 'showBaz'],
|
||||
|
@ -105,7 +105,7 @@ describe('FeatureRegistry', () => {
|
|||
expect(allPrivilege.savedObject.all).toEqual(['telemetry']);
|
||||
});
|
||||
|
||||
it(`automatically grants 'read' access to config saved objects for both privileges`, () => {
|
||||
it(`automatically grants 'read' access to config and url saved objects for both privileges`, () => {
|
||||
const feature: Feature = {
|
||||
id: 'test-feature',
|
||||
name: 'Test Feature',
|
||||
|
@ -134,11 +134,11 @@ describe('FeatureRegistry', () => {
|
|||
|
||||
const allPrivilege = result[0].privileges.all;
|
||||
const readPrivilege = result[0].privileges.read;
|
||||
expect(allPrivilege.savedObject.read).toEqual(['config']);
|
||||
expect(readPrivilege.savedObject.read).toEqual(['config']);
|
||||
expect(allPrivilege.savedObject.read).toEqual(['config', 'url']);
|
||||
expect(readPrivilege.savedObject.read).toEqual(['config', 'url']);
|
||||
});
|
||||
|
||||
it(`automatically grants 'all' access to telemetry and 'read' to config saved objects for the reserved privilege`, () => {
|
||||
it(`automatically grants 'all' access to telemetry and 'read' to [config, url] saved objects for the reserved privilege`, () => {
|
||||
const feature: Feature = {
|
||||
id: 'test-feature',
|
||||
name: 'Test Feature',
|
||||
|
@ -162,7 +162,7 @@ describe('FeatureRegistry', () => {
|
|||
|
||||
const reservedPrivilege = result[0]!.reserved!.privilege;
|
||||
expect(reservedPrivilege.savedObject.all).toEqual(['telemetry']);
|
||||
expect(reservedPrivilege.savedObject.read).toEqual(['config']);
|
||||
expect(reservedPrivilege.savedObject.read).toEqual(['config', 'url']);
|
||||
});
|
||||
|
||||
it(`does not duplicate the automatic grants if specified on the incoming feature`, () => {
|
||||
|
@ -175,14 +175,14 @@ describe('FeatureRegistry', () => {
|
|||
ui: [],
|
||||
savedObject: {
|
||||
all: ['telemetry'],
|
||||
read: ['config'],
|
||||
read: ['config', 'url'],
|
||||
},
|
||||
},
|
||||
read: {
|
||||
ui: [],
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: ['config'],
|
||||
read: ['config', 'url'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -195,8 +195,8 @@ describe('FeatureRegistry', () => {
|
|||
const allPrivilege = result[0].privileges.all;
|
||||
const readPrivilege = result[0].privileges.read;
|
||||
expect(allPrivilege.savedObject.all).toEqual(['telemetry']);
|
||||
expect(allPrivilege.savedObject.read).toEqual(['config']);
|
||||
expect(readPrivilege.savedObject.read).toEqual(['config']);
|
||||
expect(allPrivilege.savedObject.read).toEqual(['config', 'url']);
|
||||
expect(readPrivilege.savedObject.read).toEqual(['config', 'url']);
|
||||
});
|
||||
|
||||
it(`does not allow duplicate features to be registered`, () => {
|
||||
|
|
|
@ -371,7 +371,7 @@ function applyAutomaticAllPrivilegeGrants(...allPrivileges: Array<FeatureKibanaP
|
|||
allPrivileges.forEach(allPrivilege => {
|
||||
if (allPrivilege) {
|
||||
allPrivilege.savedObject.all = uniq([...allPrivilege.savedObject.all, 'telemetry']);
|
||||
allPrivilege.savedObject.read = uniq([...allPrivilege.savedObject.read, 'config']);
|
||||
allPrivilege.savedObject.read = uniq([...allPrivilege.savedObject.read, 'config', 'url']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ function applyAutomaticReadPrivilegeGrants(
|
|||
) {
|
||||
readPrivileges.forEach(readPrivilege => {
|
||||
if (readPrivilege) {
|
||||
readPrivilege.savedObject.read = uniq([...readPrivilege.savedObject.read, 'config']);
|
||||
readPrivilege.savedObject.read = uniq([...readPrivilege.savedObject.read, 'config', 'url']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ const buildKibanaFeatures = (savedObjectTypes: string[]) => {
|
|||
read: {
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: ['index-pattern', 'search', 'url'],
|
||||
read: ['index-pattern', 'search'],
|
||||
},
|
||||
ui: ['show'],
|
||||
},
|
||||
|
|
|
@ -23,5 +23,6 @@ export default function ({ loadTestFile }) {
|
|||
loadTestFile(require.resolve('./apm'));
|
||||
loadTestFile(require.resolve('./siem'));
|
||||
loadTestFile(require.resolve('./code'));
|
||||
loadTestFile(require.resolve('./short_urls'));
|
||||
});
|
||||
}
|
||||
|
|
119
x-pack/test/api_integration/apis/short_urls/feature_controls.ts
Normal file
119
x-pack/test/api_integration/apis/short_urls/feature_controls.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { SecurityService } from '../../../common/services';
|
||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function featureControlsTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
||||
const supertest = getService('supertestWithoutAuth');
|
||||
const security: SecurityService = getService('security');
|
||||
|
||||
describe('feature controls', () => {
|
||||
const kibanaUsername = 'kibana_user';
|
||||
const kibanaUserRoleName = 'kibana_user';
|
||||
|
||||
const kibanaUserPassword = `${kibanaUsername}-password`;
|
||||
|
||||
let urlId: string;
|
||||
|
||||
// a sampling of features to test against
|
||||
const features = [
|
||||
{
|
||||
featureId: 'discover',
|
||||
canAccess: true,
|
||||
},
|
||||
{
|
||||
featureId: 'dashboard',
|
||||
canAccess: true,
|
||||
},
|
||||
{
|
||||
featureId: 'visualize',
|
||||
canAccess: true,
|
||||
},
|
||||
{
|
||||
featureId: 'infrastructure',
|
||||
canAccess: true,
|
||||
},
|
||||
{
|
||||
featureId: 'canvas',
|
||||
canAccess: true,
|
||||
},
|
||||
{
|
||||
featureId: 'maps',
|
||||
canAccess: true,
|
||||
},
|
||||
{
|
||||
featureId: 'unknown-feature',
|
||||
canAccess: false,
|
||||
},
|
||||
];
|
||||
|
||||
before(async () => {
|
||||
for (const feature of features) {
|
||||
await security.role.create(`${feature.featureId}-role`, {
|
||||
kibana: [
|
||||
{
|
||||
base: [],
|
||||
feature: {
|
||||
[feature.featureId]: ['read'],
|
||||
},
|
||||
spaces: ['*'],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await security.user.create(`${feature.featureId}-user`, {
|
||||
password: kibanaUserPassword,
|
||||
roles: [`${feature.featureId}-role`],
|
||||
full_name: 'a kibana user',
|
||||
});
|
||||
}
|
||||
|
||||
await security.user.create(kibanaUsername, {
|
||||
password: kibanaUserPassword,
|
||||
roles: [kibanaUserRoleName],
|
||||
full_name: 'a kibana user',
|
||||
});
|
||||
|
||||
await supertest
|
||||
.post(`/api/shorten_url`)
|
||||
.auth(kibanaUsername, kibanaUserPassword)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({ url: '/app/kibana#foo/bar/baz' })
|
||||
.then((resp: Record<string, any>) => {
|
||||
urlId = resp.body.urlId;
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
const users = features.map(feature => security.user.delete(`${feature.featureId}-user`));
|
||||
const roles = features.map(feature => security.role.delete(`${feature.featureId}-role`));
|
||||
await Promise.all([...users, ...roles]);
|
||||
await security.user.delete(kibanaUsername);
|
||||
});
|
||||
|
||||
features.forEach(feature => {
|
||||
it(`users with "read" access to ${feature.featureId} ${
|
||||
feature.canAccess ? 'should' : 'should not'
|
||||
} be able to access short-urls`, async () => {
|
||||
await supertest
|
||||
.get(`/goto/${urlId}`)
|
||||
.auth(`${feature.featureId}-user`, kibanaUserPassword)
|
||||
.then((resp: Record<string, any>) => {
|
||||
if (feature.canAccess) {
|
||||
expect(resp.status).to.eql(302);
|
||||
expect(resp.headers.location).to.eql('/app/kibana#foo/bar/baz');
|
||||
} else {
|
||||
expect(resp.status).to.eql(500);
|
||||
expect(resp.headers.location).to.eql(undefined);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
16
x-pack/test/api_integration/apis/short_urls/index.ts
Normal file
16
x-pack/test/api_integration/apis/short_urls/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* 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 { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function shortUrlsApiIntegrationTests({
|
||||
loadTestFile,
|
||||
}: KibanaFunctionalTestDefaultProviders) {
|
||||
describe('Short URLs', () => {
|
||||
loadTestFile(require.resolve('./feature_controls'));
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue