Skip to content

Commit 44a0c4e

Browse files
committed
incluyde sub features in privilege check
1 parent 8b2a423 commit 44a0c4e

File tree

2 files changed

+91
-7
lines changed

2 files changed

+91
-7
lines changed

x-pack/plugins/alerts/server/authorization/alerts_authorization.test.ts

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,71 @@ function mockFeature(appName: string, typeName?: string) {
6868
});
6969
}
7070

71+
function mockFeatureWithSubFeature(appName: string, typeName: string) {
72+
return new Feature({
73+
id: appName,
74+
name: appName,
75+
app: [],
76+
privileges: {
77+
all: {
78+
savedObject: {
79+
all: [],
80+
read: [],
81+
},
82+
ui: [],
83+
},
84+
read: {
85+
savedObject: {
86+
all: [],
87+
read: [],
88+
},
89+
ui: [],
90+
},
91+
},
92+
subFeatures: [
93+
{
94+
name: appName,
95+
privilegeGroups: [
96+
{
97+
groupType: 'independent',
98+
privileges: [
99+
{
100+
id: 'doSomethingAlertRelated',
101+
name: 'sub feature alert',
102+
includeIn: 'all',
103+
alerting: {
104+
all: [typeName],
105+
},
106+
savedObject: {
107+
all: [],
108+
read: [],
109+
},
110+
ui: ['doSomethingAlertRelated'],
111+
},
112+
{
113+
id: 'doSomethingAlertRelated',
114+
name: 'sub feature alert',
115+
includeIn: 'read',
116+
alerting: {
117+
read: [typeName],
118+
},
119+
savedObject: {
120+
all: [],
121+
read: [],
122+
},
123+
ui: ['doSomethingAlertRelated'],
124+
},
125+
],
126+
},
127+
],
128+
},
129+
],
130+
});
131+
}
132+
71133
const myAppFeature = mockFeature('myApp', 'myType');
72134
const myOtherAppFeature = mockFeature('myOtherApp', 'myType');
135+
const myAppWithSubFeature = mockFeatureWithSubFeature('myAppWithSubFeature', 'myType');
73136
const myFeatureWithoutAlerting = mockFeature('myOtherApp');
74137

75138
beforeEach(() => {
@@ -91,7 +154,12 @@ beforeEach(() => {
91154
async executor() {},
92155
producer: 'myApp',
93156
}));
94-
features.getFeatures.mockReturnValue([myAppFeature, myOtherAppFeature, myFeatureWithoutAlerting]);
157+
features.getFeatures.mockReturnValue([
158+
myAppFeature,
159+
myOtherAppFeature,
160+
myAppWithSubFeature,
161+
myFeatureWithoutAlerting,
162+
]);
95163
});
96164

97165
describe('ensureAuthorized', () => {
@@ -460,7 +528,7 @@ describe('getFindAuthorizationFilter', () => {
460528
alertTypeRegistry.list.mockReturnValue(setOfAlertTypes);
461529

462530
expect((await alertAuthorization.getFindAuthorizationFilter()).filter).toMatchInlineSnapshot(
463-
`"((alert.attributes.alertTypeId:myAppAlertType and alert.attributes.consumer:(alerts or myApp or myOtherApp)) or (alert.attributes.alertTypeId:alertingAlertType and alert.attributes.consumer:(alerts or myApp or myOtherApp)))"`
531+
`"((alert.attributes.alertTypeId:myAppAlertType and alert.attributes.consumer:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (alert.attributes.alertTypeId:alertingAlertType and alert.attributes.consumer:(alerts or myApp or myOtherApp or myAppWithSubFeature)))"`
464532
);
465533

466534
expect(auditLogger.alertsAuthorizationSuccess).not.toHaveBeenCalled();
@@ -639,6 +707,7 @@ describe('filterByAlertTypeAuthorization', () => {
639707
"alerts",
640708
"myApp",
641709
"myOtherApp",
710+
"myAppWithSubFeature",
642711
],
643712
"defaultActionGroupId": "default",
644713
"id": "myAppAlertType",
@@ -652,6 +721,7 @@ describe('filterByAlertTypeAuthorization', () => {
652721
"alerts",
653722
"myApp",
654723
"myOtherApp",
724+
"myAppWithSubFeature",
655725
],
656726
"defaultActionGroupId": "default",
657727
"id": "alertingAlertType",

x-pack/plugins/alerts/server/authorization/alerts_authorization.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ALERTS_FEATURE_ID } from '../../common';
1111
import { AlertTypeRegistry } from '../types';
1212
import { SecurityPluginSetup } from '../../../security/server';
1313
import { RegistryAlertType } from '../alert_type_registry';
14+
import { FeatureKibanaPrivileges, SubFeaturePrivilegeConfig } from '../../../features/common';
1415
import { PluginStartContract as FeaturesPluginStart } from '../../../features/server';
1516
import { AlertsAuthorizationAuditLogger, ScopeType } from './audit_logger';
1617

@@ -189,12 +190,17 @@ export class AlertsAuthorization {
189190
const featuresIds = this.features
190191
.getFeatures()
191192
// ignore features which don't grant privileges to alerting
192-
.filter(({ privileges }) => {
193+
.filter(({ privileges, subFeatures }) => {
193194
return (
194-
(privileges?.all.alerting?.all?.length ?? 0 > 0) ||
195-
(privileges?.all.alerting?.read?.length ?? 0 > 0) ||
196-
(privileges?.read.alerting?.all?.length ?? 0 > 0) ||
197-
(privileges?.read.alerting?.read?.length ?? 0 > 0)
195+
hasAnyAlertingPrivileges(privileges?.all) ||
196+
hasAnyAlertingPrivileges(privileges?.read) ||
197+
subFeatures.some((subFeature) =>
198+
subFeature.privilegeGroups.some((privilegeGroup) =>
199+
privilegeGroup.privileges.some((subPrivileges) =>
200+
hasAnyAlertingPrivileges(subPrivileges)
201+
)
202+
)
203+
)
198204
);
199205
})
200206
.map((feature) => feature.id);
@@ -294,3 +300,11 @@ export function ensureFieldIsSafeForQuery(field: string, value: string): boolean
294300
}
295301
return true;
296302
}
303+
304+
function hasAnyAlertingPrivileges(
305+
privileges?: FeatureKibanaPrivileges | SubFeaturePrivilegeConfig
306+
): boolean {
307+
return (
308+
((privileges?.alerting?.all?.length ?? 0) || (privileges?.alerting?.read?.length ?? 0)) > 0
309+
);
310+
}

0 commit comments

Comments
 (0)