diff --git a/x-pack/test/api_integration/apis/apm/feature_controls.ts b/x-pack/test/api_integration/apis/apm/feature_controls.ts index b2aa2a70ef364..d47abe3f48fd0 100644 --- a/x-pack/test/api_integration/apis/apm/feature_controls.ts +++ b/x-pack/test/api_integration/apis/apm/feature_controls.ts @@ -19,142 +19,201 @@ 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'; + body?: any; + }; + expectForbidden: (result: any) => void; + expectResponse: (result: any) => void; + } + const endpoints: Endpoint[] = [ + { + req: { url: `/api/apm/services/foo/errors?start=${start}&end=${end}&uiFilters=%7B%7D` }, + expectForbidden: expect404, + expectResponse: expect200, + }, { - url: `/api/apm/services/foo/errors?start=${start}&end=${end}&uiFilters=%7B%7D&_debug=true`, + 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/bar?start=${start}&end=${end}&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}&groupId=bar&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/errors/distribution?start=${start}&end=${end}&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/foo/metrics/charts?start=${start}&end=${end}&agentName=cool-agent&uiFilters=%7B%7D`, + req: { url: `/api/apm/services?start=${start}&end=${end}&uiFilters=%7B%7D` }, expectForbidden: expect404, expectResponse: expect200, }, { - url: `/api/apm/services?start=${start}&end=${end}&uiFilters=%7B%7D`, + req: { url: `/api/apm/services/foo/agent_name?start=${start}&end=${end}` }, expectForbidden: expect404, expectResponse: expect200, }, { - url: `/api/apm/services/foo/agent_name?start=${start}&end=${end}`, + req: { url: `/api/apm/services/foo/transaction_types?start=${start}&end=${end}` }, expectForbidden: expect404, expectResponse: expect200, }, { - url: `/api/apm/services/foo/transaction_types?start=${start}&end=${end}`, + req: { url: `/api/apm/traces?start=${start}&end=${end}&uiFilters=%7B%7D` }, expectForbidden: expect404, expectResponse: expect200, }, { - url: `/api/apm/traces?start=${start}&end=${end}&uiFilters=%7B%7D`, + req: { url: `/api/apm/traces/foo?start=${start}&end=${end}` }, expectForbidden: expect404, expectResponse: expect200, }, { - url: `/api/apm/traces/foo?start=${start}&end=${end}`, + 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?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}&transactionType=bar&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}&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/charts?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, }, { - url: `/api/apm/services/foo/transaction_groups/distribution?start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%7D`, + req: { + method: 'post', + url: `/api/apm/settings/agent-configuration/search`, + body: { service: { name: 'test-service' } }, + }, expectForbidden: expect404, expectResponse: expect200, }, ]; + const elasticsearchRole = { + indices: [ + { names: ['apm-*', '.apm-agent-configuration'], privileges: ['read', 'view_index_metadata'] }, + ], + }; + async function executeRequest( - endpoint: string, + { 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 = supertest[method](`${basePath}${url}`); + + // send body as json + if (body) { + request = request + .send({ + service: { + name: 'test-service', + }, + }) + .set('Content-Type', 'application/json'); + } + + 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 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 executeRequest(endpoint.req, username, password, spaceId); + try { + if (expectation === 'forbidden') { + endpoint.expectForbidden(result); + } else { + endpoint.expectResponse(result); + } + } catch (e) { + const { body, req } = result.response; + throw new Error( + `Endpoint: ${req.method} ${req.path} + Status code: ${body.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', () => { + 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 +222,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 +245,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 +253,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 +269,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 +297,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 +317,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 }); }); }); });