@@ -145,7 +145,8 @@ public boolean hasFieldOrDocumentLevelSecurity() {
145145 }
146146
147147 private IsResourceAuthorizedPredicate buildIndexMatcherPredicateForAction (String action ) {
148- final Set <String > ordinaryIndices = new HashSet <>();
148+ final Set <String > dataAccessOrdinaryIndices = new HashSet <>();
149+ final Set <String > failureAccessOrdinaryIndices = new HashSet <>();
149150 final Set <String > restrictedIndices = new HashSet <>();
150151 final Set <String > grantMappingUpdatesOnIndices = new HashSet <>();
151152 final Set <String > grantMappingUpdatesOnRestrictedIndices = new HashSet <>();
@@ -155,7 +156,11 @@ private IsResourceAuthorizedPredicate buildIndexMatcherPredicateForAction(String
155156 if (group .allowRestrictedIndices ) {
156157 restrictedIndices .addAll (Arrays .asList (group .indices ()));
157158 } else {
158- ordinaryIndices .addAll (Arrays .asList (group .indices ()));
159+ if (group .failureStoreOnly ) {
160+ failureAccessOrdinaryIndices .addAll (Arrays .asList (group .indices ()));
161+ } else {
162+ dataAccessOrdinaryIndices .addAll (Arrays .asList (group .indices ()));
163+ }
159164 }
160165 } else if (isMappingUpdateAction && containsPrivilegeThatGrantsMappingUpdatesForBwc (group )) {
161166 // special BWC case for certain privileges: allow put mapping on indices and aliases (but not on data streams), even if
@@ -167,40 +172,56 @@ private IsResourceAuthorizedPredicate buildIndexMatcherPredicateForAction(String
167172 }
168173 }
169174 }
170- final StringMatcher nameMatcher = indexMatcher (ordinaryIndices , restrictedIndices );
175+ final StringMatcher dataAccessNameMatcher = indexMatcher (dataAccessOrdinaryIndices , restrictedIndices );
176+ // TODO handle restricted indices for failure access
177+ final StringMatcher failureAccessNameMatcher = indexMatcher (failureAccessOrdinaryIndices , Set .of ());
171178 final StringMatcher bwcSpecialCaseMatcher = indexMatcher (grantMappingUpdatesOnIndices , grantMappingUpdatesOnRestrictedIndices );
172- return new IsResourceAuthorizedPredicate (nameMatcher , bwcSpecialCaseMatcher );
179+ return new IsResourceAuthorizedPredicate (dataAccessNameMatcher , failureAccessNameMatcher , bwcSpecialCaseMatcher );
173180 }
174181
175182 /**
176183 * This encapsulates the authorization test for resources.
177184 * There is an additional test for resources that are missing or that are not a datastream or a backing index.
178185 */
179- public static class IsResourceAuthorizedPredicate implements BiPredicate < String , IndexAbstraction > {
186+ public static class IsResourceAuthorizedPredicate {
180187
181188 private final BiPredicate <String , IndexAbstraction > biPredicate ;
189+ private final BiPredicate <String , IndexAbstraction > failureAccessBiPredicate ;
182190
183191 // public for tests
184- public IsResourceAuthorizedPredicate (StringMatcher resourceNameMatcher , StringMatcher additionalNonDatastreamNameMatcher ) {
192+ public IsResourceAuthorizedPredicate (
193+ StringMatcher resourceNameMatcher ,
194+ StringMatcher failureAccessNameMatcher ,
195+ StringMatcher additionalNonDatastreamNameMatcher
196+ ) {
185197 this ((String name , @ Nullable IndexAbstraction indexAbstraction ) -> {
186198 assert indexAbstraction == null || name .equals (indexAbstraction .getName ());
187199 return resourceNameMatcher .test (name )
188200 || (isPartOfDatastream (indexAbstraction ) == false && additionalNonDatastreamNameMatcher .test (name ));
201+ }, (String name , @ Nullable IndexAbstraction indexAbstraction ) -> {
202+ assert indexAbstraction == null || name .equals (indexAbstraction .getName ());
203+ return failureAccessNameMatcher .test (name );
189204 });
190205 }
191206
192- private IsResourceAuthorizedPredicate (BiPredicate <String , IndexAbstraction > biPredicate ) {
207+ private IsResourceAuthorizedPredicate (
208+ BiPredicate <String , IndexAbstraction > biPredicate ,
209+ BiPredicate <String , IndexAbstraction > failureAccessBiPredicate
210+ ) {
193211 this .biPredicate = biPredicate ;
212+ this .failureAccessBiPredicate = failureAccessBiPredicate ;
194213 }
195214
196215 /**
197216 * Given another {@link IsResourceAuthorizedPredicate} instance in {@param other},
198217 * return a new {@link IsResourceAuthorizedPredicate} instance that is equivalent to the conjunction of
199218 * authorization tests of that other instance and this one.
200219 */
201- @ Override
202- public final IsResourceAuthorizedPredicate and (BiPredicate <? super String , ? super IndexAbstraction > other ) {
203- return new IsResourceAuthorizedPredicate (this .biPredicate .and (other ));
220+ public final IsResourceAuthorizedPredicate and (IsResourceAuthorizedPredicate other ) {
221+ return new IsResourceAuthorizedPredicate (
222+ this .biPredicate .and (other .biPredicate ),
223+ this .failureAccessBiPredicate .and (other .failureAccessBiPredicate )
224+ );
204225 }
205226
206227 /**
@@ -209,7 +230,11 @@ public final IsResourceAuthorizedPredicate and(BiPredicate<? super String, ? sup
209230 * Returns {@code true} if access to the given resource is authorized or {@code false} otherwise.
210231 */
211232 public final boolean test (IndexAbstraction indexAbstraction ) {
212- return test (indexAbstraction .getName (), indexAbstraction );
233+ return test (indexAbstraction .getName (), indexAbstraction , null );
234+ }
235+
236+ public final boolean test (IndexAbstraction indexAbstraction , @ Nullable String selector ) {
237+ return test (indexAbstraction .getName (), indexAbstraction , selector );
213238 }
214239
215240 /**
@@ -218,9 +243,19 @@ public final boolean test(IndexAbstraction indexAbstraction) {
218243 * if it doesn't.
219244 * Returns {@code true} if access to the given resource is authorized or {@code false} otherwise.
220245 */
221- @ Override
222246 public boolean test (String name , @ Nullable IndexAbstraction indexAbstraction ) {
223- return biPredicate .test (name , indexAbstraction );
247+ return test (name , indexAbstraction , null );
248+ }
249+
250+ public boolean test (String name , @ Nullable IndexAbstraction indexAbstraction , @ Nullable String selector ) {
251+ if (selector == null || IndexComponentSelector .DATA .getKey ().equals (selector )) {
252+ return biPredicate .test (name , indexAbstraction );
253+ } else if (IndexComponentSelector .FAILURES .getKey ().equals (selector )) {
254+ return failureAccessBiPredicate .test (name , indexAbstraction );
255+ } else {
256+ assert selector .equals (IndexComponentSelector .ALL_APPLICABLE .getKey ()) : "unexpected selector [" + selector + "]" ;
257+ return biPredicate .test (name , indexAbstraction ) && failureAccessBiPredicate .test (name , indexAbstraction );
258+ }
224259 }
225260
226261 private static boolean isPartOfDatastream (IndexAbstraction indexAbstraction ) {
@@ -354,7 +389,7 @@ public Automaton allowedActionsMatcher(String index) {
354389 * Represents the set of data required about an IndexAbstraction (index/alias/datastream) in order to perform authorization on that
355390 * object (including setting up the necessary data structures for Field and Document Level Security).
356391 */
357- private static class IndexResource {
392+ public static class IndexResource {
358393 /**
359394 * The name of the IndexAbstraction on which authorization is being performed
360395 */
0 commit comments