diff --git a/src/main/java/org/opensearch/security/resolver/IndexResolverReplacer.java b/src/main/java/org/opensearch/security/resolver/IndexResolverReplacer.java index bb8fdd2ab0..898d2cf80c 100644 --- a/src/main/java/org/opensearch/security/resolver/IndexResolverReplacer.java +++ b/src/main/java/org/opensearch/security/resolver/IndexResolverReplacer.java @@ -224,6 +224,7 @@ private void resolveIndexPatterns(final String name, final IndicesOptions indice final Collection matchingAliases; Collection matchingAllIndices; + Collection matchingDataStreams = null; if (isLocalAll(original)) { if (isTraceEnabled) { @@ -259,8 +260,11 @@ private void resolveIndexPatterns(final String name, final IndicesOptions indice final boolean isDebugEnabled = log.isDebugEnabled(); try { matchingAllIndices = Arrays.asList(resolver.concreteIndexNames(state, indicesOptions, localRequestedPatterns.toArray(new String[0]))); + matchingDataStreams = resolver.dataStreamNames(state, indicesOptions, localRequestedPatterns.toArray(new String[0])); + if (isDebugEnabled) { - log.debug("Resolved pattern {} to {}", localRequestedPatterns, matchingAllIndices); + log.debug("Resolved pattern {} to indices: {} and data-streams: {}", + localRequestedPatterns, matchingAllIndices, matchingDataStreams); } } catch (IndexNotFoundException e1) { if (isDebugEnabled) { @@ -271,13 +275,16 @@ private void resolveIndexPatterns(final String name, final IndicesOptions indice } } - if (isTraceEnabled) { - log.trace("Resolved patterns {} for {} ({}) to [aliases {}, allIndices {}, originalRequested{}, remote indices {}]", - original, name, this.name, matchingAliases, matchingAllIndices, Arrays.toString(original), remoteIndices); + if (matchingDataStreams == null || matchingDataStreams.size() == 0) { + matchingDataStreams = Arrays.asList(NOOP); } - resolveTo(matchingAliases, matchingAllIndices, original, remoteIndices); + if (isTraceEnabled) { + log.trace("Resolved patterns {} for {} ({}) to [aliases {}, allIndices {}, dataStreams {}, originalRequested{}, remote indices {}]", + original, name, this.name, matchingAliases, matchingAllIndices, matchingDataStreams, Arrays.toString(original), remoteIndices); + } + resolveTo(matchingAliases, matchingAllIndices, matchingDataStreams, original, remoteIndices); } private void resolveToLocalAll() { @@ -286,9 +293,11 @@ private void resolveToLocalAll() { originalRequested.add(Resolved.ANY); } - private void resolveTo(Iterable matchingAliases, Iterable matchingAllIndices, String[] original, Iterable remoteIndices) { + private void resolveTo(Iterable matchingAliases, Iterable matchingAllIndices, + Iterable matchingDataStreams, String[] original, Iterable remoteIndices) { aliases.addAll(matchingAliases); allIndices.addAll(matchingAllIndices); + allIndices.addAll(matchingDataStreams); originalRequested.add(original); this.remoteIndices.addAll(remoteIndices); } diff --git a/src/test/java/org/opensearch/security/DataStreamIntegrationTests.java b/src/test/java/org/opensearch/security/DataStreamIntegrationTests.java index 070f670841..3d314c685e 100644 --- a/src/test/java/org/opensearch/security/DataStreamIntegrationTests.java +++ b/src/test/java/org/opensearch/security/DataStreamIntegrationTests.java @@ -34,7 +34,9 @@ public void createSampleDataStreams(RestHelper rh) throws Exception{ rh.executePutRequest("/_index_template/my-data-stream-template", getIndexTemplateBody(), encodeBasicHeader("ds1", "nagilum")); rh.executePutRequest("/_data_stream/my-data-stream11", getIndexTemplateBody(), encodeBasicHeader("ds3", "nagilum")); + rh.executePutRequest("/_data_stream/my-data-stream21", getIndexTemplateBody(), encodeBasicHeader("ds3", "nagilum")); rh.executePutRequest("/_data_stream/my-data-stream22", getIndexTemplateBody(), encodeBasicHeader("ds3", "nagilum")); + rh.executePutRequest("/_data_stream/my-data-stream23", getIndexTemplateBody(), encodeBasicHeader("ds3", "nagilum")); rh.executePutRequest("/_data_stream/my-data-stream33", getIndexTemplateBody(), encodeBasicHeader("ds3", "nagilum")); } @@ -89,6 +91,27 @@ public void testGetDataStream() throws Exception { response = rh.executeGetRequest("/_data_stream/my-data-stream33", encodeBasicHeader("ds3", "nagilum")); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream*", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream21,my-data-stream22", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream*", encodeBasicHeader("ds1", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream2*", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream21,my-data-stream22", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream*", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream*", encodeBasicHeader("ds3", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); } @Test @@ -103,18 +126,39 @@ public void testDeleteDataStream() throws Exception { Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); response = rh.executeDeleteRequest("/_data_stream/my-data-stream11", encodeBasicHeader("ds1", "nagilum")); - Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); response = rh.executeDeleteRequest("/_data_stream/my-data-stream11", encodeBasicHeader("ds2", "nagilum")); Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); response = rh.executeDeleteRequest("/_data_stream/my-data-stream22", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeDeleteRequest("/_data_stream/my-data-stream33", encodeBasicHeader("ds3", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeDeleteRequest("/_data_stream/my-data-stream*", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeDeleteRequest("/_data_stream/my-data-stream21,my-data-stream22", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeDeleteRequest("/_data_stream/my-data-stream*", encodeBasicHeader("ds1", "nagilum")); Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); - response = rh.executeDeleteRequest("/_data_stream/my-data-stream22", encodeBasicHeader("ds1", "nagilum")); + response = rh.executeDeleteRequest("/_data_stream/my-data-stream21,my-data-stream22", encodeBasicHeader("ds1", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeDeleteRequest("/_data_stream/my-data-stream2*", encodeBasicHeader("ds2", "nagilum")); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); - response = rh.executeDeleteRequest("/_data_stream/my-data-stream33", encodeBasicHeader("ds3", "nagilum")); + response = rh.executeDeleteRequest("/_data_stream/my-data-stream21,my-data-stream22", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeDeleteRequest("/_data_stream/my-data-stream*", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeDeleteRequest("/_data_stream/my-data-stream*", encodeBasicHeader("ds3", "nagilum")); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); } @@ -143,5 +187,71 @@ public void testDataStreamStats() throws Exception { response = rh.executeGetRequest("/_data_stream/my-data-stream33/_stats", encodeBasicHeader("ds3", "nagilum")); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream*/_stats", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream21,my-data-stream22/_stats", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream*/_stats", encodeBasicHeader("ds1", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream2*/_stats", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream21,my-data-stream22/_stats", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream*/_stats", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("/_data_stream/my-data-stream*/_stats", encodeBasicHeader("ds3", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + } + + @Test + public void testBackingIndicesOfDataStream() throws Exception { + + setup(); + RestHelper rh = nonSslRestHelper(); + createSampleDataStreams(rh); + HttpResponse response; + + response = rh.executeGetRequest("my-data-stream11", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("my-data-stream22", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest(".ds-my-data-stream11-000001", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest(".ds-my-data-stream22-000001", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest(".ds-my-data-stream21-000001,.ds-my-data-stream22-000001", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest(".ds-my-data-stream2*", encodeBasicHeader("ds0", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest("my-data-stream11", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest("my-data-stream22", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest(".ds-my-data-stream11-000001", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest(".ds-my-data-stream22-000001", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest(".ds-my-data-stream21-000001,.ds-my-data-stream22-000001", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + + response = rh.executeGetRequest(".ds-my-data-stream2*", encodeBasicHeader("ds2", "nagilum")); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); } } diff --git a/src/test/resources/roles.yml b/src/test/resources/roles.yml index 4622a477ab..c7a171523b 100644 --- a/src/test/resources/roles.yml +++ b/src/test/resources/roles.yml @@ -1080,6 +1080,17 @@ index_template_perm: allowed_actions: - "indices:admin/index_template/*" +data_stream_0: + reserved: true + hidden: false + description: "Migrated from v6 (all types mapped)" + cluster_permissions: [] + index_permissions: + - index_patterns: + - "*my-data-stream2*" + allowed_actions: + - "indices:admin/get" + data_stream_1: reserved: true hidden: false @@ -1091,7 +1102,6 @@ data_stream_1: allowed_actions: - "indices:admin/data_stream/get" - "indices:admin/data_stream/create" - - "indices:admin/data_stream/delete" data_stream_2: reserved: true @@ -1105,6 +1115,8 @@ data_stream_2: - "indices:admin/data_stream/get" - "indices:admin/data_stream/create" - "indices:monitor/data_stream/stats" + - "indices:admin/data_stream/delete" + - "indices:admin/get" data_stream_3: reserved: true diff --git a/src/test/resources/roles_mapping.yml b/src/test/resources/roles_mapping.yml index f5c39dc7c0..6cf3ae377b 100644 --- a/src/test/resources/roles_mapping.yml +++ b/src/test/resources/roles_mapping.yml @@ -393,6 +393,11 @@ index_template_perm: hidden: false users: - "ds1" +data_stream_0: + reserved: false + hidden: false + users: + - "ds0" data_stream_1: reserved: false hidden: false