Support wildcards in has_privileges API (elastic/x-pack-elasticsearch#1454)
The has_privileges API now supports wildcards. The semantics are that the user must have a superset of the wildcard being checked. --------------------- Role | Check | Result --------------------- * | foo* | true f* | foo* | true foo* | foo* | true foo* | foo? | true foo? | foo? | true foo? | foo* | false foo | foo* | false Original commit: elastic/x-pack-elasticsearch@817550db17
This commit is contained in:
parent
da40720ef0
commit
e177f79aa3
|
@ -12,7 +12,6 @@ import java.util.HashMap;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.lucene.util.automaton.Automaton;
|
||||
import org.apache.lucene.util.automaton.Operations;
|
||||
|
@ -81,7 +80,7 @@ public class TransportHasPrivilegesAction extends HandledTransportAction<HasPriv
|
|||
cluster.put(checkAction, testPrivilege(checkPrivilege, rolePrivilege.getAutomaton()));
|
||||
}
|
||||
|
||||
final Map<IndicesPermission.Group, Predicate<String>> predicateCache = new HashMap<>();
|
||||
final Map<IndicesPermission.Group, Automaton> predicateCache = new HashMap<>();
|
||||
|
||||
final Map<String, HasPrivilegesResponse.IndexPrivileges> indices = new LinkedHashMap<>();
|
||||
boolean allMatch = true;
|
||||
|
@ -109,13 +108,15 @@ public class TransportHasPrivilegesAction extends HandledTransportAction<HasPriv
|
|||
}
|
||||
|
||||
private boolean testIndexMatch(String checkIndex, String checkPrivilegeName, Role userRole,
|
||||
Map<IndicesPermission.Group, Predicate<String>> predicateCache) {
|
||||
Map<IndicesPermission.Group, Automaton> predicateCache) {
|
||||
final IndexPrivilege checkPrivilege = IndexPrivilege.get(Collections.singleton(checkPrivilegeName));
|
||||
|
||||
final Automaton checkIndexAutomaton = Automatons.patterns(checkIndex);
|
||||
|
||||
List<Automaton> privilegeAutomatons = new ArrayList<>();
|
||||
for (IndicesPermission.Group group : userRole.indices().groups()) {
|
||||
final Predicate<String> predicate = predicateCache.computeIfAbsent(group, g -> Automatons.predicate(g.indices()));
|
||||
if (predicate.test(checkIndex)) {
|
||||
final Automaton groupIndexAutomaton = predicateCache.computeIfAbsent(group, g -> Automatons.patterns(g.indices()));
|
||||
if (testIndex(checkIndexAutomaton, groupIndexAutomaton)) {
|
||||
final IndexPrivilege rolePrivilege = group.privilege();
|
||||
if (rolePrivilege.name().contains(checkPrivilegeName)) {
|
||||
return true;
|
||||
|
@ -126,7 +127,11 @@ public class TransportHasPrivilegesAction extends HandledTransportAction<HasPriv
|
|||
return testPrivilege(checkPrivilege, Automatons.unionAndMinimize(privilegeAutomatons));
|
||||
}
|
||||
|
||||
private boolean testPrivilege(Privilege checkPrivilege, Automaton roleAutomaton) {
|
||||
private static boolean testIndex(Automaton checkIndex, Automaton roleIndex) {
|
||||
return Operations.subsetOf(checkIndex, roleIndex);
|
||||
}
|
||||
|
||||
private static boolean testPrivilege(Privilege checkPrivilege, Automaton roleAutomaton) {
|
||||
return Operations.subsetOf(checkPrivilege.getAutomaton(), roleAutomaton);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,14 +191,16 @@ public class TransportHasPrivilegesActionTests extends ESTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* We intentionally ignore wildcards in the request. This tests that
|
||||
* <code>log*</code> in the request isn't granted by <code>logstash-*</code>
|
||||
* in the role, but <code>logstash-2016-*</code> is, because it's just
|
||||
* treated as the name of an index.
|
||||
* Wildcards in the request are treated as
|
||||
* <em>does the user have ___ privilege on every possible index that matches this pattern?</em>
|
||||
* Or, expressed differently,
|
||||
* <em>does the user have ___ privilege on a wildcard that covers (is a superset of) this pattern?</em>
|
||||
*/
|
||||
public void testWildcardsInRequestAreIgnored() throws Exception {
|
||||
public void testWildcardHandling() throws Exception {
|
||||
role = Role.builder("test3")
|
||||
.add(IndexPrivilege.ALL, "logstash-*")
|
||||
.add(IndexPrivilege.ALL, "logstash-*", "foo?")
|
||||
.add(IndexPrivilege.READ, "abc*")
|
||||
.add(IndexPrivilege.WRITE, "*xyz")
|
||||
.build();
|
||||
|
||||
final HasPrivilegesRequest request = new HasPrivilegesRequest();
|
||||
|
@ -207,11 +209,31 @@ public class TransportHasPrivilegesActionTests extends ESTestCase {
|
|||
request.indexPrivileges(
|
||||
RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices("logstash-2016-*")
|
||||
.privileges("write")
|
||||
.privileges("write") // Yes, because (ALL,"logstash-*")
|
||||
.build(),
|
||||
RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices("logstash-*")
|
||||
.privileges("read") // Yes, because (ALL,"logstash-*")
|
||||
.build(),
|
||||
RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices("log*")
|
||||
.privileges("read")
|
||||
.privileges("manage") // No, because "log*" includes indices that "logstash-*" does not
|
||||
.build(),
|
||||
RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices("foo*", "foo?")
|
||||
.privileges("read") // Yes, "foo?", but not "foo*", because "foo*" > "foo?"
|
||||
.build(),
|
||||
RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices("abcd*")
|
||||
.privileges("read", "write") // read = Yes, because (READ, "abc*"), write = No
|
||||
.build(),
|
||||
RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices("abc*xyz")
|
||||
.privileges("read", "write", "manage") // read = Yes ( READ "abc*"), write = Yes (WRITE, "*xyz"), manage = No
|
||||
.build(),
|
||||
RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices("a*xyz")
|
||||
.privileges("read", "write", "manage") // read = No, write = Yes (WRITE, "*xyz"), manage = No
|
||||
.build()
|
||||
);
|
||||
final PlainActionFuture<HasPrivilegesResponse> future = new PlainActionFuture();
|
||||
|
@ -220,10 +242,16 @@ public class TransportHasPrivilegesActionTests extends ESTestCase {
|
|||
final HasPrivilegesResponse response = future.get();
|
||||
assertThat(response, notNullValue());
|
||||
assertThat(response.isCompleteMatch(), is(false));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(2));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(8));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
new IndexPrivileges("logstash-2016-*", Collections.singletonMap("write", true)),
|
||||
new IndexPrivileges("log*", Collections.singletonMap("read", false))
|
||||
new IndexPrivileges("logstash-*", Collections.singletonMap("read", true)),
|
||||
new IndexPrivileges("log*", Collections.singletonMap("manage", false)),
|
||||
new IndexPrivileges("foo?", Collections.singletonMap("read", true)),
|
||||
new IndexPrivileges("foo*", Collections.singletonMap("read", false)),
|
||||
new IndexPrivileges("abcd*", mapBuilder().put("read", true).put("write", false).map()),
|
||||
new IndexPrivileges("abc*xyz", mapBuilder().put("read", true).put("write", true).put("manage", false).map()),
|
||||
new IndexPrivileges("a*xyz", mapBuilder().put("read", false).put("write", true).put("manage", false).map())
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -259,4 +287,9 @@ public class TransportHasPrivilegesActionTests extends ESTestCase {
|
|||
)
|
||||
));
|
||||
}
|
||||
|
||||
private static MapBuilder<String, Boolean> mapBuilder() {
|
||||
return MapBuilder.newMapBuilder();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue