Added the notion of IndicesResolver
A strategy for extracting the related indices from a request. The default strategy relies on the request to either be `IndicesRequest` or `CompositeIndicesRequest`. But depending on the request type, there might be other strategies as well. For example, `GetIndexTemplatesRequest` only holds the template name and therefore requires a different strategy where the template is looked up in the cluster metadata and the indices are resolved from there. This also cleans up the Permission class and makes sure that the indices are resolved once per request (and not once per configured group permission) Original commit: elastic/x-pack-elasticsearch@95192ccdff
This commit is contained in:
parent
1154f13345
commit
f040d895b3
|
@ -5,16 +5,18 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authz;
|
package org.elasticsearch.shield.authz;
|
||||||
|
|
||||||
import org.elasticsearch.action.CompositeIndicesRequest;
|
|
||||||
import org.elasticsearch.action.IndicesRequest;
|
|
||||||
import org.elasticsearch.cluster.metadata.MetaData;
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
import org.elasticsearch.common.base.Predicate;
|
import org.elasticsearch.common.base.Predicate;
|
||||||
import org.elasticsearch.common.collect.ImmutableList;
|
import org.elasticsearch.common.collect.ImmutableList;
|
||||||
|
import org.elasticsearch.shield.authz.indicesresolver.DefaultIndicesResolver;
|
||||||
|
import org.elasticsearch.shield.authz.indicesresolver.IndicesResolver;
|
||||||
import org.elasticsearch.shield.support.AutomatonPredicate;
|
import org.elasticsearch.shield.support.AutomatonPredicate;
|
||||||
import org.elasticsearch.shield.support.Automatons;
|
import org.elasticsearch.shield.support.Automatons;
|
||||||
import org.elasticsearch.transport.TransportRequest;
|
import org.elasticsearch.transport.TransportRequest;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a permission in the system. There are 3 types of permissions:
|
* Represents a permission in the system. There are 3 types of permissions:
|
||||||
|
@ -136,6 +138,11 @@ public interface Permission {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static IndicesResolver[] indicesResolvers = new IndicesResolver[] {
|
||||||
|
// add special resolvers here
|
||||||
|
new DefaultIndicesResolver()
|
||||||
|
};
|
||||||
|
|
||||||
private Group[] groups;
|
private Group[] groups;
|
||||||
|
|
||||||
public Indices(Collection<Group> groups) {
|
public Indices(Collection<Group> groups) {
|
||||||
|
@ -178,21 +185,25 @@ public interface Permission {
|
||||||
return new AutomatonPredicate(Automatons.patterns(indices.build()));
|
return new AutomatonPredicate(Automatons.patterns(indices.build()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override @SuppressWarnings("unchecked")
|
||||||
public boolean check(String action, TransportRequest request, MetaData metaData) {
|
public boolean check(String action, TransportRequest request, MetaData metaData) {
|
||||||
boolean isIndicesRequest = request instanceof CompositeIndicesRequest || request instanceof IndicesRequest;
|
Set<String> indices = Collections.emptySet();
|
||||||
if (!isIndicesRequest) {
|
for (IndicesResolver resolver : indicesResolvers) {
|
||||||
return false;
|
if (resolver.requestType().isInstance(request)) {
|
||||||
|
indices = resolver.resolve(request, metaData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (Group group : groups) {
|
|
||||||
if (group.check(action, request, metaData)) {
|
for (int i = 0; i < groups.length; i++) {
|
||||||
|
if (groups[i].check(action, indices)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Group implements Permission {
|
public static class Group {
|
||||||
|
|
||||||
private final Privilege.Index privilege;
|
private final Privilege.Index privilege;
|
||||||
private final Predicate<String> actionMatcher;
|
private final Predicate<String> actionMatcher;
|
||||||
|
@ -215,52 +226,22 @@ public interface Permission {
|
||||||
return indices;
|
return indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean check(String action, Set<String> indices) {
|
||||||
public boolean check(String action, TransportRequest request, MetaData metaData) {
|
|
||||||
|
|
||||||
assert request instanceof IndicesRequest || request instanceof CompositeIndicesRequest :
|
|
||||||
"the only requests passing the action matcher should be IndicesRequests";
|
|
||||||
|
|
||||||
if (!actionMatcher.apply(action)) {
|
if (!actionMatcher.apply(action)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request instanceof CompositeIndicesRequest) {
|
for (String index : indices) {
|
||||||
CompositeIndicesRequest compositeIndicesRequest = (CompositeIndicesRequest) request;
|
if (!indexNameMatcher.apply(index)) {
|
||||||
for (IndicesRequest indicesRequest : compositeIndicesRequest.subRequests()) {
|
return false;
|
||||||
for (String index : explodeWildcards(indicesRequest, metaData)) {
|
|
||||||
if (!indexNameMatcher.apply(index)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (String index : explodeWildcards((IndicesRequest) request, metaData)) {
|
|
||||||
if (!indexNameMatcher.apply(index)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] explodeWildcards(IndicesRequest indicesRequest, MetaData metaData) {
|
|
||||||
if (indicesRequest.indicesOptions().expandWildcardsOpen() || indicesRequest.indicesOptions().expandWildcardsClosed()) {
|
|
||||||
if (MetaData.isAllIndices(indicesRequest.indices())) {
|
|
||||||
if (indicesRequest.indicesOptions().expandWildcardsOpen() && indicesRequest.indicesOptions().expandWildcardsClosed()) {
|
|
||||||
return metaData.concreteAllIndices();
|
|
||||||
}
|
|
||||||
if (indicesRequest.indicesOptions().expandWildcardsOpen()) {
|
|
||||||
return metaData.concreteAllOpenIndices();
|
|
||||||
}
|
|
||||||
return metaData.concreteAllClosedIndices();
|
|
||||||
|
|
||||||
}
|
|
||||||
return metaData.convertFromWildcards(indicesRequest.indices(), indicesRequest.indicesOptions());
|
|
||||||
}
|
|
||||||
return indicesRequest.indices();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.shield.authz.indicesresolver;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.CompositeIndicesRequest;
|
||||||
|
import org.elasticsearch.action.IndicesRequest;
|
||||||
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
|
import org.elasticsearch.common.collect.Sets;
|
||||||
|
import org.elasticsearch.transport.TransportRequest;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DefaultIndicesResolver implements IndicesResolver<TransportRequest> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<TransportRequest> requestType() {
|
||||||
|
return TransportRequest.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> resolve(TransportRequest request, MetaData metaData) {
|
||||||
|
|
||||||
|
boolean isIndicesRequest = request instanceof CompositeIndicesRequest || request instanceof IndicesRequest;
|
||||||
|
assert isIndicesRequest : "the only requests passing the action matcher should be IndicesRequests";
|
||||||
|
|
||||||
|
// if for some reason we are missing an action... just for safety we'll reject
|
||||||
|
if (!isIndicesRequest) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request instanceof CompositeIndicesRequest) {
|
||||||
|
Set<String> indices = Sets.newHashSet();
|
||||||
|
CompositeIndicesRequest compositeIndicesRequest = (CompositeIndicesRequest) request;
|
||||||
|
for (IndicesRequest indicesRequest : compositeIndicesRequest.subRequests()) {
|
||||||
|
Collections.addAll(indices, explodeWildcards(indicesRequest, metaData));
|
||||||
|
}
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sets.newHashSet(explodeWildcards((IndicesRequest) request, metaData));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] explodeWildcards(IndicesRequest indicesRequest, MetaData metaData) {
|
||||||
|
if (indicesRequest.indicesOptions().expandWildcardsOpen() || indicesRequest.indicesOptions().expandWildcardsClosed()) {
|
||||||
|
if (MetaData.isAllIndices(indicesRequest.indices())) {
|
||||||
|
if (indicesRequest.indicesOptions().expandWildcardsOpen() && indicesRequest.indicesOptions().expandWildcardsClosed()) {
|
||||||
|
return metaData.concreteAllIndices();
|
||||||
|
}
|
||||||
|
if (indicesRequest.indicesOptions().expandWildcardsOpen()) {
|
||||||
|
return metaData.concreteAllOpenIndices();
|
||||||
|
}
|
||||||
|
return metaData.concreteAllClosedIndices();
|
||||||
|
|
||||||
|
}
|
||||||
|
return metaData.convertFromWildcards(indicesRequest.indices(), indicesRequest.indicesOptions());
|
||||||
|
}
|
||||||
|
return indicesRequest.indices();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.shield.authz.indicesresolver;
|
||||||
|
|
||||||
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
|
import org.elasticsearch.transport.TransportRequest;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IndicesResolver<Request extends TransportRequest> {
|
||||||
|
|
||||||
|
Class<Request> requestType();
|
||||||
|
|
||||||
|
Set<String> resolve(Request request, MetaData metaData);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue