Skip to content

Commit

Permalink
[Security Solution] Add Endpoint policy feature checks (#83972) (#84372)
Browse files Browse the repository at this point in the history
  • Loading branch information
pzl authored Nov 25, 2020
1 parent 781fcf4 commit 723e730
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,8 @@ export const factory = (): PolicyConfig => {
},
};
};

/**
* Reflects what string the Endpoint will use when message field is default/empty
*/
export const DefaultMalwareMessage = 'Elastic Security { action } { filename }';
33 changes: 14 additions & 19 deletions x-pack/plugins/security_solution/common/license/license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Observable, Subscription } from 'rxjs';
import { ILicense } from '../../../licensing/common/types';
import { ILicense, LicenseType } from '../../../licensing/common/types';

// Generic license service class that works with the license observable
// Both server and client plugins instancates a singleton version of this class
Expand Down Expand Up @@ -36,25 +36,20 @@ export class LicenseService {
return this.observable;
}

public isGoldPlus() {
return (
this.licenseInformation?.isAvailable &&
this.licenseInformation?.isActive &&
this.licenseInformation?.hasAtLeast('gold')
);
public isAtLeast(level: LicenseType): boolean {
return isAtLeast(this.licenseInformation, level);
}
public isPlatinumPlus() {
return (
this.licenseInformation?.isAvailable &&
this.licenseInformation?.isActive &&
this.licenseInformation?.hasAtLeast('platinum')
);
public isGoldPlus(): boolean {
return this.isAtLeast('gold');
}
public isEnterprise() {
return (
this.licenseInformation?.isAvailable &&
this.licenseInformation?.isActive &&
this.licenseInformation?.hasAtLeast('enterprise')
);
public isPlatinumPlus(): boolean {
return this.isAtLeast('platinum');
}
public isEnterprise(): boolean {
return this.isAtLeast('enterprise');
}
}

export const isAtLeast = (license: ILicense | null, level: LicenseType): boolean => {
return license !== null && license.isAvailable && license.isActive && license.hasAtLeast(level);
};
110 changes: 110 additions & 0 deletions x-pack/plugins/security_solution/common/license/policy_config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* 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 {
isEndpointPolicyValidForLicense,
unsetPolicyFeaturesAboveLicenseLevel,
} from './policy_config';
import { DefaultMalwareMessage, factory } from '../endpoint/models/policy_config';
import { licenseMock } from '../../../licensing/common/licensing.mock';

describe('policy_config and licenses', () => {
const Platinum = licenseMock.createLicense({ license: { type: 'platinum', mode: 'platinum' } });
const Gold = licenseMock.createLicense({ license: { type: 'gold', mode: 'gold' } });
const Basic = licenseMock.createLicense({ license: { type: 'basic', mode: 'basic' } });

describe('isEndpointPolicyValidForLicense', () => {
it('allows malware notification to be disabled with a Platinum license', () => {
const policy = factory();
policy.windows.popup.malware.enabled = false; // make policy change
const valid = isEndpointPolicyValidForLicense(policy, Platinum);
expect(valid).toBeTruthy();
});
it('blocks windows malware notification changes below Platinum licenses', () => {
const policy = factory();
policy.windows.popup.malware.enabled = false; // make policy change
let valid = isEndpointPolicyValidForLicense(policy, Gold);
expect(valid).toBeFalsy();

valid = isEndpointPolicyValidForLicense(policy, Basic);
expect(valid).toBeFalsy();
});

it('blocks mac malware notification changes below Platinum licenses', () => {
const policy = factory();
policy.mac.popup.malware.enabled = false; // make policy change
let valid = isEndpointPolicyValidForLicense(policy, Gold);
expect(valid).toBeFalsy();

valid = isEndpointPolicyValidForLicense(policy, Basic);
expect(valid).toBeFalsy();
});

it('allows malware notification message changes with a Platinum license', () => {
const policy = factory();
policy.windows.popup.malware.message = 'BOOM'; // make policy change
const valid = isEndpointPolicyValidForLicense(policy, Platinum);
expect(valid).toBeTruthy();
});
it('blocks windows malware notification message changes below Platinum licenses', () => {
const policy = factory();
policy.windows.popup.malware.message = 'BOOM'; // make policy change
let valid = isEndpointPolicyValidForLicense(policy, Gold);
expect(valid).toBeFalsy();

valid = isEndpointPolicyValidForLicense(policy, Basic);
expect(valid).toBeFalsy();
});
it('blocks mac malware notification message changes below Platinum licenses', () => {
const policy = factory();
policy.mac.popup.malware.message = 'BOOM'; // make policy change
let valid = isEndpointPolicyValidForLicense(policy, Gold);
expect(valid).toBeFalsy();

valid = isEndpointPolicyValidForLicense(policy, Basic);
expect(valid).toBeFalsy();
});

it('allows default policyConfig with Basic', () => {
const policy = factory();
const valid = isEndpointPolicyValidForLicense(policy, Basic);
expect(valid).toBeTruthy();
});
});

describe('unsetPolicyFeaturesAboveLicenseLevel', () => {
it('does not change any fields with a Platinum license', () => {
const policy = factory();
const popupMessage = 'WOOP WOOP';
policy.windows.popup.malware.message = popupMessage;
policy.mac.popup.malware.message = popupMessage;
policy.windows.popup.malware.enabled = false;

const retPolicy = unsetPolicyFeaturesAboveLicenseLevel(policy, Platinum);
expect(retPolicy.windows.popup.malware.enabled).toBeFalsy();
expect(retPolicy.windows.popup.malware.message).toEqual(popupMessage);
expect(retPolicy.mac.popup.malware.message).toEqual(popupMessage);
});
it('resets Platinum-paid fields for lower license tiers', () => {
const defaults = factory(); // reference
const policy = factory(); // what we will modify, and should be reset
const popupMessage = 'WOOP WOOP';
policy.windows.popup.malware.message = popupMessage;
policy.mac.popup.malware.message = popupMessage;
policy.windows.popup.malware.enabled = false;

const retPolicy = unsetPolicyFeaturesAboveLicenseLevel(policy, Gold);
expect(retPolicy.windows.popup.malware.enabled).toEqual(
defaults.windows.popup.malware.enabled
);
expect(retPolicy.windows.popup.malware.message).not.toEqual(popupMessage);
expect(retPolicy.mac.popup.malware.message).not.toEqual(popupMessage);

// need to invert the test, since it could be either value
expect(['', DefaultMalwareMessage]).toContain(retPolicy.windows.popup.malware.message);
});
});
});
66 changes: 66 additions & 0 deletions x-pack/plugins/security_solution/common/license/policy_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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 { ILicense } from '../../../licensing/common/types';
import { isAtLeast } from './license';
import { PolicyConfig } from '../endpoint/types';
import { DefaultMalwareMessage, factory } from '../endpoint/models/policy_config';

/**
* Given an endpoint package policy, verifies that all enabled features that
* require a certain license level have a valid license for them.
*/
export const isEndpointPolicyValidForLicense = (
policy: PolicyConfig,
license: ILicense | null
): boolean => {
if (isAtLeast(license, 'platinum')) {
return true; // currently, platinum allows all features
}

const defaults = factory();

// only platinum or higher may disable malware notification
if (
policy.windows.popup.malware.enabled !== defaults.windows.popup.malware.enabled ||
policy.mac.popup.malware.enabled !== defaults.mac.popup.malware.enabled
) {
return false;
}

// Only Platinum or higher may change the malware message (which can be blank or what Endpoint defaults)
if (
[policy.windows, policy.mac].some(
(p) => p.popup.malware.message !== '' && p.popup.malware.message !== DefaultMalwareMessage
)
) {
return false;
}

return true;
};

/**
* Resets paid features in a PolicyConfig back to default values
* when unsupported by the given license level.
*/
export const unsetPolicyFeaturesAboveLicenseLevel = (
policy: PolicyConfig,
license: ILicense | null
): PolicyConfig => {
if (isAtLeast(license, 'platinum')) {
return policy;
}

const defaults = factory();
// set any license-gated features back to the defaults
policy.windows.popup.malware.enabled = defaults.windows.popup.malware.enabled;
policy.mac.popup.malware.enabled = defaults.mac.popup.malware.enabled;
policy.windows.popup.malware.message = defaults.windows.popup.malware.message;
policy.mac.popup.malware.message = defaults.mac.popup.malware.message;

return policy;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import { IHttpFetchError } from 'kibana/public';
import { DefaultMalwareMessage } from '../../../../../../common/endpoint/models/policy_config';
import { PolicyDetailsState, UpdatePolicyResponse } from '../../types';
import {
policyIdFromParams,
Expand Down Expand Up @@ -38,10 +39,8 @@ export const policyDetailsMiddlewareFactory: ImmutableMiddlewareFactory<PolicyDe
policyItem = (await sendGetPackagePolicy(http, id)).item;
// sets default user notification message if policy config message is empty
if (policyItem.inputs[0].config.policy.value.windows.popup.malware.message === '') {
policyItem.inputs[0].config.policy.value.windows.popup.malware.message =
'Elastic Security { action } { filename }';
policyItem.inputs[0].config.policy.value.mac.popup.malware.message =
'Elastic Security { action } { filename }';
policyItem.inputs[0].config.policy.value.windows.popup.malware.message = DefaultMalwareMessage;
policyItem.inputs[0].config.policy.value.mac.popup.malware.message = DefaultMalwareMessage;
}
} catch (error) {
dispatch({
Expand Down

0 comments on commit 723e730

Please sign in to comment.