Skip to content

Commit

Permalink
ensure save/edit buttons in triggers UI is based on RBAC auth
Browse files Browse the repository at this point in the history
  • Loading branch information
gmmorris committed Jul 1, 2020
1 parent 036a082 commit 33ef0b0
Show file tree
Hide file tree
Showing 19 changed files with 566 additions and 204 deletions.
3 changes: 2 additions & 1 deletion examples/alerting_example/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { PluginSetupContract as FeaturesPluginSetup } from '../../../x-pack/plug
import { alertType as alwaysFiringAlert } from './alert_types/always_firing';
import { alertType as peopleInSpaceAlert } from './alert_types/astros';
import { INDEX_THRESHOLD_ID } from '../../../x-pack/plugins/alerting_builtins/server';
import { ALERTING_EXAMPLE_APP_ID } from '../common/constants';

// this plugin's dependendencies
export interface AlertingExampleDeps {
Expand All @@ -38,7 +39,7 @@ export class AlertingExamplePlugin implements Plugin<void, void, AlertingExample
alerts.registerType(peopleInSpaceAlert);

features.registerFeature({
id: 'alertsExample',
id: ALERTING_EXAMPLE_APP_ID,
name: i18n.translate('alertsExample.featureRegistry.alertsExampleFeatureName', {
defaultMessage: 'Alerts Example',
}),
Expand Down
22 changes: 16 additions & 6 deletions x-pack/plugins/alerts/server/alerts_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2196,7 +2196,9 @@ describe('find()', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
producer: 'alerts',
authorizedConsumers: ['myApp'],
authorizedConsumers: {
myApp: { read: true, all: true },
},
},
])
);
Expand Down Expand Up @@ -3712,6 +3714,12 @@ describe('listAlertTypes', () => {
};
const setOfAlertTypes = new Set([myAppAlertType, alertingAlertType]);

const authorizedConsumers = {
alerts: { read: true, all: true },
myApp: { read: true, all: true },
myOtherApp: { read: true, all: true },
};

beforeEach(() => {
alertsClient = new AlertsClient(alertsClientParams);
});
Expand All @@ -3720,14 +3728,14 @@ describe('listAlertTypes', () => {
alertTypeRegistry.list.mockReturnValue(setOfAlertTypes);
authorization.filterByAlertTypeAuthorization.mockResolvedValue(
new Set([
{ ...myAppAlertType, authorizedConsumers: ['alerts', 'myApp', 'myOtherApp'] },
{ ...alertingAlertType, authorizedConsumers: ['alerts', 'myApp', 'myOtherApp'] },
{ ...myAppAlertType, authorizedConsumers },
{ ...alertingAlertType, authorizedConsumers },
])
);
expect(await alertsClient.listAlertTypes()).toEqual(
new Set([
{ ...myAppAlertType, authorizedConsumers: ['alerts', 'myApp', 'myOtherApp'] },
{ ...alertingAlertType, authorizedConsumers: ['alerts', 'myApp', 'myOtherApp'] },
{ ...myAppAlertType, authorizedConsumers },
{ ...alertingAlertType, authorizedConsumers },
])
);
});
Expand Down Expand Up @@ -3762,7 +3770,9 @@ describe('listAlertTypes', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
producer: 'alerts',
authorizedConsumers: ['myApp'],
authorizedConsumers: {
myApp: { read: true, all: true },
},
},
]);
authorization.filterByAlertTypeAuthorization.mockResolvedValue(authorizedTypes);
Expand Down
46 changes: 29 additions & 17 deletions x-pack/plugins/alerts/server/alerts_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ import { TaskManagerStartContract } from '../../task_manager/server';
import { taskInstanceToAlertTaskInstance } from './task_runner/alert_task_instance';
import { deleteTaskIfItExists } from './lib/delete_task_if_it_exists';
import { RegistryAlertType } from './alert_type_registry';
import { AlertsAuthorization } from './authorization/alerts_authorization';
import {
AlertsAuthorization,
WriteOperations,
ReadOperations,
} from './authorization/alerts_authorization';

export interface RegistryAlertTypeWithAuth extends RegistryAlertType {
authorizedConsumers: string[];
Expand Down Expand Up @@ -172,7 +176,11 @@ export class AlertsClient {
}

public async create({ data, options }: CreateOptions): Promise<Alert> {
await this.authorization.ensureAuthorized(data.alertTypeId, data.consumer, 'create');
await this.authorization.ensureAuthorized(
data.alertTypeId,
data.consumer,
WriteOperations.Create
);

// Throws an error if alert type isn't registered
const alertType = this.alertTypeRegistry.get(data.alertTypeId);
Expand Down Expand Up @@ -233,14 +241,18 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
result.attributes.alertTypeId,
result.attributes.consumer,
'get'
ReadOperations.Get
);
return this.getAlertFromRaw(result.id, result.attributes, result.updated_at, result.references);
}

public async getAlertState({ id }: { id: string }): Promise<AlertTaskState | void> {
const alert = await this.get({ id });
await this.authorization.ensureAuthorized(alert.alertTypeId, alert.consumer, 'getAlertState');
await this.authorization.ensureAuthorized(
alert.alertTypeId,
alert.consumer,
ReadOperations.GetAlertState
);
if (alert.scheduledTaskId) {
const { state } = taskInstanceToAlertTaskInstance(
await this.taskManager.get(alert.scheduledTaskId),
Expand Down Expand Up @@ -317,7 +329,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
attributes.alertTypeId,
attributes.consumer,
'delete'
WriteOperations.Delete
);

const removeResult = await this.unsecuredSavedObjectsClient.delete('alert', id);
Expand Down Expand Up @@ -348,7 +360,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
alertSavedObject.attributes.alertTypeId,
alertSavedObject.attributes.consumer,
'update'
WriteOperations.Update
);

const updateResult = await this.updateAlert({ id, data }, alertSavedObject);
Expand Down Expand Up @@ -454,7 +466,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
attributes.alertTypeId,
attributes.consumer,
'updateApiKey'
WriteOperations.UpdateApiKey
);

const username = await this.getUserName();
Expand Down Expand Up @@ -516,7 +528,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
attributes.alertTypeId,
attributes.consumer,
'enable'
WriteOperations.Enable
);

if (attributes.enabled === false) {
Expand Down Expand Up @@ -568,7 +580,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
attributes.alertTypeId,
attributes.consumer,
'disable'
WriteOperations.Disable
);

if (attributes.enabled === true) {
Expand Down Expand Up @@ -600,7 +612,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
attributes.alertTypeId,
attributes.consumer,
'muteAll'
WriteOperations.MuteAll
);

await this.unsecuredSavedObjectsClient.update('alert', id, {
Expand All @@ -615,7 +627,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
attributes.alertTypeId,
attributes.consumer,
'unmuteAll'
WriteOperations.UnmuteAll
);

await this.unsecuredSavedObjectsClient.update('alert', id, {
Expand All @@ -634,7 +646,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
attributes.alertTypeId,
attributes.consumer,
'muteInstance'
WriteOperations.MuteInstance
);

const mutedInstanceIds = attributes.mutedInstanceIds || [];
Expand Down Expand Up @@ -666,7 +678,7 @@ export class AlertsClient {
await this.authorization.ensureAuthorized(
attributes.alertTypeId,
attributes.consumer,
'unmuteInstance'
WriteOperations.UnmuteInstance
);
const mutedInstanceIds = attributes.mutedInstanceIds || [];
if (!attributes.muteAll && mutedInstanceIds.includes(alertInstanceId)) {
Expand All @@ -684,10 +696,10 @@ export class AlertsClient {
}

public async listAlertTypes() {
return await this.authorization.filterByAlertTypeAuthorization(
this.alertTypeRegistry.list(),
'get'
);
return await this.authorization.filterByAlertTypeAuthorization(this.alertTypeRegistry.list(), [
ReadOperations.Get,
WriteOperations.Create,
]);
}

private async scheduleAlert(id: string, alertTypeId: string) {
Expand Down
Loading

0 comments on commit 33ef0b0

Please sign in to comment.