Skip to content

Commit

Permalink
Make .async-search-* a restricted namespace (#50294)
Browse files Browse the repository at this point in the history
Hide the `.async-search-*` in Security by making it a restricted index namespace.
The namespace is hard-coded.
To grant privileges on restricted indices, one must explicitly toggle the
`allow_restricted_indices` flag in the indices permission in the role definition.
As is the case with any other index, if a certain user lacks all permissions for an
index, that index is effectively nonexistent for that user.
  • Loading branch information
albertzaharovits committed Jan 13, 2020
1 parent c31a21c commit 2b789fa
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,13 @@ public FieldValue(Object value) {
private static CharacterRunAutomaton buildAutomaton(Object value) {
if (value instanceof String) {
final String str = (String) value;
if (Regex.isSimpleMatchPattern(str) || isLuceneRegex(str)) {
if (Regex.isSimpleMatchPattern(str) || Automatons.isLuceneRegex(str)) {
return new CharacterRunAutomaton(Automatons.patterns(str));
}
}
return null;
}

private static boolean isLuceneRegex(String str) {
return str.length() > 1 && str.charAt(0) == '/' && str.charAt(str.length() - 1) == '/';
}

public Object getValue() {
return value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
Expand Down Expand Up @@ -139,7 +140,7 @@ public ResourcePrivilegesMap checkResourcePrivileges(Set<String> checkForIndexPa
final Map<IndicesPermission.Group, Automaton> predicateCache = new HashMap<>();
for (String forIndexPattern : checkForIndexPatterns) {
Automaton checkIndexAutomaton = Automatons.patterns(forIndexPattern);
if (false == allowRestrictedIndices && false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(forIndexPattern)) {
if (false == allowRestrictedIndices && false == isConcreteRestrictedIndex(forIndexPattern)) {
checkIndexAutomaton = Automatons.minusAndMinimize(checkIndexAutomaton, RestrictedIndicesNames.NAMES_AUTOMATON);
}
if (false == Operations.isEmpty(checkIndexAutomaton)) {
Expand Down Expand Up @@ -268,6 +269,13 @@ public Map<String, IndicesAccessControl.IndexAccessControl> authorize(String act
return unmodifiableMap(indexPermissions);
}

private boolean isConcreteRestrictedIndex(String indexPattern) {
if (Regex.isSimpleMatchPattern(indexPattern) || Automatons.isLuceneRegex(indexPattern)) {
return false;
}
return RestrictedIndicesNames.isRestricted(indexPattern);
}

public static class Group {
private final IndexPrivilege privilege;
private final Predicate<String> actionMatcher;
Expand Down Expand Up @@ -316,7 +324,7 @@ private boolean check(String action) {
private boolean check(String action, String index) {
assert index != null;
return check(action) && indexNameMatcher.test(index)
&& (allowRestrictedIndices || (false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index)));
&& (allowRestrictedIndices || (false == RestrictedIndicesNames.isRestricted(index)));
}

boolean hasQuery() {
Expand Down Expand Up @@ -351,13 +359,13 @@ private static Predicate<String> buildIndexMatcherPredicateForAction(String acti
final Predicate<String> predicate;
if (restrictedIndices.isEmpty()) {
predicate = indexMatcher(ordinaryIndices)
.and(index -> false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index));
.and(index -> false == RestrictedIndicesNames.isRestricted(index));
} else if (ordinaryIndices.isEmpty()) {
predicate = indexMatcher(restrictedIndices);
} else {
predicate = indexMatcher(restrictedIndices)
.or(indexMatcher(ordinaryIndices)
.and(index -> false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index)));
.and(index -> false == RestrictedIndicesNames.isRestricted(index)));
}
return predicate;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.xpack.core.security.support.Automatons;

import java.util.Arrays;
import java.util.Collections;
import java.util.Set;

Expand All @@ -21,10 +22,20 @@ public final class RestrictedIndicesNames {
public static final String INTERNAL_SECURITY_TOKENS_INDEX_7 = ".security-tokens-7";
public static final String SECURITY_TOKENS_ALIAS = ".security-tokens";

// public for tests
public static final String ASYNC_SEARCH_PREFIX = ".async-search-";
private static final Automaton ASYNC_SEARCH_AUTOMATON = Automatons.patterns(ASYNC_SEARCH_PREFIX + "*");

// public for tests
public static final Set<String> RESTRICTED_NAMES = Collections.unmodifiableSet(Sets.newHashSet(SECURITY_MAIN_ALIAS,
INTERNAL_SECURITY_MAIN_INDEX_6, INTERNAL_SECURITY_MAIN_INDEX_7, INTERNAL_SECURITY_TOKENS_INDEX_7, SECURITY_TOKENS_ALIAS));

public static final Automaton NAMES_AUTOMATON = Automatons.patterns(RESTRICTED_NAMES);
public static boolean isRestricted(String concreteIndexName) {
return RESTRICTED_NAMES.contains(concreteIndexName) || concreteIndexName.startsWith(ASYNC_SEARCH_PREFIX);
}

public static final Automaton NAMES_AUTOMATON = Automatons.unionAndMinimize(Arrays.asList(Automatons.patterns(RESTRICTED_NAMES),
ASYNC_SEARCH_AUTOMATON));

private RestrictedIndicesNames() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ static Automaton pattern(String pattern) {
}
}

/**
* Is the str a lucene type of pattern
*/
public static boolean isLuceneRegex(String str) {
return str.length() > 1 && str.charAt(0) == '/' && str.charAt(str.length() - 1) == '/';
}

private static Automaton buildAutomaton(String pattern) {
if (pattern.startsWith("/")) { // it's a lucene regexp
if (pattern.length() == 1 || !pattern.endsWith("/")) {
Expand Down
Loading

0 comments on commit 2b789fa

Please sign in to comment.