Categorize search template action as a composite indices request (elastic/elasticsearch#4209)
When we encounter a composite request, we authorize at first without looking at the indices, to see whether the action can be executed at all. We then rely on the action to delegate to an inner action per sub-request, which will be authorized based on the indices it refers to. The first step works great for the simulate mode of search template, as it doesn't involve any index. The second step will make sure that when search template involves a search, it will be authorized as a normal search request would, based on the indices it reads from. Note that the wildcard expansion happens now on the search side, it doesn't have to happen when executing the first authorization step, hence SearchTemplateRequest doesn't have to implement IndicesRequest, only SearchRequest has to (which it does already). Closes elastic/elasticsearch#4171 Original commit: elastic/x-pack-elasticsearch@d586bd90cb
This commit is contained in:
parent
a414e3a7d9
commit
34d6dc1db1
|
@ -340,6 +340,7 @@ public class AuthorizationService extends AbstractComponent {
|
|||
action.equals(MultiSearchAction.NAME) ||
|
||||
action.equals("indices:data/read/mpercolate") ||
|
||||
action.equals("indices:data/read/msearch/template") ||
|
||||
action.equals("indices:data/read/search/template") ||
|
||||
action.equals("indices:data/write/reindex");
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
doAnswer((i) -> {
|
||||
ActionListener callback =
|
||||
(ActionListener) i.getArguments()[1];
|
||||
callback.onResponse(roleMap.get((String)i.getArguments()[0]));
|
||||
callback.onResponse(roleMap.get(i.getArguments()[0]));
|
||||
return Void.TYPE;
|
||||
}).when(rolesStore).roles(any(String.class), any(ActionListener.class));
|
||||
authorizationService = new AuthorizationService(Settings.EMPTY, rolesStore, clusterService,
|
||||
|
@ -771,11 +771,12 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
|
||||
public void testCompositeActionsIndicesAreCheckedAtTheShardLevel() {
|
||||
String action;
|
||||
switch(randomIntBetween(0, 6)) {
|
||||
switch(randomIntBetween(0, 5)) {
|
||||
case 0:
|
||||
action = MultiGetAction.NAME + "[shard]";
|
||||
break;
|
||||
case 1:
|
||||
//reindex, msearch, search template, and multi search template delegate to search
|
||||
action = SearchAction.NAME;
|
||||
break;
|
||||
case 2:
|
||||
|
@ -788,11 +789,8 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
action = "indices:data/read/mpercolate[s]";
|
||||
break;
|
||||
case 5:
|
||||
action = "indices:data/read/search/template";
|
||||
break;
|
||||
case 6:
|
||||
//reindex delegates to search and index
|
||||
action = randomBoolean() ? SearchAction.NAME : IndexAction.NAME;
|
||||
//reindex delegates to index, other than search covered above
|
||||
action = IndexAction.NAME;
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -810,7 +808,7 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private static Tuple<String, TransportRequest> randomCompositeRequest() {
|
||||
switch(randomIntBetween(0, 6)) {
|
||||
switch(randomIntBetween(0, 7)) {
|
||||
case 0:
|
||||
return Tuple.tuple(MultiGetAction.NAME, new MultiGetRequest().add("index", "type", "id"));
|
||||
case 1:
|
||||
|
@ -824,6 +822,8 @@ public class AuthorizationServiceTests extends ESTestCase {
|
|||
case 5:
|
||||
return Tuple.tuple("indices:data/read/msearch/template", new MockCompositeIndicesRequest());
|
||||
case 6:
|
||||
return Tuple.tuple("indices:data/read/search/template", new MockCompositeIndicesRequest());
|
||||
case 7:
|
||||
return Tuple.tuple("indices:data/write/reindex", new MockCompositeIndicesRequest());
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -203,7 +203,7 @@ public class ReadActionsTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
public void testMultiSearchUnauthorizedIndex() {
|
||||
//index1 is not authorized, the whole request fails due to that
|
||||
//index1 is not authorized, only that specific item fails
|
||||
createIndicesWithRandomAliases("test1", "test2", "test3", "index1");
|
||||
{
|
||||
MultiSearchResponse multiSearchResponse = client().prepareMultiSearch()
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
---
|
||||
setup:
|
||||
- skip:
|
||||
features: headers
|
||||
|
||||
- do:
|
||||
cluster.health:
|
||||
wait_for_status: yellow
|
||||
|
||||
- do:
|
||||
xpack.security.put_user:
|
||||
username: "inline_template_user"
|
||||
body: >
|
||||
{
|
||||
"password": "changeme",
|
||||
"roles" : [ "role" ]
|
||||
}
|
||||
|
||||
- do:
|
||||
xpack.security.put_role:
|
||||
name: "role"
|
||||
body: >
|
||||
{
|
||||
"indices": [
|
||||
{
|
||||
"names": "foobar",
|
||||
"privileges": ["read"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: foobar
|
||||
type: type
|
||||
id: 1
|
||||
body:
|
||||
title: "contains some words"
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: unauthorized_index
|
||||
type: type
|
||||
id: 2
|
||||
body:
|
||||
title: "contains some words too"
|
||||
|
||||
- do:
|
||||
indices.refresh: {}
|
||||
|
||||
---
|
||||
teardown:
|
||||
- do:
|
||||
xpack.security.delete_user:
|
||||
username: "inline_template_user"
|
||||
ignore: 404
|
||||
|
||||
---
|
||||
"Test inline template against specific index":
|
||||
- do:
|
||||
headers:
|
||||
Authorization: "Basic aW5saW5lX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU="
|
||||
search_template:
|
||||
index: foobar
|
||||
body:
|
||||
inline:
|
||||
query:
|
||||
match:
|
||||
title: "{{query_string}}"
|
||||
params:
|
||||
query_string: "search for these words"
|
||||
|
||||
- match: { hits.total: 1}
|
||||
- match: { hits.hits.0._id: "1"}
|
||||
|
||||
---
|
||||
"Test inline template against all indices":
|
||||
- do:
|
||||
headers:
|
||||
Authorization: "Basic aW5saW5lX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU="
|
||||
search_template:
|
||||
body:
|
||||
inline:
|
||||
query:
|
||||
match:
|
||||
title: "{{query_string}}"
|
||||
params:
|
||||
query_string: "search for these words"
|
||||
|
||||
- match: { hits.total: 1}
|
||||
- match: { hits.hits.0._id: "1"}
|
||||
|
||||
---
|
||||
"Test inline template against wildcard expression":
|
||||
- do:
|
||||
headers:
|
||||
Authorization: "Basic aW5saW5lX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU="
|
||||
search_template:
|
||||
index: foo*
|
||||
body:
|
||||
inline:
|
||||
query:
|
||||
match:
|
||||
title: "{{query_string}}"
|
||||
params:
|
||||
query_string: "search for these words"
|
||||
|
||||
- match: { hits.total: 1}
|
||||
- match: { hits.hits.0._id: "1"}
|
||||
---
|
||||
"Test unauthorized inline template against wildcard expression":
|
||||
|
||||
- do:
|
||||
headers:
|
||||
Authorization: "Basic aW5saW5lX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU="
|
||||
search_template:
|
||||
index: unauthorized*
|
||||
body:
|
||||
inline:
|
||||
query:
|
||||
match:
|
||||
title: "{{query_string}}"
|
||||
params:
|
||||
query_string: "search for these words"
|
||||
|
||||
- match: { hits.total: 0}
|
||||
|
||||
---
|
||||
"Basic multi-search template":
|
||||
|
||||
- do:
|
||||
headers:
|
||||
Authorization: "Basic aW5saW5lX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU="
|
||||
msearch_template:
|
||||
body:
|
||||
- index: foobar
|
||||
- inline:
|
||||
query:
|
||||
match:
|
||||
title: "{{query_string}}"
|
||||
params:
|
||||
query_string: "search for these words"
|
||||
- index: unauthorized*
|
||||
- inline:
|
||||
query:
|
||||
match:
|
||||
title: "{{query_string}}"
|
||||
params:
|
||||
query_string: "search for these words"
|
||||
|
||||
- match: { responses.0.hits.total: 1 }
|
||||
- match: { responses.1.hits.total: 0 }
|
||||
|
Loading…
Reference in New Issue