From 392e67851e4f634be388d768a4f855b6bc3de5c5 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Sat, 20 May 2017 21:34:38 +0200 Subject: [PATCH] Preserve aliases in index permissions (elastic/x-pack-elasticsearch#1501) Aliases might be contained in requests that check index permissions to disable caches etc. This commit preserves permissions for aliases as well. Original commit: elastic/x-pack-elasticsearch@233195aeba46d2e4620334e34bd52c8b2a5958f5 --- ...cumentLevelSecurityRequestInterceptor.java | 2 +- .../accesscontrol/IndicesAccessControl.java | 17 ++ .../authz/permission/IndicesPermission.java | 3 + .../accesscontrol/IndicesPermissionTests.java | 50 +++++ .../authenticate/10_field_level_security.yml | 181 ++++++++++++++++++ 5 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 plugin/src/test/resources/rest-api-spec/test/authenticate/10_field_level_security.yml diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java b/plugin/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java index 854886c6dcd..d1381493920 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java @@ -35,7 +35,7 @@ abstract class FieldAndDocumentLevelSecurityRequestInterceptor getQueries() { return queries; } + + @Override + public String toString() { + return "IndexAccessControl{" + + "granted=" + granted + + ", fieldPermissions=" + fieldPermissions + + ", queries=" + queries + + '}'; + } + } + + @Override + public String toString() { + return "IndicesAccessControl{" + + "granted=" + granted + + ", indexPermissions=" + indexPermissions + + '}'; } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/permission/IndicesPermission.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/permission/IndicesPermission.java index 1e796a418d9..8a0824d43c6 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/permission/IndicesPermission.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/permission/IndicesPermission.java @@ -118,9 +118,11 @@ public final class IndicesPermission implements Iterable fieldPermissions = fieldPermissionsByIndex.computeIfAbsent(index, (k) -> new HashSet<>()); + fieldPermissionsByIndex.put(indexOrAlias, fieldPermissions); fieldPermissions.add(group.getFieldPermissions()); DocumentLevelPermissions permissions = roleQueriesByIndex.computeIfAbsent(index, (k) -> new DocumentLevelPermissions()); + roleQueriesByIndex.putIfAbsent(indexOrAlias, permissions); if (group.hasQuery()) { permissions.addAll(group.getQuery()); } else { @@ -136,6 +138,7 @@ public final class IndicesPermission implements Iterable fooQuery = Collections.singleton(new BytesArray("{foo}")); + allFields = randomFrom(new String[]{"*"}, new String[]{"foo", "*"}, + new String[]{randomAlphaOfLengthBetween(1, 10), "*"}); + role = Role.builder("_role") + .add(new FieldPermissions(fieldPermissionDef(allFields, null)), fooQuery, IndexPrivilege.ALL, "_alias") + .add(new FieldPermissions(fieldPermissionDef(allFields, null)), query, IndexPrivilege.ALL, "_alias").build(); + permissions = role.authorize(SearchAction.NAME, Sets.newHashSet("_alias"), md, fieldPermissionsCache); + Set bothQueries = Sets.union(fooQuery, query); + assertThat(permissions.getIndexPermissions("_index"), notNullValue()); + assertFalse(permissions.getIndexPermissions("_index").getFieldPermissions().hasFieldLevelSecurity()); + assertThat(permissions.getIndexPermissions("_index").getQueries().size(), equalTo(2)); + assertThat(permissions.getIndexPermissions("_index").getQueries(), equalTo(bothQueries)); + + assertThat(permissions.getIndexPermissions("_index_1"), notNullValue()); + assertFalse(permissions.getIndexPermissions("_index_1").getFieldPermissions().hasFieldLevelSecurity()); + assertThat(permissions.getIndexPermissions("_index_1").getQueries().size(), equalTo(2)); + assertThat(permissions.getIndexPermissions("_index_1").getQueries(), equalTo(bothQueries)); + + assertThat(permissions.getIndexPermissions("_alias"), notNullValue()); + assertFalse(permissions.getIndexPermissions("_alias").getFieldPermissions().hasFieldLevelSecurity()); + assertThat(permissions.getIndexPermissions("_alias").getQueries().size(), equalTo(2)); + assertThat(permissions.getIndexPermissions("_alias").getQueries(), equalTo(bothQueries)); + } public void testAuthorizeMultipleGroupsMixedDls() { diff --git a/plugin/src/test/resources/rest-api-spec/test/authenticate/10_field_level_security.yml b/plugin/src/test/resources/rest-api-spec/test/authenticate/10_field_level_security.yml new file mode 100644 index 00000000000..e8c98ef9a18 --- /dev/null +++ b/plugin/src/test/resources/rest-api-spec/test/authenticate/10_field_level_security.yml @@ -0,0 +1,181 @@ +--- +setup: + - skip: + features: headers + + - do: + cluster.health: + wait_for_status: yellow + + - do: + xpack.security.put_role: + name: "readall" + body: > + { + "indices": [ + { + "names": ["*"], + "privileges": ["read"] + } + ] + } + + - do: + xpack.security.put_role: + name: "limitread" + body: > + { + "indices": [ + { + "names": ["*"], + "privileges": ["read"], + "query": {"match": {"marker": "test_1"}} + } + ] + } + + - do: + xpack.security.put_user: + username: "full" + body: > + { + "password" : "changeme", + "roles" : [ "readall" ], + "full_name" : "user who can read all data" + } + + - do: + xpack.security.put_user: + username: "limited" + body: > + { + "password" : "changeme", + "roles" : [ "limitread" ], + "full_name" : "user who can read some data" + } +--- +teardown: + - do: + xpack.security.delete_user: + username: "full" + ignore: 404 + + - do: + xpack.security.delete_user: + username: "limited" + ignore: 404 + + - do: + xpack.security.delete_role: + name: "readall" + ignore: 404 + + - do: + xpack.security.delete_role: + name: "limitread" + ignore: 404 + +--- +"Test doc level security against alias with different users": + + - do: + indices.create: + index: test_index + body: + aliases: + the_alias : {} + mappings: + doc: + properties: + location: + properties: + city: + type: "keyword" + settings: + index: + number_of_shards: 1 + number_of_replicas: 0 + + - do: + bulk: + refresh: true + body: + - '{"index": {"_index": "test_index", "_type": "doc"}}' + - '{"marker": "test_1", "location.city": "bos"}' + - '{"index": {"_index": "test_index", "_type": "doc"}}' + - '{"marker": "test_2", "location.city": "ams"}' + + - do: + headers: { Authorization: "Basic ZnVsbDpjaGFuZ2VtZQ==" } # full - user + search: + index: the_alias + size: 0 + from: 0 + body: + aggs: + cities: + terms: + field: location.city + + - match: { _shards.total: 1 } + - match: { hits.total: 2 } + - length: { aggregations.cities.buckets: 2 } + - match: { aggregations.cities.buckets.0.key: "ams" } + - match: { aggregations.cities.buckets.0.doc_count: 1 } + - match: { aggregations.cities.buckets.1.key: "bos" } + - match: { aggregations.cities.buckets.1.doc_count: 1 } + + - do: + headers: { Authorization: "Basic bGltaXRlZDpjaGFuZ2VtZQ==" } # limited - user + search: + index: the_alias + size: 0 + from: 0 + body: + aggs: + cities: + terms: + field: location.city + + - match: { _shards.total: 1 } + - match: { hits.total: 1 } + - length: { aggregations.cities.buckets: 1 } + - match: { aggregations.cities.buckets.0.key: "bos" } + - match: { aggregations.cities.buckets.0.doc_count: 1 } + + - do: + headers: { Authorization: "Basic bGltaXRlZDpjaGFuZ2VtZQ==" } # limited - user + search: + index: the_* + size: 0 + from: 0 + body: + aggs: + cities: + terms: + field: location.city + + - match: { _shards.total: 1 } + - match: { hits.total: 1 } + - length: { aggregations.cities.buckets: 1 } + - match: { aggregations.cities.buckets.0.key: "bos" } + - match: { aggregations.cities.buckets.0.doc_count: 1 } + + - do: + headers: { Authorization: "Basic bGltaXRlZDpjaGFuZ2VtZQ==" } # limited - user + search: + index: test_* + size: 0 + from: 0 + body: + aggs: + cities: + terms: + field: location.city + + - match: { _shards.total: 1 } + - match: { hits.total: 1 } + - length: { aggregations.cities.buckets: 1 } + - match: { aggregations.cities.buckets.0.key: "bos" } + - match: { aggregations.cities.buckets.0.doc_count: 1 } +