[Alerting] Alerting authorization should always exempt alerts consumer (#108220) (#108258)

* Reverting changes to genericize exempt consumer id

* Adding unit test for find auth filter when user has no privileges

Co-authored-by: ymao1 <ying.mao@elastic.co>
This commit is contained in:
Kibana Machine 2021-08-11 17:14:38 -04:00 committed by GitHub
parent b3a714db5d
commit 3ad2da42aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 302 deletions

View file

@ -75,35 +75,6 @@ test('creates an alerting authorization client with proper constructor arguments
auditLogger: expect.any(AlertingAuthorizationAuditLogger),
getSpace: expect.any(Function),
getSpaceId: expect.any(Function),
exemptConsumerIds: [],
});
expect(AlertingAuthorizationAuditLogger).toHaveBeenCalled();
expect(securityPluginSetup.audit.getLogger).toHaveBeenCalledWith(ALERTS_FEATURE_ID);
});
test('creates an alerting authorization client with proper constructor arguments when exemptConsumerIds are specified', async () => {
const factory = new AlertingAuthorizationClientFactory();
factory.initialize({
securityPluginSetup,
securityPluginStart,
...alertingAuthorizationClientFactoryParams,
});
const request = KibanaRequest.from(fakeRequest);
const { AlertingAuthorizationAuditLogger } = jest.requireMock('./authorization/audit_logger');
factory.create(request, ['exemptConsumerA', 'exemptConsumerB']);
const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization');
expect(AlertingAuthorization).toHaveBeenCalledWith({
request,
authorization: securityPluginStart.authz,
ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry,
features: alertingAuthorizationClientFactoryParams.features,
auditLogger: expect.any(AlertingAuthorizationAuditLogger),
getSpace: expect.any(Function),
getSpaceId: expect.any(Function),
exemptConsumerIds: ['exemptConsumerA', 'exemptConsumerB'],
});
expect(AlertingAuthorizationAuditLogger).toHaveBeenCalled();
@ -126,7 +97,6 @@ test('creates an alerting authorization client with proper constructor arguments
auditLogger: expect.any(AlertingAuthorizationAuditLogger),
getSpace: expect.any(Function),
getSpaceId: expect.any(Function),
exemptConsumerIds: [],
});
expect(AlertingAuthorizationAuditLogger).toHaveBeenCalled();

View file

@ -45,7 +45,7 @@ export class AlertingAuthorizationClientFactory {
this.getSpaceId = options.getSpaceId;
}
public create(request: KibanaRequest, exemptConsumerIds: string[] = []): AlertingAuthorization {
public create(request: KibanaRequest): AlertingAuthorization {
const { securityPluginSetup, securityPluginStart, features } = this;
return new AlertingAuthorization({
authorization: securityPluginStart?.authz,
@ -57,7 +57,6 @@ export class AlertingAuthorizationClientFactory {
auditLogger: new AlertingAuthorizationAuditLogger(
securityPluginSetup?.audit.getLogger(ALERTS_FEATURE_ID)
),
exemptConsumerIds,
});
}
}

View file

@ -37,8 +37,6 @@ const realAuditLogger = new AlertingAuthorizationAuditLogger();
const getSpace = jest.fn();
const getSpaceId = () => 'space1';
const exemptConsumerIds: string[] = [];
const mockAuthorizationAction = (
type: string,
app: string,
@ -235,7 +233,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
expect(getSpace).toHaveBeenCalledWith(request);
@ -251,7 +248,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
await alertAuthorization.ensureAuthorized({
@ -275,7 +271,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
await alertAuthorization.ensureAuthorized({
@ -302,7 +297,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
checkPrivileges.mockResolvedValueOnce({
@ -359,7 +353,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
checkPrivileges.mockResolvedValueOnce({
@ -402,7 +395,7 @@ describe('AlertingAuthorization', () => {
`);
});
test('ensures the user has privileges to execute rules for the specified rule type and operation without consumer when consumer is exempt', async () => {
test('ensures the user has privileges to execute rules for the specified rule type and operation without consumer when consumer is alerts', async () => {
const { authorization } = mockSecurity();
const checkPrivileges: jest.MockedFunction<
ReturnType<typeof authorization.checkPrivilegesDynamicallyWithRequest>
@ -416,7 +409,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds: ['exemptConsumer'],
});
checkPrivileges.mockResolvedValueOnce({
@ -427,7 +419,7 @@ describe('AlertingAuthorization', () => {
await alertAuthorization.ensureAuthorized({
ruleTypeId: 'myType',
consumer: 'exemptConsumer',
consumer: 'alerts',
operation: WriteOperations.Create,
entity: AlertingAuthorizationEntity.Rule,
});
@ -437,7 +429,7 @@ describe('AlertingAuthorization', () => {
expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(2);
expect(authorization.actions.alerting.get).toHaveBeenCalledWith(
'myType',
'exemptConsumer',
'alerts',
'rule',
'create'
);
@ -458,14 +450,14 @@ describe('AlertingAuthorization', () => {
"some-user",
"myType",
0,
"exemptConsumer",
"alerts",
"create",
"rule",
]
`);
});
test('ensures the user has privileges to execute alerts for the specified rule type and operation without consumer when consumer is exempt', async () => {
test('ensures the user has privileges to execute alerts for the specified rule type and operation without consumer when consumer is alerts', async () => {
const { authorization } = mockSecurity();
const checkPrivileges: jest.MockedFunction<
ReturnType<typeof authorization.checkPrivilegesDynamicallyWithRequest>
@ -479,7 +471,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds: ['exemptConsumer'],
});
checkPrivileges.mockResolvedValueOnce({
@ -490,7 +481,7 @@ describe('AlertingAuthorization', () => {
await alertAuthorization.ensureAuthorized({
ruleTypeId: 'myType',
consumer: 'exemptConsumer',
consumer: 'alerts',
operation: WriteOperations.Update,
entity: AlertingAuthorizationEntity.Alert,
});
@ -500,7 +491,7 @@ describe('AlertingAuthorization', () => {
expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(2);
expect(authorization.actions.alerting.get).toHaveBeenCalledWith(
'myType',
'exemptConsumer',
'alerts',
'alert',
'update'
);
@ -521,7 +512,7 @@ describe('AlertingAuthorization', () => {
"some-user",
"myType",
0,
"exemptConsumer",
"alerts",
"update",
"alert",
]
@ -548,7 +539,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
await alertAuthorization.ensureAuthorized({
@ -614,7 +604,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
await alertAuthorization.ensureAuthorized({
@ -674,7 +663,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
checkPrivileges.mockResolvedValueOnce({
@ -733,7 +721,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
checkPrivileges.mockResolvedValueOnce({
@ -796,7 +783,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
checkPrivileges.mockResolvedValueOnce({
@ -855,7 +841,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
checkPrivileges.mockResolvedValueOnce({
@ -947,7 +932,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
const {
filter,
@ -970,7 +954,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter(
AlertingAuthorizationEntity.Rule,
@ -1005,7 +988,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
expect(
@ -1020,11 +1002,54 @@ describe('AlertingAuthorization', () => {
).filter
).toEqual(
esKuery.fromKueryExpression(
`((path.to.rule_type_id:myAppAlertType and consumer-field:(myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:myOtherAppAlertType and consumer-field:(myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:mySecondAppAlertType and consumer-field:(myApp or myOtherApp or myAppWithSubFeature)))`
`((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:myOtherAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:mySecondAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)))`
)
);
expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled();
});
test('throws if user has no privileges to any rule type', async () => {
const { authorization } = mockSecurity();
const checkPrivileges: jest.MockedFunction<
ReturnType<typeof authorization.checkPrivilegesDynamicallyWithRequest>
> = jest.fn();
authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges);
checkPrivileges.mockResolvedValueOnce({
username: 'some-user',
hasAllRequested: false,
privileges: {
kibana: [
{
privilege: mockAuthorizationAction('myType', 'myOtherApp', 'rule', 'create'),
authorized: false,
},
{
privilege: mockAuthorizationAction('myType', 'myApp', 'rule', 'create'),
authorized: false,
},
],
},
});
const alertAuthorization = new AlertingAuthorization({
request,
authorization,
ruleTypeRegistry,
features,
auditLogger,
getSpace,
getSpaceId,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
await expect(
alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, {
type: AlertingAuthorizationFilterType.KQL,
fieldNames: {
ruleTypeId: 'path.to.rule_type_id',
consumer: 'consumer-field',
},
})
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unauthorized some-user/find"`);
expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled();
});
test('creates an `ensureRuleTypeIsAuthorized` function which throws if type is unauthorized', async () => {
const { authorization } = mockSecurity();
const checkPrivileges: jest.MockedFunction<
@ -1068,7 +1093,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter(
@ -1142,7 +1166,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter(
@ -1217,7 +1240,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
const {
@ -1270,7 +1292,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
const { filter } = await alertAuthorization.getFindAuthorizationFilter(
AlertingAuthorizationEntity.Alert,
@ -1325,7 +1346,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
@ -1341,93 +1361,7 @@ describe('AlertingAuthorization', () => {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"myApp": Object {
"all": true,
"read": true,
},
"myAppWithSubFeature": Object {
"all": true,
"read": true,
},
"myOtherApp": Object {
"all": true,
"read": true,
},
},
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myAppAlertType",
"producer": "myApp",
"recoveryActionGroup": Object {
"id": "recovered",
"name": "Recovered",
},
},
Object {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"myApp": Object {
"all": true,
"read": true,
},
"myAppWithSubFeature": Object {
"all": true,
"read": true,
},
"myOtherApp": Object {
"all": true,
"read": true,
},
},
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myOtherAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myOtherAppAlertType",
"producer": "myOtherApp",
"recoveryActionGroup": Object {
"id": "recovered",
"name": "Recovered",
},
},
}
`);
});
test('augments a list of types with all features and exempt consumer ids when there is no authorization api', async () => {
const alertAuthorization = new AlertingAuthorization({
request,
ruleTypeRegistry,
features,
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds: ['exemptConsumerA', 'exemptConsumerB'],
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
await expect(
alertAuthorization.filterByRuleTypeAuthorization(
new Set([myAppAlertType, myOtherAppAlertType]),
[WriteOperations.Create],
AlertingAuthorizationEntity.Rule
)
).resolves.toMatchInlineSnapshot(`
Set {
Object {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"exemptConsumerA": Object {
"all": true,
"read": true,
},
"exemptConsumerB": Object {
"alerts": Object {
"all": true,
"read": true,
},
@ -1460,11 +1394,7 @@ describe('AlertingAuthorization', () => {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"exemptConsumerA": Object {
"all": true,
"read": true,
},
"exemptConsumerB": Object {
"alerts": Object {
"all": true,
"read": true,
},
@ -1541,7 +1471,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
@ -1578,113 +1507,7 @@ describe('AlertingAuthorization', () => {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"myApp": Object {
"all": true,
"read": true,
},
"myOtherApp": Object {
"all": true,
"read": true,
},
},
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myAppAlertType",
"producer": "myApp",
"recoveryActionGroup": Object {
"id": "recovered",
"name": "Recovered",
},
},
}
`);
});
test('augments a list of types with consumers and exempt consumer ids under which the operation is authorized', async () => {
const { authorization } = mockSecurity();
const checkPrivileges: jest.MockedFunction<
ReturnType<typeof authorization.checkPrivilegesDynamicallyWithRequest>
> = jest.fn();
authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges);
checkPrivileges.mockResolvedValueOnce({
username: 'some-user',
hasAllRequested: false,
privileges: {
kibana: [
{
privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'rule', 'create'),
authorized: true,
},
{
privilege: mockAuthorizationAction(
'myOtherAppAlertType',
'myOtherApp',
'rule',
'create'
),
authorized: false,
},
{
privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'rule', 'create'),
authorized: true,
},
{
privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'rule', 'create'),
authorized: true,
},
],
},
});
const alertAuthorization = new AlertingAuthorization({
request,
authorization,
ruleTypeRegistry,
features,
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds: ['exemptConsumerA'],
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
await expect(
alertAuthorization.filterByRuleTypeAuthorization(
new Set([myAppAlertType, myOtherAppAlertType]),
[WriteOperations.Create],
AlertingAuthorizationEntity.Rule
)
).resolves.toMatchInlineSnapshot(`
Set {
Object {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"myApp": Object {
"all": true,
"read": true,
},
},
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myOtherAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myOtherAppAlertType",
"producer": "myOtherApp",
"recoveryActionGroup": Object {
"id": "recovered",
"name": "Recovered",
},
},
Object {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"exemptConsumerA": Object {
"alerts": Object {
"all": true,
"read": true,
},
@ -1713,7 +1536,7 @@ describe('AlertingAuthorization', () => {
`);
});
test('authorizes user under exempt consumers when they are authorized by the producer', async () => {
test('authorizes user under the `alerts` consumer when they are authorized by the producer', async () => {
const { authorization } = mockSecurity();
const checkPrivileges: jest.MockedFunction<
ReturnType<typeof authorization.checkPrivilegesDynamicallyWithRequest>
@ -1744,7 +1567,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds: ['exemptConsumerA'],
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
@ -1760,7 +1582,7 @@ describe('AlertingAuthorization', () => {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"exemptConsumerA": Object {
"alerts": Object {
"all": true,
"read": true,
},
@ -1850,7 +1672,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
@ -1866,6 +1687,10 @@ describe('AlertingAuthorization', () => {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"alerts": Object {
"all": false,
"read": true,
},
"myApp": Object {
"all": true,
"read": true,
@ -1891,6 +1716,10 @@ describe('AlertingAuthorization', () => {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"alerts": Object {
"all": false,
"read": true,
},
"myApp": Object {
"all": false,
"read": true,
@ -1960,7 +1789,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
@ -1976,6 +1804,10 @@ describe('AlertingAuthorization', () => {
"actionGroups": Array [],
"actionVariables": undefined,
"authorizedConsumers": Object {
"alerts": Object {
"all": true,
"read": true,
},
"myApp": Object {
"all": true,
"read": true,
@ -2067,7 +1899,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);
@ -2142,7 +1973,6 @@ describe('AlertingAuthorization', () => {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
});
ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes);

View file

@ -9,7 +9,7 @@ import Boom from '@hapi/boom';
import { map, mapValues, fromPairs, has } from 'lodash';
import { KibanaRequest } from 'src/core/server';
import { JsonObject } from '@kbn/utility-types';
import { RuleTypeRegistry } from '../types';
import { ALERTS_FEATURE_ID, RuleTypeRegistry } from '../types';
import { SecurityPluginSetup } from '../../../security/server';
import { RegistryRuleType } from '../rule_type_registry';
import { PluginStartContract as FeaturesPluginStart } from '../../../features/server';
@ -71,7 +71,6 @@ export interface ConstructorOptions {
getSpace: (request: KibanaRequest) => Promise<Space | undefined>;
getSpaceId: (request: KibanaRequest) => string | undefined;
auditLogger: AlertingAuthorizationAuditLogger;
exemptConsumerIds: string[];
authorization?: SecurityPluginSetup['authz'];
}
@ -82,7 +81,6 @@ export class AlertingAuthorization {
private readonly auditLogger: AlertingAuthorizationAuditLogger;
private readonly featuresIds: Promise<Set<string>>;
private readonly allPossibleConsumers: Promise<AuthorizedConsumers>;
private readonly exemptConsumerIds: string[];
private readonly spaceId: string | undefined;
constructor({
@ -93,18 +91,12 @@ export class AlertingAuthorization {
auditLogger,
getSpace,
getSpaceId,
exemptConsumerIds,
}: ConstructorOptions) {
this.request = request;
this.authorization = authorization;
this.ruleTypeRegistry = ruleTypeRegistry;
this.auditLogger = auditLogger;
// List of consumer ids that are exempt from privilege check. This should be used sparingly.
// An example of this is the Rules Management `consumer` as we don't want to have to
// manually authorize each rule type in the management UI.
this.exemptConsumerIds = exemptConsumerIds;
this.spaceId = getSpaceId(request);
this.featuresIds = getSpace(request)
@ -132,7 +124,7 @@ export class AlertingAuthorization {
this.allPossibleConsumers = this.featuresIds.then((featuresIds) => {
return featuresIds.size
? asAuthorizedConsumers([...this.exemptConsumerIds, ...featuresIds], {
? asAuthorizedConsumers([ALERTS_FEATURE_ID, ...featuresIds], {
read: true,
all: true,
})
@ -185,8 +177,10 @@ export class AlertingAuthorization {
),
};
// Skip authorizing consumer if it is in the list of exempt consumer ids
const shouldAuthorizeConsumer = !this.exemptConsumerIds.includes(consumer);
// Skip authorizing consumer if consumer is the Rules Management consumer (`alerts`)
// This means that rules and their derivative alerts created in the Rules Management UI
// will only be subject to checking if user has access to the rule producer.
const shouldAuthorizeConsumer = consumer !== ALERTS_FEATURE_ID;
const checkPrivileges = authorization.checkPrivilegesDynamicallyWithRequest(this.request);
const { hasAllRequested, username, privileges } = await checkPrivileges({
@ -199,8 +193,8 @@ export class AlertingAuthorization {
requiredPrivilegesByScope.producer,
]
: [
// skip consumer privilege checks for exempt consumer ids as all rule types can
// be created for exempt consumers if user has producer level privileges
// skip consumer privilege checks under `alerts` as all rule types can
// be created under `alerts` if you have producer level privileges
requiredPrivilegesByScope.producer,
],
});
@ -448,14 +442,12 @@ export class AlertingAuthorization {
ruleType.authorizedConsumers[feature]
);
if (isAuthorizedAtProducerLevel && this.exemptConsumerIds.length > 0) {
// granting privileges under the producer automatically authorized exempt consumer IDs as well
this.exemptConsumerIds.forEach((exemptId: string) => {
ruleType.authorizedConsumers[exemptId] = mergeHasPrivileges(
hasPrivileges,
ruleType.authorizedConsumers[exemptId]
);
});
if (isAuthorizedAtProducerLevel) {
// granting privileges under the producer automatically authorized the Rules Management UI as well
ruleType.authorizedConsumers[ALERTS_FEATURE_ID] = mergeHasPrivileges(
hasPrivileges,
ruleType.authorizedConsumers[ALERTS_FEATURE_ID]
);
}
authorizedRuleTypes.add(ruleType);
}

View file

@ -21,7 +21,6 @@ import { securityMock } from '../../security/server/mocks';
import { PluginStartContract as ActionsStartContract } from '../../actions/server';
import { actionsMock, actionsAuthorizationMock } from '../../actions/server/mocks';
import { LegacyAuditLogger } from '../../security/server';
import { ALERTS_FEATURE_ID } from '../common';
import { eventLogMock } from '../../event_log/server/mocks';
import { alertingAuthorizationMock } from './authorization/alerting_authorization.mock';
import { alertingAuthorizationClientFactoryMock } from './alerting_authorization_client_factory.mock';
@ -105,9 +104,7 @@ test('creates an alerts client with proper constructor arguments when security i
includedHiddenTypes: ['alert', 'api_key_pending_invalidation'],
});
expect(alertingAuthorizationClientFactory.create).toHaveBeenCalledWith(request, [
ALERTS_FEATURE_ID,
]);
expect(alertingAuthorizationClientFactory.create).toHaveBeenCalledWith(request);
expect(rulesClientFactoryParams.actions.getActionsAuthorizationWithRequest).toHaveBeenCalledWith(
request
@ -148,9 +145,7 @@ test('creates an alerts client with proper constructor arguments', async () => {
includedHiddenTypes: ['alert', 'api_key_pending_invalidation'],
});
expect(alertingAuthorizationClientFactory.create).toHaveBeenCalledWith(request, [
ALERTS_FEATURE_ID,
]);
expect(alertingAuthorizationClientFactory.create).toHaveBeenCalledWith(request);
expect(jest.requireMock('./rules_client').RulesClient).toHaveBeenCalledWith({
unsecuredSavedObjectsClient: savedObjectsClient,

View file

@ -19,7 +19,6 @@ import { EncryptedSavedObjectsClient } from '../../encrypted_saved_objects/serve
import { TaskManagerStartContract } from '../../task_manager/server';
import { IEventLogClientService } from '../../../plugins/event_log/server';
import { AlertingAuthorizationClientFactory } from './alerting_authorization_client_factory';
import { ALERTS_FEATURE_ID } from '../common';
export interface RulesClientFactoryOpts {
logger: Logger;
taskManager: TaskManagerStartContract;
@ -87,7 +86,7 @@ export class RulesClientFactory {
excludedWrappers: ['security'],
includedHiddenTypes: ['alert', 'api_key_pending_invalidation'],
}),
authorization: this.authorization.create(request, [ALERTS_FEATURE_ID]),
authorization: this.authorization.create(request),
actionsAuthorization: actions.getActionsAuthorizationWithRequest(request),
namespace: this.spaceIdToNamespace(spaceId),
encryptedSavedObjectsClient: this.encryptedSavedObjectsClient,