mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* Add route to update alert api key * Allow updating an API key when the alert is disabled * Fix typecheck failures * Fix broken file references
This commit is contained in:
parent
9a11739fdf
commit
979fd4686e
11 changed files with 278 additions and 0 deletions
|
@ -17,6 +17,7 @@ const createAlertsClientMock = () => {
|
|||
update: jest.fn(),
|
||||
enable: jest.fn(),
|
||||
disable: jest.fn(),
|
||||
updateApiKey: jest.fn(),
|
||||
};
|
||||
return mocked;
|
||||
};
|
||||
|
|
|
@ -1247,3 +1247,35 @@ describe('update()', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateApiKey()', () => {
|
||||
test('updates the API key for the alert', async () => {
|
||||
const alertsClient = new AlertsClient(alertsClientParams);
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
interval: '10s',
|
||||
alertTypeId: '2',
|
||||
enabled: true,
|
||||
},
|
||||
references: [],
|
||||
});
|
||||
alertsClientParams.createAPIKey.mockResolvedValueOnce({
|
||||
created: true,
|
||||
result: { id: '123', api_key: 'abc' },
|
||||
});
|
||||
|
||||
await alertsClient.updateApiKey({ id: '1' });
|
||||
expect(savedObjectsClient.update).toHaveBeenCalledWith(
|
||||
'alert',
|
||||
'1',
|
||||
{
|
||||
apiKey: Buffer.from('123:abc').toString('base64'),
|
||||
apiKeyOwner: 'elastic',
|
||||
updatedBy: 'elastic',
|
||||
},
|
||||
{ references: [] }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -221,6 +221,27 @@ export class AlertsClient {
|
|||
return this.getAlertFromRaw(id, updatedObject.attributes, updatedObject.references);
|
||||
}
|
||||
|
||||
public async updateApiKey({ id }: { id: string }) {
|
||||
const { references } = await this.savedObjectsClient.get('alert', id);
|
||||
|
||||
const apiKey = await this.createAPIKey();
|
||||
const username = await this.getUserName();
|
||||
await this.savedObjectsClient.update(
|
||||
'alert',
|
||||
id,
|
||||
{
|
||||
updatedBy: username,
|
||||
apiKeyOwner: apiKey.created ? username : null,
|
||||
apiKey: apiKey.created
|
||||
? Buffer.from(`${apiKey.result.id}:${apiKey.result.api_key}`).toString('base64')
|
||||
: null,
|
||||
},
|
||||
{
|
||||
references,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async enable({ id }: { id: string }) {
|
||||
const existingObject = await this.savedObjectsClient.get('alert', id);
|
||||
if (existingObject.attributes.enabled === false) {
|
||||
|
|
|
@ -27,6 +27,7 @@ import {
|
|||
updateAlertRoute,
|
||||
enableAlertRoute,
|
||||
disableAlertRoute,
|
||||
updateApiKeyRoute,
|
||||
} from './routes';
|
||||
|
||||
// Extend PluginProperties to indicate which plugins are guaranteed to exist
|
||||
|
@ -125,6 +126,7 @@ export function init(server: Server) {
|
|||
updateAlertRoute(server);
|
||||
enableAlertRoute(server);
|
||||
disableAlertRoute(server);
|
||||
updateApiKeyRoute(server);
|
||||
|
||||
// Expose functions
|
||||
server.decorate('request', 'getAlertsClient', function() {
|
||||
|
|
|
@ -12,3 +12,4 @@ export { listAlertTypesRoute } from './list_alert_types';
|
|||
export { updateAlertRoute } from './update';
|
||||
export { enableAlertRoute } from './enable';
|
||||
export { disableAlertRoute } from './disable';
|
||||
export { updateApiKeyRoute } from './update_api_key';
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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 { createMockServer } from './_mock_server';
|
||||
import { updateApiKeyRoute } from './update_api_key';
|
||||
|
||||
const { server, alertsClient } = createMockServer();
|
||||
updateApiKeyRoute(server);
|
||||
|
||||
test('updates api key for an alert', async () => {
|
||||
const request = {
|
||||
method: 'POST',
|
||||
url: '/api/alert/1/_update_api_key',
|
||||
};
|
||||
|
||||
const { statusCode } = await server.inject(request);
|
||||
expect(statusCode).toBe(204);
|
||||
expect(alertsClient.updateApiKey).toHaveBeenCalledWith({ id: '1' });
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 Hapi from 'hapi';
|
||||
|
||||
export function updateApiKeyRoute(server: Hapi.Server) {
|
||||
server.route({
|
||||
method: 'POST',
|
||||
path: '/api/alert/{id}/_update_api_key',
|
||||
options: {
|
||||
tags: ['access:alerting-all'],
|
||||
response: {
|
||||
emptyStatusCode: 204,
|
||||
},
|
||||
},
|
||||
async handler(request: Hapi.Request, h: Hapi.ResponseToolkit) {
|
||||
const alertsClient = request.getAlertsClient!();
|
||||
await alertsClient.updateApiKey({ id: request.params.id });
|
||||
return h.response();
|
||||
},
|
||||
});
|
||||
}
|
|
@ -17,6 +17,7 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./get'));
|
||||
loadTestFile(require.resolve('./list_alert_types'));
|
||||
loadTestFile(require.resolve('./update'));
|
||||
loadTestFile(require.resolve('./update_api_key'));
|
||||
loadTestFile(require.resolve('./alerts'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { UserAtSpaceScenarios, Spaces } from '../../scenarios';
|
||||
import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib';
|
||||
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function createUpdateApiKeyTests({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
const supertestWithoutAuth = getService('supertestWithoutAuth');
|
||||
|
||||
describe('update_api_key', () => {
|
||||
const objectRemover = new ObjectRemover(supertest);
|
||||
const OtherSpace = Spaces.find(space => space.id === 'other');
|
||||
|
||||
if (!OtherSpace) {
|
||||
throw new Error('Space "other" not defined in scenarios');
|
||||
}
|
||||
|
||||
after(() => objectRemover.removeAll());
|
||||
|
||||
for (const scenario of UserAtSpaceScenarios) {
|
||||
const { user, space } = scenario;
|
||||
describe(scenario.id, () => {
|
||||
it('should handle update alert api key request appropriately', async () => {
|
||||
const { body: createdAlert } = await supertest
|
||||
.post(`${getUrlPrefix(space.id)}/api/alert`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send(getTestAlertData())
|
||||
.expect(200);
|
||||
objectRemover.add(space.id, createdAlert.id, 'alert');
|
||||
|
||||
const response = await supertestWithoutAuth
|
||||
.post(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}/_update_api_key`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.auth(user.username, user.password);
|
||||
|
||||
switch (scenario.id) {
|
||||
case 'no_kibana_privileges at space1':
|
||||
case 'space_1_all at space2':
|
||||
case 'global_read at space1':
|
||||
expect(response.statusCode).to.eql(404);
|
||||
expect(response.body).to.eql({
|
||||
statusCode: 404,
|
||||
error: 'Not Found',
|
||||
message: 'Not Found',
|
||||
});
|
||||
break;
|
||||
case 'superuser at space1':
|
||||
case 'space_1_all at space1':
|
||||
expect(response.statusCode).to.eql(204);
|
||||
expect(response.body).to.eql('');
|
||||
const { body: updatedAlert } = await supertestWithoutAuth
|
||||
.get(`${getUrlPrefix(space.id)}/api/alert/${createdAlert.id}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.auth(user.username, user.password)
|
||||
.expect(200);
|
||||
expect(updatedAlert.apiKeyOwner).to.eql(user.username);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`);
|
||||
}
|
||||
});
|
||||
|
||||
it(`shouldn't update alert api key from another space`, async () => {
|
||||
const { body: createdAlert } = await supertest
|
||||
.post(`${getUrlPrefix(space.id)}/api/alert`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send(getTestAlertData())
|
||||
.expect(200);
|
||||
objectRemover.add(space.id, createdAlert.id, 'alert');
|
||||
|
||||
const response = await supertestWithoutAuth
|
||||
.post(`${getUrlPrefix(OtherSpace.id)}/api/alert/${createdAlert.id}/_update_api_key`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.auth(user.username, user.password);
|
||||
|
||||
expect(response.statusCode).to.eql(404);
|
||||
switch (scenario.id) {
|
||||
case 'no_kibana_privileges at space1':
|
||||
case 'space_1_all at space2':
|
||||
case 'global_read at space1':
|
||||
case 'space_1_all at space1':
|
||||
expect(response.body).to.eql({
|
||||
statusCode: 404,
|
||||
error: 'Not Found',
|
||||
message: 'Not Found',
|
||||
});
|
||||
break;
|
||||
case 'superuser at space1':
|
||||
expect(response.body).to.eql({
|
||||
statusCode: 404,
|
||||
error: 'Not Found',
|
||||
message: `Saved object [alert/${createdAlert.id}] not found`,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
|
@ -17,6 +17,7 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./get'));
|
||||
loadTestFile(require.resolve('./list_alert_types'));
|
||||
loadTestFile(require.resolve('./update'));
|
||||
loadTestFile(require.resolve('./update_api_key'));
|
||||
loadTestFile(require.resolve('./alerts'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { Spaces } from '../../scenarios';
|
||||
import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib';
|
||||
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
||||
|
||||
/**
|
||||
* Eventhough security is disabled, this test checks the API behavior.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function createUpdateApiKeyTests({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('update_api_key', () => {
|
||||
const objectRemover = new ObjectRemover(supertest);
|
||||
|
||||
after(() => objectRemover.removeAll());
|
||||
|
||||
it('should handle update alert api key appropriately', async () => {
|
||||
const { body: createdAlert } = await supertest
|
||||
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send(getTestAlertData())
|
||||
.expect(200);
|
||||
objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert');
|
||||
|
||||
await supertest
|
||||
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}/_update_api_key`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.expect(204, '');
|
||||
|
||||
const { body: updatedAlert } = await supertest
|
||||
.get(`${getUrlPrefix(Spaces.space1.id)}/api/alert/${createdAlert.id}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.expect(200);
|
||||
expect(updatedAlert.apiKeyOwner).to.eql(null);
|
||||
});
|
||||
|
||||
it(`shouldn't update alert api key from another space`, async () => {
|
||||
const { body: createdAlert } = await supertest
|
||||
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alert`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send(getTestAlertData())
|
||||
.expect(200);
|
||||
objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert');
|
||||
|
||||
await supertest
|
||||
.post(`${getUrlPrefix(Spaces.other.id)}/api/alert/${createdAlert.id}/_update_api_key`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.expect(404, {
|
||||
statusCode: 404,
|
||||
error: 'Not Found',
|
||||
message: `Saved object [alert/${createdAlert.id}] not found`,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue