Skip to content

Support enable/disable rules on request configuration rules - #12702

Merged
allyoucanmap merged 2 commits into
geosolutions-it:masterfrom
offtherailz:security-rules-enabled
Jul 28, 2026
Merged

Support enable/disable rules on request configuration rules#12702
allyoucanmap merged 2 commits into
geosolutions-it:masterfrom
offtherailz:security-rules-enabled

Conversation

@offtherailz

@offtherailz offtherailz commented Jul 21, 2026

Copy link
Copy Markdown
Member

Fixes #12704

Summary

  • Entries in requestsConfigurationRules (and legacy authenticationRules) can now declare an enabled property: a plain boolean or a plugin expression string (same syntax as cfg.disablePluginIf), e.g. "{includes(state('usergroups'), 'editor')}".
  • Rules without enabled keep the current behaviour (always applied).
  • Reuses the existing PluginsUtils.handleExpression/getMonitoredState machinery, no new expression syntax introduced.
  • Docs updated in local-config.md.

Test plan

  • Added tests in SecurityUtils-test.js: no enabled property, enabled: false, expression resolving false, expression resolving true against state('usergroups').
  • Ran the full SecurityUtils-test.js suite locally via karma (chrome headless) — 59/59 passing, no regressions.

@tdipisa

tdipisa commented Jul 21, 2026

Copy link
Copy Markdown
Member

Converted to draft waiting for 2026.02.00 to be out

@tdipisa
tdipisa marked this pull request as ready for review July 22, 2026 16:31
Comment thread web/client/utils/SecurityUtils.js Outdated
*/
const isRuleEnabled = (rule) => {
const enabled = rule?.enabled ?? true;
const monitoredState = getMonitoredState(getState());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other getMonitoredState are including also the ConfigUtils.getConfigProp('monitorState') as second argument to include additional monitorState configured in a custom localConfig.json

const monitoredState = getMonitoredState(getState(), ConfigUtils.getConfigProp('monitorState'));

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread web/client/utils/SecurityUtils.js Outdated
Comment on lines +260 to +264
const isRuleEnabled = (rule) => {
const enabled = rule?.enabled ?? true;
const monitoredState = getMonitoredState(getState());
return !!handleExpression((path) => get(monitoredState, path), undefined, enabled);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a proposal, if we think isRuleEnabled is enough we can keep it for the moment.

At the moment we run isRuleEnabled for each rule, which means we call getMonitoredState and its internal memoize resolver (filterState) once per rule on every request. This could be costly because the resolver builds the cache key with JSON.stringify over every monitored entry, and the entry list is configurable via monitorState, so we cannot predict what ends up in there (it could technically be a large object).

The proposal is a function that takes rules and returns filtered rules:

/**
 * Filters out rules whose `enabled` property resolves to falsy.
 * `enabled` is a boolean or a plugin expression string (same syntax as `cfg.disablePluginIf`).
 * Rules without an `enabled` property are always applied.
 * @param {object[]} rules the request configuration rules
 * @returns {object[]} the enabled rules
 */
const filterEnabledRules = (rules = []) => {
    const needsMonitoredState = rules.some(rule => isString(rule?.enabled));
    const monitoredState = needsMonitoredState ? getMonitoredState(getState(), ConfigUtils.getConfigProp('monitorState')) : {};
    const getMonitored = (path) => get(monitoredState, path);
    return rules.filter(rule => !!handleExpression(getMonitored, undefined, rule?.enabled ?? true));
};

applied like this:

return filterEnabledRules(stateRules);
return filterEnabledRules(configRules);
return filterEnabledRules(convertAuthenticationRulesToRequestConfiguration(authRules));

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Each entry in requestsConfigurationRules (and legacy authenticationRules)
can now set enabled to a boolean or a plugin expression string, evaluated
the same way as cfg.disablePluginIf (e.g. via state('usergroups')). Lets
an auth/header rule apply only to matching user groups.
Include the monitorState configuration in the monitored state, as every
other getMonitoredState caller does, so expressions can use custom
entries from localConfig.json.

Resolve the monitored state once per filtering and only when a rule
actually declares an expression: building it serializes every monitored
entry, and getRequestConfigurationRules runs on each request.
@offtherailz
offtherailz force-pushed the security-rules-enabled branch from 407ccc6 to c556aac Compare July 27, 2026 16:25
@offtherailz
offtherailz requested a review from allyoucanmap July 27, 2026 16:25
@allyoucanmap
allyoucanmap merged commit 13dbeab into geosolutions-it:master Jul 28, 2026
15 checks passed
@offtherailz

Copy link
Copy Markdown
Member Author

Successfully created backport PR for 2026.02.xx:

@allyoucanmap

Copy link
Copy Markdown
Contributor

@ElenaGallo please test this fix on dev, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support enable/disable rules on request configuration rules

3 participants