diff --git a/build.gradle b/build.gradle index 09dd96fcb1..c3658aa403 100644 --- a/build.gradle +++ b/build.gradle @@ -613,11 +613,8 @@ dependencies { implementation 'com.rfksystems:blake2b:2.0.0' implementation 'com.password4j:password4j:1.8.2' - // Action privileges - implementation 'com.selectivem.collections:checklists:1.2.1' - implementation 'com.selectivem.collections:compact-subsets:1.2.1' - implementation 'com.selectivem.collections:interfaces:1.2.1' - runtimeOnly 'com.selectivem.collections:backing-collections:1.2.1' + // Action privileges: check tables and compact collections + implementation 'com.selectivem.collections:special-collections-complete:1.3.0' //JWT implementation "io.jsonwebtoken:jjwt-api:${jjwt_version}" diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 4238293084..b524d156df 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -165,6 +165,7 @@ import org.opensearch.security.http.NonSslHttpServerTransport; import org.opensearch.security.http.XFFResolver; import org.opensearch.security.identity.SecurityTokenManager; +import org.opensearch.security.privileges.ActionPrivileges; import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.privileges.PrivilegesInterceptor; import org.opensearch.security.privileges.RestLayerPrivilegesEvaluator; @@ -2009,6 +2010,10 @@ public List> getSettings() { Property.Filtered ) ); + + // Privileges evaluation + settings.add(ActionPrivileges.PRECOMPUTED_PRIVILEGES_MAX_HEAP_SIZE); + settings.add(ActionPrivileges.PRECOMPUTED_PRIVILEGES_INCLUDE_INDICES); } return settings; diff --git a/src/main/java/org/opensearch/security/privileges/ActionPrivileges.java b/src/main/java/org/opensearch/security/privileges/ActionPrivileges.java index 3b85799104..0b76137dc4 100644 --- a/src/main/java/org/opensearch/security/privileges/ActionPrivileges.java +++ b/src/main/java/org/opensearch/security/privileges/ActionPrivileges.java @@ -20,6 +20,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -31,6 +32,10 @@ import org.opensearch.cluster.metadata.IndexAbstraction; import org.opensearch.cluster.metadata.IndexMetadata; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.common.settings.Setting; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.common.unit.ByteSizeUnit; +import org.opensearch.core.common.unit.ByteSizeValue; import org.opensearch.security.resolver.IndexResolverReplacer; import org.opensearch.security.securityconf.FlattenedActionGroups; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; @@ -38,6 +43,7 @@ import org.opensearch.security.support.WildcardMatcher; import com.selectivem.collections.CheckTable; +import com.selectivem.collections.CompactMapGroupBuilder; import com.selectivem.collections.DeduplicatingCompactSubSetBuilder; import com.selectivem.collections.ImmutableCompactSubSet; @@ -59,6 +65,38 @@ * then removed. */ public class ActionPrivileges { + + /** + * This setting controls the allowed heap size of the precomputed index privileges (in the inner class StatefulIndexPrivileges). + * If the size of the indices exceed the amount of bytes configured here, it will be truncated. Privileges evaluation will + * continue to work correctly, but it will be slower. + *

+ * This settings defaults to 10 MB. This is a generous limit. Experiments have shown that an example setup with + * 10,000 indices and 1,000 roles requires about 1 MB of heap. 100,000 indices and 100 roles require about 9 MB of heap. + * (Of course, these numbers can vary widely based on the actual role configuration). + *

+ * The setting plugins.security.privileges_evaluation.precomputed_privileges.include_indices can be used to control + * for which indices the precomputed privileges shall be created. This allows to lower the heap utilization. + */ + public static Setting PRECOMPUTED_PRIVILEGES_MAX_HEAP_SIZE = Setting.memorySizeSetting( + "plugins.security.privileges_evaluation.precomputed_privileges.max_heap_size", + new ByteSizeValue(10, ByteSizeUnit.MB), + Setting.Property.NodeScope + ); + + /** + * Determines the indices which shall be included in the precomputed index privileges. Included indices get + * the fasted privilege evaluation. + *

+ * You can use patterns like "index_*". + *

+ * Defaults to all indices. + */ + public static Setting PRECOMPUTED_PRIVILEGES_INCLUDE_INDICES = Setting.simpleString( + "plugins.security.privileges_evaluation.precomputed_privileges.include_indices", + Setting.Property.NodeScope + ); + private static final Logger log = LogManager.getLogger(ActionPrivileges.class); private final ClusterPrivileges cluster; @@ -68,6 +106,8 @@ public class ActionPrivileges { private final ImmutableSet wellKnownClusterActions; private final ImmutableSet wellKnownIndexActions; private final Supplier> indexMetadataSupplier; + private final ByteSizeValue statefulIndexMaxHeapSize; + private final WildcardMatcher statefulIndexIncludeIndices; private volatile StatefulIndexPrivileges statefulIndex; @@ -78,6 +118,7 @@ public ActionPrivileges( SecurityDynamicConfiguration rolesUnsafe, FlattenedActionGroups actionGroups, Supplier> indexMetadataSupplier, + Settings settings, ImmutableSet wellKnownClusterActions, ImmutableSet wellKnownIndexActions, ImmutableSet explicitlyRequiredIndexActions @@ -91,17 +132,24 @@ public ActionPrivileges( this.wellKnownClusterActions = wellKnownClusterActions; this.wellKnownIndexActions = wellKnownIndexActions; this.indexMetadataSupplier = indexMetadataSupplier; + this.statefulIndexMaxHeapSize = PRECOMPUTED_PRIVILEGES_MAX_HEAP_SIZE.get(settings); + String statefulIndexIncludeIndices = PRECOMPUTED_PRIVILEGES_INCLUDE_INDICES.get(settings); + this.statefulIndexIncludeIndices = Strings.isNullOrEmpty(statefulIndexIncludeIndices) + ? null + : WildcardMatcher.from(statefulIndexIncludeIndices); } public ActionPrivileges( SecurityDynamicConfiguration roles, FlattenedActionGroups actionGroups, - Supplier> indexMetadataSupplier + Supplier> indexMetadataSupplier, + Settings settings ) { this( roles, actionGroups, indexMetadataSupplier, + settings, WellKnownActions.CLUSTER_ACTIONS, WellKnownActions.INDEX_ACTIONS, WellKnownActions.EXPLICITLY_REQUIRED_INDEX_ACTIONS @@ -175,10 +223,20 @@ public PrivilegesEvaluatorResponse hasExplicitIndexPrivilege( public void updateStatefulIndexPrivileges(Map indices) { StatefulIndexPrivileges statefulIndex = this.statefulIndex; - indices = StatefulIndexPrivileges.relevantOnly(indices); + indices = StatefulIndexPrivileges.relevantOnly(indices, statefulIndexIncludeIndices); if (statefulIndex == null || !statefulIndex.indices.equals(indices)) { - this.statefulIndex = new StatefulIndexPrivileges(roles, actionGroups, wellKnownIndexActions, indices); + this.statefulIndex = new StatefulIndexPrivileges(roles, actionGroups, wellKnownIndexActions, indices, statefulIndexMaxHeapSize); + } + } + + int getEstimatedStatefulIndexByteSize() { + StatefulIndexPrivileges statefulIndex = this.statefulIndex; + + if (statefulIndex != null) { + return statefulIndex.estimatedByteSize; + } else { + return 0; } } @@ -238,7 +296,6 @@ static class ClusterPrivileges { roles.getCEntries().keySet() ); Map> actionToRoles = new HashMap<>(); - Map> explicitPermissionToRoles = new HashMap<>(); ImmutableSet.Builder rolesWithWildcardPermissions = ImmutableSet.builder(); ImmutableMap.Builder rolesToActionMatcher = ImmutableMap.builder(); @@ -787,6 +844,8 @@ static class StatefulIndexPrivileges { */ private final ImmutableSet wellKnownIndexActions; + private final int estimatedByteSize; + /** * Creates pre-computed index privileges based on the given parameters. *

@@ -798,16 +857,20 @@ static class StatefulIndexPrivileges { SecurityDynamicConfiguration roles, FlattenedActionGroups actionGroups, ImmutableSet wellKnownIndexActions, - Map indices + Map indices, + ByteSizeValue statefulIndexMaxHeapSize ) { + Map< + String, + CompactMapGroupBuilder.MapBuilder>> actionToIndexToRoles = + new HashMap<>(); + CompactMapGroupBuilder> indexMapBuilder = + new CompactMapGroupBuilder<>(indices.keySet()); DeduplicatingCompactSubSetBuilder roleSetBuilder = new DeduplicatingCompactSubSetBuilder<>( roles.getCEntries().keySet() ); - Map>> actionToIndexToRoles = new HashMap<>(); - int leafs = 0; // This counts the number of leafs in the actionToIndexToRoles data structure. Useful for estimating the size. - - for (Map.Entry entry : roles.getCEntries().entrySet()) { + top: for (Map.Entry entry : roles.getCEntries().entrySet()) { try { String roleName = entry.getKey(); RoleV7 role = entry.getValue(); @@ -839,23 +902,34 @@ static class StatefulIndexPrivileges { Map.Entry::getKey )) { for (String action : matchedActions) { - Map> indexToRoles = actionToIndexToRoles - .computeIfAbsent(action, k -> new HashMap<>()); + CompactMapGroupBuilder.MapBuilder< + String, + DeduplicatingCompactSubSetBuilder.SubSetBuilder> indexToRoles = actionToIndexToRoles + .computeIfAbsent( + action, + k -> indexMapBuilder.createMapBuilder((k2) -> roleSetBuilder.createSubSetBuilder()) + ); - indexToRoles.computeIfAbsent(indicesEntry.getKey(), k -> roleSetBuilder.createSubSetBuilder()) - .add(roleName); - leafs++; + indexToRoles.get(indicesEntry.getKey()).add(roleName); if (indicesEntry.getValue() instanceof IndexAbstraction.Alias) { // For aliases we additionally add the sub-indices to the privilege map for (IndexMetadata subIndex : indicesEntry.getValue().getIndices()) { - indexToRoles.computeIfAbsent( - subIndex.getIndex().getName(), - k -> roleSetBuilder.createSubSetBuilder() - ).add(roleName); - leafs++; + indexToRoles.get(subIndex.getIndex().getName()).add(roleName); } } + + if (roleSetBuilder.getEstimatedByteSize() + indexMapBuilder + .getEstimatedByteSize() > statefulIndexMaxHeapSize.getBytes()) { + log.info( + "Size of precomputed index privileges exceeds configured limit ({}). Using capped data structure." + + "This might lead to slightly lower performance during privilege evaluation. Consider raising {} or limiting the performance critical indices using {}.", + statefulIndexMaxHeapSize, + PRECOMPUTED_PRIVILEGES_MAX_HEAP_SIZE.getKey(), + PRECOMPUTED_PRIVILEGES_INCLUDE_INDICES.getKey() + ); + break top; + } } } } @@ -867,22 +941,15 @@ static class StatefulIndexPrivileges { DeduplicatingCompactSubSetBuilder.Completed completedRoleSetBuilder = roleSetBuilder.build(); - log.debug("StatefulIndexPermissions data structure contains {} leafs", leafs); + this.estimatedByteSize = roleSetBuilder.getEstimatedByteSize() + indexMapBuilder.getEstimatedByteSize(); + log.debug("Estimated size of StatefulIndexPermissions data structure: ", this.estimatedByteSize); this.actionToIndexToRoles = actionToIndexToRoles.entrySet() .stream() .collect( ImmutableMap.toImmutableMap( entry -> entry.getKey(), - entry -> entry.getValue() - .entrySet() - .stream() - .collect( - ImmutableMap.toImmutableMap( - entry2 -> entry2.getKey(), - entry2 -> entry2.getValue().build(completedRoleSetBuilder) - ) - ) + entry -> entry.getValue().build(subSetBuilder -> subSetBuilder.build(completedRoleSetBuilder)) ) ); @@ -966,10 +1033,15 @@ private String backingIndexToDataStream(String index, Map relevantOnly(Map indices) { + static Map relevantOnly(Map indices, WildcardMatcher includeIndices) { boolean doFilter = false; for (IndexAbstraction indexAbstraction : indices.values()) { + if (includeIndices != null && !includeIndices.test(indexAbstraction.getName())) { + doFilter = true; + break; + } + if (indexAbstraction instanceof IndexAbstraction.Index) { if (indexAbstraction.getParentDataStream() != null || indexAbstraction.getWriteIndex().getState() == IndexMetadata.State.CLOSE) { @@ -986,6 +1058,10 @@ static Map relevantOnly(Map ImmutableMap.Builder builder = ImmutableMap.builder(); for (IndexAbstraction indexAbstraction : indices.values()) { + if (includeIndices != null && !includeIndices.test(indexAbstraction.getName())) { + continue; + } + if (indexAbstraction instanceof IndexAbstraction.Index) { if (indexAbstraction.getParentDataStream() == null && indexAbstraction.getWriteIndex().getState() != IndexMetadata.State.CLOSE) { diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index 9abecf00e2..b972392191 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -149,6 +149,7 @@ public class PrivilegesEvaluator { private final PitPrivilegesEvaluator pitPrivilegesEvaluator; private DynamicConfigModel dcm; private final NamedXContentRegistry namedXContentRegistry; + private final Settings settings; private volatile ActionPrivileges actionPrivileges; public PrivilegesEvaluator( @@ -172,6 +173,7 @@ public PrivilegesEvaluator( this.threadContext = threadContext; this.privilegesInterceptor = privilegesInterceptor; this.clusterStateSupplier = clusterStateSupplier; + this.settings = settings; this.checkSnapshotRestoreWritePrivileges = settings.getAsBoolean( ConfigConstants.SECURITY_CHECK_SNAPSHOT_RESTORE_WRITE_PRIVILEGES, @@ -235,7 +237,8 @@ void updateConfiguration( ActionPrivileges actionPrivileges = new ActionPrivileges( DynamicConfigFactory.addStatics(rolesConfiguration.clone()), flattenedActionGroups, - () -> clusterStateSupplier.get().metadata().getIndicesLookup() + () -> clusterStateSupplier.get().metadata().getIndicesLookup(), + settings ); actionPrivileges.updateStatefulIndexPrivileges(clusterStateSupplier.get().metadata().getIndicesLookup()); this.actionPrivileges = actionPrivileges; diff --git a/src/main/java/org/opensearch/security/privileges/TermsAggregationEvaluator.java b/src/main/java/org/opensearch/security/privileges/TermsAggregationEvaluator.java index 851c29cd32..a2cd1c16a7 100644 --- a/src/main/java/org/opensearch/security/privileges/TermsAggregationEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/TermsAggregationEvaluator.java @@ -54,7 +54,8 @@ public class TermsAggregationEvaluator { MultiGetAction.NAME, GetAction.NAME, SearchAction.NAME, - FieldCapabilitiesAction.NAME ); + FieldCapabilitiesAction.NAME + ); private static final QueryBuilder NONE_QUERY = new MatchNoneQueryBuilder(); diff --git a/src/test/java/org/opensearch/security/privileges/ActionPrivilegesTest.java b/src/test/java/org/opensearch/security/privileges/ActionPrivilegesTest.java index efe6d92938..e4ce2d4bec 100644 --- a/src/test/java/org/opensearch/security/privileges/ActionPrivilegesTest.java +++ b/src/test/java/org/opensearch/security/privileges/ActionPrivilegesTest.java @@ -13,14 +13,17 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.fasterxml.jackson.core.JsonProcessingException; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -37,6 +40,7 @@ import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.user.User; +import org.opensearch.security.util.MockIndexMetadataBuilder; import static org.opensearch.security.privileges.PrivilegeEvaluatorResponseMatcher.isAllowed; import static org.opensearch.security.privileges.PrivilegeEvaluatorResponseMatcher.isForbidden; @@ -56,7 +60,8 @@ @Suite.SuiteClasses({ ActionPrivilegesTest.ClusterPrivileges.class, ActionPrivilegesTest.IndexPrivileges.IndicesAndAliases.class, - ActionPrivilegesTest.IndexPrivileges.DataStreams.class }) + ActionPrivilegesTest.IndexPrivileges.DataStreams.class, + ActionPrivilegesTest.StatefulIndexPrivilegesHeapSize.class }) public class ActionPrivilegesTest { public static class ClusterPrivileges { @Test @@ -65,7 +70,7 @@ public void clusterAction_wellKnown() throws Exception { " cluster_permissions:\n" + // " - cluster:monitor/nodes/stats*", CType.ROLES); - ActionPrivileges subject = new ActionPrivileges(roles, FlattenedActionGroups.EMPTY, null); + ActionPrivileges subject = new ActionPrivileges(roles, FlattenedActionGroups.EMPTY, null, Settings.EMPTY); assertThat(subject.hasClusterPrivilege(ctx("test_role"), "cluster:monitor/nodes/stats"), isAllowed()); assertThat( @@ -84,7 +89,7 @@ public void clusterAction_notWellKnown() throws Exception { " cluster_permissions:\n" + // " - cluster:monitor/nodes/stats*", CType.ROLES); - ActionPrivileges subject = new ActionPrivileges(roles, FlattenedActionGroups.EMPTY, null); + ActionPrivileges subject = new ActionPrivileges(roles, FlattenedActionGroups.EMPTY, null, Settings.EMPTY); assertThat(subject.hasClusterPrivilege(ctx("test_role"), "cluster:monitor/nodes/stats/somethingnotwellknown"), isAllowed()); assertThat( @@ -270,6 +275,7 @@ public IndicesAndAliases(IndexSpec indexSpec, ActionSpec actionSpec, Statefulnes roles, FlattenedActionGroups.EMPTY, () -> INDEX_METADATA, + Settings.EMPTY, WellKnownActions.CLUSTER_ACTIONS, WellKnownActions.INDEX_ACTIONS, WellKnownActions.INDEX_ACTIONS @@ -437,7 +443,7 @@ public DataStreams(IndexSpec indexSpec, ActionSpec actionSpec, Statefulness stat : ImmutableSet.of("indices:foobar/unknown"); this.indexSpec.indexMetadata = INDEX_METADATA; - this.subject = new ActionPrivileges(roles, FlattenedActionGroups.EMPTY, () -> INDEX_METADATA); + this.subject = new ActionPrivileges(roles, FlattenedActionGroups.EMPTY, () -> INDEX_METADATA, Settings.EMPTY); if (statefulness == Statefulness.STATEFUL) { this.subject.updateStatefulIndexPrivileges(INDEX_METADATA); @@ -595,6 +601,114 @@ enum Statefulness { } } + /** + * Verifies that the heap size used by StatefulIndexPrivileges stays within expected bounds. + */ + @RunWith(Parameterized.class) + public static class StatefulIndexPrivilegesHeapSize { + + final Map indices; + final SecurityDynamicConfiguration roles; + final int expectedEstimatedNumberOfBytes; + + @Test + public void estimatedSize() throws Exception { + ActionPrivileges subject = new ActionPrivileges(roles, FlattenedActionGroups.EMPTY, () -> indices, Settings.EMPTY); + + subject.updateStatefulIndexPrivileges(indices); + + int lowerBound = (int) (expectedEstimatedNumberOfBytes * 0.9); + int upperBound = (int) (expectedEstimatedNumberOfBytes * 1.1); + + int actualEstimatedNumberOfBytes = subject.getEstimatedStatefulIndexByteSize(); + + Assert.assertTrue( + "estimatedNumberOfBytes: " + lowerBound + " < " + actualEstimatedNumberOfBytes + " < " + upperBound, + lowerBound < actualEstimatedNumberOfBytes && actualEstimatedNumberOfBytes < upperBound + ); + } + + public StatefulIndexPrivilegesHeapSize(int numberOfIndices, int numberOfRoles, int expectedEstimatedNumberOfBytes) { + this.indices = createIndices(numberOfIndices); + this.roles = createRoles(numberOfRoles, numberOfIndices); + this.expectedEstimatedNumberOfBytes = expectedEstimatedNumberOfBytes; + } + + @Parameterized.Parameters(name = "{0} indices; {1} roles; estimated number of bytes: {2}") + public static Collection params() { + List result = new ArrayList<>(); + + // indices; roles; expected number of bytes + result.add(new Object[] { 100, 10, 10_000 }); + result.add(new Object[] { 100, 100, 13_000 }); + result.add(new Object[] { 100, 1000, 26_000 }); + + result.add(new Object[] { 1000, 10, 92_000 }); + result.add(new Object[] { 1000, 100, 94_000 }); + result.add(new Object[] { 1000, 1000, 112_000 }); + + result.add(new Object[] { 10_000, 10, 890_000 }); + result.add(new Object[] { 10_000, 100, 930_000 }); + + return result; + } + + static Map createIndices(int numberOfIndices) { + String[] names = new String[numberOfIndices]; + + for (int i = 0; i < numberOfIndices; i++) { + names[i] = "index_" + i; + } + + return MockIndexMetadataBuilder.indices(names).build(); + } + + static SecurityDynamicConfiguration createRoles(int numberOfRoles, int numberOfIndices) { + try { + Random random = new Random(1); + Map rolesDocument = new HashMap<>(); + List allowedActions = Arrays.asList( + "indices:data/read*", + "indices:admin/mappings/fields/get*", + "indices:admin/resolve/index", + "indices:data/write*", + "indices:admin/mapping/put" + ); + + for (int i = 0; i < numberOfRoles; i++) { + List indexPatterns = new ArrayList<>(); + int numberOfIndexPatterns = Math.min( + (int) ((Math.abs(random.nextGaussian() + 0.3)) * 0.5 * numberOfIndices), + numberOfIndices + ); + + int numberOfIndexPatterns10th = numberOfIndexPatterns / 10; + + if (numberOfIndexPatterns10th > 0) { + for (int k = 0; k < numberOfIndexPatterns10th; k++) { + indexPatterns.add("index_" + random.nextInt(numberOfIndices / 10) + "*"); + } + } else { + for (int k = 0; k < numberOfIndexPatterns; k++) { + indexPatterns.add("index_" + random.nextInt(numberOfIndices)); + } + } + + Map roleDocument = ImmutableMap.of( + "index_permissions", + Arrays.asList(ImmutableMap.of("index_patterns", indexPatterns, "allowed_actions", allowedActions)) + ); + + rolesDocument.put("role_" + i, roleDocument); + } + + return SecurityDynamicConfiguration.fromMap(rolesDocument, CType.ROLES, 2); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + } + static PrivilegesEvaluationContext ctx(String... roles) { User user = new User("test_user"); user.addAttributes(ImmutableMap.of("attrs.dept_no", "a11")); diff --git a/src/test/java/org/opensearch/security/privileges/SystemIndexAccessEvaluatorTest.java b/src/test/java/org/opensearch/security/privileges/SystemIndexAccessEvaluatorTest.java index 13f19c2629..b3c476d42c 100644 --- a/src/test/java/org/opensearch/security/privileges/SystemIndexAccessEvaluatorTest.java +++ b/src/test/java/org/opensearch/security/privileges/SystemIndexAccessEvaluatorTest.java @@ -129,7 +129,7 @@ public void setup( 2 ); - this.actionPrivileges = new ActionPrivileges(rolesConfig, FlattenedActionGroups.EMPTY, () -> indexMetadata); + this.actionPrivileges = new ActionPrivileges(rolesConfig, FlattenedActionGroups.EMPTY, () -> indexMetadata, Settings.EMPTY); } catch (JsonProcessingException e) { throw new RuntimeException(e); }