You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ji...@apache.org on 2019/06/27 18:38:15 UTC

[geode] branch develop updated: GEODE-6897: re-organize all the security tests and add missing permissions to controllers. (#3744)

This is an automated email from the ASF dual-hosted git repository.

jinmeiliao pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new c243ac0   GEODE-6897: re-organize all the security tests and add missing permissions to controllers. (#3744)
c243ac0 is described below

commit c243ac03a89aa5abaaed52bae182be226e5d6652
Author: Jinmei Liao <ji...@pivotal.io>
AuthorDate: Thu Jun 27 11:38:02 2019 -0700

     GEODE-6897: re-organize all the security tests and add missing permissions to controllers. (#3744)
---
 .../RegionManagementRestSecurityDUnitTest.java     | 127 -------------
 .../RegionManagementSecurityRestDUnitTest.java     | 206 ---------------------
 ...usterManagementSecurityRestIntegrationTest.java | 176 ++++++++++++++++++
 .../controllers/RegionManagementController.java    |   2 +
 4 files changed, 178 insertions(+), 333 deletions(-)

diff --git a/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementRestSecurityDUnitTest.java b/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementRestSecurityDUnitTest.java
deleted file mode 100644
index 2489fcc..0000000
--- a/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementRestSecurityDUnitTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.management.internal.rest;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Properties;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Test;
-
-import org.apache.geode.cache.configuration.RegionConfig;
-import org.apache.geode.cache.configuration.RegionType;
-import org.apache.geode.examples.SimpleSecurityManager;
-import org.apache.geode.management.api.ClusterManagementResult;
-import org.apache.geode.management.api.RealizationResult;
-import org.apache.geode.test.dunit.rules.ClusterStartupRule;
-import org.apache.geode.test.dunit.rules.MemberVM;
-import org.apache.geode.test.junit.rules.GeodeDevRestClient;
-
-public class RegionManagementRestSecurityDUnitTest {
-  @ClassRule
-  public static ClusterStartupRule cluster = new ClusterStartupRule();
-
-  private static MemberVM locator, server;
-
-  private static GeodeDevRestClient restClient;
-
-  private static Properties config;
-
-  private static String json;
-
-  @BeforeClass
-  public static void beforeClass() throws Exception {
-    locator = cluster.startLocatorVM(0, l -> l.withHttpService()
-        .withSecurityManager(SimpleSecurityManager.class));
-
-    config = new Properties();
-    config.setProperty("security-username", "cluster");
-    config.setProperty("security-password", "cluster");
-
-    server = cluster.startServerVM(1, config, locator.getPort());
-    restClient =
-        new GeodeDevRestClient("/management/v2", "localhost", locator.getHttpPort(), false);
-
-    RegionConfig regionConfig = new RegionConfig();
-    regionConfig.setName("customers");
-    regionConfig.setType(RegionType.REPLICATE);
-    ObjectMapper mapper = new ObjectMapper();
-    json = mapper.writeValueAsString(regionConfig);
-  }
-
-  @Test
-  public void createRegionWithoutCredentials_failsWithAuthenticationError() throws Exception {
-    ClusterManagementResult<?> result =
-        restClient.doPostAndAssert("/regions", json)
-            .hasStatusCode(401)
-            .getClusterManagementResult();
-
-    assertThat(result.isSuccessful()).isFalse();
-    assertThat(result.getStatusCode())
-        .isEqualTo(ClusterManagementResult.StatusCode.UNAUTHENTICATED);
-    assertThat(result.getStatusMessage()).contains("authentication is required");
-  }
-
-  @Test
-  public void createRegionWithBadCredentials_failsWithAuthenticationError() throws Exception {
-    ClusterManagementResult<?> result =
-        restClient.doPostAndAssert("/regions", json, "baduser", "badpassword")
-            .hasStatusCode(401)
-            .getClusterManagementResult();
-
-    assertThat(result.isSuccessful()).isFalse();
-    assertThat(result.getStatusCode())
-        .isEqualTo(ClusterManagementResult.StatusCode.UNAUTHENTICATED);
-    assertThat(result.getStatusMessage()).contains("Authentication error");
-  }
-
-  @Test
-  public void createRegionNotAuthorized_failsWithAuthorizationError() throws Exception {
-    ClusterManagementResult<?> result =
-        restClient.doPostAndAssert("/regions", json, "notauthorized", "notauthorized")
-            .hasStatusCode(403)
-            .getClusterManagementResult();
-
-    assertThat(result.isSuccessful()).isFalse();
-    assertThat(result.getStatusCode()).isEqualTo(ClusterManagementResult.StatusCode.UNAUTHORIZED);
-    assertThat(result.getStatusMessage()).contains("not authorized for DATA:MANAGE");
-  }
-
-  @Test
-  public void createRegionWithCredentials_CreatesRegion() throws Exception {
-    ClusterManagementResult<?> result =
-        restClient.doPostAndAssert("/regions", json, "datamanage", "datamanage")
-            .hasStatusCode(201)
-            .getClusterManagementResult();
-
-    assertThat(result.isSuccessful()).isTrue();
-    assertThat(result.getStatusCode()).isEqualTo(ClusterManagementResult.StatusCode.OK);
-    assertThat(result.getMemberStatuses()).extracting(RealizationResult::getMemberName)
-        .containsExactly("server-1");
-
-    // make sure region is created
-    server.invoke(() -> RegionManagementDunitTest.verifyRegionCreated("customers", "REPLICATE"));
-
-    // make sure region is persisted
-    locator.invoke(() -> RegionManagementDunitTest.verifyRegionPersisted("customers", "REPLICATE",
-        "cluster"));
-
-    // verify that additional server can be started with the cluster configuration
-    cluster.startServerVM(2, config, locator.getPort());
-  }
-}
diff --git a/geode-web-management/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementSecurityRestDUnitTest.java b/geode-web-management/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementSecurityRestDUnitTest.java
deleted file mode 100644
index b4e00cd..0000000
--- a/geode-web-management/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementSecurityRestDUnitTest.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package org.apache.geode.management.internal.rest;
-
-import static org.hamcrest.Matchers.is;
-import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-import java.util.List;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.context.web.WebAppConfiguration;
-import org.springframework.web.context.WebApplicationContext;
-
-import org.apache.geode.cache.configuration.RegionConfig;
-import org.apache.geode.cache.configuration.RegionType;
-import org.apache.geode.examples.SimpleSecurityManager;
-import org.apache.geode.management.api.ClusterManagementResult;
-import org.apache.geode.management.configuration.RuntimeRegionConfig;
-import org.apache.geode.management.internal.api.LocatorClusterManagementService;
-import org.apache.geode.test.dunit.rules.ClusterStartupRule;
-
-@RunWith(SpringRunner.class)
-@ContextConfiguration(locations = {"classpath*:WEB-INF/management-servlet.xml"},
-    loader = SecuredLocatorContextLoader.class)
-@WebAppConfiguration
-public class RegionManagementSecurityRestDUnitTest {
-
-  private static final String REGION = "products";
-
-  @Autowired
-  private WebApplicationContext webApplicationContext;
-
-  @Rule
-  public ClusterStartupRule cluster = new ClusterStartupRule(1);
-
-  private LocatorWebContext context;
-
-  private RegionConfig regionConfig;
-  private String json;
-
-  @Before
-  public void before() throws JsonProcessingException {
-    regionConfig = new RegionConfig();
-    regionConfig.setName(REGION);
-    regionConfig.setType(RegionType.REPLICATE);
-    ObjectMapper mapper = new ObjectMapper();
-    json = mapper.writeValueAsString(regionConfig);
-    context = new LocatorWebContext(webApplicationContext);
-
-    cluster.setSkipLocalDistributedSystemCleanup(true);
-    int locatorPort = context.getLocator().getPort();
-
-    cluster.startServerVM(1, s -> s.withConnectionToLocator(locatorPort)
-        .withSecurityManager(SimpleSecurityManager.class)
-        .withCredential("cluster", "cluster"));
-  }
-
-  @After
-  public void after() {
-    LocatorClusterManagementService client =
-        (LocatorClusterManagementService) context.getLocator().getClusterManagementService();
-
-    ClusterManagementResult<RuntimeRegionConfig> result = client.list(new RegionConfig());
-    List<RuntimeRegionConfig> regions = result.getResult();
-
-    regions.forEach(r -> client.delete(new RegionConfig(r)));
-  }
-
-  @Test
-  public void createRegionFails_when_notAuthorized() throws Exception {
-    context.perform(post("/v2/regions")
-        .with(httpBasic("user", "user"))
-        .content(json))
-        .andExpect(status().isForbidden())
-        .andExpect(jsonPath("$.statusCode", is("UNAUTHORIZED")))
-        .andExpect(jsonPath("$.statusMessage",
-            is("user not authorized for DATA:MANAGE")));
-  }
-
-  @Test
-  public void createRegionFails_when_noCredentials() throws Exception {
-    context.perform(post("/v2/regions")
-        .content(json))
-        .andExpect(status().isUnauthorized())
-        .andExpect(jsonPath("$.statusCode", is("UNAUTHENTICATED")))
-        .andExpect(jsonPath("$.statusMessage",
-            is("Full authentication is required to access this resource")));
-  }
-
-  @Test
-  public void createRegionFails_when_wrongCredentials() throws Exception {
-    context.perform(post("/v2/regions")
-        .with(httpBasic("user", "wrong_password"))
-        .content(json))
-        .andExpect(status().isUnauthorized())
-        .andExpect(jsonPath("$.statusCode", is("UNAUTHENTICATED")))
-        .andExpect(jsonPath("$.statusMessage",
-            is("Authentication error. Please check your credentials.")));
-  }
-
-  @Test
-  public void createRegion_succeeds() throws Exception {
-    createRegion();
-  }
-
-  @Test
-  public void deleteRegionFails_when_notAuthorized() throws Exception {
-    createRegion();
-
-    context.perform(delete("/v2/regions/" + REGION)
-        .with(httpBasic("user", "user"))
-        .content(json))
-        .andExpect(status().isForbidden())
-        .andExpect(jsonPath("$.statusCode", is("UNAUTHORIZED")))
-        .andExpect(jsonPath("$.statusMessage",
-            is("user not authorized for DATA:MANAGE")));
-  }
-
-  @Test
-  public void deleteRegionFails_when_noCredentials() throws Exception {
-    createRegion();
-
-    context.perform(delete("/v2/regions/" + REGION)
-        .content(json))
-        .andExpect(status().isUnauthorized())
-        .andExpect(jsonPath("$.statusCode", is("UNAUTHENTICATED")))
-        .andExpect(jsonPath("$.statusMessage",
-            is("Full authentication is required to access this resource")));
-  }
-
-  @Test
-  public void deleteRegionFails_when_wrongCredentials() throws Exception {
-    createRegion();
-
-    context.perform(delete("/v2/regions/" + REGION)
-        .with(httpBasic("user", "wrong_password"))
-        .content(json))
-        .andExpect(status().isUnauthorized())
-        .andExpect(jsonPath("$.statusCode", is("UNAUTHENTICATED")))
-        .andExpect(jsonPath("$.statusMessage",
-            is("Authentication error. Please check your credentials.")));
-  }
-
-  @Test
-  public void deleteRegion_succeeds() throws Exception {
-    createRegion();
-
-    context.perform(delete("/v2/regions/" + REGION)
-        .with(httpBasic("dataManage", "dataManage"))
-        .content(json))
-        .andExpect(status().isOk())
-        .andExpect(jsonPath("$.statusCode", is("OK")))
-        .andExpect(jsonPath("$.statusMessage",
-            is("Successfully removed config for [cluster]")));
-  }
-
-  @Test
-  public void listRegion_succeeds() throws Exception {
-    createRegion();
-
-    context.perform(get("/v2/regions/" + REGION)
-        .with(httpBasic("clusterRead", "clusterRead"))
-        .content(json))
-        .andExpect(status().isOk())
-        .andExpect(jsonPath("$.statusCode", is("OK")))
-        .andExpect(jsonPath("$.result[0].entryCount", is(0)));
-  }
-
-  private void createRegion() throws Exception {
-    context.perform(post("/v2/regions")
-        .with(httpBasic("dataManage", "dataManage"))
-        .content(json))
-        .andExpect(status().isCreated())
-        .andExpect(jsonPath("$.statusCode", is("OK")))
-        .andExpect(jsonPath("$.statusMessage",
-            is("Successfully updated config for cluster")));
-  }
-
-}
diff --git a/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/ClusterManagementSecurityRestIntegrationTest.java b/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/ClusterManagementSecurityRestIntegrationTest.java
new file mode 100644
index 0000000..6807699
--- /dev/null
+++ b/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/ClusterManagementSecurityRestIntegrationTest.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.rest;
+
+import static org.hamcrest.Matchers.is;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
+import org.springframework.web.context.WebApplicationContext;
+
+import org.apache.geode.cache.configuration.GatewayReceiverConfig;
+import org.apache.geode.cache.configuration.PdxType;
+import org.apache.geode.cache.configuration.RegionConfig;
+import org.apache.geode.cache.configuration.RegionType;
+import org.apache.geode.util.internal.GeodeJsonMapper;
+
+@RunWith(SpringRunner.class)
+@ContextConfiguration(locations = {"classpath*:WEB-INF/management-servlet.xml"},
+    loader = SecuredLocatorContextLoader.class)
+@WebAppConfiguration
+public class ClusterManagementSecurityRestIntegrationTest {
+
+  private static final String REGION = "products";
+  @Autowired
+  private WebApplicationContext webApplicationContext;
+
+  private LocatorWebContext context;
+
+  private static List<TestContext> testContexts = new ArrayList<>();
+  private static ObjectMapper mapper;
+
+  @BeforeClass
+  public static void beforeClass() throws JsonProcessingException {
+    mapper = GeodeJsonMapper.getMapper();
+    RegionConfig regionConfig = new RegionConfig();
+    regionConfig.setName(REGION);
+    regionConfig.setType(RegionType.REPLICATE);
+
+    testContexts.add(new TestContext(post("/v2/regions"), "DATA:MANAGE")
+        .setContent(mapper.writeValueAsString(regionConfig)));
+
+    // additional credentials needed to create persistent regions
+    regionConfig.setType(RegionType.REPLICATE_PERSISTENT);
+    testContexts.add(new TestContext(post("/v2/regions"), "CLUSTER:WRITE:DISK")
+        .setCredentials("dataManage", "dataManage")
+        .setContent(mapper.writeValueAsString(regionConfig)));
+
+    testContexts.add(new TestContext(get("/v2/regions"), "CLUSTER:READ"));
+    testContexts.add(new TestContext(get("/v2/regions/regionA"), "CLUSTER:READ:regionA"));
+    testContexts.add(new TestContext(delete("/v2/regions/regionA"), "DATA:MANAGE"));
+    testContexts.add(new TestContext(get("/v2/regions/regionA/indexes"), "CLUSTER:READ:QUERY"));
+    testContexts.add(new TestContext(get("/v2/regions/regionA/indexes"), "CLUSTER:READ:QUERY"));
+    testContexts
+        .add(new TestContext(get("/v2/regions/regionA/indexes/index1"), "CLUSTER:READ:QUERY"));
+
+    testContexts.add(new TestContext(get("/v2/gateways/receivers"), "CLUSTER:READ"));
+    testContexts.add(new TestContext(post("/v2/gateways/receivers"), "CLUSTER:MANAGE")
+        .setContent(mapper.writeValueAsString(new GatewayReceiverConfig())));
+
+    testContexts.add(new TestContext(get("/v2/members"), "CLUSTER:READ"));
+    testContexts.add(new TestContext(get("/v2/members/server1"), "CLUSTER:READ"));
+
+    testContexts.add(new TestContext(post("/v2/configurations/pdx"), "CLUSTER:MANAGE")
+        .setContent(mapper.writeValueAsString(new PdxType())));
+  }
+
+  @Before
+  public void before() {
+    context = new LocatorWebContext(webApplicationContext);
+  }
+
+
+  @Test
+  public void notAuthorized() throws Exception {
+    for (TestContext testContext : testContexts) {
+      MockHttpServletRequestBuilder requestBuilder = testContext.request
+          .with(httpBasic(testContext.username, testContext.password));
+      if (testContext.content != null) {
+        requestBuilder.content(testContext.content);
+      }
+      context.perform(requestBuilder)
+          .andExpect(status().isForbidden())
+          .andExpect(jsonPath("$.statusCode", is("UNAUTHORIZED")))
+          .andExpect(jsonPath("$.statusMessage",
+              is(testContext.username + " not authorized for " + testContext.permission)));
+    }
+  }
+
+  @Test
+  public void noCredentials() throws Exception {
+    context.perform(post("/v2/regions"))
+        .andExpect(status().isUnauthorized())
+        .andExpect(jsonPath("$.statusCode", is("UNAUTHENTICATED")))
+        .andExpect(jsonPath("$.statusMessage",
+            is("Full authentication is required to access this resource")));
+  }
+
+  @Test
+  public void wrongCredentials() throws Exception {
+    context.perform(post("/v2/regions")
+        .with(httpBasic("user", "wrong_password")))
+        .andExpect(status().isUnauthorized())
+        .andExpect(jsonPath("$.statusCode", is("UNAUTHENTICATED")))
+        .andExpect(jsonPath("$.statusMessage",
+            is("Authentication error. Please check your credentials.")));
+  }
+
+  @Test
+  public void successful() throws Exception {
+    RegionConfig regionConfig = new RegionConfig();
+    regionConfig.setName(REGION);
+    regionConfig.setType(RegionType.REPLICATE);
+    context.perform(post("/v2/regions")
+        .with(httpBasic("dataManage", "dataManage"))
+        .content(mapper.writeValueAsString(regionConfig)))
+        .andExpect(status().isCreated())
+        .andExpect(jsonPath("$.statusCode", is("OK")))
+        .andExpect(jsonPath("$.statusMessage",
+            is("Successfully updated config for cluster")));
+  }
+
+  private static class TestContext {
+    MockHttpServletRequestBuilder request;
+    String content;
+    String permission;
+    String username = "user";
+    String password = "user";
+
+    public TestContext(MockHttpServletRequestBuilder request, String permission) {
+      this.request = request;
+      this.permission = permission;
+    }
+
+    public TestContext setContent(String content) {
+      this.content = content;
+      return this;
+    }
+
+    public TestContext setCredentials(String username, String password) {
+      this.username = username;
+      this.password = password;
+      return this;
+    }
+  }
+}
diff --git a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/RegionManagementController.java b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/RegionManagementController.java
index e98e203..5d4c520 100644
--- a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/RegionManagementController.java
+++ b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/RegionManagementController.java
@@ -105,6 +105,7 @@ public class RegionManagementController extends AbstractManagementController {
   @RequestMapping(method = RequestMethod.GET,
       value = REGION_CONFIG_ENDPOINT + "/{regionName}/indexes")
   @ResponseBody
+  @PreAuthorize("@securityService.authorize('CLUSTER', 'READ', 'QUERY')")
   public ClusterManagementResult<RegionConfig.Index> listIndex(
       @PathVariable String regionName,
       @RequestParam(required = false) String id) {
@@ -123,6 +124,7 @@ public class RegionManagementController extends AbstractManagementController {
   @RequestMapping(method = RequestMethod.GET,
       value = REGION_CONFIG_ENDPOINT + "/{regionName}/indexes/{id}")
   @ResponseBody
+  @PreAuthorize("@securityService.authorize('CLUSTER', 'READ', 'QUERY')")
   public ClusterManagementResult<RegionConfig.Index> getIndex(
       @PathVariable String regionName,
       @PathVariable String id) {