Skip to content

Failure Store Access Authorization #123986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
178 commits
Select commit Hold shift + click to select a range
0ff0bf5
WIP
n1v0lg Feb 13, 2025
78170dc
More
n1v0lg Feb 13, 2025
4c0d584
Moar
n1v0lg Feb 13, 2025
37d5427
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 14, 2025
0789eea
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 16, 2025
9976ca1
More
n1v0lg Feb 16, 2025
bcd42c0
Fix
n1v0lg Feb 16, 2025
6ceb401
Fix imports
n1v0lg Feb 17, 2025
793215f
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 17, 2025
a531e5f
More fixes
n1v0lg Feb 17, 2025
2ccd969
Moar
n1v0lg Feb 17, 2025
444112b
Superuser etc
n1v0lg Feb 17, 2025
79d15eb
Composite role store tests
n1v0lg Feb 17, 2025
125e808
Test fixes
n1v0lg Feb 17, 2025
671cf70
Test fixes
n1v0lg Feb 17, 2025
1988a21
Fix more
n1v0lg Feb 17, 2025
ffcf427
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 17, 2025
c8fc1f7
Keep selector with index privilege
n1v0lg Feb 17, 2025
0858cd3
Remote indices too
n1v0lg Feb 17, 2025
8fcb15c
Undo docs test
n1v0lg Feb 17, 2025
bf3d46b
Simlify
n1v0lg Feb 17, 2025
4d301c9
Cleaner selector handling
n1v0lg Feb 17, 2025
b03a593
Fix test
n1v0lg Feb 17, 2025
d0e61c1
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 17, 2025
da43e54
Union
n1v0lg Feb 17, 2025
8582f80
Rework IndexPrivilege#get
n1v0lg Feb 18, 2025
9732f8d
Assert on names
n1v0lg Feb 18, 2025
0c848e4
More clean up and TODOs
n1v0lg Feb 18, 2025
83f2148
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 18, 2025
fc01664
Fix and simplify
n1v0lg Feb 18, 2025
79433cb
Test fixes
n1v0lg Feb 18, 2025
6ae9f84
Javadoc and test fixes
n1v0lg Feb 18, 2025
66ccd33
More test fixes
n1v0lg Feb 18, 2025
7e1e2c0
Moar
n1v0lg Feb 18, 2025
37dd755
Fix assertion
n1v0lg Feb 18, 2025
aae20bd
Tests
n1v0lg Feb 18, 2025
d434496
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 19, 2025
253f6ab
Test get privileges
n1v0lg Feb 19, 2025
5922f1f
Javadoc and renames
n1v0lg Feb 19, 2025
8f2eddc
Fix refactor wonkiness
n1v0lg Feb 19, 2025
e7fcf93
Naming so hard
n1v0lg Feb 19, 2025
17855ab
Javadoc
n1v0lg Feb 19, 2025
4a44748
More split tests
n1v0lg Feb 19, 2025
481da2a
Tests
n1v0lg Feb 19, 2025
8036ecf
FLS DLS tests
n1v0lg Feb 19, 2025
d470e5a
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 19, 2025
12d00b8
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 19, 2025
16668b0
Automaton and fls dls test
n1v0lg Feb 19, 2025
879b2b6
Manage roles
n1v0lg Feb 19, 2025
6b9640b
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 19, 2025
f6b6cfb
More
n1v0lg Feb 19, 2025
cafd8d2
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 19, 2025
c2baa5b
Fix test
n1v0lg Feb 19, 2025
baf63ed
Fix
n1v0lg Feb 19, 2025
22b861f
Fix and more tests
n1v0lg Feb 20, 2025
2bc314e
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Feb 20, 2025
18258c1
Beef up coverage
n1v0lg Feb 20, 2025
cd4897b
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Mar 3, 2025
6422450
WIP review feedback
n1v0lg Mar 3, 2025
79a7fd5
More
n1v0lg Mar 3, 2025
747597e
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Mar 3, 2025
b05f82b
Assert in config cluser privs
n1v0lg Mar 3, 2025
a603121
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Mar 3, 2025
172141f
Tests
n1v0lg Mar 3, 2025
20f4c5c
More
n1v0lg Mar 3, 2025
aae2ace
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Mar 3, 2025
183cebc
Deterministic order
n1v0lg Mar 3, 2025
35a9935
Merge branch 'main' into read-failure-store-privilege-role-building
n1v0lg Mar 3, 2025
efd11b5
WIP
n1v0lg Mar 3, 2025
95d6369
Authz and test
n1v0lg Mar 4, 2025
fa783df
Merge
n1v0lg Mar 4, 2025
126d615
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 4, 2025
2a654ba
Deal with privilege ordering
n1v0lg Mar 4, 2025
8b1fedb
Merge branch 'read-failure-store-privilege-authz' of github.com:n1v0l…
n1v0lg Mar 4, 2025
47c30cc
Comments
n1v0lg Mar 4, 2025
55c88db
Handle resources with same name different selector
n1v0lg Mar 4, 2025
58e938b
WIP index resolution
n1v0lg Mar 5, 2025
4456c2d
Selectors
n1v0lg Mar 5, 2025
a750b38
x-pack
n1v0lg Mar 5, 2025
df8c04d
More
n1v0lg Mar 5, 2025
674277a
Fix resolvers
n1v0lg Mar 5, 2025
dfe957a
More
n1v0lg Mar 6, 2025
ba33b7c
Write tests
n1v0lg Mar 6, 2025
5a81747
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 6, 2025
1e33a1f
Moar
n1v0lg Mar 6, 2025
2bd7437
WIP clean up tests
n1v0lg Mar 6, 2025
94b71b7
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 6, 2025
abcb1a3
Moar
n1v0lg Mar 6, 2025
e555f74
More tests
n1v0lg Mar 6, 2025
9aafa69
WIP clean up
n1v0lg Mar 6, 2025
ab87f55
Refactor but is it better
n1v0lg Mar 7, 2025
1b96a23
Util
n1v0lg Mar 7, 2025
776d49a
Check selector first
n1v0lg Mar 7, 2025
39995f8
More
n1v0lg Mar 7, 2025
f76392a
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 7, 2025
6b0b6c9
Inline
n1v0lg Mar 7, 2025
d728fd6
Fix sig
n1v0lg Mar 7, 2025
2a22090
Timer
n1v0lg Mar 7, 2025
375fe69
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 9, 2025
365b2b8
Rework name handling
n1v0lg Mar 10, 2025
db2be5d
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 10, 2025
28f207f
Spotless
n1v0lg Mar 10, 2025
084ac8c
More tests
n1v0lg Mar 10, 2025
d8ed014
Toss supplier
n1v0lg Mar 10, 2025
be718df
Moar
n1v0lg Mar 10, 2025
400a1f7
Fix
n1v0lg Mar 10, 2025
fb599ca
Prevent privilege checks
n1v0lg Mar 10, 2025
79d50be
Null check
n1v0lg Mar 10, 2025
0c4ec24
WIP unit tests
n1v0lg Mar 10, 2025
c8205fb
Fix
n1v0lg Mar 10, 2025
599658d
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 10, 2025
aa74147
More selector handling
n1v0lg Mar 10, 2025
a3e6429
WIP test clean up and async search
n1v0lg Mar 10, 2025
e77fb81
Tests and flags
n1v0lg Mar 11, 2025
e8d9542
Use API keys
n1v0lg Mar 11, 2025
0f01492
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 11, 2025
4d7d0f5
API keys with assigned role descriptors
n1v0lg Mar 11, 2025
a1e9c5b
Nit
n1v0lg Mar 11, 2025
6a938f1
Assert
n1v0lg Mar 11, 2025
f7e1690
Fix customer authz engine
n1v0lg Mar 11, 2025
49f9c4c
Clean up
n1v0lg Mar 11, 2025
ca566e8
More
n1v0lg Mar 11, 2025
8efd2d2
Moar
n1v0lg Mar 11, 2025
4f56acc
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 11, 2025
24db961
More comments
n1v0lg Mar 11, 2025
240007e
Assert
n1v0lg Mar 11, 2025
a5b5ac4
Better method name
n1v0lg Mar 11, 2025
2f218db
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 11, 2025
8222abc
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 11, 2025
bdf134a
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 12, 2025
092371e
Tests tests tests
n1v0lg Mar 12, 2025
ff82c48
Merge branch 'read-failure-store-privilege-authz' of github.com:n1v0l…
n1v0lg Mar 12, 2025
903941e
More
n1v0lg Mar 12, 2025
5d0d5d8
Action matcher
n1v0lg Mar 12, 2025
da81d50
Assertions and WIP API key tests
n1v0lg Mar 12, 2025
cd6e74a
More api key tests
n1v0lg Mar 12, 2025
e5d3447
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 12, 2025
fc5c405
Nit
n1v0lg Mar 12, 2025
dae2ce8
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 12, 2025
af90738
Support selectors in allowedActionsMatcher
n1v0lg Mar 12, 2025
82959d7
More unsupported places
n1v0lg Mar 12, 2025
3d66d16
HasPrivileges validation
n1v0lg Mar 12, 2025
8020982
TODO
n1v0lg Mar 12, 2025
1667883
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 12, 2025
063954b
Nits
n1v0lg Mar 12, 2025
758fadb
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 13, 2025
4590f04
Basic FLS tests
n1v0lg Mar 13, 2025
d78cc3e
DLS
n1v0lg Mar 13, 2025
3b6e030
More assertions
n1v0lg Mar 13, 2025
0b09483
Tweak interface
n1v0lg Mar 13, 2025
2ccbcdf
More fixes
n1v0lg Mar 13, 2025
a2ea6f2
Skip pointless map
n1v0lg Mar 13, 2025
d3f50dc
Fix tests
n1v0lg Mar 13, 2025
4ca9978
Assert
n1v0lg Mar 13, 2025
b23f04c
Tests and comments
n1v0lg Mar 14, 2025
fa467f4
Assert
n1v0lg Mar 14, 2025
2931c85
Javadoc
n1v0lg Mar 14, 2025
21f1218
Rm nullable annotations
n1v0lg Mar 14, 2025
9cb1db6
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 14, 2025
75dbd7b
More tests
n1v0lg Mar 14, 2025
1ee4988
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 17, 2025
917b2c7
Update docs/changelog/123986.yaml
n1v0lg Mar 17, 2025
2bb84a0
PIT tests
n1v0lg Mar 17, 2025
1698536
Merge branch 'read-failure-store-privilege-authz' of github.com:n1v0l…
n1v0lg Mar 17, 2025
80619ec
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 17, 2025
f7c5c8e
Changelog
n1v0lg Mar 17, 2025
bfe9448
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 18, 2025
d05ddcf
Address review comments
n1v0lg Mar 19, 2025
6465b7a
Delete docs/changelog/123986.yaml
n1v0lg Mar 19, 2025
5b71fb7
RM changelog
n1v0lg Mar 19, 2025
6dd03c6
Merge branch 'read-failure-store-privilege-authz' of github.com:n1v0l…
n1v0lg Mar 19, 2025
75224d8
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 19, 2025
a5b59bb
Fix edge cases
n1v0lg Mar 19, 2025
91879e7
Clean up
n1v0lg Mar 19, 2025
ff94545
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 19, 2025
998ad64
Fix tests
n1v0lg Mar 20, 2025
3c04acf
Merge branch 'read-failure-store-privilege-authz' of github.com:n1v0l…
n1v0lg Mar 20, 2025
21c920a
Merge branch 'main' into read-failure-store-privilege-authz
n1v0lg Mar 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package org.elasticsearch.example;

import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.IndexComponentSelector;
import org.elasticsearch.action.support.SubscribableListener;
import org.elasticsearch.cluster.metadata.IndexAbstraction;
import org.elasticsearch.cluster.metadata.ProjectMetadata;
Expand All @@ -35,7 +36,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
Expand Down Expand Up @@ -119,19 +119,19 @@ public void loadAuthorizedIndices(
) {
if (isSuperuser(requestInfo.getAuthentication().getEffectiveSubject().getUser())) {
listener.onResponse(new AuthorizedIndices() {
public Supplier<Set<String>> all() {
public Set<String> all(IndexComponentSelector selector) {
return () -> indicesLookup.keySet();
}
public boolean check(String name) {
public boolean check(String name, IndexComponentSelector selector) {
return indicesLookup.containsKey(name);
}
});
} else {
listener.onResponse(new AuthorizedIndices() {
public Supplier<Set<String>> all() {
public Set<String> all(IndexComponentSelector selector) {
return () -> Set.of();
}
public boolean check(String name) {
public boolean check(String name, IndexComponentSelector selector) {
return false;
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,24 @@ public static IndexComponentSelector getByKey(String key) {
return KEY_REGISTRY.get(key);
}

/**
* Like {@link #getByKey(String)} but throws an exception if the key is not recognised.
* @return the selector if recognized. `null` input will return `DATA`.
* @throws IllegalArgumentException if the key was not recognised.
*/
public static IndexComponentSelector getByKeyOrThrow(@Nullable String key) {
if (key == null) {
return DATA;
}
IndexComponentSelector selector = getByKey(key);
if (selector == null) {
throw new IllegalArgumentException(
"Unknown key of index component selector [" + key + "], available options are: " + KEY_REGISTRY.keySet()
);
}
return selector;
}

public static IndexComponentSelector read(StreamInput in) throws IOException {
byte id = in.readByte();
if (in.getTransportVersion().onOrAfter(TransportVersions.REMOVE_ALL_APPLICABLE_SELECTOR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ default boolean isDataStreamRelated() {
return false;
}

/**
* @return whether this index abstraction is a failure index of a data stream
*/
default boolean isFailureIndexOfDataStream() {
return false;
}

/**
* An index abstraction type.
*/
Expand Down Expand Up @@ -183,6 +190,11 @@ public DataStream getParentDataStream() {
return dataStream;
}

@Override
public boolean isFailureIndexOfDataStream() {
return getParentDataStream() != null && getParentDataStream().isFailureStoreIndex(getName());
}

@Override
public boolean isHidden() {
return isHidden;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.BiPredicate;
import java.util.function.Function;

public class IndexAbstractionResolver {

Expand All @@ -37,8 +37,8 @@ public List<String> resolveIndexAbstractions(
Iterable<String> indices,
IndicesOptions indicesOptions,
ProjectMetadata projectMetadata,
Supplier<Set<String>> allAuthorizedAndAvailable,
Predicate<String> isAuthorized,
Function<IndexComponentSelector, Set<String>> allAuthorizedAndAvailableBySelector,
BiPredicate<String, IndexComponentSelector> isAuthorized,
boolean includeDataStreams
) {
List<String> finalIndices = new ArrayList<>();
Expand All @@ -64,14 +64,15 @@ public List<String> resolveIndexAbstractions(
);
}
indexAbstraction = expressionAndSelector.v1();
IndexComponentSelector selector = IndexComponentSelector.getByKeyOrThrow(selectorString);

// we always need to check for date math expressions
indexAbstraction = IndexNameExpressionResolver.resolveDateMathExpression(indexAbstraction);

if (indicesOptions.expandWildcardExpressions() && Regex.isSimpleMatchPattern(indexAbstraction)) {
wildcardSeen = true;
Set<String> resolvedIndices = new HashSet<>();
for (String authorizedIndex : allAuthorizedAndAvailable.get()) {
for (String authorizedIndex : allAuthorizedAndAvailableBySelector.apply(selector)) {
if (Regex.simpleMatch(indexAbstraction, authorizedIndex)
&& isIndexVisible(
indexAbstraction,
Expand Down Expand Up @@ -102,7 +103,7 @@ && isIndexVisible(
resolveSelectorsAndCollect(indexAbstraction, selectorString, indicesOptions, resolvedIndices, projectMetadata);
if (minus) {
finalIndices.removeAll(resolvedIndices);
} else if (indicesOptions.ignoreUnavailable() == false || isAuthorized.test(indexAbstraction)) {
} else if (indicesOptions.ignoreUnavailable() == false || isAuthorized.test(indexAbstraction, selector)) {
// Unauthorized names are considered unavailable, so if `ignoreUnavailable` is `true` they should be silently
// discarded from the `finalIndices` list. Other "ways of unavailable" must be handled by the action
// handler, see: https://github.com/elastic/elasticsearch/issues/90215
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.core.Assertions;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.core.Predicates;
import org.elasticsearch.core.Tuple;
Expand Down Expand Up @@ -1001,6 +1002,14 @@ public static boolean hasSelectorSuffix(String expression) {
return expression.contains(SelectorResolver.SELECTOR_SEPARATOR);
}

public static boolean hasSelector(@Nullable String expression, IndexComponentSelector selector) {
Objects.requireNonNull(selector, "null selectors not supported");
if (expression == null) {
return false;
}
return expression.endsWith(SelectorResolver.SELECTOR_SEPARATOR + selector.getKey());
}

/**
* @return If the specified string is a selector expression then this method returns the base expression and its selector part.
*/
Expand All @@ -1022,6 +1031,14 @@ public static String combineSelectorExpression(String baseExpression, @Nullable
: (baseExpression + SelectorResolver.SELECTOR_SEPARATOR + selectorExpression);
}

public static void assertExpressionHasNullOrDataSelector(String expression) {
if (Assertions.ENABLED) {
var tuple = splitSelectorExpression(expression);
assert tuple.v2() == null || IndexComponentSelector.DATA.getKey().equals(tuple.v2())
: "Expected expression [" + expression + "] to have a data selector but found [" + tuple.v2() + "]";
}
}

/**
* Resolve an array of expressions to the set of indices and aliases that these expressions match.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.indices.SystemIndices.EXTERNAL_SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY;
Expand All @@ -48,7 +47,7 @@ public class IndexAbstractionResolverTests extends ESTestCase {
private String dateTimeIndexTomorrow;

// Only used when resolving wildcard expressions
private final Supplier<Set<String>> defaultMask = () -> Set.of("index1", "index2", "data-stream1");
private final Set<String> defaultMask = Set.of("index1", "index2", "data-stream1");

@Override
public void setUp() throws Exception {
Expand Down Expand Up @@ -215,13 +214,11 @@ public void testResolveIndexAbstractions() {

public void testIsIndexVisible() {
assertThat(isIndexVisible("index1", null), is(true));
assertThat(isIndexVisible("index1", "*"), is(true));
assertThat(isIndexVisible("index1", "data"), is(true));
assertThat(isIndexVisible("index1", "failures"), is(false)); // *
// * Indices don't have failure components so the failure component is not visible

assertThat(isIndexVisible("data-stream1", null), is(true));
assertThat(isIndexVisible("data-stream1", "*"), is(true));
Copy link
Contributor

@slobodanadamovic slobodanadamovic Mar 17, 2025

Choose a reason for hiding this comment

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

This seems to be leftover from the #121900 PR, right?
Looking closer, these tests seem to pass with any string value for the selector, except the failures.
Not something we should do in this PR, but I wonder if we should validate the selector inside the isIndexVisible method and only accept null, failures or data?

Copy link
Contributor Author

@n1v0lg n1v0lg Mar 20, 2025

Choose a reason for hiding this comment

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

Yup, I'll note this down to look into in a follow up.

assertThat(isIndexVisible("data-stream1", "data"), is(true));
assertThat(isIndexVisible("data-stream1", "failures"), is(true));
}
Expand Down Expand Up @@ -290,14 +287,14 @@ public void testIsNetNewSystemIndexVisible() {
indexAbstractionResolver = new IndexAbstractionResolver(indexNameExpressionResolver);

// this covers the GET * case -- with system access, you can see everything
assertThat(isIndexVisible("other", "*"), is(true));
assertThat(isIndexVisible(".foo", "*"), is(true));
assertThat(isIndexVisible(".bar", "*"), is(true));
assertThat(isIndexVisible("other", null), is(true));
assertThat(isIndexVisible(".foo", null), is(true));
assertThat(isIndexVisible(".bar", null), is(true));

// but if you don't ask for hidden and aliases, you won't see hidden indices or aliases, naturally
assertThat(isIndexVisible("other", "*", noHiddenNoAliases), is(true));
assertThat(isIndexVisible(".foo", "*", noHiddenNoAliases), is(false));
assertThat(isIndexVisible(".bar", "*", noHiddenNoAliases), is(false));
assertThat(isIndexVisible("other", null, noHiddenNoAliases), is(true));
assertThat(isIndexVisible(".foo", null, noHiddenNoAliases), is(false));
assertThat(isIndexVisible(".bar", null, noHiddenNoAliases), is(false));
}

{
Expand All @@ -311,14 +308,14 @@ public void testIsNetNewSystemIndexVisible() {
indexAbstractionResolver = new IndexAbstractionResolver(indexNameExpressionResolver);

// this covers the GET * case -- without system access, you can't see everything
assertThat(isIndexVisible("other", "*"), is(true));
assertThat(isIndexVisible(".foo", "*"), is(false));
assertThat(isIndexVisible(".bar", "*"), is(false));
assertThat(isIndexVisible("other", null), is(true));
assertThat(isIndexVisible(".foo", null), is(false));
assertThat(isIndexVisible(".bar", null), is(false));

// no difference here in the datastream case, you can't see these then, either
assertThat(isIndexVisible("other", "*", noHiddenNoAliases), is(true));
assertThat(isIndexVisible(".foo", "*", noHiddenNoAliases), is(false));
assertThat(isIndexVisible(".bar", "*", noHiddenNoAliases), is(false));
assertThat(isIndexVisible("other", null, noHiddenNoAliases), is(true));
assertThat(isIndexVisible(".foo", null, noHiddenNoAliases), is(false));
assertThat(isIndexVisible(".bar", null, noHiddenNoAliases), is(false));
}

{
Expand All @@ -333,14 +330,14 @@ public void testIsNetNewSystemIndexVisible() {
indexAbstractionResolver = new IndexAbstractionResolver(indexNameExpressionResolver);

// this covers the GET * case -- with product (only) access, you can't see everything
assertThat(isIndexVisible("other", "*"), is(true));
assertThat(isIndexVisible(".foo", "*"), is(false));
assertThat(isIndexVisible(".bar", "*"), is(false));
assertThat(isIndexVisible("other", null), is(true));
assertThat(isIndexVisible(".foo", null), is(false));
assertThat(isIndexVisible(".bar", null), is(false));

// no difference here in the datastream case, you can't see these then, either
assertThat(isIndexVisible("other", "*", noHiddenNoAliases), is(true));
assertThat(isIndexVisible(".foo", "*", noHiddenNoAliases), is(false));
assertThat(isIndexVisible(".bar", "*", noHiddenNoAliases), is(false));
assertThat(isIndexVisible("other", null, noHiddenNoAliases), is(true));
assertThat(isIndexVisible(".foo", null, noHiddenNoAliases), is(false));
assertThat(isIndexVisible(".bar", null, noHiddenNoAliases), is(false));
}
}

Expand All @@ -366,8 +363,15 @@ private List<String> resolveAbstractionsSelectorAllowed(List<String> expressions
return resolveAbstractions(expressions, IndicesOptions.strictExpandOpen(), defaultMask);
}

private List<String> resolveAbstractions(List<String> expressions, IndicesOptions indicesOptions, Supplier<Set<String>> mask) {
return indexAbstractionResolver.resolveIndexAbstractions(expressions, indicesOptions, projectMetadata, mask, (idx) -> true, true);
private List<String> resolveAbstractions(List<String> expressions, IndicesOptions indicesOptions, Set<String> mask) {
return indexAbstractionResolver.resolveIndexAbstractions(
expressions,
indicesOptions,
projectMetadata,
(ignored) -> mask,
(ignored, nothing) -> true,
true
);
}

private boolean isIndexVisible(String index, String selector) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.IndexComponentSelector;
import org.elasticsearch.action.support.SubscribableListener;
import org.elasticsearch.cluster.metadata.DataStream;
import org.elasticsearch.cluster.metadata.IndexAbstraction;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.ProjectMetadata;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
Expand All @@ -39,7 +42,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static org.elasticsearch.action.ValidateActions.addValidationError;
Expand Down Expand Up @@ -281,22 +283,23 @@ default AuthorizationInfo getAuthenticatedUserAuthorizationInfo() {
}

/**
* Used to retrieve index-like resources that the user has access to, for a specific access action type,
* Used to retrieve index-like resources that the user has access to, for a specific access action type and selector,
* at a specific point in time (for a fixed cluster state view).
* It can also be used to check if a specific resource name is authorized (access to the resource name
* can be authorized even if it doesn't exist).
*/
interface AuthorizedIndices {
/**
* Returns all the index-like resource names that are available and accessible for an action type by a user,
* Returns all the index-like resource names that are available and accessible for an action type and selector by a user,
* at a fixed point in time (for a single cluster state view).
* The result is cached and subsequent calls to this method are idempotent.
*/
Supplier<Set<String>> all();
Set<String> all(IndexComponentSelector selector);

/**
* Checks if an index-like resource name is authorized, for an action by a user. The resource might or might not exist.
*/
boolean check(String name);
boolean check(String name, IndexComponentSelector selector);
}

/**
Expand Down Expand Up @@ -366,6 +369,31 @@ public ActionRequestValidationException validate(ActionRequestValidationExceptio
&& application.length == 0) {
validationException = addValidationError("must specify at least one privilege", validationException);
}
if (index != null) {
// no need to validate failure-store related constraints if it's not enabled
if (DataStream.isFailureStoreFeatureFlagEnabled()) {
for (RoleDescriptor.IndicesPrivileges indexPrivilege : index) {
if (indexPrivilege.getIndices() != null
&& Arrays.stream(indexPrivilege.getIndices())
// best effort prevent users from attempting to check failure selectors
.anyMatch(idx -> IndexNameExpressionResolver.hasSelector(idx, IndexComponentSelector.FAILURES))) {
validationException = addValidationError(
// TODO adjust message once HasPrivileges check supports checking failure store privileges
"failures selector is not supported in index patterns",
validationException
);
}
if (indexPrivilege.getPrivileges() != null
&& Arrays.stream(indexPrivilege.getPrivileges())
.anyMatch(p -> "read_failure_store".equals(p) || "manage_failure_store".equals(p))) {
validationException = addValidationError(
"checking failure store privileges is not supported",
validationException
);
}
}
}
}
return validationException;
}

Expand Down
Loading