Fix sub-feature privilege "minimumLicense" bug (#106008)

This commit is contained in:
Joe Portner 2021-07-19 10:47:41 -04:00 committed by GitHub
parent cc1dd52977
commit ea062391bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 178 additions and 297 deletions

View file

@ -5,9 +5,24 @@
* 2.0.
*/
import type { LicenseType } from '../../../licensing/common/types';
import { LICENSE_TYPE } from '../../../licensing/server';
import { KibanaFeature } from '../';
import { SubFeaturePrivilegeConfig } from '../../common';
import type { FeaturePrivilegeIteratorOptions } from './feature_privilege_iterator';
import { featurePrivilegeIterator } from './feature_privilege_iterator';
function getFeaturePrivilegeIterator(
feature: KibanaFeature,
options: Omit<FeaturePrivilegeIteratorOptions, 'licenseHasAtLeast'> & { licenseType: LicenseType }
) {
const { licenseType, ...otherOptions } = options;
const licenseHasAtLeast = (licenseTypeToCheck: LicenseType) => {
return LICENSE_TYPE[licenseTypeToCheck] <= LICENSE_TYPE[options.licenseType];
};
return featurePrivilegeIterator(feature, { licenseHasAtLeast, ...otherOptions });
}
describe('featurePrivilegeIterator', () => {
it('handles features with no privileges', () => {
const feature = new KibanaFeature({
@ -19,7 +34,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})
@ -90,7 +105,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})
@ -219,7 +234,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
predicate: (privilegeId) => privilegeId === 'all',
@ -357,7 +372,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: false,
licenseType: 'basic',
})
@ -519,7 +534,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})
@ -682,7 +697,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})
@ -852,7 +867,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})
@ -1020,7 +1035,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})
@ -1088,97 +1103,40 @@ describe('featurePrivilegeIterator', () => {
]);
});
it('excludes sub feature privileges when the minimum license is not met', () => {
describe('excludes sub-feature privileges when the minimum license is not met', () => {
function createSubFeaturePrivilegeConfig(licenseType: LicenseType): SubFeaturePrivilegeConfig {
return {
// This is not a realistic sub-feature privilege config, but we only need the "api" string for our test cases
id: `${licenseType}-sub-feature`,
name: '',
includeIn: 'all',
minimumLicense: licenseType,
api: [`${licenseType}-api`],
savedObject: { all: [], read: [] },
ui: [],
};
}
const feature = new KibanaFeature({
id: 'foo',
name: 'foo',
id: 'feature',
name: 'feature-name',
app: [],
category: { id: 'foo', label: 'foo' },
category: { id: 'category-id', label: 'category-label' },
privileges: {
all: {
api: ['all-api', 'read-api'],
app: ['foo'],
catalogue: ['foo-catalogue'],
management: {
section: ['foo-management'],
},
savedObject: {
all: ['all-type'],
read: ['read-type'],
},
alerting: {
rule: {
all: ['alerting-all-type'],
},
alert: {
read: ['alerting-another-read-type'],
},
},
cases: {
all: ['cases-all-type'],
read: ['cases-read-type'],
},
ui: ['ui-action'],
},
read: {
api: ['read-api'],
app: ['foo'],
catalogue: ['foo-catalogue'],
management: {
section: ['foo-management'],
},
savedObject: {
all: [],
read: ['read-type'],
},
alerting: {
rule: {
read: ['alerting-read-type'],
},
alert: {
read: ['alerting-read-type'],
},
},
cases: {
read: ['cases-read-type'],
},
ui: ['ui-action'],
},
all: { savedObject: { all: ['obj-type'], read: [] }, ui: [] },
read: { savedObject: { all: [], read: ['obj-type'] }, ui: [] },
},
subFeatures: [
{
name: 'sub feature 1',
name: `sub-feature-name`,
privilegeGroups: [
{
groupType: 'independent',
privileges: [
{
id: 'sub-feature-priv-1',
name: 'first sub feature privilege',
includeIn: 'all',
minimumLicense: 'gold',
api: ['sub-feature-api'],
app: ['sub-app'],
catalogue: ['sub-catalogue'],
management: {
section: ['other-sub-management'],
kibana: ['sub-management'],
},
savedObject: {
all: ['all-sub-type'],
read: ['read-sub-type'],
},
alerting: {
alert: {
all: ['alerting-all-sub-type'],
},
},
cases: {
all: ['cases-all-sub-type'],
read: ['cases-read-sub-type'],
},
ui: ['ui-sub-type'],
},
createSubFeaturePrivilegeConfig('gold'),
createSubFeaturePrivilegeConfig('platinum'),
createSubFeaturePrivilegeConfig('enterprise'),
// Note: we intentionally do not include a sub-feature privilege config for the "trial" license because that should never be used
],
},
],
@ -1186,70 +1144,64 @@ describe('featurePrivilegeIterator', () => {
],
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})
);
// Each of the test cases below is a minimal check to make sure the correct sub-feature privileges are applied -- nothing more, nothing less
// Note: we do not include a test case for the "basic" license, because sub-feature privileges are not enabled at that license level
expect(actualPrivileges).toEqual([
{
privilegeId: 'all',
privilege: {
api: ['all-api', 'read-api'],
app: ['foo'],
catalogue: ['foo-catalogue'],
management: {
section: ['foo-management'],
},
savedObject: {
all: ['all-type'],
read: ['read-type'],
},
alerting: {
rule: {
all: ['alerting-all-type'],
},
alert: {
read: ['alerting-another-read-type'],
},
},
cases: {
all: ['cases-all-type'],
read: ['cases-read-type'],
},
ui: ['ui-action'],
},
},
{
privilegeId: 'read',
privilege: {
api: ['read-api'],
app: ['foo'],
catalogue: ['foo-catalogue'],
management: {
section: ['foo-management'],
},
savedObject: {
all: [],
read: ['read-type'],
},
alerting: {
rule: {
read: ['alerting-read-type'],
},
alert: {
read: ['alerting-read-type'],
},
},
cases: {
read: ['cases-read-type'],
},
ui: ['ui-action'],
},
},
]);
it('with a gold license', () => {
const actualPrivileges = Array.from(
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'gold',
})
);
const expectedPrivilege = expect.objectContaining({ api: ['gold-api'] });
expect(actualPrivileges).toEqual(
expect.arrayContaining([{ privilegeId: 'all', privilege: expectedPrivilege }])
);
});
it('with a platinum license', () => {
const actualPrivileges = Array.from(
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'platinum',
})
);
const expectedPrivilege = expect.objectContaining({ api: ['gold-api', 'platinum-api'] });
expect(actualPrivileges).toEqual(
expect.arrayContaining([{ privilegeId: 'all', privilege: expectedPrivilege }])
);
});
it('with an enterprise license', () => {
const actualPrivileges = Array.from(
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'enterprise',
})
);
const expectedPrivilege = expect.objectContaining({
api: ['gold-api', 'platinum-api', 'enterprise-api'],
});
expect(actualPrivileges).toEqual(
expect.arrayContaining([{ privilegeId: 'all', privilege: expectedPrivilege }])
);
});
it('with a trial license', () => {
const actualPrivileges = Array.from(
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'trial',
})
);
const expectedPrivilege = expect.objectContaining({
api: ['gold-api', 'platinum-api', 'enterprise-api'],
});
expect(actualPrivileges).toEqual(
expect.arrayContaining([{ privilegeId: 'all', privilege: expectedPrivilege }])
);
});
});
it(`can augment primary feature privileges even if they don't specify their own`, () => {
@ -1316,7 +1268,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})
@ -1470,7 +1422,7 @@ describe('featurePrivilegeIterator', () => {
});
const actualPrivileges = Array.from(
featurePrivilegeIterator(feature, {
getFeaturePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType: 'basic',
})

View file

@ -21,9 +21,10 @@ export interface FeaturePrivilegeIteratorOptions {
augmentWithSubFeaturePrivileges: boolean;
/**
* The current license type. Controls which sub-features are returned, as they may have different license terms than the overall feature.
* Function that returns whether the current license is equal to or greater than the given license type.
* Controls which sub-features are returned, as they may have different license terms than the overall feature.
*/
licenseType: LicenseType;
licenseHasAtLeast: (licenseType: LicenseType) => boolean | undefined;
/**
* Optional predicate to filter the returned set of privileges.
@ -59,7 +60,7 @@ const featurePrivilegeIterator: FeaturePrivilegeIterator = function* featurePriv
if (options.augmentWithSubFeaturePrivileges) {
yield {
privilegeId,
privilege: mergeWithSubFeatures(privilegeId, privilege, feature, options.licenseType),
privilege: mergeWithSubFeatures(privilegeId, privilege, feature, options.licenseHasAtLeast),
};
} else {
yield { privilegeId, privilege };
@ -71,10 +72,10 @@ function mergeWithSubFeatures(
privilegeId: string,
privilege: FeatureKibanaPrivileges,
feature: KibanaFeature,
licenseType: LicenseType
licenseHasAtLeast: FeaturePrivilegeIteratorOptions['licenseHasAtLeast']
) {
const mergedConfig = _.cloneDeep(privilege);
for (const subFeaturePrivilege of subFeaturePrivilegeIterator(feature, licenseType)) {
for (const subFeaturePrivilege of subFeaturePrivilegeIterator(feature, licenseHasAtLeast)) {
if (subFeaturePrivilege.includeIn !== 'read' && subFeaturePrivilege.includeIn !== privilegeId) {
continue;
}

View file

@ -16,17 +16,17 @@ import type { LicenseType } from '../../../licensing/server';
*/
export type SubFeaturePrivilegeIterator = (
feature: KibanaFeature,
licenseType: LicenseType
licenseHasAtLeast: (licenseType: LicenseType) => boolean | undefined
) => IterableIterator<SubFeaturePrivilegeConfig>;
const subFeaturePrivilegeIterator: SubFeaturePrivilegeIterator = function* subFeaturePrivilegeIterator(
feature: KibanaFeature,
licenseType: LicenseType
licenseHasAtLeast: (licenseType: LicenseType) => boolean | undefined
): IterableIterator<SubFeaturePrivilegeConfig> {
for (const subFeature of feature.subFeatures) {
for (const group of subFeature.privilegeGroups) {
yield* group.privileges.filter(
(privilege) => !privilege.minimumLicense || privilege.minimumLicense <= licenseType
(privilege) => !privilege.minimumLicense || licenseHasAtLeast(privilege.minimumLicense)
);
}
}

View file

@ -8,7 +8,7 @@
import { buildOSSFeatures } from './oss_features';
import { featurePrivilegeIterator } from './feature_privilege_iterator';
import { KibanaFeature } from '.';
import { LicenseType } from '../../licensing/server';
import { LicenseType, LICENSE_TYPE } from '../../licensing/server';
describe('buildOSSFeatures', () => {
it('returns features including timelion', () => {
@ -86,7 +86,8 @@ Array [
new KibanaFeature(featureConfig),
{
augmentWithSubFeaturePrivileges: true,
licenseType,
licenseHasAtLeast: (licenseTypeToCheck: LicenseType) =>
LICENSE_TYPE[licenseTypeToCheck] <= LICENSE_TYPE[licenseType],
}
)) {
privileges.push(featurePrivilege);

View file

@ -7,15 +7,27 @@
import { of } from 'rxjs';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { LICENSE_TYPE } from '../../../licensing/server';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import type { LicenseType } from '../../../licensing/server';
import type { SecurityLicenseFeatures } from './license_features';
import type { SecurityLicense } from './license_service';
export const licenseMock = {
create: (features?: Partial<SecurityLicenseFeatures>): jest.Mocked<SecurityLicense> => ({
create: (
features: Partial<SecurityLicenseFeatures> = {},
licenseType: LicenseType = 'basic' // default to basic if this is not specified
): jest.Mocked<SecurityLicense> => ({
isLicenseAvailable: jest.fn().mockReturnValue(true),
isEnabled: jest.fn().mockReturnValue(true),
getType: jest.fn().mockReturnValue('basic'),
getFeatures: jest.fn(),
getFeatures: jest.fn().mockReturnValue(features),
hasAtLeast: jest
.fn()
.mockImplementation(
(licenseTypeToCheck: LicenseType) =>
LICENSE_TYPE[licenseTypeToCheck] <= LICENSE_TYPE[licenseType]
),
features$: features ? of(features as SecurityLicenseFeatures) : of(),
}),
};

View file

@ -14,8 +14,8 @@ import type { SecurityLicenseFeatures } from './license_features';
export interface SecurityLicense {
isLicenseAvailable(): boolean;
isEnabled(): boolean;
getType(): LicenseType | undefined;
getFeatures(): SecurityLicenseFeatures;
hasAtLeast(licenseType: LicenseType): boolean | undefined;
features$: Observable<SecurityLicenseFeatures>;
}
@ -39,7 +39,7 @@ export class SecurityLicenseService {
isEnabled: () => this.isSecurityEnabledFromRawLicense(rawLicense),
getType: () => rawLicense?.type,
hasAtLeast: (licenseType: LicenseType) => rawLicense?.hasAtLeast(licenseType),
getFeatures: () => this.calculateFeaturesFromRawLicense(rawLicense),

View file

@ -8,6 +8,8 @@
import type { KibanaFeature } from '../../../../../features/public';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { featuresPluginMock } from '../../../../../features/server/mocks';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import type { LicenseType } from '../../../../../licensing/server';
import type { SecurityLicenseFeatures } from '../../../../common/licensing';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { Actions } from '../../../../server/authorization';
@ -25,6 +27,7 @@ export const createRawKibanaPrivileges = (
const licensingService = {
getFeatures: () => ({ allowSubFeaturePrivileges } as SecurityLicenseFeatures),
getType: () => 'basic' as const,
hasAtLeast: (licenseType: LicenseType) => licenseType === 'basic',
};
return privilegesFactory(

View file

@ -183,7 +183,7 @@ exports[`it renders without crashing 1`] = `
"_subscribe": [Function],
},
"getFeatures": [MockFunction],
"getType": [MockFunction],
"hasAtLeast": [MockFunction],
"isEnabled": [MockFunction],
"isLicenseAvailable": [MockFunction],
}

View file

@ -24,7 +24,7 @@ exports[`it renders without crashing 1`] = `
"_subscribe": [Function],
},
"getFeatures": [MockFunction],
"getType": [MockFunction],
"hasAtLeast": [MockFunction],
"isEnabled": [MockFunction],
"isLicenseAvailable": [MockFunction],
}

View file

@ -46,8 +46,8 @@ describe('Security Plugin', () => {
license: {
isLicenseAvailable: expect.any(Function),
isEnabled: expect.any(Function),
getType: expect.any(Function),
getFeatures: expect.any(Function),
hasAtLeast: expect.any(Function),
features$: expect.any(Observable),
},
});
@ -74,8 +74,8 @@ describe('Security Plugin', () => {
license: {
isLicenseAvailable: expect.any(Function),
isEnabled: expect.any(Function),
getType: expect.any(Function),
getFeatures: expect.any(Function),
hasAtLeast: expect.any(Function),
features$: expect.any(Observable),
},
management: managementSetupMock,

View file

@ -7,11 +7,19 @@
import { KibanaFeature } from '../../../../features/server';
import { featuresPluginMock } from '../../../../features/server/mocks';
import { licenseMock } from '../../../common/licensing/index.mock';
import { Actions } from '../actions';
import { privilegesFactory } from './privileges';
const actions = new Actions('1.0.0-zeta1');
const mockLicenseServiceBasic = licenseMock.create({ allowSubFeaturePrivileges: false }, 'basic');
const mockLicenseServiceGold = licenseMock.create({ allowSubFeaturePrivileges: true }, 'gold');
const mockLicenseServicePlatinum = licenseMock.create(
{ allowSubFeaturePrivileges: true },
'platinum'
);
describe('features', () => {
test('actions defined at the feature do not cascade to the privileges', () => {
const features: KibanaFeature[] = [
@ -43,14 +51,10 @@ describe('features', () => {
}),
];
const mockFeaturesService = featuresPluginMock.createSetup();
mockFeaturesService.getKibanaFeatures.mockReturnValue(features);
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesService, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).toHaveProperty('features.foo-feature', {
@ -87,11 +91,7 @@ describe('features', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const expectedAllPrivileges = [
actions.login,
@ -191,11 +191,7 @@ describe('features', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).not.toHaveProperty('features.foo');
@ -268,15 +264,7 @@ describe('features', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(
actions,
mockFeaturesPlugin as any,
mockLicenseService
);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
@ -412,15 +400,7 @@ describe('features', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(
actions,
mockFeaturesPlugin as any,
mockLicenseService
);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.read`, [
@ -500,15 +480,7 @@ describe('features', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(
actions,
mockFeaturesPlugin as any,
mockLicenseService
);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
@ -574,15 +546,7 @@ describe('features', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(
actions,
mockFeaturesPlugin as any,
mockLicenseService
);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
@ -649,15 +613,7 @@ describe('features', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(
actions,
mockFeaturesPlugin as any,
mockLicenseService
);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
@ -718,11 +674,7 @@ describe('reserved', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).toHaveProperty('reserved.foo', [actions.version]);
@ -756,11 +708,7 @@ describe('reserved', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).toHaveProperty('reserved.foo', [
@ -830,11 +778,7 @@ describe('reserved', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual).not.toHaveProperty('reserved.foo');
@ -893,11 +837,7 @@ describe('subFeatures', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceGold);
const actual = privileges.get();
expect(actual.features).toHaveProperty(`foo.subFeaturePriv1`, [
@ -1027,11 +967,7 @@ describe('subFeatures', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceGold);
const actual = privileges.get();
expect(actual.features).toHaveProperty(`foo.subFeaturePriv1`, [
@ -1264,11 +1200,7 @@ describe('subFeatures', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceGold);
const actual = privileges.get();
expect(actual.features).toHaveProperty(`foo.subFeaturePriv1`, [
@ -1424,11 +1356,7 @@ describe('subFeatures', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceGold);
const actual = privileges.get();
expect(actual.features).toHaveProperty(`foo.subFeaturePriv1`, [
@ -1610,11 +1538,7 @@ describe('subFeatures', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceGold);
const actual = privileges.get();
expect(actual.features).toHaveProperty(`foo.subFeaturePriv1`, [
@ -1753,11 +1677,7 @@ describe('subFeatures', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: false }),
getType: jest.fn().mockReturnValue('basic'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceBasic);
const actual = privileges.get();
expect(actual.features).not.toHaveProperty(`foo.subFeaturePriv1`);
@ -1979,11 +1899,7 @@ describe('subFeatures', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('gold'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServiceGold);
const actual = privileges.get();
expect(actual.features).toHaveProperty(`foo.subFeaturePriv1`);
@ -2214,11 +2130,7 @@ describe('subFeatures', () => {
const mockFeaturesPlugin = featuresPluginMock.createSetup();
mockFeaturesPlugin.getKibanaFeatures.mockReturnValue(features);
const mockLicenseService = {
getFeatures: jest.fn().mockReturnValue({ allowSubFeaturePrivileges: true }),
getType: jest.fn().mockReturnValue('platinum'),
};
const privileges = privilegesFactory(actions, mockFeaturesPlugin as any, mockLicenseService);
const privileges = privilegesFactory(actions, mockFeaturesPlugin, mockLicenseServicePlatinum);
const actual = privileges.get();
expect(actual.features).toHaveProperty(`foo.subFeaturePriv1`);

View file

@ -23,7 +23,7 @@ export interface PrivilegesService {
export function privilegesFactory(
actions: Actions,
featuresService: FeaturesPluginSetup,
licenseService: Pick<SecurityLicense, 'getFeatures' | 'getType'>
licenseService: Pick<SecurityLicense, 'getFeatures' | 'hasAtLeast'>
) {
const featurePrivilegeBuilder = featurePrivilegeBuilderFactory(actions);
@ -31,7 +31,7 @@ export function privilegesFactory(
get() {
const features = featuresService.getKibanaFeatures();
const { allowSubFeaturePrivileges } = licenseService.getFeatures();
const licenseType = licenseService.getType()!;
const { hasAtLeast: licenseHasAtLeast } = licenseService;
const basePrivilegeFeatures = features.filter(
(feature) => !feature.excludeFromBasePrivileges
);
@ -42,7 +42,7 @@ export function privilegesFactory(
basePrivilegeFeatures.forEach((feature) => {
for (const { privilegeId, privilege } of featuresService.featurePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType,
licenseHasAtLeast,
predicate: (pId, featurePrivilege) => !featurePrivilege.excludeFromBasePrivileges,
})) {
const privilegeActions = featurePrivilegeBuilder.getActions(privilege, feature);
@ -61,7 +61,7 @@ export function privilegesFactory(
featurePrivileges[feature.id] = {};
for (const featurePrivilege of featuresService.featurePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: true,
licenseType,
licenseHasAtLeast,
})) {
featurePrivileges[feature.id][featurePrivilege.privilegeId] = [
actions.login,
@ -73,7 +73,7 @@ export function privilegesFactory(
if (allowSubFeaturePrivileges && feature.subFeatures?.length > 0) {
for (const featurePrivilege of featuresService.featurePrivilegeIterator(feature, {
augmentWithSubFeaturePrivileges: false,
licenseType,
licenseHasAtLeast,
})) {
featurePrivileges[feature.id][`minimal_${featurePrivilege.privilegeId}`] = [
actions.login,
@ -84,7 +84,7 @@ export function privilegesFactory(
for (const subFeaturePrivilege of featuresService.subFeaturePrivilegeIterator(
feature,
licenseType
licenseHasAtLeast
)) {
featurePrivileges[feature.id][subFeaturePrivilege.id] = [
actions.login,

View file

@ -119,7 +119,7 @@ describe('Security Plugin', () => {
},
},
"getFeatures": [Function],
"getType": [Function],
"hasAtLeast": [Function],
"isEnabled": [Function],
"isLicenseAvailable": [Function],
},