diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesConfiguration.java b/src/main/java/org/opensearch/security/privileges/PrivilegesConfiguration.java index 6a66b226ab..af9d91b550 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesConfiguration.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesConfiguration.java @@ -65,6 +65,13 @@ public class PrivilegesConfiguration { ); private final PrivilegesInterceptorImpl privilegesInterceptor; + /** + * Tracks the sequence numbers of roles and action groups configurations to detect changes. + * Only rebuild ActionPrivileges when these actually change. + */ + private volatile long lastRolesSeqNo = -1; + private volatile long lastActionGroupsSeqNo = -1; + /** * The pure static action groups should be ONLY used by action privileges for plugins; only those cannot and should * not have knowledge of any action groups defined in the dynamic configuration. All other functionality should @@ -109,6 +116,12 @@ public PrivilegesConfiguration( .withStaticConfig(); ConfigV7 generalConfiguration = configurationRepository.getConfiguration(CType.CONFIG).getCEntry(CType.CONFIG.name()); + // Check if roles or action groups actually changed + long currentRolesSeqNo = rolesConfiguration.getSeqNo(); + long currentActionGroupsSeqNo = actionGroupsConfiguration.getSeqNo(); + boolean rolesOrActionGroupsChanged = currentRolesSeqNo != lastRolesSeqNo + || currentActionGroupsSeqNo != lastActionGroupsSeqNo; + FlattenedActionGroups flattenedActionGroups = new FlattenedActionGroups(actionGroupsConfiguration.withStaticConfig()); this.actionGroups.set(flattenedActionGroups); @@ -142,8 +155,28 @@ public PrivilegesConfiguration( if (oldInstance != null) { oldInstance.shutdown(); } - } else { + lastRolesSeqNo = currentRolesSeqNo; + lastActionGroupsSeqNo = currentActionGroupsSeqNo; + } else if (rolesOrActionGroupsChanged) { + // Only rebuild ActionPrivileges when roles or action groups changed + log.debug( + "Roles or action groups changed (roles seqNo: {} -> {}, actionGroups seqNo: {} -> {}), rebuilding ActionPrivileges", + lastRolesSeqNo, + currentRolesSeqNo, + lastActionGroupsSeqNo, + currentActionGroupsSeqNo + ); privilegesEvaluator.get().updateConfiguration(flattenedActionGroups, rolesConfiguration, generalConfiguration); + lastRolesSeqNo = currentRolesSeqNo; + lastActionGroupsSeqNo = currentActionGroupsSeqNo; + } else { + // Only update general configuration settings (dnfof, filtered alias mode) without rebuilding ActionPrivileges + log.debug( + "Roles and action groups unchanged (seqNo: roles={}, actionGroups={}), skipping ActionPrivileges rebuild", + currentRolesSeqNo, + currentActionGroupsSeqNo + ); + privilegesEvaluator.get().updateGeneralConfiguration(generalConfiguration); } try { diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index ddbdf7be5c..53785130e1 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -67,6 +67,12 @@ void updateConfiguration( ConfigV7 generalConfiguration ); + /** + * Updates only the general configuration settings (like dnfof, filtered alias mode) without + * rebuilding ActionPrivileges. Use this when roles and action groups haven't changed. + */ + void updateGeneralConfiguration(ConfigV7 generalConfiguration); + void updateClusterStateMetadata(ClusterService clusterService); /** @@ -129,6 +135,11 @@ public void updateConfiguration( } + @Override + public void updateGeneralConfiguration(ConfigV7 generalConfiguration) { + + } + @Override public void updateClusterStateMetadata(ClusterService clusterService) { diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorImpl.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorImpl.java index 558fb6e6ad..777b2a908d 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorImpl.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorImpl.java @@ -213,9 +213,7 @@ public void updateConfiguration( SecurityDynamicConfiguration rolesConfiguration, ConfigV7 generalConfiguration ) { - this.dnfofEnabled = isDnfofEnabled(generalConfiguration); - this.dnfofForEmptyResultsEnabled = isDnfofEmptyEnabled(generalConfiguration); - this.filteredAliasMode = getFilteredAliasMode(generalConfiguration); + updateGeneralConfiguration(generalConfiguration); try { RoleBasedActionPrivileges actionPrivileges = new RoleBasedActionPrivileges(rolesConfiguration, flattenedActionGroups, settings); @@ -232,6 +230,13 @@ public void updateConfiguration( } + @Override + public void updateGeneralConfiguration(ConfigV7 generalConfiguration) { + this.dnfofEnabled = isDnfofEnabled(generalConfiguration); + this.dnfofForEmptyResultsEnabled = isDnfofEmptyEnabled(generalConfiguration); + this.filteredAliasMode = getFilteredAliasMode(generalConfiguration); + } + @Override public void updateClusterStateMetadata(ClusterService clusterService) { RoleBasedActionPrivileges actionPrivileges = this.actionPrivileges.get(); diff --git a/src/test/java/org/opensearch/security/privileges/RestLayerPrivilegesEvaluatorTest.java b/src/test/java/org/opensearch/security/privileges/RestLayerPrivilegesEvaluatorTest.java index 311176c9a0..0b2712177d 100644 --- a/src/test/java/org/opensearch/security/privileges/RestLayerPrivilegesEvaluatorTest.java +++ b/src/test/java/org/opensearch/security/privileges/RestLayerPrivilegesEvaluatorTest.java @@ -177,6 +177,11 @@ public void updateConfiguration( } + @Override + public void updateGeneralConfiguration(ConfigV7 generalConfiguration) { + + } + @Override public void updateClusterStateMetadata(ClusterService clusterService) {