Skip to content

Commit

Permalink
[Security Solution] Correct Policy Config to current license level on…
Browse files Browse the repository at this point in the history
… fetch (#85206) (#86503)
  • Loading branch information
pzl authored Dec 18, 2020
1 parent c82ee2a commit 631fd9d
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 10 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/security_solution/common/license/license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ export class LicenseService {
}

export const isAtLeast = (license: ILicense | null, level: LicenseType): boolean => {
return license !== null && license.isAvailable && license.isActive && license.hasAtLeast(level);
return !!license && license.isAvailable && license.isActive && license.hasAtLeast(level);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 React, { FC, memo, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { Dispatch } from 'redux';
import { licenseService } from '../../hooks/use_license';
import { AppAction } from '../../store/actions';
import { ILicense } from '../../../../../licensing/common/types';

export const CurrentLicense: FC = memo(({ children }) => {
const dispatch = useDispatch<Dispatch<AppAction>>();
useEffect(() => {
const subscription = licenseService
.getLicenseInformation$()
?.subscribe((licenseInformation: ILicense) => {
dispatch({
type: 'licenseChanged',
payload: licenseInformation,
});
});
return () => subscription?.unsubscribe();
}, [dispatch]);
return <>{children}</>;
});

CurrentLicense.displayName = 'CurrentLicense';
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { ILicense } from '../../../../../../../licensing/common/types';
import { GetAgentStatusResponse } from '../../../../../../../fleet/common/types/rest_spec';
import { PolicyData, UIPolicyConfig } from '../../../../../../common/endpoint/types';
import { ServerApiError } from '../../../../../common/types';
Expand Down Expand Up @@ -62,6 +63,11 @@ interface UserClickedPolicyDetailsSaveButton {
type: 'userClickedPolicyDetailsSaveButton';
}

interface LicenseChanged {
type: 'licenseChanged';
payload: ILicense;
}

export type PolicyDetailsAction =
| ServerReturnedPolicyDetailsData
| UserClickedPolicyDetailsSaveButton
Expand All @@ -70,4 +76,5 @@ export type PolicyDetailsAction =
| ServerReturnedUpdatedPolicyDetailsData
| ServerFailedToReturnPolicyDetailsData
| UserChangedPolicyConfig
| UserChangedAntivirusRegistration;
| UserChangedAntivirusRegistration
| LicenseChanged;
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '../../../../../common/mock/endpoint';
import { HttpFetchOptions } from 'kibana/public';
import { cloneDeep } from 'lodash';
import { licenseMock } from '../../../../../../../licensing/common/licensing.mock';

describe('policy details: ', () => {
let store: Store;
Expand Down Expand Up @@ -151,6 +152,49 @@ describe('policy details: ', () => {
expect(config!.linux.events.file).toEqual(true);
});
});

describe('when the policy config has paid features enabled', () => {
const CustomMessage = 'Some Popup message change';
const Basic = licenseMock.createLicense({ license: { type: 'basic', mode: 'basic' } });
const Platinum = licenseMock.createLicense({
license: { type: 'platinum', mode: 'platinum' },
});

beforeEach(() => {
const config = policyConfig(getState());
if (!config) {
throw new Error();
}

// have a paid-policy field existing in the store from a previous time
const newPayload1 = cloneDeep(config);
newPayload1.windows.popup.malware.message = CustomMessage;
dispatch({
type: 'userChangedPolicyConfig',
payload: { policyConfig: newPayload1 },
});
});

it('preserves paid fields when license level allows', () => {
dispatch({
type: 'licenseChanged',
payload: Platinum,
});
const config = policyConfig(getState());

expect(config.windows.popup.malware.message).toEqual(CustomMessage);
});

it('reverts paid fields to default when license level does not allow', () => {
dispatch({
type: 'licenseChanged',
payload: Basic,
});
const config = policyConfig(getState());

expect(config.windows.popup.malware.message).not.toEqual(CustomMessage);
});
});
});

describe('when saving policy data', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export const policyDetailsMiddlewareFactory: ImmutableMiddlewareFactory<PolicyDe
coreStart
) => {
const http = coreStart.http;

return ({ getState, dispatch }) => (next) => async (action) => {
next(action);
const state = getState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const initialPolicyDetailsState: () => Immutable<PolicyDetailsState> = ()
total: 0,
other: 0,
},
license: undefined,
});

export const policyDetailsReducer: ImmutableReducer<PolicyDetailsState, AppAction> = (
Expand Down Expand Up @@ -93,6 +94,13 @@ export const policyDetailsReducer: ImmutableReducer<PolicyDetailsState, AppActio
};
}

if (action.type === 'licenseChanged') {
return {
...state,
license: action.payload,
};
}

if (action.type === 'userChangedUrl') {
const newState: Immutable<PolicyDetailsState> = {
...state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import { createSelector } from 'reselect';
import { matchPath } from 'react-router-dom';
import { ILicense } from '../../../../../../../licensing/common/types';
import { unsetPolicyFeaturesAboveLicenseLevel } from '../../../../../../common/license/policy_config';
import { PolicyDetailsState } from '../../types';
import {
Immutable,
Expand All @@ -20,6 +22,24 @@ import { ManagementRoutePolicyDetailsParams } from '../../../../types';

/** Returns the policy details */
export const policyDetails = (state: Immutable<PolicyDetailsState>) => state.policyItem;
/** Returns current active license */
export const licenseState = (state: Immutable<PolicyDetailsState>) => state.license;

export const licensedPolicy: (
state: Immutable<PolicyDetailsState>
) => Immutable<PolicyData> | undefined = createSelector(
policyDetails,
licenseState,
(policyData, license) => {
if (policyData) {
unsetPolicyFeaturesAboveLicenseLevel(
policyData?.inputs[0]?.config.policy.value,
license as ILicense
);
}
return policyData;
}
);

/**
* Given a Policy Data (package policy) object, return back a new object with only the field
Expand Down Expand Up @@ -75,7 +95,7 @@ export const getPolicyDataForUpdate = (
*/
export const policyDetailsForUpdate: (
state: Immutable<PolicyDetailsState>
) => Immutable<NewPolicyData> | undefined = createSelector(policyDetails, (policy) => {
) => Immutable<NewPolicyData> | undefined = createSelector(licensedPolicy, (policy) => {
if (policy) {
return getPolicyDataForUpdate(policy);
}
Expand Down Expand Up @@ -111,7 +131,7 @@ const defaultFullPolicy: Immutable<PolicyConfig> = policyConfigFactory();
* Note: this will return a default full policy if the `policyItem` is `undefined`
*/
export const fullPolicy: (s: Immutable<PolicyDetailsState>) => PolicyConfig = createSelector(
policyDetails,
licensedPolicy,
(policyData) => {
return policyData?.inputs[0]?.config?.policy?.value ?? defaultFullPolicy;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { ILicense } from '../../../../../licensing/common/types';
import {
AppLocation,
Immutable,
Expand Down Expand Up @@ -66,6 +67,8 @@ export interface PolicyDetailsState {
success: boolean;
error?: ServerApiError;
};
/** current license */
license?: ILicense;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, { ComponentType, memo } from 'react';
import { CoreStart } from 'kibana/public';
import { combineReducers, createStore, compose, applyMiddleware } from 'redux';
import { Provider as ReduxStoreProvider } from 'react-redux';
import { CurrentLicense } from '../../../../../common/components/current_license';
import { StartPlugins } from '../../../../../types';
import { managementReducer } from '../../../../store/reducer';
import { managementMiddlewareFactory } from '../../../../store/middleware';
Expand Down Expand Up @@ -57,7 +58,9 @@ export const withSecurityContext = <P extends {}>({

return (
<ReduxStoreProvider store={store}>
<WrappedComponent {...props} />
<CurrentLicense>
<WrappedComponent {...props} />
</CurrentLicense>
</ReduxStoreProvider>
);
});
Expand Down
11 changes: 7 additions & 4 deletions x-pack/plugins/security_solution/public/management/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { ManagementContainer } from './pages';
import { NotFoundPage } from '../app/404';
import { CurrentLicense } from '../common/components/current_license';

/**
* Returns the React Router Routes for the management area
*/
export const ManagementRoutes = () => (
<Switch>
<Route path="/" component={ManagementContainer} />
<Route render={() => <NotFoundPage />} />
</Switch>
<CurrentLicense>
<Switch>
<Route path="/" component={ManagementContainer} />
<Route render={() => <NotFoundPage />} />
</Switch>
</CurrentLicense>
);

0 comments on commit 631fd9d

Please sign in to comment.