diff --git a/src/main/java/org/elasticsearch/shield/authz/Privilege.java b/src/main/java/org/elasticsearch/shield/authz/Privilege.java index e107865030b..6432bfc4ba4 100644 --- a/src/main/java/org/elasticsearch/shield/authz/Privilege.java +++ b/src/main/java/org/elasticsearch/shield/authz/Privilege.java @@ -13,6 +13,7 @@ import org.elasticsearch.ElasticsearchIllegalArgumentException; import org.elasticsearch.action.admin.indices.create.CreateIndexAction; import org.elasticsearch.action.get.GetAction; import org.elasticsearch.action.search.SearchAction; +import org.elasticsearch.action.suggest.SuggestAction; import org.elasticsearch.common.Strings; import org.elasticsearch.common.base.Predicate; import org.elasticsearch.common.cache.CacheBuilder; @@ -114,14 +115,15 @@ public abstract class Privilege

> { public static final Index DATA_ACCESS = new Index("data_access", "indices:data/*"); public static final Index CRUD = new Index("crud", "indices:data/write/*", "indices:data/read/*"); public static final Index READ = new Index("read", "indices:data/read/*"); - public static final Index SEARCH = new Index("search", SearchAction.NAME + "*", GetAction.NAME + "*"); + public static final Index SEARCH = new Index("search", SearchAction.NAME + "*", GetAction.NAME + "*", SuggestAction.NAME + "*"); public static final Index GET = new Index("get", GetAction.NAME + "*"); + public static final Index SUGGEST = new Index("suggest", SuggestAction.NAME + "*"); public static final Index INDEX = new Index("index", "indices:data/write/index*", "indices:data/write/update"); public static final Index DELETE = new Index("delete", "indices:data/write/delete*"); public static final Index WRITE = new Index("write", "indices:data/write/*"); private static final Index[] values = new Index[] { - NONE, ALL, MANAGE, CREATE_INDEX, MANAGE_ALIASES, MONITOR, DATA_ACCESS, CRUD, READ, SEARCH, GET, INDEX, DELETE, WRITE + NONE, ALL, MANAGE, CREATE_INDEX, MANAGE_ALIASES, MONITOR, DATA_ACCESS, CRUD, READ, SEARCH, GET, SUGGEST, INDEX, DELETE, WRITE }; public static final Predicate ACTION_MATCHER = Privilege.Index.ALL.predicate(); diff --git a/src/main/java/org/elasticsearch/shield/signature/InternalSignatureService.java b/src/main/java/org/elasticsearch/shield/signature/InternalSignatureService.java index b131e8e3d3f..e7b5a519737 100644 --- a/src/main/java/org/elasticsearch/shield/signature/InternalSignatureService.java +++ b/src/main/java/org/elasticsearch/shield/signature/InternalSignatureService.java @@ -8,7 +8,6 @@ package org.elasticsearch.shield.signature; import org.apache.commons.codec.binary.Base64; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.base.Charsets; -import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; diff --git a/src/test/java/org/elasticsearch/integration/SearchPermissionsTests.java b/src/test/java/org/elasticsearch/integration/SearchPermissionsTests.java new file mode 100644 index 00000000000..7db32bd175b --- /dev/null +++ b/src/test/java/org/elasticsearch/integration/SearchPermissionsTests.java @@ -0,0 +1,141 @@ +/* + * 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.integration; + +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.action.suggest.SuggestResponse; +import org.elasticsearch.client.Client; +import org.elasticsearch.search.suggest.SuggestBuilders; +import org.elasticsearch.shield.authc.support.SecuredStringTests; +import org.elasticsearch.shield.authc.support.UsernamePasswordToken; +import org.elasticsearch.shield.authz.AuthorizationException; +import org.elasticsearch.test.ShieldIntegrationTest; +import org.junit.Test; + +import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; +import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +@ClusterScope(scope = Scope.SUITE) +public class SearchPermissionsTests extends ShieldIntegrationTest { + + @Override + protected String configRoles() { + return super.configRoles() + "\n" + + "\n" + + "suggest_role:\n" + + " indices:\n" + + " 'a': suggest\n" + + "\n" + + "search_role:\n" + + " indices:\n" + + " 'a': search\n" + + "\n" + + "get_role:\n" + + " indices:\n" + + " 'a': get\n"; + } + + @Override + protected String configUsers() { + return super.configUsers() + + "suggest_user:{plain}passwd\n" + + "search_user:{plain}passwd\n" + + "get_user:{plain}passwd\n"; + } + + @Override + protected String configUsersRoles() { + return super.configUsersRoles() + + "suggest_role:suggest_user\n" + + "search_role:search_user\n" + + "get_role:get_user"; + } + + /** + * testing both "search" and "suggest" privileges can execute the suggest API + */ + @Test + public void testSuggestAPI() throws Exception { + IndexResponse indexResponse = index("a", "type", jsonBuilder() + .startObject() + .field("name", "value") + .endObject()); + assertThat(indexResponse.isCreated(), is(true)); + + refresh(); + + Client client = internalCluster().transportClient(); + + SuggestResponse suggestResponse = client.prepareSuggest("a") + .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd")) + .addSuggestion(SuggestBuilders.termSuggestion("name").field("name").text("val")).get(); + assertNoFailures(suggestResponse); + assertThat(suggestResponse.getSuggest().size(), is(1)); + + suggestResponse = client.prepareSuggest("a") + .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) + .addSuggestion(SuggestBuilders.termSuggestion("name").field("name").text("val")).get(); + assertNoFailures(suggestResponse); + assertThat(suggestResponse.getSuggest().size(), is(1)); + + try { + client.prepareSearch("a") + .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd")) + .get(); + fail("a user with only a suggest privilege cannot execute search"); + } catch (AuthorizationException e) { + logger.error("failed to search", e); + // expected + } + } + + /** + * testing both "search" and "get" privileges can execute the get API + */ + @Test + public void testGetAPI() throws Exception { + IndexResponse indexResponse = index("a", "type", jsonBuilder() + .startObject() + .field("name", "value") + .endObject()); + assertThat(indexResponse.isCreated(), is(true)); + + refresh(); + + Client client = internalCluster().transportClient(); + + GetResponse getResponse = client.prepareGet("a", "type", indexResponse.getId()) + .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("get_user", "passwd")) + .get(); + assertNotNull(getResponse); + assertThat(getResponse.getId(), equalTo(indexResponse.getId())); + + getResponse = client.prepareGet("a", "type", indexResponse.getId()) + .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) + .get(); + assertNotNull(getResponse); + assertThat(getResponse.getId(), equalTo(indexResponse.getId())); + + try { + client.prepareSearch("a") + .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("get_user", "passwd")) + .get(); + fail("a user with only a get privilege cannot execute search"); + } catch (AuthorizationException e) { + logger.error("failed to search", e); + // expected + } + } + + private static String userHeader(String username, String password) { + return UsernamePasswordToken.basicAuthHeaderValue(username, SecuredStringTests.build(password)); + } +} diff --git a/src/test/java/org/elasticsearch/shield/authz/PrivilegeTests.java b/src/test/java/org/elasticsearch/shield/authz/PrivilegeTests.java index 8b586f05a80..9f5f31e3c03 100644 --- a/src/test/java/org/elasticsearch/shield/authz/PrivilegeTests.java +++ b/src/test/java/org/elasticsearch/shield/authz/PrivilegeTests.java @@ -6,6 +6,9 @@ package org.elasticsearch.shield.authz; import org.elasticsearch.ElasticsearchIllegalArgumentException; +import org.elasticsearch.action.get.GetAction; +import org.elasticsearch.action.search.SearchAction; +import org.elasticsearch.action.suggest.SuggestAction; import org.elasticsearch.common.base.Predicate; import org.elasticsearch.shield.support.AutomatonPredicate; import org.elasticsearch.shield.support.Automatons; @@ -176,4 +179,15 @@ public class PrivilegeTests extends ElasticsearchTestCase { assertThat(predicate.apply("cluster:whatever"), is(false)); assertThat(predicate.apply("whatever"), is(false)); } + + @Test + public void testSearchPrivilege() throws Exception { + Predicate predicate = Privilege.Index.SEARCH.predicate(); + assertThat(predicate.apply(SearchAction.NAME), is(true)); + assertThat(predicate.apply(SearchAction.NAME + "/whatever"), is(true)); + assertThat(predicate.apply(GetAction.NAME), is(true)); + assertThat(predicate.apply(GetAction.NAME + "/whatever"), is(true)); + assertThat(predicate.apply(SuggestAction.NAME), is(true)); + assertThat(predicate.apply(SuggestAction.NAME + "/whatever"), is(true)); + } }