mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* [Code]: exclude from getting write privilege when choosing all * adjust api integration test * minor change of the role name
376 lines
11 KiB
TypeScript
376 lines
11 KiB
TypeScript
/*
|
|
* 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, SpacesService } from '../../../common/services';
|
|
import { FtrProviderContext } from '../../ftr_provider_context';
|
|
|
|
export default function featureControlsTests({ getService }: FtrProviderContext) {
|
|
const supertest = getService('supertestWithoutAuth');
|
|
const security: SecurityService = getService('security');
|
|
const spaces: SpacesService = getService('spaces');
|
|
const log = getService('log');
|
|
|
|
const expect404 = (result: any) => {
|
|
expect(result.error).to.be(undefined);
|
|
expect(result.response).not.to.be(undefined);
|
|
expect(result.response).to.have.property('statusCode', 404);
|
|
};
|
|
|
|
const expect200 = (result: any) => {
|
|
expect(result.error).to.be(undefined);
|
|
expect(result.response).not.to.be(undefined);
|
|
expect(result.response).to.have.property('statusCode', 200);
|
|
};
|
|
|
|
const endpoints = [
|
|
{
|
|
// List all repositories.
|
|
url: `/api/code/repos`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
{
|
|
// Get one repository.
|
|
url: `/api/code/repo/github.com/elastic/code-examples_empty-file`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
{
|
|
// Get the status of one repository.
|
|
url: `/api/code/repo/status/github.com/elastic/code-examples_empty-file`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
{
|
|
// Get all language server installation status.
|
|
url: `/api/code/install`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
// Search and suggestion APIs.
|
|
{
|
|
url: `/api/code/search/repo?q=starter`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
{
|
|
url: `/api/code/suggestions/repo?q=starter`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
{
|
|
url: `/api/code/search/doc?q=starter`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
{
|
|
url: `/api/code/suggestions/doc?q=starter`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
{
|
|
url: `/api/code/search/symbol?q=starter`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
{
|
|
url: `/api/code/suggestions/symbol?q=starter`,
|
|
expectForbidden: expect404,
|
|
expectResponse: expect200,
|
|
},
|
|
];
|
|
|
|
async function executeRequest(
|
|
endpoint: string,
|
|
username: string,
|
|
password: string,
|
|
spaceId?: string
|
|
) {
|
|
const basePath = spaceId ? `/s/${spaceId}` : '';
|
|
|
|
return await supertest
|
|
.get(`${basePath}${endpoint}`)
|
|
.auth(username, password)
|
|
.set('kbn-xsrf', 'foo')
|
|
.then((response: any) => ({ error: undefined, response }))
|
|
.catch((error: any) => ({ error, response: undefined }));
|
|
}
|
|
|
|
async function executeRequests(
|
|
username: string,
|
|
password: string,
|
|
spaceId: string,
|
|
expectation: 'forbidden' | 'response'
|
|
) {
|
|
for (const endpoint of endpoints) {
|
|
log.debug(`hitting ${endpoint}`);
|
|
const result = await executeRequest(endpoint.url, username, password, spaceId);
|
|
if (expectation === 'forbidden') {
|
|
endpoint.expectForbidden(result);
|
|
} else {
|
|
endpoint.expectResponse(result);
|
|
}
|
|
}
|
|
}
|
|
|
|
describe('feature controls', () => {
|
|
const codeAdminUsername = 'code_admin_user';
|
|
const codeAdminRoleName = 'code_admin_role';
|
|
const codeAdminUserPassword = `${codeAdminUsername}-password`;
|
|
|
|
before(async () => {
|
|
await security.role.create(codeAdminRoleName, {
|
|
kibana: [
|
|
{
|
|
feature: {
|
|
// Grant all permission to Code app as an admin user.
|
|
code: ['all'],
|
|
},
|
|
spaces: ['*'],
|
|
},
|
|
],
|
|
});
|
|
|
|
// Import a repository first
|
|
await security.user.create(codeAdminUsername, {
|
|
password: codeAdminUserPassword,
|
|
roles: [codeAdminRoleName],
|
|
full_name: 'Code admin user',
|
|
});
|
|
|
|
await supertest
|
|
.post(`/api/code/repo`)
|
|
.auth(codeAdminUsername, codeAdminUserPassword)
|
|
.set('kbn-xsrf', 'foo')
|
|
.send({ url: 'https://github.com/elastic/code-examples_empty-file.git' })
|
|
.expect(200);
|
|
});
|
|
|
|
after(async () => {
|
|
// Delete the repository
|
|
await supertest
|
|
.delete(`/api/code/repo/github.com/elastic/code-examples_empty-file`)
|
|
.auth(codeAdminUsername, codeAdminUserPassword)
|
|
.set('kbn-xsrf', 'foo')
|
|
.expect(200);
|
|
|
|
await security.role.delete(codeAdminRoleName);
|
|
await security.user.delete(codeAdminUsername);
|
|
});
|
|
|
|
it(`Non admin Code user cannot execute delete without all permission`, async () => {
|
|
const username = 'logstash_read';
|
|
const roleName = 'logstash_read';
|
|
const password = `${username}-password`;
|
|
try {
|
|
await security.role.create(roleName, {
|
|
kibana: [
|
|
{
|
|
feature: {
|
|
// Grant read only permission to Code app as an non-admin user.
|
|
code: ['read'],
|
|
},
|
|
spaces: ['*'],
|
|
},
|
|
],
|
|
});
|
|
|
|
await security.user.create(username, {
|
|
password,
|
|
roles: [roleName],
|
|
full_name: 'a kibana user',
|
|
});
|
|
|
|
await supertest
|
|
.delete(`/api/code/repo/github.com/elastic/code-examples_empty-file`)
|
|
.auth(username, password)
|
|
.set('kbn-xsrf', 'foo')
|
|
.expect(404);
|
|
} finally {
|
|
await security.role.delete(roleName);
|
|
await security.user.delete(username);
|
|
}
|
|
});
|
|
|
|
it(`Admin Code user can execute clone/delete with all permission`, async () => {
|
|
const username = 'another_code_admin_user';
|
|
const roleName = 'another_code_admin_role';
|
|
const password = `${username}-password`;
|
|
try {
|
|
await security.role.create(roleName, {
|
|
kibana: [
|
|
{
|
|
feature: {
|
|
// Grant all permission to Code app as an admin user.
|
|
code: ['all'],
|
|
},
|
|
spaces: ['*'],
|
|
},
|
|
],
|
|
});
|
|
|
|
await security.user.create(username, {
|
|
password,
|
|
roles: [roleName],
|
|
full_name: 'Code admin user',
|
|
});
|
|
|
|
// Clone repository
|
|
await supertest
|
|
.post(`/api/code/repo`)
|
|
.auth(username, password)
|
|
.set('kbn-xsrf', 'foo')
|
|
.send({ url: 'https://github.com/elastic/code-examples_single-image.git' })
|
|
.expect(200);
|
|
|
|
// Delete repository
|
|
await supertest
|
|
.delete(`/api/code/repo/github.com/elastic/code-examples_single-image`)
|
|
.auth(username, password)
|
|
.set('kbn-xsrf', 'foo')
|
|
.expect(200);
|
|
} finally {
|
|
await security.role.delete(roleName);
|
|
await security.user.delete(username);
|
|
}
|
|
});
|
|
|
|
it(`APIs can't be accessed by .code-* read privileges role`, async () => {
|
|
const username = 'logstash_read';
|
|
const roleName = 'logstash_read';
|
|
const password = `${username}-password`;
|
|
try {
|
|
await security.role.create(roleName, {});
|
|
|
|
await security.user.create(username, {
|
|
password,
|
|
roles: [roleName],
|
|
full_name: 'a kibana user',
|
|
});
|
|
|
|
await executeRequests(username, password, '', 'forbidden');
|
|
} finally {
|
|
await security.role.delete(roleName);
|
|
await security.user.delete(username);
|
|
}
|
|
});
|
|
|
|
it(`APIs can be accessed global all with .code-* read privileges role`, async () => {
|
|
const username = 'global_all';
|
|
const roleName = 'global_all';
|
|
const password = `${username}-password`;
|
|
try {
|
|
await security.role.create(roleName, {
|
|
kibana: [
|
|
{
|
|
base: ['all'],
|
|
spaces: ['*'],
|
|
},
|
|
],
|
|
});
|
|
|
|
await security.user.create(username, {
|
|
password,
|
|
roles: [roleName],
|
|
full_name: 'a kibana user',
|
|
});
|
|
|
|
await executeRequests(username, password, '', 'response');
|
|
} finally {
|
|
await security.role.delete(roleName);
|
|
await security.user.delete(username);
|
|
}
|
|
});
|
|
|
|
it(`APIs can't be accessed by dashboard all with .code-* read privileges role`, async () => {
|
|
const username = 'dashboard_all';
|
|
const roleName = 'dashboard_all';
|
|
const password = `${username}-password`;
|
|
try {
|
|
await security.role.create(roleName, {
|
|
kibana: [
|
|
{
|
|
feature: {
|
|
dashboard: ['all'],
|
|
},
|
|
spaces: ['*'],
|
|
},
|
|
],
|
|
});
|
|
|
|
await security.user.create(username, {
|
|
password,
|
|
roles: [roleName],
|
|
full_name: 'a kibana user',
|
|
});
|
|
|
|
await executeRequests(username, password, '', 'forbidden');
|
|
} finally {
|
|
await security.role.delete(roleName);
|
|
await security.user.delete(username);
|
|
}
|
|
});
|
|
|
|
describe('spaces', () => {
|
|
// the following tests create a user_1 which has Code read access to space_1 and dashboard all access to space_2
|
|
const space1Id = 'space_1';
|
|
const space2Id = 'space_2';
|
|
|
|
const roleName = 'user_1';
|
|
const username = 'user_1';
|
|
const password = 'user_1-password';
|
|
|
|
before(async () => {
|
|
await spaces.create({
|
|
id: space1Id,
|
|
name: space1Id,
|
|
disabledFeatures: [],
|
|
});
|
|
await spaces.create({
|
|
id: space2Id,
|
|
name: space2Id,
|
|
disabledFeatures: [],
|
|
});
|
|
await security.role.create(roleName, {
|
|
kibana: [
|
|
{
|
|
feature: {
|
|
code: ['read'],
|
|
},
|
|
spaces: [space1Id],
|
|
},
|
|
{
|
|
feature: {
|
|
dashboard: ['all'],
|
|
},
|
|
spaces: [space2Id],
|
|
},
|
|
],
|
|
});
|
|
await security.user.create(username, {
|
|
password,
|
|
roles: [roleName],
|
|
});
|
|
});
|
|
|
|
after(async () => {
|
|
await spaces.delete(space1Id);
|
|
await spaces.delete(space2Id);
|
|
await security.role.delete(roleName);
|
|
await security.user.delete(username);
|
|
});
|
|
|
|
it('user_1 can access APIs in space_1', async () => {
|
|
await executeRequests(username, password, space1Id, 'response');
|
|
});
|
|
|
|
it(`user_1 cannot access APIs in space_2`, async () => {
|
|
await executeRequests(username, password, space2Id, 'forbidden');
|
|
});
|
|
});
|
|
});
|
|
}
|