From b67cdeecafe096e319dcd13649aa1232b82205b5 Mon Sep 17 00:00:00 2001 From: kobelb Date: Thu, 31 May 2018 09:32:59 -0400 Subject: [PATCH 01/14] Porting over the saved objects tests, a bunch are failing, I believe because security is preventing the requests --- .../test/rbac_api_integration/apis/index.js | 11 ++ .../apis/saved_objects/bulk_get.js | 128 ++++++++++++++ .../apis/saved_objects/create.js | 88 ++++++++++ .../apis/saved_objects/delete.js | 65 +++++++ .../apis/saved_objects/find.js | 163 ++++++++++++++++++ .../apis/saved_objects/get.js | 81 +++++++++ .../apis/saved_objects/index.js | 16 ++ .../apis/saved_objects/update.js | 95 ++++++++++ x-pack/test/rbac_api_integration/config.js | 54 ++++++ 9 files changed, 701 insertions(+) create mode 100644 x-pack/test/rbac_api_integration/apis/index.js create mode 100644 x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js create mode 100644 x-pack/test/rbac_api_integration/apis/saved_objects/create.js create mode 100644 x-pack/test/rbac_api_integration/apis/saved_objects/delete.js create mode 100644 x-pack/test/rbac_api_integration/apis/saved_objects/find.js create mode 100644 x-pack/test/rbac_api_integration/apis/saved_objects/get.js create mode 100644 x-pack/test/rbac_api_integration/apis/saved_objects/index.js create mode 100644 x-pack/test/rbac_api_integration/apis/saved_objects/update.js create mode 100644 x-pack/test/rbac_api_integration/config.js diff --git a/x-pack/test/rbac_api_integration/apis/index.js b/x-pack/test/rbac_api_integration/apis/index.js new file mode 100644 index 00000000000000..eff74e5f38dbe2 --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/index.js @@ -0,0 +1,11 @@ +/* + * 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 default function ({ loadTestFile }) { + describe('apis RBAC', () => { + loadTestFile(require.resolve('./saved_objects')); + }); +} diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js new file mode 100644 index 00000000000000..a1baa5be46bc77 --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js @@ -0,0 +1,128 @@ +/* + * 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 'expect.js'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + + const BULK_REQUESTS = [ + { + type: 'visualization', + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + }, + { + type: 'dashboard', + id: 'does not exist', + }, + { + type: 'config', + id: '7.0.0-alpha1', + }, + ]; + + describe('_bulk_get', () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + + it('should return 200 with individual responses', async () => ( + await supertest + .post(`/api/saved_objects/_bulk_get`) + .send(BULK_REQUESTS) + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + saved_objects: [ + { + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + type: 'visualization', + updated_at: '2017-09-21T18:51:23.794Z', + version: resp.body.saved_objects[0].version, + attributes: { + title: 'Count of requests', + description: '', + version: 1, + // cheat for some of the more complex attributes + visState: resp.body.saved_objects[0].attributes.visState, + uiStateJSON: resp.body.saved_objects[0].attributes.uiStateJSON, + kibanaSavedObjectMeta: resp.body.saved_objects[0].attributes.kibanaSavedObjectMeta + } + }, + { + id: 'does not exist', + type: 'dashboard', + error: { + statusCode: 404, + message: 'Not found' + } + }, + { + id: '7.0.0-alpha1', + type: 'config', + updated_at: '2017-09-21T18:49:16.302Z', + version: resp.body.saved_objects[2].version, + attributes: { + buildNum: 8467, + defaultIndex: '91200a00-9efd-11e7-acb3-3dab96693fab' + } + } + ] + }); + }) + )); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); + + it('should return 200 with individual responses', async () => ( + await supertest + .post('/api/saved_objects/_bulk_get') + .send(BULK_REQUESTS) + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + saved_objects: [ + { + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + type: 'visualization', + error: { + statusCode: 404, + message: 'Not found' + } + }, + { + id: 'does not exist', + type: 'dashboard', + error: { + statusCode: 404, + message: 'Not found' + } + }, + { + id: '7.0.0-alpha1', + type: 'config', + error: { + statusCode: 404, + message: 'Not found' + } + } + ] + }); + }) + )); + }); + }); +} diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js new file mode 100644 index 00000000000000..306320f9e6117d --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js @@ -0,0 +1,88 @@ +/* + * 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 'expect.js'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + + describe('create', () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + it('should return 200', async () => { + await supertest + .post(`/api/saved_objects/visualization`) + .send({ + attributes: { + title: 'My favorite vis' + } + }) + .expect(200) + .then(resp => { + // loose uuid validation + expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); + + // loose ISO8601 UTC time with milliseconds validation + expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); + + expect(resp.body).to.eql({ + id: resp.body.id, + type: 'visualization', + updated_at: resp.body.updated_at, + version: 1, + attributes: { + title: 'My favorite vis' + } + }); + }); + }); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); + + it('should return 200 and create kibana index', async () => { + await supertest + .post(`/api/saved_objects/visualization`) + .send({ + attributes: { + title: 'My favorite vis' + } + }) + .expect(200) + .then(resp => { + // loose uuid validation + expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); + + // loose ISO8601 UTC time with milliseconds validation + expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); + + expect(resp.body).to.eql({ + id: resp.body.id, + type: 'visualization', + updated_at: resp.body.updated_at, + version: 1, + attributes: { + title: 'My favorite vis' + } + }); + }); + + expect(await es.indices.exists({ index: '.kibana' })) + .to.be(true); + }); + }); + }); +} diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js new file mode 100644 index 00000000000000..38cd61c1f78d71 --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js @@ -0,0 +1,65 @@ +/* + * 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 'expect.js'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + + describe('delete', () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + + it('should return 200 when deleting a doc', async () => ( + await supertest + .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .expect(200) + .then(resp => { + expect(resp.body).to.eql({}); + }) + )); + + it('should return generic 404 when deleting an unknown doc', async () => ( + await supertest + .delete(`/api/saved_objects/dashboard/not-a-real-id`) + .expect(404) + .then(resp => { + expect(resp.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found' + }); + }) + )); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); + + it('returns generic 404 when kibana index is missing', async () => ( + await supertest + .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .expect(404) + .then(resp => { + expect(resp.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found' + }); + }) + )); + }); + }); +} diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js new file mode 100644 index 00000000000000..c8a3b3c9f9d0a1 --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js @@ -0,0 +1,163 @@ +/* + * 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 'expect.js'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + + describe('find', () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + + it('should return 200 with individual responses', async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&fields=title') + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + page: 1, + per_page: 20, + total: 1, + saved_objects: [ + { + type: 'visualization', + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + version: 1, + attributes: { + 'title': 'Count of requests' + } + } + ] + }); + }) + )); + + describe('unknown type', () => { + it('should return 200 with empty response', async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags') + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + page: 1, + per_page: 20, + total: 0, + saved_objects: [] + }); + }) + )); + }); + + describe('page beyond total', () => { + it('should return 200 with empty response', async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + page: 100, + per_page: 100, + total: 1, + saved_objects: [] + }); + }) + )); + }); + + describe('unknown search field', () => { + it('should return 200 with empty response', async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags&search_fields=a') + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + page: 1, + per_page: 20, + total: 0, + saved_objects: [] + }); + }) + )); + }); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); + + it('should return 200 with empty response', async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization') + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + page: 1, + per_page: 20, + total: 0, + saved_objects: [] + }); + }) + )); + + describe('unknown type', () => { + it('should return 200 with empty response', async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags') + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + page: 1, + per_page: 20, + total: 0, + saved_objects: [] + }); + }) + )); + }); + + describe('page beyond total', () => { + it('should return 200 with empty response', async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + page: 100, + per_page: 100, + total: 0, + saved_objects: [] + }); + }) + )); + }); + + describe('unknown search field', () => { + it('should return 200 with empty response', async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags&search_fields=a') + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + page: 1, + per_page: 20, + total: 0, + saved_objects: [] + }); + }) + )); + }); + }); + }); +} diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js new file mode 100644 index 00000000000000..f8b6e97d8f3673 --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js @@ -0,0 +1,81 @@ +/* + * 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 'expect.js'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + + describe('get', () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + + it('should return 200', async () => ( + await supertest + .get(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + type: 'visualization', + updated_at: '2017-09-21T18:51:23.794Z', + version: resp.body.version, + attributes: { + title: 'Count of requests', + description: '', + version: 1, + // cheat for some of the more complex attributes + visState: resp.body.attributes.visState, + uiStateJSON: resp.body.attributes.uiStateJSON, + kibanaSavedObjectMeta: resp.body.attributes.kibanaSavedObjectMeta + } + }); + }) + )); + + describe('doc does not exist', () => { + it('should return same generic error as when index does not exist', async () => ( + await supertest + .get(`/api/saved_objects/visualization/foobar`) + .expect(404) + .then(resp => { + expect(resp.body).to.eql({ + error: 'Not Found', + message: 'Not Found', + statusCode: 404, + }); + }) + )); + }); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); + + it('should return basic 404 without mentioning index', async () => ( + await supertest + .get('/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab') + .expect(404) + .then(resp => { + expect(resp.body).to.eql({ + error: 'Not Found', + message: 'Not Found', + statusCode: 404, + }); + }) + )); + }); + }); +} diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js new file mode 100644 index 00000000000000..b71739edf56995 --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js @@ -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. + */ + +export default function ({ loadTestFile }) { + describe('saved_objects', () => { + loadTestFile(require.resolve('./bulk_get')); + loadTestFile(require.resolve('./create')); + loadTestFile(require.resolve('./delete')); + loadTestFile(require.resolve('./find')); + loadTestFile(require.resolve('./get')); + loadTestFile(require.resolve('./update')); + }); +} diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/update.js b/x-pack/test/rbac_api_integration/apis/saved_objects/update.js new file mode 100644 index 00000000000000..91c26fddc4c7a8 --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/update.js @@ -0,0 +1,95 @@ +/* + * 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 'expect.js'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + + describe('update', () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + it('should return 200', async () => { + await supertest + .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .send({ + attributes: { + title: 'My second favorite vis' + } + }) + .expect(200) + .then(resp => { + // loose uuid validation + expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); + + // loose ISO8601 UTC time with milliseconds validation + expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); + + expect(resp.body).to.eql({ + id: resp.body.id, + type: 'visualization', + updated_at: resp.body.updated_at, + version: 2, + attributes: { + title: 'My second favorite vis' + } + }); + }); + }); + + describe('unknown id', () => { + it('should return a generic 404', async () => { + await supertest + .put(`/api/saved_objects/visualization/not an id`) + .send({ + attributes: { + title: 'My second favorite vis' + } + }) + .expect(404) + .then(resp => { + expect(resp.body).eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found' + }); + }); + }); + }); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); + + it('should return generic 404', async () => ( + await supertest + .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .send({ + attributes: { + title: 'My second favorite vis' + } + }) + .expect(404) + .then(resp => { + expect(resp.body).eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found' + }); + }) + )); + }); + }); +} diff --git a/x-pack/test/rbac_api_integration/config.js b/x-pack/test/rbac_api_integration/config.js new file mode 100644 index 00000000000000..86467bd1d10aa9 --- /dev/null +++ b/x-pack/test/rbac_api_integration/config.js @@ -0,0 +1,54 @@ +/* + * 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 path from 'path'; +import { resolveKibanaPath } from '@kbn/plugin-helpers'; + +export default async function ({ readConfigFile }) { + + const config = { + kibana: { + api: await readConfigFile(resolveKibanaPath('test/api_integration/config.js')), + functional: await readConfigFile(require.resolve('../../../test/functional/config.js')) + }, + xpack: { + api: await readConfigFile(require.resolve('../api_integration/config.js')) + } + }; + + return { + testFiles: [require.resolve('./apis')], + servers: config.xpack.api.get('servers'), + services: { + es: config.kibana.functional.get('services.es'), + supertest: config.kibana.api.get('services.supertest'), + esArchiver: config.kibana.functional.get('services.esArchiver'), + }, + junit: { + reportName: 'X-Pack RBAC API Integration Tests', + }, + + esArchiver: { + directory: resolveKibanaPath(path.join('test', 'api_integration', 'fixtures', 'es_archiver')) + }, + + esTestCluster: { + ...config.xpack.api.get('esTestCluster'), + serverArgs: [ + ...config.xpack.api.get('esTestCluster.serverArgs'), + ], + }, + + kbnTestServer: { + ...config.xpack.api.get('kbnTestServer'), + serverArgs: [ + ...config.xpack.api.get('kbnTestServer.serverArgs'), + '--optimize.enabled=false', + // '--xpack.security.rbac.enabled=true' + ], + }, + }; +} From f00036a78e1eba87cc0736a1ac75905da2b762e9 Mon Sep 17 00:00:00 2001 From: kobelb Date: Thu, 31 May 2018 10:24:58 -0400 Subject: [PATCH 02/14] Running saved objects tests with rbac and xsrf disabled --- x-pack/test/rbac_api_integration/config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/rbac_api_integration/config.js b/x-pack/test/rbac_api_integration/config.js index 86467bd1d10aa9..f3b927e07f814d 100644 --- a/x-pack/test/rbac_api_integration/config.js +++ b/x-pack/test/rbac_api_integration/config.js @@ -47,7 +47,8 @@ export default async function ({ readConfigFile }) { serverArgs: [ ...config.xpack.api.get('kbnTestServer.serverArgs'), '--optimize.enabled=false', - // '--xpack.security.rbac.enabled=true' + '--xpack.security.rbac.enabled=true', + '--server.xsrf.disableProtection=true', ], }, }; From 469f99dc1f31a35dfab1267f0406020245b89a3e Mon Sep 17 00:00:00 2001 From: kobelb Date: Thu, 31 May 2018 11:47:01 -0400 Subject: [PATCH 03/14] Adding users --- .../apis/saved_objects/index.js | 25 ++++++++++++++++++- x-pack/test/rbac_api_integration/config.js | 3 ++- .../test/rbac_api_integration/services/es.js | 20 +++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 x-pack/test/rbac_api_integration/services/es.js diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js index b71739edf56995..cd94329e584d4d 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js @@ -4,8 +4,31 @@ * you may not use this file except in compliance with the Elastic License. */ -export default function ({ loadTestFile }) { +export default function ({ loadTestFile, getService }) { + const es = getService('es'); + describe('saved_objects', () => { + before(async () => { + await es.shield.putUser({ + username: 'a_kibana_user', + body: { + password: 'password', + roles: ['kibana_rbac_user'], + full_name: 'a kibana user', + email: 'a_kibana_user@elastic.co', + } + }); + + await es.shield.putUser({ + username: 'a_kibana_dashboard_only_user', + body: { + password: 'password', + roles: ["kibana_rbac_dashboard_only_user"], + full_name: 'a kibana dashboard only user', + email: 'a_kibana_dashboard_only_user@elastic.co', + } + }); + }); loadTestFile(require.resolve('./bulk_get')); loadTestFile(require.resolve('./create')); loadTestFile(require.resolve('./delete')); diff --git a/x-pack/test/rbac_api_integration/config.js b/x-pack/test/rbac_api_integration/config.js index f3b927e07f814d..15e5791045970e 100644 --- a/x-pack/test/rbac_api_integration/config.js +++ b/x-pack/test/rbac_api_integration/config.js @@ -6,6 +6,7 @@ import path from 'path'; import { resolveKibanaPath } from '@kbn/plugin-helpers'; +import { EsProvider } from './services/es'; export default async function ({ readConfigFile }) { @@ -23,7 +24,7 @@ export default async function ({ readConfigFile }) { testFiles: [require.resolve('./apis')], servers: config.xpack.api.get('servers'), services: { - es: config.kibana.functional.get('services.es'), + es: EsProvider, supertest: config.kibana.api.get('services.supertest'), esArchiver: config.kibana.functional.get('services.esArchiver'), }, diff --git a/x-pack/test/rbac_api_integration/services/es.js b/x-pack/test/rbac_api_integration/services/es.js new file mode 100644 index 00000000000000..420541fa7ec5f6 --- /dev/null +++ b/x-pack/test/rbac_api_integration/services/es.js @@ -0,0 +1,20 @@ +/* + * 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 { format as formatUrl } from 'url'; + +import elasticsearch from 'elasticsearch'; +import shieldPlugin from '../../../server/lib/esjs_shield_plugin'; + +export function EsProvider({ getService }) { + const config = getService('config'); + + return new elasticsearch.Client({ + host: formatUrl(config.get('servers.elasticsearch')), + requestTimeout: config.get('timeouts.esRequestTimeout'), + plugins: [shieldPlugin] + }); +} From 6841a6dcf3f21a4f921594279105618ca831febe Mon Sep 17 00:00:00 2001 From: kobelb Date: Thu, 31 May 2018 12:52:25 -0400 Subject: [PATCH 04/14] BulkGet now tests under 3 users --- .../apis/saved_objects/authentication.js | 20 ++ .../apis/saved_objects/bulk_get.js | 248 +++++++++++------- .../apis/saved_objects/index.js | 10 +- 3 files changed, 182 insertions(+), 96 deletions(-) create mode 100644 x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js b/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js new file mode 100644 index 00000000000000..f76b2453fa2fa3 --- /dev/null +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js @@ -0,0 +1,20 @@ +/* + * 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 const AUTHENTICATION = { + SUPERUSER: { + USERNAME: 'elastic', + PASSWORD: 'changeme,' + }, + KIBANA_RBAC_USER: { + USERNAME: 'a_kibana_rbac_user', + PASSWORD: 'password' + }, + KIBANA_RBAC_DASHBOARD_ONLY_USER: { + USERNAME: 'a_kibana_rbac_dashboard_only_user', + PASSWORD: 'password' + } +}; diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js index a1baa5be46bc77..5bdabd69d47b89 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js @@ -5,6 +5,7 @@ */ import expect from 'expect.js'; +import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -27,102 +28,165 @@ export default function ({ getService }) { ]; describe('_bulk_get', () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); + const expectResults = resp => { + expect(resp.body).to.eql({ + saved_objects: [ + { + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + type: 'visualization', + updated_at: '2017-09-21T18:51:23.794Z', + version: resp.body.saved_objects[0].version, + attributes: { + title: 'Count of requests', + description: '', + version: 1, + // cheat for some of the more complex attributes + visState: resp.body.saved_objects[0].attributes.visState, + uiStateJSON: resp.body.saved_objects[0].attributes.uiStateJSON, + kibanaSavedObjectMeta: + resp.body.saved_objects[0].attributes.kibanaSavedObjectMeta, + }, + }, + { + id: 'does not exist', + type: 'dashboard', + error: { + statusCode: 404, + message: 'Not found', + }, + }, + { + id: '7.0.0-alpha1', + type: 'config', + updated_at: '2017-09-21T18:49:16.302Z', + version: resp.body.saved_objects[2].version, + attributes: { + buildNum: 8467, + defaultIndex: '91200a00-9efd-11e7-acb3-3dab96693fab', + }, + }, + ], + }); + }; - it('should return 200 with individual responses', async () => ( - await supertest - .post(`/api/saved_objects/_bulk_get`) - .send(BULK_REQUESTS) - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - saved_objects: [ - { - id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', - type: 'visualization', - updated_at: '2017-09-21T18:51:23.794Z', - version: resp.body.saved_objects[0].version, - attributes: { - title: 'Count of requests', - description: '', - version: 1, - // cheat for some of the more complex attributes - visState: resp.body.saved_objects[0].attributes.visState, - uiStateJSON: resp.body.saved_objects[0].attributes.uiStateJSON, - kibanaSavedObjectMeta: resp.body.saved_objects[0].attributes.kibanaSavedObjectMeta - } - }, - { - id: 'does not exist', - type: 'dashboard', - error: { - statusCode: 404, - message: 'Not found' - } - }, - { - id: '7.0.0-alpha1', - type: 'config', - updated_at: '2017-09-21T18:49:16.302Z', - version: resp.body.saved_objects[2].version, - attributes: { - buildNum: 8467, - defaultIndex: '91200a00-9efd-11e7-acb3-3dab96693fab' - } - } - ] - }); - }) - )); + const expect404s = resp => { + expect(resp.body).to.eql({ + saved_objects: [ + { + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + type: 'visualization', + error: { + statusCode: 404, + message: 'Not found', + }, + }, + { + id: 'does not exist', + type: 'dashboard', + error: { + statusCode: 404, + message: 'Not found', + }, + }, + { + id: '7.0.0-alpha1', + type: 'config', + error: { + statusCode: 404, + message: 'Not found', + }, + }, + ], + }); + }; + + const bulkGetTest = (description, { auth, assert }) => { + describe(description, () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + + it('should return 200 with individual responses', async () => { + await supertest + .post(`/api/saved_objects/_bulk_get`) + .auth(auth.username, auth.password) + .send(BULK_REQUESTS) + .expect(assert.withIndex.statusCode) + .then(assert.withIndex.response); + }); + }); + + describe('without kibana index', () => { + before( + async () => + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + ); + + it('should return 200 with individual responses', async () => { + await supertest + .post('/api/saved_objects/_bulk_get') + .auth(auth.username, auth.password) + .send(BULK_REQUESTS) + .expect(assert.withoutIndex.statusCode) + .then(assert.withoutIndex.response); + }); + }); + }); + }; + + bulkGetTest(`superuser`, { + auth: { + username: AUTHENTICATION.SUPERUSER.USERNAME, + password: AUTHENTICATION.SUPERUSER.PASSWORD, + }, + assert: { + withIndex: { + statusCode: 200, + response: expectResults, + }, + withoutIndex: { + statusCode: 200, + response: expect404s + } + } }); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); + bulkGetTest(`kibana rbac user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, + }, + assert: { + withIndex: { + statusCode: 200, + response: expectResults, + }, + withoutIndex: { + statusCode: 200, + response: expect404s + } + } + }); - it('should return 200 with individual responses', async () => ( - await supertest - .post('/api/saved_objects/_bulk_get') - .send(BULK_REQUESTS) - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - saved_objects: [ - { - id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', - type: 'visualization', - error: { - statusCode: 404, - message: 'Not found' - } - }, - { - id: 'does not exist', - type: 'dashboard', - error: { - statusCode: 404, - message: 'Not found' - } - }, - { - id: '7.0.0-alpha1', - type: 'config', - error: { - statusCode: 404, - message: 'Not found' - } - } - ] - }); - }) - )); + bulkGetTest(`kibana rbac dashboard only user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, + }, + assert: { + withIndex: { + statusCode: 200, + response: expectResults, + }, + withoutIndex: { + statusCode: 200, + response: expect404s + } + } }); }); } diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js index cd94329e584d4d..392967e4933300 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js @@ -4,15 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AUTHENTICATION } from "./authentication"; + export default function ({ loadTestFile, getService }) { const es = getService('es'); describe('saved_objects', () => { before(async () => { await es.shield.putUser({ - username: 'a_kibana_user', + username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, body: { - password: 'password', + password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, roles: ['kibana_rbac_user'], full_name: 'a kibana user', email: 'a_kibana_user@elastic.co', @@ -20,9 +22,9 @@ export default function ({ loadTestFile, getService }) { }); await es.shield.putUser({ - username: 'a_kibana_dashboard_only_user', + username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, body: { - password: 'password', + password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, roles: ["kibana_rbac_dashboard_only_user"], full_name: 'a kibana dashboard only user', email: 'a_kibana_dashboard_only_user@elastic.co', From cd0df76c3f3bfd49065c703dd0b0710df8002fd4 Mon Sep 17 00:00:00 2001 From: kobelb Date: Thu, 31 May 2018 14:18:02 -0400 Subject: [PATCH 05/14] Adding create tests --- .../apis/saved_objects/authentication.js | 2 +- .../apis/saved_objects/bulk_get.js | 6 +- .../apis/saved_objects/create.js | 186 ++++++++++++------ x-pack/test/rbac_api_integration/config.js | 1 + 4 files changed, 128 insertions(+), 67 deletions(-) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js b/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js index f76b2453fa2fa3..4eb11893e6ca2e 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js @@ -7,7 +7,7 @@ export const AUTHENTICATION = { SUPERUSER: { USERNAME: 'elastic', - PASSWORD: 'changeme,' + PASSWORD: 'changeme' }, KIBANA_RBAC_USER: { USERNAME: 'a_kibana_rbac_user', diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js index 5bdabd69d47b89..286c29383120d0 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js @@ -8,7 +8,7 @@ import expect from 'expect.js'; import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { - const supertest = getService('supertest'); + const supertest = getService('supertestWithoutAuth'); const es = getService('es'); const esArchiver = getService('esArchiver'); @@ -106,7 +106,7 @@ export default function ({ getService }) { before(() => esArchiver.load('saved_objects/basic')); after(() => esArchiver.unload('saved_objects/basic')); - it('should return 200 with individual responses', async () => { + it(`should return ${assert.withIndex.statusCode}`, async () => { await supertest .post(`/api/saved_objects/_bulk_get`) .auth(auth.username, auth.password) @@ -126,7 +126,7 @@ export default function ({ getService }) { }) ); - it('should return 200 with individual responses', async () => { + it(`should return ${assert.withoutIndex.statusCode}`, async () => { await supertest .post('/api/saved_objects/_bulk_get') .auth(auth.username, auth.password) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js index 306320f9e6117d..463bb2dfcfeb2d 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js @@ -5,84 +5,144 @@ */ import expect from 'expect.js'; +import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { - const supertest = getService('supertest'); + const supertest = getService('supertestWithoutAuth'); const es = getService('es'); const esArchiver = getService('esArchiver'); describe('create', () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - it('should return 200', async () => { - await supertest - .post(`/api/saved_objects/visualization`) - .send({ - attributes: { - title: 'My favorite vis' - } - }) - .expect(200) - .then(resp => { - // loose uuid validation - expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); + const expectResults = (resp) => { + expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); - // loose ISO8601 UTC time with milliseconds validation - expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); + // loose ISO8601 UTC time with milliseconds validation + expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); - expect(resp.body).to.eql({ - id: resp.body.id, - type: 'visualization', - updated_at: resp.body.updated_at, - version: 1, - attributes: { - title: 'My favorite vis' - } - }); - }); + expect(resp.body).to.eql({ + id: resp.body.id, + type: 'visualization', + updated_at: resp.body.updated_at, + version: 1, + attributes: { + title: 'My favorite vis' + } }); - }); - - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); + }; - it('should return 200 and create kibana index', async () => { - await supertest - .post(`/api/saved_objects/visualization`) - .send({ - attributes: { - title: 'My favorite vis' - } - }) - .expect(200) - .then(resp => { - // loose uuid validation - expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); + const expectForbidden = (resp) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: 'Unable to create visualization, missing action:saved-objects/visualization/create' + }); + }; - // loose ISO8601 UTC time with milliseconds validation - expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); + const expectIndexCreated = async (indexCreated) => { + expect(await es.indices.exists({ index: '.kibana' })) + .to.be(indexCreated); + }; - expect(resp.body).to.eql({ - id: resp.body.id, - type: 'visualization', - updated_at: resp.body.updated_at, - version: 1, - attributes: { - title: 'My favorite vis' - } - }); + const createTest = (description, { auth, assert }) => { + describe(description, () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + it(`should return ${assert.withIndex.statusCode}`, async () => { + await supertest + .post(`/api/saved_objects/visualization`) + .auth(auth.username, auth.password) + .send({ + attributes: { + title: 'My favorite vis' + } + }) + .expect(assert.withIndex.statusCode) + .then(assert.withIndex.response); }); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); + + const statusCode = assert.withoutIndex.statusCode; + const indexCreated = assert.withoutIndex.indexCreated; + it(`should return ${statusCode} and ${ indexCreated ? 'create' : 'not create'} the kibana index`, async () => { + await supertest + .post(`/api/saved_objects/visualization`) + .auth(auth.username, auth.password) + .send({ + attributes: { + title: 'My favorite vis' + } + }) + .expect(assert.withoutIndex.statusCode) + .then(assert.withoutIndex.response); - expect(await es.indices.exists({ index: '.kibana' })) - .to.be(true); + await expectIndexCreated(assert.withoutIndex.indexCreated); + }); + }); }); + }; + + createTest(`superuser`, { + auth: { + username: AUTHENTICATION.SUPERUSER.USERNAME, + password: AUTHENTICATION.SUPERUSER.PASSWORD, + }, + assert: { + withIndex: { + statusCode: 200, + response: expectResults, + }, + withoutIndex: { + statusCode: 200, + response: expectResults, + indexCreated: true + } + } + }); + + createTest(`kibana rbac user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, + }, + assert: { + withIndex: { + statusCode: 200, + response: expectResults, + }, + withoutIndex: { + statusCode: 200, + response: expectResults, + indexCreated: true + } + } + }); + + createTest(`kibana rbac dashboard only user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, + }, + assert: { + withIndex: { + statusCode: 403, + response: expectForbidden, + }, + withoutIndex: { + statusCode: 403, + response: expectForbidden, + indexCreated: false + } + } }); }); } diff --git a/x-pack/test/rbac_api_integration/config.js b/x-pack/test/rbac_api_integration/config.js index 15e5791045970e..481b14913da919 100644 --- a/x-pack/test/rbac_api_integration/config.js +++ b/x-pack/test/rbac_api_integration/config.js @@ -26,6 +26,7 @@ export default async function ({ readConfigFile }) { services: { es: EsProvider, supertest: config.kibana.api.get('services.supertest'), + supertestWithoutAuth: config.xpack.api.get('services.supertestWithoutAuth'), esArchiver: config.kibana.functional.get('services.esArchiver'), }, junit: { From 2ebd865f9cf9943bbd2f75e2619249412d515d7e Mon Sep 17 00:00:00 2001 From: kobelb Date: Thu, 31 May 2018 14:52:05 -0400 Subject: [PATCH 06/14] Adding delete tests --- .../apis/saved_objects/delete.js | 172 +++++++++++++----- 1 file changed, 128 insertions(+), 44 deletions(-) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js index 38cd61c1f78d71..825ec7ab129e98 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js @@ -5,61 +5,145 @@ */ import expect from 'expect.js'; +import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { - const supertest = getService('supertest'); + const supertest = getService('supertestWithoutAuth'); const es = getService('es'); const esArchiver = getService('esArchiver'); describe('delete', () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - it('should return 200 when deleting a doc', async () => ( - await supertest - .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) - .expect(200) - .then(resp => { - expect(resp.body).to.eql({}); - }) - )); + const expectEmpty = (resp) => { + expect(resp.body).to.eql({}); + }; - it('should return generic 404 when deleting an unknown doc', async () => ( - await supertest - .delete(`/api/saved_objects/dashboard/not-a-real-id`) - .expect(404) - .then(resp => { - expect(resp.body).to.eql({ - statusCode: 404, - error: 'Not Found', - message: 'Not Found' - }); - }) - )); + const expectNotFound = (resp) => { + expect(resp.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found' + }); + }; + + const expectForbidden = (resp) => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: 'Unable to delete dashboard, missing action:saved-objects/dashboard/delete' + }); + }; + + const deleteTest = (description, { auth, assert }) => { + describe(description, () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + + it(`should return ${assert.withIndex.deletingDoc.statusCode} when deleting a doc`, async () => ( + await supertest + .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .auth(auth.username, auth.password) + .expect(assert.withIndex.deletingDoc.statusCode) + .then(assert.withIndex.deletingDoc.response) + )); + + it(`should return generic ${assert.withIndex.deletingUnknownDoc.statusCode} when deleting an unknown doc`, async () => ( + await supertest + .delete(`/api/saved_objects/dashboard/not-a-real-id`) + .auth(auth.username, auth.password) + .expect(assert.withIndex.deletingUnknownDoc.statusCode) + .then(assert.withIndex.deletingUnknownDoc.response) + )); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); + + it(`returns generic ${assert.withoutIndex.statusCode} when kibana index is missing`, async () => ( + await supertest + .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.statusCode) + .then(assert.withoutIndex.response) + )); + }); + }); + }; + + deleteTest(`superuser`, { + auth: { + username: AUTHENTICATION.SUPERUSER.USERNAME, + password: AUTHENTICATION.SUPERUSER.PASSWORD, + }, + assert: { + withIndex: { + deletingDoc: { + statusCode: 200, + response: expectEmpty, + }, + deletingUnknownDoc: { + statusCode: 404, + resposne: expectNotFound, + } + }, + withoutIndex: { + statusCode: 404, + response: expectNotFound, + } + } }); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); + deleteTest(`kibana rbac user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, + }, + assert: { + withIndex: { + deletingDoc: { + statusCode: 200, + response: expectEmpty, + }, + deletingUnknownDoc: { + statusCode: 404, + resposne: expectNotFound, + } + }, + withoutIndex: { + statusCode: 404, + response: expectNotFound, + } + } + }); - it('returns generic 404 when kibana index is missing', async () => ( - await supertest - .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) - .expect(404) - .then(resp => { - expect(resp.body).to.eql({ - statusCode: 404, - error: 'Not Found', - message: 'Not Found' - }); - }) - )); + deleteTest(`kibana rbac dashboard only user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, + }, + assert: { + withIndex: { + deletingDoc: { + statusCode: 403, + response: expectForbidden, + }, + deletingUnknownDoc: { + statusCode: 403, + response: expectForbidden, + } + }, + withoutIndex: { + statusCode: 403, + response: expectForbidden, + } + } }); }); } From 3444d9369d9b9f9fc7dd847e5cf0a3bb6cb0a4fc Mon Sep 17 00:00:00 2001 From: kobelb Date: Thu, 31 May 2018 16:13:37 -0400 Subject: [PATCH 07/14] Adding find tests --- .../apis/saved_objects/find.js | 369 ++++++++++++------ 1 file changed, 239 insertions(+), 130 deletions(-) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js index c8a3b3c9f9d0a1..39f915c818f93f 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js @@ -5,6 +5,7 @@ */ import expect from 'expect.js'; +import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -12,152 +13,260 @@ export default function ({ getService }) { const esArchiver = getService('esArchiver'); describe('find', () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - - it('should return 200 with individual responses', async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization&fields=title') - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - page: 1, - per_page: 20, - total: 1, - saved_objects: [ - { - type: 'visualization', - id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', - version: 1, - attributes: { - 'title': 'Count of requests' - } - } - ] - }); - }) - )); - describe('unknown type', () => { - it('should return 200 with empty response', async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags') - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - page: 1, - per_page: 20, - total: 0, - saved_objects: [] - }); - }) - )); + const expectResults = (resp) => { + expect(resp.body).to.eql({ + page: 1, + per_page: 20, + total: 1, + saved_objects: [ + { + type: 'visualization', + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + version: 1, + attributes: { + 'title': 'Count of requests' + } + } + ] }); + }; - describe('page beyond total', () => { - it('should return 200 with empty response', async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - page: 100, - per_page: 100, - total: 1, - saved_objects: [] - }); - }) - )); + const createExpectEmpty = (page, perPage, total) => (resp) => { + expect(resp.body).to.eql({ + page: page, + per_page: perPage, + total: total, + saved_objects: [] }); + }; + + const findTest = (description, { auth, assert }) => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); - describe('unknown search field', () => { - it('should return 200 with empty response', async () => ( + it(`should return ${assert.withIndex.normal.statusCode} with individual responses`, async () => ( await supertest - .get('/api/saved_objects/_find?type=wigwags&search_fields=a') - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - page: 1, - per_page: 20, - total: 0, - saved_objects: [] - }); - }) + .get('/api/saved_objects/_find?type=visualization&fields=title') + .auth(auth.username, auth.password) + .expect(assert.withIndex.normal.statusCode) + .then(assert.withIndex.normal.response) )); - }); - }); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); - - it('should return 200 with empty response', async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization') - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - page: 1, - per_page: 20, - total: 0, - saved_objects: [] - }); - }) - )); + describe('unknown type', () => { + it(`should return ${assert.withIndex.unknownType.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags') + .auth(auth.username, auth.password) + .expect(assert.withIndex.unknownType.statusCode) + .then(assert.withIndex.unknownType.response) + )); + }); - describe('unknown type', () => { - it('should return 200 with empty response', async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags') - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - page: 1, - per_page: 20, - total: 0, - saved_objects: [] - }); - }) - )); + describe('page beyond total', () => { + it(`should return ${assert.withIndex.pageBeyondTotal.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') + .auth(auth.username, auth.password) + .expect(assert.withIndex.pageBeyondTotal.statusCode) + .then(assert.withIndex.pageBeyondTotal.response) + )); + }); + + describe('unknown search field', () => { + it(`should return ${assert.withIndex.unknownSearchField.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags&search_fields=a') + .auth(auth.username, auth.password) + .expect(assert.withIndex.unknownSearchField.statusCode) + .then(assert.withIndex.unknownSearchField.response) + )); + }); }); - describe('page beyond total', () => { - it('should return 200 with empty response', async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - page: 100, - per_page: 100, - total: 0, - saved_objects: [] - }); - }) + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) )); - }); - describe('unknown search field', () => { - it('should return 200 with empty response', async () => ( + it(`should return ${assert.withoutIndex.normal.statusCode} with empty response`, async () => ( await supertest - .get('/api/saved_objects/_find?type=wigwags&search_fields=a') - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - page: 1, - per_page: 20, - total: 0, - saved_objects: [] - }); - }) + .get('/api/saved_objects/_find?type=visualization') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.normal.statusCode) + .then(assert.withoutIndex.normal.response) )); + + describe('unknown type', () => { + it(`should return ${assert.withoutIndex.unknownType.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.unknownType.statusCode) + .then(assert.withoutIndex.unknownType.response) + )); + }); + + describe('page beyond total', () => { + it(`should return ${assert.withoutIndex.pageBeyondTotal.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.pageBeyondTotal.statusCode) + .then(assert.withoutIndex.pageBeyondTotal.response) + )); + }); + + describe('unknown search field', () => { + it(`should return ${assert.withoutIndex.unknownSearchField.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags&search_fields=a') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.unknownSearchField.statusCode) + .then(assert.withoutIndex.unknownSearchField.response) + )); + }); }); + }; + + findTest(`superuser`, { + auth: { + username: AUTHENTICATION.SUPERUSER.USERNAME, + password: AUTHENTICATION.SUPERUSER.PASSWORD, + }, + assert: { + withIndex: { + normal: { + statusCode: 200, + response: expectResults, + }, + unknownType: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + pageBeyondTotal: { + statusCode: 200, + response: createExpectEmpty(100, 100, 1), + }, + unknownSearchField: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + }, + withoutIndex: { + normal: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + unknownType: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + pageBeyondTotal: { + statusCode: 200, + response: createExpectEmpty(100, 100, 0), + }, + unknownSearchField: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + }, + } + }); + + findTest(`kibana rbac user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, + }, + assert: { + withIndex: { + normal: { + statusCode: 200, + response: expectResults, + }, + unknownType: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + pageBeyondTotal: { + statusCode: 200, + response: createExpectEmpty(100, 100, 1), + }, + unknownSearchField: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + }, + withoutIndex: { + normal: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + unknownType: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + pageBeyondTotal: { + statusCode: 200, + response: createExpectEmpty(100, 100, 0), + }, + unknownSearchField: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + }, + } + }); + + findTest(`kibana rbac dashboard only user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, + }, + assert: { + withIndex: { + normal: { + statusCode: 200, + response: expectResults, + }, + unknownType: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + pageBeyondTotal: { + statusCode: 200, + response: createExpectEmpty(100, 100, 1), + }, + unknownSearchField: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + }, + withoutIndex: { + normal: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + unknownType: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + pageBeyondTotal: { + statusCode: 200, + response: createExpectEmpty(100, 100, 0), + }, + unknownSearchField: { + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + }, + } }); }); } From 5f171dbda5d0dca128c9d621a389f9b260731cb3 Mon Sep 17 00:00:00 2001 From: kobelb Date: Thu, 31 May 2018 16:33:13 -0400 Subject: [PATCH 08/14] Adding get tests --- .../apis/saved_objects/get.js | 184 ++++++++++++------ 1 file changed, 129 insertions(+), 55 deletions(-) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js index f8b6e97d8f3673..afb6371e77798b 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js @@ -5,6 +5,7 @@ */ import expect from 'expect.js'; +import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -12,70 +13,143 @@ export default function ({ getService }) { const esArchiver = getService('esArchiver'); describe('get', () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - it('should return 200', async () => ( - await supertest - .get(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', - type: 'visualization', - updated_at: '2017-09-21T18:51:23.794Z', - version: resp.body.version, - attributes: { - title: 'Count of requests', - description: '', - version: 1, - // cheat for some of the more complex attributes - visState: resp.body.attributes.visState, - uiStateJSON: resp.body.attributes.uiStateJSON, - kibanaSavedObjectMeta: resp.body.attributes.kibanaSavedObjectMeta - } - }); + const expectResults = (resp) => { + expect(resp.body).to.eql({ + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + type: 'visualization', + updated_at: '2017-09-21T18:51:23.794Z', + version: resp.body.version, + attributes: { + title: 'Count of requests', + description: '', + version: 1, + // cheat for some of the more complex attributes + visState: resp.body.attributes.visState, + uiStateJSON: resp.body.attributes.uiStateJSON, + kibanaSavedObjectMeta: resp.body.attributes.kibanaSavedObjectMeta + } + }); + }; + + const expectNotFound = (resp) => { + expect(resp.body).to.eql({ + error: 'Not Found', + message: 'Not Found', + statusCode: 404, + }); + }; + + const getTest = (description, { auth, assert }) => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + + it('should return 200', async () => ( + await supertest + .get(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .auth(auth.username, auth.password) + .expect(assert.withIndex.exists.statusCode) + .then(assert.withIndex.exists.response) + )); + + describe('doc does not exist', () => { + it('should return same generic error as when index does not exist', async () => ( + await supertest + .get(`/api/saved_objects/visualization/foobar`) + .auth(auth.username, auth.password) + .expect(assert.withIndex.doesntExist.statusCode) + .then(assert.withIndex.doesntExist.response) + )); + }); + }); + + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], }) - )); + )); - describe('doc does not exist', () => { - it('should return same generic error as when index does not exist', async () => ( + it('should return basic 404 without mentioning index', async () => ( await supertest - .get(`/api/saved_objects/visualization/foobar`) - .expect(404) - .then(resp => { - expect(resp.body).to.eql({ - error: 'Not Found', - message: 'Not Found', - statusCode: 404, - }); - }) + .get('/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.statusCode) + .then(assert.withoutIndex.response) )); }); + }; + + getTest(`superuser`, { + auth: { + username: AUTHENTICATION.SUPERUSER.USERNAME, + password: AUTHENTICATION.SUPERUSER.PASSWORD, + }, + assert: { + withIndex: { + exists: { + statusCode: 200, + response: expectResults, + }, + doesntExist: { + statusCode: 404, + response: expectNotFound, + }, + }, + withoutIndex: { + statusCode: 404, + response: expectNotFound, + } + } }); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); + getTest(`kibana rbac user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, + }, + assert: { + withIndex: { + exists: { + statusCode: 200, + response: expectResults, + }, + doesntExist: { + statusCode: 404, + response: expectNotFound, + }, + }, + withoutIndex: { + statusCode: 404, + response: expectNotFound, + } + } + }); - it('should return basic 404 without mentioning index', async () => ( - await supertest - .get('/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab') - .expect(404) - .then(resp => { - expect(resp.body).to.eql({ - error: 'Not Found', - message: 'Not Found', - statusCode: 404, - }); - }) - )); + getTest(`kibana rbac dashboard only user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, + }, + assert: { + withIndex: { + exists: { + statusCode: 200, + response: expectResults, + }, + doesntExist: { + statusCode: 404, + response: expectNotFound, + }, + }, + withoutIndex: { + statusCode: 404, + response: expectNotFound, + } + } }); }); } From d885d43d9a1028b39021fb9f92ad80a8a1e01cd7 Mon Sep 17 00:00:00 2001 From: kobelb Date: Fri, 1 Jun 2018 08:26:12 -0400 Subject: [PATCH 09/14] Adding bulkGet forbidden tests --- .../apis/saved_objects/authentication.js | 4 +++ .../apis/saved_objects/bulk_get.js | 27 +++++++++++++++++++ .../apis/saved_objects/index.js | 10 +++++++ 3 files changed, 41 insertions(+) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js b/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js index 4eb11893e6ca2e..e095a032934eaf 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js @@ -5,6 +5,10 @@ */ export const AUTHENTICATION = { + NOT_A_KIBANA_USER: { + USERNAME: 'not_a_kibana_user', + PASSWORD: 'password' + }, SUPERUSER: { USERNAME: 'elastic', PASSWORD: 'changeme' diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js index 286c29383120d0..94fdc84b55abb5 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js @@ -100,6 +100,16 @@ export default function ({ getService }) { }); }; + const expectForbidden = resp => { + //eslint-disable-next-line max-len + const missingActions = `saved-objects/config/mget,action:saved-objects/dashboard/mget,version:7.0.0-alpha1,action:login,action:saved-objects/visualization/mget`; + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `Unable to mget visualization,dashboard,config, missing action:${missingActions}` + }); + }; + const bulkGetTest = (description, { auth, assert }) => { describe(description, () => { describe('with kibana index', () => { @@ -138,6 +148,23 @@ export default function ({ getService }) { }); }; + bulkGetTest(`not a kibana user`, { + auth: { + username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, + password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, + }, + assert: { + withIndex: { + statusCode: 403, + response: expectForbidden, + }, + withoutIndex: { + statusCode: 403, + response: expectForbidden + } + } + }); + bulkGetTest(`superuser`, { auth: { username: AUTHENTICATION.SUPERUSER.USERNAME, diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js index 392967e4933300..7ac9d5e7c77349 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js @@ -11,6 +11,16 @@ export default function ({ loadTestFile, getService }) { describe('saved_objects', () => { before(async () => { + await es.shield.putUser({ + username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, + body: { + password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, + roles: [], + full_name: 'not a kibana user', + email: 'not_a_kibana_user@elastic.co', + } + }); + await es.shield.putUser({ username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, body: { From e91073cb39c6ce614395062793e1073a5bd55e50 Mon Sep 17 00:00:00 2001 From: kobelb Date: Fri, 1 Jun 2018 11:47:56 -0400 Subject: [PATCH 10/14] Adding not a kibana user tests --- .../lib/authorization/has_privileges.js | 3 +- .../lib/authorization/has_privileges.test.js | 18 +- .../secure_saved_objects_client.js | 2 +- .../apis/saved_objects/bulk_get.js | 4 +- .../apis/saved_objects/create.js | 26 +- .../apis/saved_objects/delete.js | 33 ++- .../apis/saved_objects/find.js | 222 +++++++++++------- .../apis/saved_objects/get.js | 99 +++++--- 8 files changed, 276 insertions(+), 131 deletions(-) diff --git a/x-pack/plugins/security/server/lib/authorization/has_privileges.js b/x-pack/plugins/security/server/lib/authorization/has_privileges.js index 03a0642ecb8e8c..5f119db027cb6f 100644 --- a/x-pack/plugins/security/server/lib/authorization/has_privileges.js +++ b/x-pack/plugins/security/server/lib/authorization/has_privileges.js @@ -48,7 +48,8 @@ export function hasPrivilegesWithServer(server) { return { success, - missing: missingPrivileges, + // We don't want to expose the version privilege to consumers, as it's an implementation detail only to detect version mismatch + missing: missingPrivileges.filter(p => p !== versionPrivilege), username: privilegeCheck.username, }; }; diff --git a/x-pack/plugins/security/server/lib/authorization/has_privileges.test.js b/x-pack/plugins/security/server/lib/authorization/has_privileges.test.js index aed3dbcfe94ccd..b2e2759c3419b3 100644 --- a/x-pack/plugins/security/server/lib/authorization/has_privileges.test.js +++ b/x-pack/plugins/security/server/lib/authorization/has_privileges.test.js @@ -241,8 +241,8 @@ test(`throws error if missing version privilege and has login privilege`, async test(`doesn't throw error if missing version privilege and missing login privilege`, async () => { const mockServer = createMockServer(); mockResponse(false, { - [getVersionPrivilege(defaultVersion)]: true, - [getLoginPrivilege()]: true, + [getVersionPrivilege(defaultVersion)]: false, + [getLoginPrivilege()]: false, foo: true, }); @@ -250,3 +250,17 @@ test(`doesn't throw error if missing version privilege and missing login privile const hasPrivileges = hasPrivilegesWithRequest({}); await hasPrivileges(['foo']); }); + +test(`excludes version privilege when missing version privilege and missing login privilege`, async () => { + const mockServer = createMockServer(); + mockResponse(false, { + [getVersionPrivilege(defaultVersion)]: false, + [getLoginPrivilege()]: false, + foo: true, + }); + + const hasPrivilegesWithRequest = hasPrivilegesWithServer(mockServer); + const hasPrivileges = hasPrivilegesWithRequest({}); + const result = await hasPrivileges(['foo']); + expect(result.missing).toEqual([getLoginPrivilege()]); +}); diff --git a/x-pack/plugins/security/server/lib/saved_objects_client/secure_saved_objects_client.js b/x-pack/plugins/security/server/lib/saved_objects_client/secure_saved_objects_client.js index 08ee87d5f281bf..b8c63f586fecd7 100644 --- a/x-pack/plugins/security/server/lib/saved_objects_client/secure_saved_objects_client.js +++ b/x-pack/plugins/security/server/lib/saved_objects_client/secure_saved_objects_client.js @@ -104,7 +104,7 @@ export class SecureSavedObjectsClient { this._auditLogger.savedObjectsAuthorizationSuccess(result.username, action, types, args); } else { this._auditLogger.savedObjectsAuthorizationFailure(result.username, action, types, result.missing, args); - const msg = `Unable to ${action} ${types.join(',')}, missing ${result.missing.join(',')}`; + const msg = `Unable to ${action} ${types.sort().join(',')}, missing ${result.missing.sort().join(',')}`; throw this._client.errors.decorateForbiddenError(new Error(msg)); } } diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js index 94fdc84b55abb5..7a6765de622e64 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js @@ -102,11 +102,11 @@ export default function ({ getService }) { const expectForbidden = resp => { //eslint-disable-next-line max-len - const missingActions = `saved-objects/config/mget,action:saved-objects/dashboard/mget,version:7.0.0-alpha1,action:login,action:saved-objects/visualization/mget`; + const missingActions = `action:login,action:saved-objects/config/mget,action:saved-objects/dashboard/mget,action:saved-objects/visualization/mget`; expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: `Unable to mget visualization,dashboard,config, missing action:${missingActions}` + message: `Unable to mget config,dashboard,visualization, missing ${missingActions}` }); }; diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js index 463bb2dfcfeb2d..7f9de2f111e8f1 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js @@ -30,11 +30,11 @@ export default function ({ getService }) { }); }; - const expectForbidden = (resp) => { + const createExpectForbidden = canLogin => resp => { expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: 'Unable to create visualization, missing action:saved-objects/visualization/create' + message: `Unable to create visualization, missing ${canLogin ? '' : 'action:login,'}action:saved-objects/visualization/create` }); }; @@ -91,6 +91,24 @@ export default function ({ getService }) { }); }; + createTest(`not a kibana user`, { + auth: { + username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, + password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, + }, + assert: { + withIndex: { + statusCode: 403, + response: createExpectForbidden(false), + }, + withoutIndex: { + statusCode: 403, + response: createExpectForbidden(false), + indexCreated: false + } + } + }); + createTest(`superuser`, { auth: { username: AUTHENTICATION.SUPERUSER.USERNAME, @@ -135,11 +153,11 @@ export default function ({ getService }) { assert: { withIndex: { statusCode: 403, - response: expectForbidden, + response: createExpectForbidden(true), }, withoutIndex: { statusCode: 403, - response: expectForbidden, + response: createExpectForbidden(true), indexCreated: false } } diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js index 825ec7ab129e98..07dcb563f40d38 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js @@ -26,11 +26,11 @@ export default function ({ getService }) { }); }; - const expectForbidden = (resp) => { + const createExpectForbidden = canLogin => resp => { expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: 'Unable to delete dashboard, missing action:saved-objects/dashboard/delete' + message: `Unable to delete dashboard, missing ${canLogin ? '' : 'action:login,'}action:saved-objects/dashboard/delete` }); }; @@ -77,6 +77,29 @@ export default function ({ getService }) { }); }; + deleteTest(`not a kibana user`, { + auth: { + username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, + password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, + }, + assert: { + withIndex: { + deletingDoc: { + statusCode: 403, + response: createExpectForbidden(false), + }, + deletingUnknownDoc: { + statusCode: 403, + resposne: createExpectForbidden(false), + } + }, + withoutIndex: { + statusCode: 403, + response: createExpectForbidden(false), + } + } + }); + deleteTest(`superuser`, { auth: { username: AUTHENTICATION.SUPERUSER.USERNAME, @@ -132,16 +155,16 @@ export default function ({ getService }) { withIndex: { deletingDoc: { statusCode: 403, - response: expectForbidden, + response: createExpectForbidden(true), }, deletingUnknownDoc: { statusCode: 403, - response: expectForbidden, + response: createExpectForbidden(true), } }, withoutIndex: { statusCode: 403, - response: expectForbidden, + response: createExpectForbidden(true), } } }); diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js index 39f915c818f93f..1a145aa6efc614 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js @@ -8,7 +8,7 @@ import expect from 'expect.js'; import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { - const supertest = getService('supertest'); + const supertest = getService('supertestWithoutAuth'); const es = getService('es'); const esArchiver = getService('esArchiver'); @@ -41,99 +41,155 @@ export default function ({ getService }) { }); }; - const findTest = (description, { auth, assert }) => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - - it(`should return ${assert.withIndex.normal.statusCode} with individual responses`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization&fields=title') - .auth(auth.username, auth.password) - .expect(assert.withIndex.normal.statusCode) - .then(assert.withIndex.normal.response) - )); + const createExpectForbidden = (canLogin, type) => resp => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `Unable to search ${type}, missing ${canLogin ? '' : 'action:login,'}action:saved-objects/${type}/search` + }); + }; - describe('unknown type', () => { - it(`should return ${assert.withIndex.unknownType.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags') - .auth(auth.username, auth.password) - .expect(assert.withIndex.unknownType.statusCode) - .then(assert.withIndex.unknownType.response) - )); - }); + const findTest = (description, { auth, assert }) => { + describe(description, () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); - describe('page beyond total', () => { - it(`should return ${assert.withIndex.pageBeyondTotal.statusCode} with empty response`, async () => ( + it(`should return ${assert.withIndex.normal.statusCode} with individual responses`, async () => ( await supertest - .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') + .get('/api/saved_objects/_find?type=visualization&fields=title') .auth(auth.username, auth.password) - .expect(assert.withIndex.pageBeyondTotal.statusCode) - .then(assert.withIndex.pageBeyondTotal.response) + .expect(assert.withIndex.normal.statusCode) + .then(assert.withIndex.normal.response) )); - }); - describe('unknown search field', () => { - it(`should return ${assert.withIndex.unknownSearchField.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags&search_fields=a') - .auth(auth.username, auth.password) - .expect(assert.withIndex.unknownSearchField.statusCode) - .then(assert.withIndex.unknownSearchField.response) - )); - }); - }); + describe('unknown type', () => { + it(`should return ${assert.withIndex.unknownType.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags') + .auth(auth.username, auth.password) + .expect(assert.withIndex.unknownType.statusCode) + .then(assert.withIndex.unknownType.response) + )); + }); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); + describe('page beyond total', () => { + it(`should return ${assert.withIndex.pageBeyondTotal.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') + .auth(auth.username, auth.password) + .expect(assert.withIndex.pageBeyondTotal.statusCode) + .then(assert.withIndex.pageBeyondTotal.response) + )); + }); - it(`should return ${assert.withoutIndex.normal.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization') - .auth(auth.username, auth.password) - .expect(assert.withoutIndex.normal.statusCode) - .then(assert.withoutIndex.normal.response) - )); - - describe('unknown type', () => { - it(`should return ${assert.withoutIndex.unknownType.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags') - .auth(auth.username, auth.password) - .expect(assert.withoutIndex.unknownType.statusCode) - .then(assert.withoutIndex.unknownType.response) - )); + describe('unknown search field', () => { + it(`should return ${assert.withIndex.unknownSearchField.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags&search_fields=a') + .auth(auth.username, auth.password) + .expect(assert.withIndex.unknownSearchField.statusCode) + .then(assert.withIndex.unknownSearchField.response) + )); + }); }); - describe('page beyond total', () => { - it(`should return ${assert.withoutIndex.pageBeyondTotal.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') - .auth(auth.username, auth.password) - .expect(assert.withoutIndex.pageBeyondTotal.statusCode) - .then(assert.withoutIndex.pageBeyondTotal.response) + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) )); - }); - describe('unknown search field', () => { - it(`should return ${assert.withoutIndex.unknownSearchField.statusCode} with empty response`, async () => ( + it(`should return ${assert.withoutIndex.normal.statusCode} with empty response`, async () => ( await supertest - .get('/api/saved_objects/_find?type=wigwags&search_fields=a') + .get('/api/saved_objects/_find?type=visualization') .auth(auth.username, auth.password) - .expect(assert.withoutIndex.unknownSearchField.statusCode) - .then(assert.withoutIndex.unknownSearchField.response) + .expect(assert.withoutIndex.normal.statusCode) + .then(assert.withoutIndex.normal.response) )); + + describe('unknown type', () => { + it(`should return ${assert.withoutIndex.unknownType.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.unknownType.statusCode) + .then(assert.withoutIndex.unknownType.response) + )); + }); + + describe('page beyond total', () => { + it(`should return ${assert.withoutIndex.pageBeyondTotal.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.pageBeyondTotal.statusCode) + .then(assert.withoutIndex.pageBeyondTotal.response) + )); + }); + + describe('unknown search field', () => { + it(`should return ${assert.withoutIndex.unknownSearchField.statusCode} with empty response`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=wigwags&search_fields=a') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.unknownSearchField.statusCode) + .then(assert.withoutIndex.unknownSearchField.response) + )); + }); }); }); + }; + findTest(`not a kibana user`, { + auth: { + username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, + password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, + }, + assert: { + withIndex: { + normal: { + statusCode: 403, + response: createExpectForbidden(false, 'visualization'), + }, + unknownType: { + statusCode: 403, + response: createExpectForbidden(false, 'wigwags'), + }, + pageBeyondTotal: { + statusCode: 403, + response: createExpectForbidden(false, 'visualization'), + }, + unknownSearchField: { + statusCode: 403, + response: createExpectForbidden(false, 'wigwags'), + }, + }, + withoutIndex: { + normal: { + statusCode: 403, + response: createExpectForbidden(false, 'visualization'), + }, + unknownType: { + statusCode: 403, + response: createExpectForbidden(false, 'wigwags'), + }, + pageBeyondTotal: { + statusCode: 403, + response: createExpectForbidden(false, 'visualization'), + }, + unknownSearchField: { + statusCode: 403, + response: createExpectForbidden(false, 'wigwags'), + }, + }, + } + }); + findTest(`superuser`, { auth: { username: AUTHENTICATION.SUPERUSER.USERNAME, @@ -236,16 +292,16 @@ export default function ({ getService }) { response: expectResults, }, unknownType: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), + statusCode: 403, + response: createExpectForbidden(true, 'wigwags'), }, pageBeyondTotal: { statusCode: 200, response: createExpectEmpty(100, 100, 1), }, unknownSearchField: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), + statusCode: 403, + response: createExpectForbidden(true, 'wigwags'), }, }, withoutIndex: { @@ -254,16 +310,16 @@ export default function ({ getService }) { response: createExpectEmpty(1, 20, 0), }, unknownType: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), + statusCode: 403, + response: createExpectForbidden(true, 'wigwags'), }, pageBeyondTotal: { statusCode: 200, response: createExpectEmpty(100, 100, 0), }, unknownSearchField: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), + statusCode: 403, + response: createExpectForbidden(true, 'wigwags'), }, }, } diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js index afb6371e77798b..94d0e9b30191f3 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js @@ -8,7 +8,7 @@ import expect from 'expect.js'; import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { - const supertest = getService('supertest'); + const supertest = getService('supertestWithoutAuth'); const es = getService('es'); const esArchiver = getService('esArchiver'); @@ -40,49 +40,82 @@ export default function ({ getService }) { }); }; - const getTest = (description, { auth, assert }) => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); + const expectForbidden = resp => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `Unable to get visualization, missing action:login,action:saved-objects/visualization/get` + }); + }; - it('should return 200', async () => ( - await supertest - .get(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) - .auth(auth.username, auth.password) - .expect(assert.withIndex.exists.statusCode) - .then(assert.withIndex.exists.response) - )); + const getTest = (description, { auth, assert }) => { + describe(description, () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); - describe('doc does not exist', () => { - it('should return same generic error as when index does not exist', async () => ( + it('should return 200', async () => ( await supertest - .get(`/api/saved_objects/visualization/foobar`) + .get(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) .auth(auth.username, auth.password) - .expect(assert.withIndex.doesntExist.statusCode) - .then(assert.withIndex.doesntExist.response) + .expect(assert.withIndex.exists.statusCode) + .then(assert.withIndex.exists.response) )); + + describe('doc does not exist', () => { + it('should return same generic error as when index does not exist', async () => ( + await supertest + .get(`/api/saved_objects/visualization/foobar`) + .auth(auth.username, auth.password) + .expect(assert.withIndex.doesntExist.statusCode) + .then(assert.withIndex.doesntExist.response) + )); + }); }); - }); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], + }) + )); - it('should return basic 404 without mentioning index', async () => ( - await supertest - .get('/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab') - .auth(auth.username, auth.password) - .expect(assert.withoutIndex.statusCode) - .then(assert.withoutIndex.response) - )); + it('should return basic 404 without mentioning index', async () => ( + await supertest + .get('/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab') + .auth(auth.username, auth.password) + .expect(assert.withoutIndex.statusCode) + .then(assert.withoutIndex.response) + )); + }); }); }; + getTest(`not a kibana user`, { + auth: { + username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, + password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, + }, + assert: { + withIndex: { + exists: { + statusCode: 403, + response: expectForbidden, + }, + doesntExist: { + statusCode: 403, + response: expectForbidden, + }, + }, + withoutIndex: { + statusCode: 403, + response: expectForbidden, + } + } + }); + getTest(`superuser`, { auth: { username: AUTHENTICATION.SUPERUSER.USERNAME, From 4044ddee6061b344c0996415533518779ad8cdf3 Mon Sep 17 00:00:00 2001 From: kobelb Date: Fri, 1 Jun 2018 12:07:31 -0400 Subject: [PATCH 11/14] Update tests --- .../apis/saved_objects/update.js | 249 +++++++++++++----- 1 file changed, 178 insertions(+), 71 deletions(-) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/update.js b/x-pack/test/rbac_api_integration/apis/saved_objects/update.js index 91c26fddc4c7a8..f8924eeaa6e20d 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/update.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/update.js @@ -5,91 +5,198 @@ */ import expect from 'expect.js'; +import { AUTHENTICATION } from './authentication'; export default function ({ getService }) { - const supertest = getService('supertest'); + const supertest = getService('supertestWithoutAuth'); const es = getService('es'); const esArchiver = getService('esArchiver'); describe('update', () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - it('should return 200', async () => { - await supertest - .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) - .send({ - attributes: { - title: 'My second favorite vis' - } - }) - .expect(200) - .then(resp => { - // loose uuid validation - expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); - - // loose ISO8601 UTC time with milliseconds validation - expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); - - expect(resp.body).to.eql({ - id: resp.body.id, - type: 'visualization', - updated_at: resp.body.updated_at, - version: 2, - attributes: { - title: 'My second favorite vis' - } + const expectResults = resp => { + // loose uuid validation + expect(resp.body).to.have.property('id').match(/^[0-9a-f-]{36}$/); + + // loose ISO8601 UTC time with milliseconds validation + expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); + + expect(resp.body).to.eql({ + id: resp.body.id, + type: 'visualization', + updated_at: resp.body.updated_at, + version: 2, + attributes: { + title: 'My second favorite vis' + } + }); + }; + + const expectNotFound = resp => { + expect(resp.body).eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found' + }); + }; + + const createExpectForbidden = canLogin => resp => { + expect(resp.body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: `Unable to update visualization, missing ${canLogin ? '' : 'action:login,'}action:saved-objects/visualization/update` + }); + }; + + const updateTest = (description, { auth, assert }) => { + describe(description, () => { + describe('with kibana index', () => { + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + it('should return 200', async () => { + await supertest + .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .auth(auth.username, auth.password) + .send({ + attributes: { + title: 'My second favorite vis' + } + }) + .expect(assert.withIndex.exists.statusCode) + .then(assert.withIndex.exists.response); + }); + + describe('unknown id', () => { + it('should return a generic 404', async () => { + await supertest + .put(`/api/saved_objects/visualization/not an id`) + .auth(auth.username, auth.password) + .send({ + attributes: { + title: 'My second favorite vis' + } + }) + .expect(assert.withIndex.doesntExist.statusCode) + .then(assert.withIndex.doesntExist.response); }); }); - }); + }); - describe('unknown id', () => { - it('should return a generic 404', async () => { - await supertest - .put(`/api/saved_objects/visualization/not an id`) - .send({ - attributes: { - title: 'My second favorite vis' - } + describe('without kibana index', () => { + before(async () => ( + // just in case the kibana server has recreated it + await es.indices.delete({ + index: '.kibana', + ignore: [404], }) - .expect(404) - .then(resp => { - expect(resp.body).eql({ - statusCode: 404, - error: 'Not Found', - message: 'Not Found' - }); - }); + )); + + it('should return generic 404', async () => ( + await supertest + .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .auth(auth.username, auth.password) + .send({ + attributes: { + title: 'My second favorite vis' + } + }) + .expect(assert.withoutIndex.statusCode) + .then(assert.withoutIndex.response) + )); }); }); + }; + + updateTest(`not a kibana user`, { + auth: { + username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, + password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, + }, + assert: { + withIndex: { + exists: { + statusCode: 403, + response: createExpectForbidden(false), + }, + doesntExist: { + statusCode: 403, + response: createExpectForbidden(false), + }, + }, + withoutIndex: { + statusCode: 403, + response: createExpectForbidden(false), + } + } }); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); - - it('should return generic 404', async () => ( - await supertest - .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) - .send({ - attributes: { - title: 'My second favorite vis' - } - }) - .expect(404) - .then(resp => { - expect(resp.body).eql({ - statusCode: 404, - error: 'Not Found', - message: 'Not Found' - }); - }) - )); + updateTest(`superuser`, { + auth: { + username: AUTHENTICATION.SUPERUSER.USERNAME, + password: AUTHENTICATION.SUPERUSER.PASSWORD, + }, + assert: { + withIndex: { + exists: { + statusCode: 200, + response: expectResults, + }, + doesntExist: { + statusCode: 404, + response: expectNotFound, + }, + }, + withoutIndex: { + statusCode: 404, + response: expectNotFound, + } + } }); + + updateTest(`kibana rbac user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, + }, + assert: { + withIndex: { + exists: { + statusCode: 200, + response: expectResults, + }, + doesntExist: { + statusCode: 404, + response: expectNotFound, + }, + }, + withoutIndex: { + statusCode: 404, + response: expectNotFound, + } + } + }); + + updateTest(`kibana rbac dashboard only user`, { + auth: { + username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, + password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, + }, + assert: { + withIndex: { + exists: { + statusCode: 403, + response: createExpectForbidden(true), + }, + doesntExist: { + statusCode: 403, + response: createExpectForbidden(true), + }, + }, + withoutIndex: { + statusCode: 403, + response: createExpectForbidden(true), + } + } + }); + }); } From fc90d7c5dbe3a55609c39a22b08e79ac9c06cf1d Mon Sep 17 00:00:00 2001 From: kobelb Date: Fri, 1 Jun 2018 15:27:12 -0400 Subject: [PATCH 12/14] Renaming the actions/privileges to be closer to the functions on the saved object client itself --- x-pack/plugins/security/server/lib/audit_logger.test.js | 2 +- .../plugins/security/server/lib/privileges/privileges.js | 4 ++-- .../saved_objects_client/secure_saved_objects_client.js | 8 ++++---- .../rbac_api_integration/apis/saved_objects/bulk_get.js | 4 ++-- .../rbac_api_integration/apis/saved_objects/create.js | 2 +- .../rbac_api_integration/apis/saved_objects/delete.js | 2 +- .../test/rbac_api_integration/apis/saved_objects/find.js | 2 +- .../test/rbac_api_integration/apis/saved_objects/get.js | 2 +- .../rbac_api_integration/apis/saved_objects/update.js | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/security/server/lib/audit_logger.test.js b/x-pack/plugins/security/server/lib/audit_logger.test.js index da727552aae58a..51c8698da818d6 100644 --- a/x-pack/plugins/security/server/lib/audit_logger.test.js +++ b/x-pack/plugins/security/server/lib/audit_logger.test.js @@ -48,7 +48,7 @@ describe(`#savedObjectsAuthorizationFailure`, () => { const username = 'foo-user'; const action = 'foo-action'; const types = [ 'foo-type-1', 'foo-type-2' ]; - const missing = [`action:saved-objects/${types[0]}/foo-action`, `action:saved-objects/${types[1]}/foo-action`]; + const missing = [`action:saved_objects/${types[0]}/foo-action`, `action:saved_objects/${types[1]}/foo-action`]; const args = { 'foo': 'bar', 'baz': 'quz', diff --git a/x-pack/plugins/security/server/lib/privileges/privileges.js b/x-pack/plugins/security/server/lib/privileges/privileges.js index 129d4b3abfb3ea..e2dc9b2ff7ece3 100644 --- a/x-pack/plugins/security/server/lib/privileges/privileges.js +++ b/x-pack/plugins/security/server/lib/privileges/privileges.js @@ -40,13 +40,13 @@ export function buildPrivilegeMap(application, kibanaVersion) { } function buildSavedObjectsReadPrivileges() { - const readActions = ['get', 'mget', 'search']; + const readActions = ['get', 'bulk_get', 'find']; return buildSavedObjectsPrivileges(readActions); } function buildSavedObjectsPrivileges(actions) { const objectTypes = ['config', 'dashboard', 'graph-workspace', 'index-pattern', 'search', 'timelion-sheet', 'url', 'visualization']; return objectTypes - .map(type => actions.map(action => `action:saved-objects/${type}/${action}`)) + .map(type => actions.map(action => `action:saved_objects/${type}/${action}`)) .reduce((acc, types) => [...acc, ...types], []); } diff --git a/x-pack/plugins/security/server/lib/saved_objects_client/secure_saved_objects_client.js b/x-pack/plugins/security/server/lib/saved_objects_client/secure_saved_objects_client.js index b8c63f586fecd7..0a2f9490c16649 100644 --- a/x-pack/plugins/security/server/lib/saved_objects_client/secure_saved_objects_client.js +++ b/x-pack/plugins/security/server/lib/saved_objects_client/secure_saved_objects_client.js @@ -34,7 +34,7 @@ export class SecureSavedObjectsClient { async bulkCreate(objects, options = {}) { const types = uniq(objects.map(o => o.type)); - await this._performAuthorizationCheck(types, 'create', { + await this._performAuthorizationCheck(types, 'bulk_create', { objects, options, }); @@ -52,7 +52,7 @@ export class SecureSavedObjectsClient { } async find(options = {}) { - await this._performAuthorizationCheck(options.type, 'search', { + await this._performAuthorizationCheck(options.type, 'find', { options, }); @@ -61,7 +61,7 @@ export class SecureSavedObjectsClient { async bulkGet(objects = []) { const types = uniq(objects.map(o => o.type)); - await this._performAuthorizationCheck(types, 'mget', { + await this._performAuthorizationCheck(types, 'bulk_get', { objects, }); @@ -90,7 +90,7 @@ export class SecureSavedObjectsClient { async _performAuthorizationCheck(typeOrTypes, action, args) { const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes]; - const actions = types.map(type => `action:saved-objects/${type}/${action}`); + const actions = types.map(type => `action:saved_objects/${type}/${action}`); let result; try { diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js index 7a6765de622e64..c867adf105f47c 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js @@ -102,11 +102,11 @@ export default function ({ getService }) { const expectForbidden = resp => { //eslint-disable-next-line max-len - const missingActions = `action:login,action:saved-objects/config/mget,action:saved-objects/dashboard/mget,action:saved-objects/visualization/mget`; + const missingActions = `action:login,action:saved_objects/config/bulk_get,action:saved_objects/dashboard/bulk_get,action:saved_objects/visualization/bulk_get`; expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: `Unable to mget config,dashboard,visualization, missing ${missingActions}` + message: `Unable to bulk_get config,dashboard,visualization, missing ${missingActions}` }); }; diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js index 7f9de2f111e8f1..f2663d6dc99171 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js @@ -34,7 +34,7 @@ export default function ({ getService }) { expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: `Unable to create visualization, missing ${canLogin ? '' : 'action:login,'}action:saved-objects/visualization/create` + message: `Unable to create visualization, missing ${canLogin ? '' : 'action:login,'}action:saved_objects/visualization/create` }); }; diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js index 07dcb563f40d38..ae085381d02699 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js @@ -30,7 +30,7 @@ export default function ({ getService }) { expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: `Unable to delete dashboard, missing ${canLogin ? '' : 'action:login,'}action:saved-objects/dashboard/delete` + message: `Unable to delete dashboard, missing ${canLogin ? '' : 'action:login,'}action:saved_objects/dashboard/delete` }); }; diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js index 1a145aa6efc614..b9421a38017034 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js @@ -45,7 +45,7 @@ export default function ({ getService }) { expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: `Unable to search ${type}, missing ${canLogin ? '' : 'action:login,'}action:saved-objects/${type}/search` + message: `Unable to find ${type}, missing ${canLogin ? '' : 'action:login,'}action:saved_objects/${type}/find` }); }; diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js index 94d0e9b30191f3..77bedd1bb55ef9 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js @@ -44,7 +44,7 @@ export default function ({ getService }) { expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: `Unable to get visualization, missing action:login,action:saved-objects/visualization/get` + message: `Unable to get visualization, missing action:login,action:saved_objects/visualization/get` }); }; diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/update.js b/x-pack/test/rbac_api_integration/apis/saved_objects/update.js index f8924eeaa6e20d..fd5016d10639b8 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/update.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/update.js @@ -43,7 +43,7 @@ export default function ({ getService }) { expect(resp.body).to.eql({ statusCode: 403, error: 'Forbidden', - message: `Unable to update visualization, missing ${canLogin ? '' : 'action:login,'}action:saved-objects/visualization/update` + message: `Unable to update visualization, missing ${canLogin ? '' : 'action:login,'}action:saved_objects/visualization/update` }); }; From 49a3f497c0196b89bb8fad3c2457e38a482afe4b Mon Sep 17 00:00:00 2001 From: kobelb Date: Mon, 4 Jun 2018 09:30:26 -0400 Subject: [PATCH 13/14] Cleaning up tests and removing without index tests I'm considering the without index tests to be out of scope for the RBAC API testing, and we already have unit coverage for these and integration coverage via the OSS Saved Objects API tests. --- .../apis/saved_objects/bulk_get.js | 108 +----- .../apis/saved_objects/create.js | 99 ++---- .../apis/saved_objects/delete.js | 127 +++---- .../apis/saved_objects/find.js | 334 ++++++------------ .../apis/saved_objects/get.js | 125 +++---- .../apis/saved_objects/index.js | 2 +- .../saved_objects/{ => lib}/authentication.js | 0 .../apis/saved_objects/update.js | 140 +++----- 8 files changed, 277 insertions(+), 658 deletions(-) rename x-pack/test/rbac_api_integration/apis/saved_objects/{ => lib}/authentication.js (100%) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js index c867adf105f47c..18fe5a015dc785 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/bulk_get.js @@ -5,11 +5,10 @@ */ import expect from 'expect.js'; -import { AUTHENTICATION } from './authentication'; +import { AUTHENTICATION } from './lib/authentication'; export default function ({ getService }) { const supertest = getService('supertestWithoutAuth'); - const es = getService('es'); const esArchiver = getService('esArchiver'); const BULK_REQUESTS = [ @@ -69,37 +68,6 @@ export default function ({ getService }) { }); }; - const expect404s = resp => { - expect(resp.body).to.eql({ - saved_objects: [ - { - id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', - type: 'visualization', - error: { - statusCode: 404, - message: 'Not found', - }, - }, - { - id: 'does not exist', - type: 'dashboard', - error: { - statusCode: 404, - message: 'Not found', - }, - }, - { - id: '7.0.0-alpha1', - type: 'config', - error: { - statusCode: 404, - message: 'Not found', - }, - }, - ], - }); - }; - const expectForbidden = resp => { //eslint-disable-next-line max-len const missingActions = `action:login,action:saved_objects/config/bulk_get,action:saved_objects/dashboard/bulk_get,action:saved_objects/visualization/bulk_get`; @@ -110,40 +78,18 @@ export default function ({ getService }) { }); }; - const bulkGetTest = (description, { auth, assert }) => { + const bulkGetTest = (description, { auth, tests }) => { describe(description, () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - - it(`should return ${assert.withIndex.statusCode}`, async () => { - await supertest - .post(`/api/saved_objects/_bulk_get`) - .auth(auth.username, auth.password) - .send(BULK_REQUESTS) - .expect(assert.withIndex.statusCode) - .then(assert.withIndex.response); - }); - }); - - describe('without kibana index', () => { - before( - async () => - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - ); + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); - it(`should return ${assert.withoutIndex.statusCode}`, async () => { - await supertest - .post('/api/saved_objects/_bulk_get') - .auth(auth.username, auth.password) - .send(BULK_REQUESTS) - .expect(assert.withoutIndex.statusCode) - .then(assert.withoutIndex.response); - }); + it(`should return ${tests.default.statusCode}`, async () => { + await supertest + .post(`/api/saved_objects/_bulk_get`) + .auth(auth.username, auth.password) + .send(BULK_REQUESTS) + .expect(tests.default.statusCode) + .then(tests.default.response); }); }); }; @@ -153,14 +99,10 @@ export default function ({ getService }) { username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, }, - assert: { - withIndex: { + tests: { + default: { statusCode: 403, response: expectForbidden, - }, - withoutIndex: { - statusCode: 403, - response: expectForbidden } } }); @@ -170,15 +112,11 @@ export default function ({ getService }) { username: AUTHENTICATION.SUPERUSER.USERNAME, password: AUTHENTICATION.SUPERUSER.PASSWORD, }, - assert: { - withIndex: { + tests: { + default: { statusCode: 200, response: expectResults, }, - withoutIndex: { - statusCode: 200, - response: expect404s - } } }); @@ -187,15 +125,11 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, }, - assert: { - withIndex: { + tests: { + default: { statusCode: 200, response: expectResults, }, - withoutIndex: { - statusCode: 200, - response: expect404s - } } }); @@ -204,15 +138,11 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, }, - assert: { - withIndex: { + tests: { + default: { statusCode: 200, response: expectResults, }, - withoutIndex: { - statusCode: 200, - response: expect404s - } } }); }); diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js index f2663d6dc99171..0db0fc41b5c4a6 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/create.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/create.js @@ -5,11 +5,10 @@ */ import expect from 'expect.js'; -import { AUTHENTICATION } from './authentication'; +import { AUTHENTICATION } from './lib/authentication'; export default function ({ getService }) { const supertest = getService('supertestWithoutAuth'); - const es = getService('es'); const esArchiver = getService('esArchiver'); describe('create', () => { @@ -38,55 +37,21 @@ export default function ({ getService }) { }); }; - const expectIndexCreated = async (indexCreated) => { - expect(await es.indices.exists({ index: '.kibana' })) - .to.be(indexCreated); - }; - - const createTest = (description, { auth, assert }) => { + const createTest = (description, { auth, tests }) => { describe(description, () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - it(`should return ${assert.withIndex.statusCode}`, async () => { - await supertest - .post(`/api/saved_objects/visualization`) - .auth(auth.username, auth.password) - .send({ - attributes: { - title: 'My favorite vis' - } - }) - .expect(assert.withIndex.statusCode) - .then(assert.withIndex.response); - }); - }); - - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + it(`should return ${tests.default.statusCode}`, async () => { + await supertest + .post(`/api/saved_objects/visualization`) + .auth(auth.username, auth.password) + .send({ + attributes: { + title: 'My favorite vis' + } }) - )); - - const statusCode = assert.withoutIndex.statusCode; - const indexCreated = assert.withoutIndex.indexCreated; - it(`should return ${statusCode} and ${ indexCreated ? 'create' : 'not create'} the kibana index`, async () => { - await supertest - .post(`/api/saved_objects/visualization`) - .auth(auth.username, auth.password) - .send({ - attributes: { - title: 'My favorite vis' - } - }) - .expect(assert.withoutIndex.statusCode) - .then(assert.withoutIndex.response); - - await expectIndexCreated(assert.withoutIndex.indexCreated); - }); + .expect(tests.default.statusCode) + .then(tests.default.response); }); }); }; @@ -96,16 +61,11 @@ export default function ({ getService }) { username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, }, - assert: { - withIndex: { + tests: { + default: { statusCode: 403, response: createExpectForbidden(false), }, - withoutIndex: { - statusCode: 403, - response: createExpectForbidden(false), - indexCreated: false - } } }); @@ -114,16 +74,11 @@ export default function ({ getService }) { username: AUTHENTICATION.SUPERUSER.USERNAME, password: AUTHENTICATION.SUPERUSER.PASSWORD, }, - assert: { - withIndex: { + tests: { + default: { statusCode: 200, response: expectResults, }, - withoutIndex: { - statusCode: 200, - response: expectResults, - indexCreated: true - } } }); @@ -132,16 +87,11 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, }, - assert: { - withIndex: { + tests: { + default: { statusCode: 200, response: expectResults, }, - withoutIndex: { - statusCode: 200, - response: expectResults, - indexCreated: true - } } }); @@ -150,16 +100,11 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, }, - assert: { - withIndex: { + tests: { + default: { statusCode: 403, response: createExpectForbidden(true), }, - withoutIndex: { - statusCode: 403, - response: createExpectForbidden(true), - indexCreated: false - } } }); }); diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js index ae085381d02699..7dc2d0dfaaa38f 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js @@ -5,11 +5,10 @@ */ import expect from 'expect.js'; -import { AUTHENTICATION } from './authentication'; +import { AUTHENTICATION } from './lib/authentication'; export default function ({ getService }) { const supertest = getService('supertestWithoutAuth'); - const es = getService('es'); const esArchiver = getService('esArchiver'); describe('delete', () => { @@ -34,46 +33,26 @@ export default function ({ getService }) { }); }; - const deleteTest = (description, { auth, assert }) => { + const deleteTest = (description, { auth, tests }) => { describe(description, () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); - it(`should return ${assert.withIndex.deletingDoc.statusCode} when deleting a doc`, async () => ( - await supertest - .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) - .auth(auth.username, auth.password) - .expect(assert.withIndex.deletingDoc.statusCode) - .then(assert.withIndex.deletingDoc.response) - )); + it(`should return ${tests.actualId.statusCode} when deleting a doc`, async () => ( + await supertest + .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .auth(auth.username, auth.password) + .expect(tests.actualId.statusCode) + .then(tests.actualId.response) + )); - it(`should return generic ${assert.withIndex.deletingUnknownDoc.statusCode} when deleting an unknown doc`, async () => ( - await supertest - .delete(`/api/saved_objects/dashboard/not-a-real-id`) - .auth(auth.username, auth.password) - .expect(assert.withIndex.deletingUnknownDoc.statusCode) - .then(assert.withIndex.deletingUnknownDoc.response) - )); - }); - - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); - - it(`returns generic ${assert.withoutIndex.statusCode} when kibana index is missing`, async () => ( - await supertest - .delete(`/api/saved_objects/dashboard/be3733a0-9efe-11e7-acb3-3dab96693fab`) - .auth(auth.username, auth.password) - .expect(assert.withoutIndex.statusCode) - .then(assert.withoutIndex.response) - )); - }); + it(`should return ${tests.invalidId.statusCode} when deleting an unknown doc`, async () => ( + await supertest + .delete(`/api/saved_objects/dashboard/not-a-real-id`) + .auth(auth.username, auth.password) + .expect(tests.invalidId.statusCode) + .then(tests.invalidId.response) + )); }); }; @@ -82,20 +61,14 @@ export default function ({ getService }) { username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, }, - assert: { - withIndex: { - deletingDoc: { - statusCode: 403, - response: createExpectForbidden(false), - }, - deletingUnknownDoc: { - statusCode: 403, - resposne: createExpectForbidden(false), - } - }, - withoutIndex: { + tests: { + actualId: { statusCode: 403, response: createExpectForbidden(false), + }, + invalidId: { + statusCode: 403, + resposne: createExpectForbidden(false), } } }); @@ -105,20 +78,14 @@ export default function ({ getService }) { username: AUTHENTICATION.SUPERUSER.USERNAME, password: AUTHENTICATION.SUPERUSER.PASSWORD, }, - assert: { - withIndex: { - deletingDoc: { - statusCode: 200, - response: expectEmpty, - }, - deletingUnknownDoc: { - statusCode: 404, - resposne: expectNotFound, - } + tests: { + actualId: { + statusCode: 200, + response: expectEmpty, }, - withoutIndex: { + invalidId: { statusCode: 404, - response: expectNotFound, + resposne: expectNotFound, } } }); @@ -128,20 +95,14 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, }, - assert: { - withIndex: { - deletingDoc: { - statusCode: 200, - response: expectEmpty, - }, - deletingUnknownDoc: { - statusCode: 404, - resposne: expectNotFound, - } + tests: { + actualId: { + statusCode: 200, + response: expectEmpty, }, - withoutIndex: { + invalidId: { statusCode: 404, - response: expectNotFound, + resposne: expectNotFound, } } }); @@ -151,18 +112,12 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, }, - assert: { - withIndex: { - deletingDoc: { - statusCode: 403, - response: createExpectForbidden(true), - }, - deletingUnknownDoc: { - statusCode: 403, - response: createExpectForbidden(true), - } + tests: { + actualId: { + statusCode: 403, + response: createExpectForbidden(true), }, - withoutIndex: { + invalidId: { statusCode: 403, response: createExpectForbidden(true), } diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js index b9421a38017034..72a3fa2ec2bfce 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/find.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/find.js @@ -5,11 +5,10 @@ */ import expect from 'expect.js'; -import { AUTHENTICATION } from './authentication'; +import { AUTHENTICATION } from './lib/authentication'; export default function ({ getService }) { const supertest = getService('supertestWithoutAuth'); - const es = getService('es'); const esArchiver = getService('esArchiver'); describe('find', () => { @@ -49,100 +48,49 @@ export default function ({ getService }) { }); }; - const findTest = (description, { auth, assert }) => { + const findTest = (description, { auth, tests }) => { describe(description, () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - - it(`should return ${assert.withIndex.normal.statusCode} with individual responses`, async () => ( + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + + it(`should return ${tests.normal.statusCode} with ${tests.normal.description}`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&fields=title') + .auth(auth.username, auth.password) + .expect(tests.normal.statusCode) + .then(tests.normal.response) + )); + + describe('unknown type', () => { + it(`should return ${tests.unknownType.statusCode} with ${tests.unknownType.description}`, async () => ( await supertest - .get('/api/saved_objects/_find?type=visualization&fields=title') + .get('/api/saved_objects/_find?type=wigwags') .auth(auth.username, auth.password) - .expect(assert.withIndex.normal.statusCode) - .then(assert.withIndex.normal.response) + .expect(tests.unknownType.statusCode) + .then(tests.unknownType.response) )); - - describe('unknown type', () => { - it(`should return ${assert.withIndex.unknownType.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags') - .auth(auth.username, auth.password) - .expect(assert.withIndex.unknownType.statusCode) - .then(assert.withIndex.unknownType.response) - )); - }); - - describe('page beyond total', () => { - it(`should return ${assert.withIndex.pageBeyondTotal.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') - .auth(auth.username, auth.password) - .expect(assert.withIndex.pageBeyondTotal.statusCode) - .then(assert.withIndex.pageBeyondTotal.response) - )); - }); - - describe('unknown search field', () => { - it(`should return ${assert.withIndex.unknownSearchField.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags&search_fields=a') - .auth(auth.username, auth.password) - .expect(assert.withIndex.unknownSearchField.statusCode) - .then(assert.withIndex.unknownSearchField.response) - )); - }); }); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) + describe('page beyond total', () => { + it(`should return ${tests.pageBeyondTotal.statusCode} with ${tests.pageBeyondTotal.description}`, async () => ( + await supertest + .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') + .auth(auth.username, auth.password) + .expect(tests.pageBeyondTotal.statusCode) + .then(tests.pageBeyondTotal.response) )); + }); - it(`should return ${assert.withoutIndex.normal.statusCode} with empty response`, async () => ( + describe('unknown search field', () => { + it(`should return ${tests.unknownSearchField.statusCode} with ${tests.unknownSearchField.description}`, async () => ( await supertest - .get('/api/saved_objects/_find?type=visualization') + .get('/api/saved_objects/_find?type=wigwags&search_fields=a') .auth(auth.username, auth.password) - .expect(assert.withoutIndex.normal.statusCode) - .then(assert.withoutIndex.normal.response) + .expect(tests.unknownSearchField.statusCode) + .then(tests.unknownSearchField.response) )); - - describe('unknown type', () => { - it(`should return ${assert.withoutIndex.unknownType.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags') - .auth(auth.username, auth.password) - .expect(assert.withoutIndex.unknownType.statusCode) - .then(assert.withoutIndex.unknownType.response) - )); - }); - - describe('page beyond total', () => { - it(`should return ${assert.withoutIndex.pageBeyondTotal.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=visualization&page=100&per_page=100') - .auth(auth.username, auth.password) - .expect(assert.withoutIndex.pageBeyondTotal.statusCode) - .then(assert.withoutIndex.pageBeyondTotal.response) - )); - }); - - describe('unknown search field', () => { - it(`should return ${assert.withoutIndex.unknownSearchField.statusCode} with empty response`, async () => ( - await supertest - .get('/api/saved_objects/_find?type=wigwags&search_fields=a') - .auth(auth.username, auth.password) - .expect(assert.withoutIndex.unknownSearchField.statusCode) - .then(assert.withoutIndex.unknownSearchField.response) - )); - }); }); }); - }; findTest(`not a kibana user`, { @@ -150,42 +98,26 @@ export default function ({ getService }) { username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, }, - assert: { - withIndex: { - normal: { - statusCode: 403, - response: createExpectForbidden(false, 'visualization'), - }, - unknownType: { - statusCode: 403, - response: createExpectForbidden(false, 'wigwags'), - }, - pageBeyondTotal: { - statusCode: 403, - response: createExpectForbidden(false, 'visualization'), - }, - unknownSearchField: { - statusCode: 403, - response: createExpectForbidden(false, 'wigwags'), - }, + tests: { + normal: { + description: 'forbidden login and find visualization message', + statusCode: 403, + response: createExpectForbidden(false, 'visualization'), + }, + unknownType: { + description: 'forbidden login and find wigwags message', + statusCode: 403, + response: createExpectForbidden(false, 'wigwags'), }, - withoutIndex: { - normal: { - statusCode: 403, - response: createExpectForbidden(false, 'visualization'), - }, - unknownType: { - statusCode: 403, - response: createExpectForbidden(false, 'wigwags'), - }, - pageBeyondTotal: { - statusCode: 403, - response: createExpectForbidden(false, 'visualization'), - }, - unknownSearchField: { - statusCode: 403, - response: createExpectForbidden(false, 'wigwags'), - }, + pageBeyondTotal: { + description: 'forbidden login and find visualization message', + statusCode: 403, + response: createExpectForbidden(false, 'visualization'), + }, + unknownSearchField: { + description: 'forbidden login and find wigwags message', + statusCode: 403, + response: createExpectForbidden(false, 'wigwags'), }, } }); @@ -195,44 +127,28 @@ export default function ({ getService }) { username: AUTHENTICATION.SUPERUSER.USERNAME, password: AUTHENTICATION.SUPERUSER.PASSWORD, }, - assert: { - withIndex: { - normal: { - statusCode: 200, - response: expectResults, - }, - unknownType: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - pageBeyondTotal: { - statusCode: 200, - response: createExpectEmpty(100, 100, 1), - }, - unknownSearchField: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, + tests: { + normal: { + description: 'individual responses', + statusCode: 200, + response: expectResults, }, - withoutIndex: { - normal: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - unknownType: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - pageBeyondTotal: { - statusCode: 200, - response: createExpectEmpty(100, 100, 0), - }, - unknownSearchField: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, + unknownType: { + description: 'empty result', + statusCode: 200, + response: createExpectEmpty(1, 20, 0), }, - } + pageBeyondTotal: { + description: 'empty result', + statusCode: 200, + response: createExpectEmpty(100, 100, 1), + }, + unknownSearchField: { + description: 'empty result', + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + }, }); findTest(`kibana rbac user`, { @@ -240,44 +156,28 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, }, - assert: { - withIndex: { - normal: { - statusCode: 200, - response: expectResults, - }, - unknownType: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - pageBeyondTotal: { - statusCode: 200, - response: createExpectEmpty(100, 100, 1), - }, - unknownSearchField: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, + tests: { + normal: { + description: 'individual responses', + statusCode: 200, + response: expectResults, }, - withoutIndex: { - normal: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - unknownType: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - pageBeyondTotal: { - statusCode: 200, - response: createExpectEmpty(100, 100, 0), - }, - unknownSearchField: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, + unknownType: { + description: 'empty result', + statusCode: 200, + response: createExpectEmpty(1, 20, 0), }, - } + pageBeyondTotal: { + description: 'empty result', + statusCode: 200, + response: createExpectEmpty(100, 100, 1), + }, + unknownSearchField: { + description: 'empty result', + statusCode: 200, + response: createExpectEmpty(1, 20, 0), + }, + }, }); findTest(`kibana rbac dashboard only user`, { @@ -285,42 +185,26 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, }, - assert: { - withIndex: { - normal: { - statusCode: 200, - response: expectResults, - }, - unknownType: { - statusCode: 403, - response: createExpectForbidden(true, 'wigwags'), - }, - pageBeyondTotal: { - statusCode: 200, - response: createExpectEmpty(100, 100, 1), - }, - unknownSearchField: { - statusCode: 403, - response: createExpectForbidden(true, 'wigwags'), - }, + tests: { + normal: { + description: 'individual responses', + statusCode: 200, + response: expectResults, + }, + unknownType: { + description: 'forbidden find wigwags message', + statusCode: 403, + response: createExpectForbidden(true, 'wigwags'), + }, + pageBeyondTotal: { + description: 'empty result', + statusCode: 200, + response: createExpectEmpty(100, 100, 1), }, - withoutIndex: { - normal: { - statusCode: 200, - response: createExpectEmpty(1, 20, 0), - }, - unknownType: { - statusCode: 403, - response: createExpectForbidden(true, 'wigwags'), - }, - pageBeyondTotal: { - statusCode: 200, - response: createExpectEmpty(100, 100, 0), - }, - unknownSearchField: { - statusCode: 403, - response: createExpectForbidden(true, 'wigwags'), - }, + unknownSearchField: { + description: 'forbidden find wigwags message', + statusCode: 403, + response: createExpectForbidden(true, 'wigwags'), }, } }); diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js index 77bedd1bb55ef9..e5a462d30d30cb 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/get.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/get.js @@ -5,11 +5,10 @@ */ import expect from 'expect.js'; -import { AUTHENTICATION } from './authentication'; +import { AUTHENTICATION } from './lib/authentication'; export default function ({ getService }) { const supertest = getService('supertestWithoutAuth'); - const es = getService('es'); const esArchiver = getService('esArchiver'); describe('get', () => { @@ -48,46 +47,26 @@ export default function ({ getService }) { }); }; - const getTest = (description, { auth, assert }) => { + const getTest = (description, { auth, tests }) => { describe(description, () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); - it('should return 200', async () => ( - await supertest - .get(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) - .auth(auth.username, auth.password) - .expect(assert.withIndex.exists.statusCode) - .then(assert.withIndex.exists.response) - )); - - describe('doc does not exist', () => { - it('should return same generic error as when index does not exist', async () => ( - await supertest - .get(`/api/saved_objects/visualization/foobar`) - .auth(auth.username, auth.password) - .expect(assert.withIndex.doesntExist.statusCode) - .then(assert.withIndex.doesntExist.response) - )); - }); - }); + it(`should return ${tests.exists.statusCode}`, async () => ( + await supertest + .get(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .auth(auth.username, auth.password) + .expect(tests.exists.statusCode) + .then(tests.exists.response) + )); - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], - }) - )); - - it('should return basic 404 without mentioning index', async () => ( + describe('document does not exist', () => { + it(`should return ${tests.doesntExist.statusCode}`, async () => ( await supertest - .get('/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab') + .get(`/api/saved_objects/visualization/foobar`) .auth(auth.username, auth.password) - .expect(assert.withoutIndex.statusCode) - .then(assert.withoutIndex.response) + .expect(tests.doesntExist.statusCode) + .then(tests.doesntExist.response) )); }); }); @@ -98,21 +77,15 @@ export default function ({ getService }) { username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, }, - assert: { - withIndex: { - exists: { - statusCode: 403, - response: expectForbidden, - }, - doesntExist: { - statusCode: 403, - response: expectForbidden, - }, + tests: { + exists: { + statusCode: 403, + response: expectForbidden, }, - withoutIndex: { + doesntExist: { statusCode: 403, response: expectForbidden, - } + }, } }); @@ -121,21 +94,15 @@ export default function ({ getService }) { username: AUTHENTICATION.SUPERUSER.USERNAME, password: AUTHENTICATION.SUPERUSER.PASSWORD, }, - assert: { - withIndex: { - exists: { - statusCode: 200, - response: expectResults, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, + tests: { + exists: { + statusCode: 200, + response: expectResults, }, - withoutIndex: { + doesntExist: { statusCode: 404, response: expectNotFound, - } + }, } }); @@ -144,21 +111,15 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, }, - assert: { - withIndex: { - exists: { - statusCode: 200, - response: expectResults, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, + tests: { + exists: { + statusCode: 200, + response: expectResults, }, - withoutIndex: { + doesntExist: { statusCode: 404, response: expectNotFound, - } + }, } }); @@ -167,21 +128,15 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, }, - assert: { - withIndex: { - exists: { - statusCode: 200, - response: expectResults, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, + tests: { + exists: { + statusCode: 200, + response: expectResults, }, - withoutIndex: { + doesntExist: { statusCode: 404, response: expectNotFound, - } + }, } }); }); diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js index 7ac9d5e7c77349..644bf23220648e 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/index.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/index.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AUTHENTICATION } from "./authentication"; +import { AUTHENTICATION } from "./lib/authentication"; export default function ({ loadTestFile, getService }) { const es = getService('es'); diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js b/x-pack/test/rbac_api_integration/apis/saved_objects/lib/authentication.js similarity index 100% rename from x-pack/test/rbac_api_integration/apis/saved_objects/authentication.js rename to x-pack/test/rbac_api_integration/apis/saved_objects/lib/authentication.js diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/update.js b/x-pack/test/rbac_api_integration/apis/saved_objects/update.js index fd5016d10639b8..a9f5f0ab81aaba 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/update.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/update.js @@ -5,11 +5,10 @@ */ import expect from 'expect.js'; -import { AUTHENTICATION } from './authentication'; +import { AUTHENTICATION } from './lib/authentication'; export default function ({ getService }) { const supertest = getService('supertestWithoutAuth'); - const es = getService('es'); const esArchiver = getService('esArchiver'); describe('update', () => { @@ -47,61 +46,36 @@ export default function ({ getService }) { }); }; - const updateTest = (description, { auth, assert }) => { + const updateTest = (description, { auth, tests }) => { describe(description, () => { - describe('with kibana index', () => { - before(() => esArchiver.load('saved_objects/basic')); - after(() => esArchiver.unload('saved_objects/basic')); - it('should return 200', async () => { - await supertest - .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) - .auth(auth.username, auth.password) - .send({ - attributes: { - title: 'My second favorite vis' - } - }) - .expect(assert.withIndex.exists.statusCode) - .then(assert.withIndex.exists.response); - }); - - describe('unknown id', () => { - it('should return a generic 404', async () => { - await supertest - .put(`/api/saved_objects/visualization/not an id`) - .auth(auth.username, auth.password) - .send({ - attributes: { - title: 'My second favorite vis' - } - }) - .expect(assert.withIndex.doesntExist.statusCode) - .then(assert.withIndex.doesntExist.response); - }); - }); - }); - - describe('without kibana index', () => { - before(async () => ( - // just in case the kibana server has recreated it - await es.indices.delete({ - index: '.kibana', - ignore: [404], + before(() => esArchiver.load('saved_objects/basic')); + after(() => esArchiver.unload('saved_objects/basic')); + it(`should return ${tests.exists.statusCode}`, async () => { + await supertest + .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .auth(auth.username, auth.password) + .send({ + attributes: { + title: 'My second favorite vis' + } }) - )); + .expect(tests.exists.statusCode) + .then(tests.exists.response); + }); - it('should return generic 404', async () => ( + describe('unknown id', () => { + it(`should return ${tests.doesntExist.statusCode}`, async () => { await supertest - .put(`/api/saved_objects/visualization/dd7caf20-9efd-11e7-acb3-3dab96693fab`) + .put(`/api/saved_objects/visualization/not an id`) .auth(auth.username, auth.password) .send({ attributes: { title: 'My second favorite vis' } }) - .expect(assert.withoutIndex.statusCode) - .then(assert.withoutIndex.response) - )); + .expect(tests.doesntExist.statusCode) + .then(tests.doesntExist.response); + }); }); }); }; @@ -111,21 +85,15 @@ export default function ({ getService }) { username: AUTHENTICATION.NOT_A_KIBANA_USER.USERNAME, password: AUTHENTICATION.NOT_A_KIBANA_USER.PASSWORD, }, - assert: { - withIndex: { - exists: { - statusCode: 403, - response: createExpectForbidden(false), - }, - doesntExist: { - statusCode: 403, - response: createExpectForbidden(false), - }, + tests: { + exists: { + statusCode: 403, + response: createExpectForbidden(false), }, - withoutIndex: { + doesntExist: { statusCode: 403, response: createExpectForbidden(false), - } + }, } }); @@ -134,21 +102,15 @@ export default function ({ getService }) { username: AUTHENTICATION.SUPERUSER.USERNAME, password: AUTHENTICATION.SUPERUSER.PASSWORD, }, - assert: { - withIndex: { - exists: { - statusCode: 200, - response: expectResults, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, + tests: { + exists: { + statusCode: 200, + response: expectResults, }, - withoutIndex: { + doesntExist: { statusCode: 404, response: expectNotFound, - } + }, } }); @@ -157,21 +119,15 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_USER.PASSWORD, }, - assert: { - withIndex: { - exists: { - statusCode: 200, - response: expectResults, - }, - doesntExist: { - statusCode: 404, - response: expectNotFound, - }, + tests: { + exists: { + statusCode: 200, + response: expectResults, }, - withoutIndex: { + doesntExist: { statusCode: 404, response: expectNotFound, - } + }, } }); @@ -180,21 +136,15 @@ export default function ({ getService }) { username: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.USERNAME, password: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER.PASSWORD, }, - assert: { - withIndex: { - exists: { - statusCode: 403, - response: createExpectForbidden(true), - }, - doesntExist: { - statusCode: 403, - response: createExpectForbidden(true), - }, + tests: { + exists: { + statusCode: 403, + response: createExpectForbidden(true), }, - withoutIndex: { + doesntExist: { statusCode: 403, response: createExpectForbidden(true), - } + }, } }); From dcd7285e4da3068507f8d9f217b870ede3858ae9 Mon Sep 17 00:00:00 2001 From: kobelb Date: Mon, 4 Jun 2018 15:59:24 -0400 Subject: [PATCH 14/14] Fixing misspelling --- .../test/rbac_api_integration/apis/saved_objects/delete.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js index 7dc2d0dfaaa38f..ea73c927b869e5 100644 --- a/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js +++ b/x-pack/test/rbac_api_integration/apis/saved_objects/delete.js @@ -68,7 +68,7 @@ export default function ({ getService }) { }, invalidId: { statusCode: 403, - resposne: createExpectForbidden(false), + response: createExpectForbidden(false), } } }); @@ -85,7 +85,7 @@ export default function ({ getService }) { }, invalidId: { statusCode: 404, - resposne: expectNotFound, + response: expectNotFound, } } }); @@ -102,7 +102,7 @@ export default function ({ getService }) { }, invalidId: { statusCode: 404, - resposne: expectNotFound, + response: expectNotFound, } } });