[APM] Add API test for agent configuration (#46316) (#46336)

This commit is contained in:
Søren Louv-Jansen 2019-09-23 16:18:18 +02:00 committed by GitHub
parent 330b9d17f9
commit 377fae55f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -9,7 +9,8 @@ import { SecurityService, SpacesService } from '../../../common/services';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function featureControlsTests({ getService }: FtrProviderContext) {
const supertest = getService('supertestWithoutAuth');
const supertest = getService('supertest');
const supertestWithoutAuth = getService('supertestWithoutAuth');
const security: SecurityService = getService('security');
const spaces: SpacesService = getService('spaces');
const log = getService('log');
@ -19,142 +20,240 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
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);
expect(result.response.statusCode).to.be(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);
expect(result.response.statusCode).to.be(200);
};
const endpoints = [
interface Endpoint {
req: {
url: string;
method?: 'get' | 'post' | 'delete';
body?: any;
};
expectForbidden: (result: any) => void;
expectResponse: (result: any) => void;
}
const endpoints: Endpoint[] = [
{
url: `/api/apm/services/foo/errors?start=${start}&end=${end}&uiFilters=%7B%7D&_debug=true`,
req: { url: `/api/apm/services/foo/errors?start=${start}&end=${end}&uiFilters=%7B%7D` },
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/errors/bar?start=${start}&end=${end}&uiFilters=%7B%7D`,
req: { url: `/api/apm/services/foo/errors/bar?start=${start}&end=${end}&uiFilters=%7B%7D` },
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/errors/distribution?start=${start}&end=${end}&groupId=bar&uiFilters=%7B%7D`,
req: {
url: `/api/apm/services/foo/errors/distribution?start=${start}&end=${end}&groupId=bar&uiFilters=%7B%7D`,
},
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/errors/distribution?start=${start}&end=${end}&uiFilters=%7B%7D`,
req: {
url: `/api/apm/services/foo/errors/distribution?start=${start}&end=${end}&uiFilters=%7B%7D`,
},
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/metrics/charts?start=${start}&end=${end}&agentName=cool-agent&uiFilters=%7B%7D`,
req: {
url: `/api/apm/services/foo/metrics/charts?start=${start}&end=${end}&agentName=cool-agent&uiFilters=%7B%7D`,
},
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services?start=${start}&end=${end}&uiFilters=%7B%7D`,
req: { url: `/api/apm/services?start=${start}&end=${end}&uiFilters=%7B%7D` },
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/agent_name?start=${start}&end=${end}`,
req: { url: `/api/apm/services/foo/agent_name?start=${start}&end=${end}` },
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/transaction_types?start=${start}&end=${end}`,
req: { url: `/api/apm/services/foo/transaction_types?start=${start}&end=${end}` },
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/traces?start=${start}&end=${end}&uiFilters=%7B%7D`,
req: { url: `/api/apm/traces?start=${start}&end=${end}&uiFilters=%7B%7D` },
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/traces/foo?start=${start}&end=${end}`,
req: { url: `/api/apm/traces/foo?start=${start}&end=${end}` },
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/transaction_groups?start=${start}&end=${end}&transactionType=bar&uiFilters=%7B%7D`,
req: {
url: `/api/apm/services/foo/transaction_groups?start=${start}&end=${end}&transactionType=bar&uiFilters=%7B%7D`,
},
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&transactionType=bar&uiFilters=%7B%7D`,
req: {
url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&transactionType=bar&uiFilters=%7B%7D`,
},
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&uiFilters=%7B%7D`,
req: {
url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&uiFilters=%7B%7D`,
},
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%7D`,
req: {
url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%7D`,
},
expectForbidden: expect404,
expectResponse: expect200,
},
{
url: `/api/apm/services/foo/transaction_groups/distribution?start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%7D`,
req: {
url: `/api/apm/services/foo/transaction_groups/distribution?start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%7D`,
},
expectForbidden: expect404,
expectResponse: expect200,
},
{
req: {
method: 'post',
url: `/api/apm/settings/agent-configuration/search`,
body: { service: { name: 'test-service' } },
},
expectForbidden: expect404,
expectResponse: expect200,
},
];
async function executeRequest(
endpoint: string,
const elasticsearchRole = {
indices: [
{ names: ['apm-*'], privileges: ['read', 'view_index_metadata'] },
{ names: ['.apm-agent-configuration'], privileges: ['read', 'write', 'view_index_metadata'] },
],
};
async function executeAsUser(
{ method = 'get', url, body }: Endpoint['req'],
username: string,
password: string,
spaceId?: string
) {
const basePath = spaceId ? `/s/${spaceId}` : '';
return await supertest
.get(`${basePath}${endpoint}`)
let request = supertestWithoutAuth[method](`${basePath}${url}`);
// json body
if (body) {
request = request.send(body);
}
return await request
.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'
) {
async function executeAsAdmin({ method = 'get', url, body }: Endpoint['req'], spaceId?: string) {
const basePath = spaceId ? `/s/${spaceId}` : '';
let request = supertest[method](`${basePath}${url}`);
// json body
if (body) {
request = request.send(body);
}
const response = await request.set('kbn-xsrf', 'foo');
const { statusCode, req } = response;
if (statusCode !== 200) {
log.debug(`Endpoint: ${req.method} ${req.path}
Status code: ${statusCode}
Response: ${response.body.message}`);
}
return response;
}
async function executeRequests({
username,
password,
expectation,
spaceId,
}: {
username: string;
password: string;
expectation: 'forbidden' | 'response';
spaceId?: string;
}) {
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);
log.debug(`hitting ${endpoint.req.url}`);
const result = await executeAsUser(endpoint.req, username, password, spaceId);
try {
if (expectation === 'forbidden') {
endpoint.expectForbidden(result);
} else {
endpoint.expectResponse(result);
}
} catch (e) {
const { statusCode, body, req } = result.response;
throw new Error(
`Endpoint: ${req.method} ${req.path}
Status code: ${statusCode}
Response: ${body.message}
${e.message}`
);
}
}
}
describe('feature controls', () => {
it(`APIs can't be accessed by apm-* read privileges role`, async () => {
describe('apm feature controls', () => {
let res: any;
before(async () => {
log.debug('creating agent configuration');
res = await executeAsAdmin({
method: 'post',
url: '/api/apm/settings/agent-configuration/new',
body: {
service: { name: 'test-service' },
settings: { transaction_sample_rate: 0.5 },
},
});
});
after(async () => {
log.debug('deleting agent configuration');
const configurationId = res.body._id;
await executeAsAdmin({
method: 'delete',
url: `/api/apm/settings/agent-configuration/${configurationId}`,
});
});
it(`APIs can't be accessed by logstash_read user`, async () => {
const username = 'logstash_read';
const roleName = 'logstash_read';
const password = `${username}-password`;
try {
await security.role.create(roleName, {
elasticsearch: {
indices: [
{
names: ['apm-*'],
privileges: ['read', 'view_index_metadata'],
},
],
},
elasticsearch: elasticsearchRole,
});
await security.user.create(username, {
@ -163,33 +262,21 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
full_name: 'a kibana user',
});
await executeRequests(username, password, '', 'forbidden');
await executeRequests({ username, password, expectation: 'forbidden' });
} finally {
await security.role.delete(roleName);
await security.user.delete(username);
}
});
it('APIs can be accessed global all with apm-* read privileges role', async () => {
it('APIs can be accessed by global_all user', async () => {
const username = 'global_all';
const roleName = 'global_all';
const password = `${username}-password`;
try {
await security.role.create(roleName, {
elasticsearch: {
indices: [
{
names: ['apm-*'],
privileges: ['read', 'view_index_metadata'],
},
],
},
kibana: [
{
base: ['all'],
spaces: ['*'],
},
],
elasticsearch: elasticsearchRole,
kibana: [{ base: ['all'], spaces: ['*'] }],
});
await security.user.create(username, {
@ -198,7 +285,7 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
full_name: 'a kibana user',
});
await executeRequests(username, password, '', 'response');
await executeRequests({ username, password, expectation: 'response' });
} finally {
await security.role.delete(roleName);
await security.user.delete(username);
@ -206,28 +293,14 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
});
// this could be any role which doesn't have access to the APM feature
it(`APIs can't be accessed by dashboard all with apm-* read privileges role`, async () => {
it(`APIs can't be accessed by dashboard_all user`, async () => {
const username = 'dashboard_all';
const roleName = 'dashboard_all';
const password = `${username}-password`;
try {
await security.role.create(roleName, {
elasticsearch: {
indices: [
{
names: ['apm-*'],
privileges: ['read', 'view_index_metadata'],
},
],
},
kibana: [
{
feature: {
dashboard: ['all'],
},
spaces: ['*'],
},
],
elasticsearch: elasticsearchRole,
kibana: [{ feature: { dashboard: ['all'] }, spaces: ['*'] }],
});
await security.user.create(username, {
@ -236,7 +309,7 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
full_name: 'a kibana user',
});
await executeRequests(username, password, '', 'forbidden');
await executeRequests({ username, password, expectation: 'forbidden' });
} finally {
await security.role.delete(roleName);
await security.user.delete(username);
@ -264,27 +337,10 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
disabledFeatures: [],
});
await security.role.create(roleName, {
elasticsearch: {
indices: [
{
names: ['apm-*'],
privileges: ['read', 'view_index_metadata'],
},
],
},
elasticsearch: elasticsearchRole,
kibana: [
{
feature: {
apm: ['read'],
},
spaces: [space1Id],
},
{
feature: {
dashboard: ['all'],
},
spaces: [space2Id],
},
{ feature: { apm: ['read'] }, spaces: [space1Id] },
{ feature: { dashboard: ['all'] }, spaces: [space2Id] },
],
});
await security.user.create(username, {
@ -301,11 +357,11 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
});
it('user_1 can access APIs in space_1', async () => {
await executeRequests(username, password, space1Id, 'response');
await executeRequests({ username, password, expectation: 'response', spaceId: space1Id });
});
it(`user_1 can't access APIs in space_2`, async () => {
await executeRequests(username, password, space2Id, 'forbidden');
await executeRequests({ username, password, expectation: 'forbidden', spaceId: space2Id });
});
});
});