diff --git a/src/test/java/org/opensearch/security/IndexTemplateClusterPermissionsCheckTest.java b/src/test/java/org/opensearch/security/IndexTemplateClusterPermissionsCheckTest.java new file mode 100644 index 0000000000..b38e372560 --- /dev/null +++ b/src/test/java/org/opensearch/security/IndexTemplateClusterPermissionsCheckTest.java @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security; + +import org.apache.http.HttpStatus; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.security.test.helper.rest.RestHelper; +import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; + +public class IndexTemplateClusterPermissionsCheckTest extends SingleClusterTest{ + private RestHelper rh; + + final static String indexTemplateBody = "{ \"index_patterns\": [\"sem1234*\"], \"template\": { \"settings\": { \"number_of_shards\": 2, \"number_of_replicas\": 1 }, \"mappings\": { \"properties\": { \"timestamp\": { \"type\": \"date\", \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\" }, \"value\": { \"type\": \"double\" } } } } }"; + + private String getFailureResponseReason(String user) { + return "no permissions for [indices:admin/index_template/put] and User [name=" + user + ", backend_roles=[], requestedTenant=null]"; + } + + @Before + public void setupRestHelper() throws Exception{ + setup(); + rh = nonSslRestHelper(); + } + @Test + public void testPutIndexTemplateByNonPrivilegedUser() throws Exception { + String expectedFailureResponse = getFailureResponseReason("ds3"); + + // should fail, as `ds3` user doesn't have correct permissions + HttpResponse response = rh.executePutRequest("/_index_template/sem1234", indexTemplateBody, encodeBasicHeader("ds3", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + Assert.assertEquals(expectedFailureResponse, response.findValueInJson("error.root_cause[0].reason")); + } + + @Test + public void testPutIndexTemplateByPrivilegedUser() throws Exception { + // should pass, as `sem-user` user has correct permissions + HttpResponse response = rh.executePutRequest("/_index_template/sem1234", indexTemplateBody, encodeBasicHeader("sem-user", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + } + + @Test + public void testPutIndexTemplateAsIndexLevelPermission() throws Exception { + String expectedFailureResponse = getFailureResponseReason("sem-user2"); + + // should fail, as `sem-user2` is assigned `put-template` permission as index-level, not cluster-level + HttpResponse response = rh.executePutRequest("/_index_template/sem1234", indexTemplateBody, encodeBasicHeader("sem-user2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + Assert.assertEquals(expectedFailureResponse, response.findValueInJson("error.root_cause[0].reason")); + } + + } diff --git a/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java b/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java index fe32c5a465..07bbd433a1 100644 --- a/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java +++ b/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java @@ -379,11 +379,27 @@ public String findValueInJson(final String jsonDotPath) { fail("Invalid json dot path '" + jsonDotPath + "', rewrite with '.' characters between path elements."); } do { - final String pathEntry = jsonPathScanner.next(); + String pathEntry = jsonPathScanner.next(); + // if pathEntry is an array lookup + boolean isArrayLookup = pathEntry.contains("["); + int arrayEntryIdx = -1; + if (isArrayLookup) { + arrayEntryIdx = Integer.parseInt(pathEntry.replaceAll("[^0-9]", "")); + pathEntry = pathEntry.replaceAll("[^a-zA-Z_-]", ""); + } + if (!currentNode.has(pathEntry)) { fail("Unable to resolve '" + jsonDotPath + "', on path entry '" + pathEntry + "' from available fields " + currentNode.toPrettyString()); } currentNode = currentNode.get(pathEntry); + + // if it's an Array lookup we get the request index item + if (isArrayLookup) { + if(!currentNode.isArray()) { + fail("Unable to resolve '" + jsonDotPath + "', the '" + pathEntry + "' field is not an array " + currentNode.toPrettyString()); + } + currentNode = currentNode.get(arrayEntryIdx); + } } while (jsonPathScanner.hasNext()); if (!currentNode.isValueNode()) { diff --git a/src/test/resources/internal_users.yml b/src/test/resources/internal_users.yml index 6a0999e34e..99d821ce33 100644 --- a/src/test/resources/internal_users.yml +++ b/src/test/resources/internal_users.yml @@ -350,3 +350,9 @@ hidden_test: hash: $2a$12$n5nubfWATfQjSYHiWtUyeOxMIxFInUHOAx8VMmGmxFNPGpaBmeB.m opendistro_security_roles: - hidden_test +sem-user: + hash: $2a$12$n5nubfWATfQjSYHiWtUyeOxMIxFInUHOAx8VMmGmxFNPGpaBmeB.m + #password is: nagilum +sem-user2: + hash: $2a$12$n5nubfWATfQjSYHiWtUyeOxMIxFInUHOAx8VMmGmxFNPGpaBmeB.m + #password is: nagilum diff --git a/src/test/resources/roles.yml b/src/test/resources/roles.yml index c7a171523b..20e7c38cdb 100644 --- a/src/test/resources/roles.yml +++ b/src/test/resources/roles.yml @@ -1095,7 +1095,7 @@ data_stream_1: reserved: true hidden: false description: "Migrated from v6 (all types mapped)" - cluster_permissions: [] + cluster_permissions: [ "indices:admin/index_template/put" ] index_permissions: - index_patterns: - "my-data-stream*" @@ -1137,3 +1137,25 @@ hidden_test: - hidden_test_not_hidden allowed_actions: - "*" + +sem-role: + reserved: true + hidden: false + description: "Migrated from v6 (all types mapped)" + cluster_permissions: [ "cluster_monitor", "indices:admin/index_template/put" ] + index_permissions: + - index_patterns: + - "sem*" + allowed_actions: + - "*" + +sem-role2: + reserved: true + hidden: false + description: "Migrated from v6 (all types mapped)" + cluster_permissions: [ "cluster_monitor" ] + index_permissions: + - index_patterns: + - "sem*" + allowed_actions: + - "indices:admin/index_template/put" diff --git a/src/test/resources/roles_mapping.yml b/src/test/resources/roles_mapping.yml index 6cf3ae377b..9253b0c970 100644 --- a/src/test/resources/roles_mapping.yml +++ b/src/test/resources/roles_mapping.yml @@ -413,3 +413,13 @@ data_stream_3: hidden: false users: - "ds3" +sem-role: + reserved: false + hidden: false + users: + - "sem-user" +sem-role2: + reserved: false + hidden: false + users: + - "sem-user2"