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 2021/08/23 16:11:35 UTC

[geode] 03/03: GEODE-9521: Add test to cover multi-servers scenario for re-authentic… (#6782)

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

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

commit 5bbd1c9e33b130f0ae0eec77bf7316681a457714
Author: Jinmei Liao <ji...@pivotal.io>
AuthorDate: Mon Aug 23 08:58:40 2021 -0700

    GEODE-9521: Add test to cover multi-servers scenario for re-authentic… (#6782)
---
 .../geode/security/AuthExpirationDUnitTest.java    |  65 +++++-----
 .../AuthExpirationMultiServerDUnitTest.java        | 136 +++++++++++++++++++++
 .../geode/security/ExpirableSecurityManager.java   |  29 +++--
 3 files changed, 194 insertions(+), 36 deletions(-)

diff --git a/geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationDUnitTest.java b/geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationDUnitTest.java
index 0aae286..8c8eaff 100644
--- a/geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationDUnitTest.java
+++ b/geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationDUnitTest.java
@@ -48,8 +48,8 @@ import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactor
 @RunWith(Parameterized.class)
 @Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
 public class AuthExpirationDUnitTest {
-  static RegionService regionService0;
-  static RegionService regionService1;
+  static RegionService user0Service;
+  static RegionService user1Service;
 
   @Parameterized.Parameter
   public String clientVersion;
@@ -110,9 +110,14 @@ public class AuthExpirationDUnitTest {
 
     // all put operation succeeded
     Region<Object, Object> region = server.getCache().getRegion("/region");
-    assertThat(ExpirableSecurityManager.getExpiredUsers().size()).isEqualTo(1);
-    assertThat(ExpirableSecurityManager.getExpiredUsers().contains("user1")).isTrue();
     assertThat(region.size()).isEqualTo(2);
+    Map<String, List<String>> authorizedOps = ExpirableSecurityManager.getAuthorizedOps();
+    Map<String, List<String>> unAuthorizedOps = ExpirableSecurityManager.getUnAuthorizedOps();
+    assertThat(authorizedOps.keySet().size()).isEqualTo(2);
+    assertThat(authorizedOps.get("user1")).asList().containsExactly("DATA:WRITE:region:0");
+    assertThat(authorizedOps.get("user2")).asList().containsExactly("DATA:WRITE:region:1");
+    assertThat(unAuthorizedOps.keySet().size()).isEqualTo(1);
+    assertThat(unAuthorizedOps.get("user1")).asList().containsExactly("DATA:WRITE:region:1");
   }
 
   @Test
@@ -125,48 +130,52 @@ public class AuthExpirationDUnitTest {
             .withServerConnection(serverPort));
 
     clientVM.invoke(() -> {
-      UpdatableUserAuthInitialize.setUser("serviceUser0");
+      UpdatableUserAuthInitialize.setUser("user0");
       ClientCache clientCache = ClusterStartupRule.getClientCache();
-      assert clientCache != null;
       clientCache.createClientRegionFactory(ClientRegionShortcut.PROXY).create("region");
       Properties userSecurityProperties = new Properties();
       userSecurityProperties.put(SECURITY_CLIENT_AUTH_INIT,
           UpdatableUserAuthInitialize.class.getName());
-      regionService0 = clientCache.createAuthenticatedView(userSecurityProperties);
-      Region<Object, Object> region = regionService0.getRegion("/region");
+      user0Service = clientCache.createAuthenticatedView(userSecurityProperties);
+      Region<Object, Object> region = user0Service.getRegion("/region");
       region.put(0, "value0");
 
-      UpdatableUserAuthInitialize.setUser("serviceUser1");
+      UpdatableUserAuthInitialize.setUser("user1");
       userSecurityProperties.put(SECURITY_CLIENT_AUTH_INIT,
           UpdatableUserAuthInitialize.class.getName());
-      regionService1 = clientCache.createAuthenticatedView(userSecurityProperties);
-      region = regionService1.getRegion("/region");
+      user1Service = clientCache.createAuthenticatedView(userSecurityProperties);
+      region = user1Service.getRegion("/region");
       region.put(1, "value1");
     });
 
-    ExpirableSecurityManager.addExpiredUser("serviceUser1");
+    ExpirableSecurityManager.addExpiredUser("user1");
 
     clientVM.invoke(() -> {
-      Region<Object, Object> region = regionService1.getRegion("/region");
-      UpdatableUserAuthInitialize.setUser("serviceUser2");
-      region.put(2, "value2");
-
-      region = regionService0.getRegion("/region");
-      region.put(3, "value3");
-      regionService0.close();
-      regionService1.close();
+
+      Region<Object, Object> region = user0Service.getRegion("/region");
+      region.put(2, "value3");
+
+      UpdatableUserAuthInitialize.setUser("user1_extended");
+      region = user1Service.getRegion("/region");
+      region.put(3, "value2");
+
+      user0Service.close();
+      user1Service.close();
     });
 
     Region<Object, Object> region = server.getCache().getRegion("/region");
-    assertThat(ExpirableSecurityManager.getExpiredUsers().size()).isEqualTo(1);
-    assertThat(ExpirableSecurityManager.getExpiredUsers().contains("serviceUser1")).isTrue();
-    Map<Object, List<ResourcePermission>> authorizedOps =
-        ExpirableSecurityManager.getAuthorizedOps();
-    assertThat(authorizedOps.size()).isEqualTo(3);
-    assertThat(authorizedOps.get("serviceUser0").size()).isEqualTo(2);
-    assertThat(authorizedOps.get("serviceUser1").size()).isEqualTo(1);
-    assertThat(authorizedOps.get("serviceUser2").size()).isEqualTo(1);
     assertThat(region.size()).isEqualTo(4);
+
+    Map<String, List<String>> authorizedOps = ExpirableSecurityManager.getAuthorizedOps();
+    assertThat(authorizedOps.keySet().size()).isEqualTo(3);
+    assertThat(authorizedOps.get("user0")).asList().containsExactly("DATA:WRITE:region:0",
+        "DATA:WRITE:region:2");
+    assertThat(authorizedOps.get("user1")).asList().containsExactly("DATA:WRITE:region:1");
+    assertThat(authorizedOps.get("user1_extended")).asList().containsExactly("DATA:WRITE:region:3");
+
+    Map<String, List<String>> unAuthorizedOps = ExpirableSecurityManager.getUnAuthorizedOps();
+    assertThat(unAuthorizedOps.keySet().size()).isEqualTo(1);
+    assertThat(unAuthorizedOps.get("user1")).asList().containsExactly("DATA:WRITE:region:3");
   }
 
 }
diff --git a/geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationMultiServerDUnitTest.java b/geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationMultiServerDUnitTest.java
new file mode 100644
index 0000000..0dbc8ac
--- /dev/null
+++ b/geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationMultiServerDUnitTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.security;
+
+import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_CLIENT_AUTH_INIT;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.categories.SecurityTest;
+import org.apache.geode.test.junit.rules.ClientCacheRule;
+
+@Category({SecurityTest.class})
+public class AuthExpirationMultiServerDUnitTest implements Serializable {
+  public static final String REPLICATE_REGION = "replicateRegion";
+  public static final String PARTITION_REGION = "partitionRegion";
+  private MemberVM locator, server1, server2;
+  private int locatorPort;
+
+  @Rule
+  public ClusterStartupRule lsRule = new ClusterStartupRule();
+
+  @Rule
+  public ClientCacheRule clientCacheRule = new ClientCacheRule();
+
+  @Before
+  public void setup() {
+    locator = lsRule.startLocatorVM(0, l -> l.withSecurityManager(ExpirableSecurityManager.class));
+    locatorPort = locator.getPort();
+    server1 = lsRule.startServerVM(1, s -> s.withSecurityManager(ExpirableSecurityManager.class)
+        .withCredential("test", "test")
+        .withRegion(RegionShortcut.REPLICATE, REPLICATE_REGION)
+        .withRegion(RegionShortcut.PARTITION, PARTITION_REGION)
+        .withConnectionToLocator(locatorPort));
+    server2 = lsRule.startServerVM(2, s -> s.withSecurityManager(ExpirableSecurityManager.class)
+        .withCredential("test", "test")
+        .withRegion(RegionShortcut.REPLICATE, REPLICATE_REGION)
+        .withRegion(RegionShortcut.PARTITION, PARTITION_REGION)
+        .withConnectionToLocator(locatorPort));
+  }
+
+  @Test
+  public void clientReAuthenticationWorksOnMultipleServers() throws Exception {
+    UpdatableUserAuthInitialize.setUser("user1");
+    clientCacheRule
+        .withProperty(SECURITY_CLIENT_AUTH_INIT, UpdatableUserAuthInitialize.class.getName())
+        .withPoolSubscription(true)
+        .withServerConnection(server1.getPort());
+    clientCacheRule.createCache();
+    Region<Object, Object> region1 = clientCacheRule.createProxyRegion(REPLICATE_REGION);
+    Region<Object, Object> region2 = clientCacheRule.createProxyRegion(PARTITION_REGION);
+    region1.put("0", "value0");
+    region2.put("0", "value0");
+
+    expireUserOnAllVms("user1");
+
+    UpdatableUserAuthInitialize.setUser("user2");
+    region1.put("1", "value1");
+    region2.put("1", "value1");
+
+    // locator only validates peer
+    locator.invoke(() -> {
+      Map<String, List<String>> authorizedOps = ExpirableSecurityManager.getAuthorizedOps();
+      assertThat(authorizedOps.keySet().contains("test")).isTrue();
+      assertThat(authorizedOps.keySet().size()).isEqualTo(1);
+      Map<String, List<String>> unAuthorizedOps = ExpirableSecurityManager.getUnAuthorizedOps();
+      assertThat(unAuthorizedOps.keySet().size()).isEqualTo(0);
+    });
+
+    // client is connected to server1, server1 gets all the initial contact,
+    // authorization checks happens here
+    server1.invoke(() -> {
+      Map<String, List<String>> authorizedOps = ExpirableSecurityManager.getAuthorizedOps();
+      assertThat(authorizedOps.get("user1")).asList().containsExactlyInAnyOrder(
+          "DATA:WRITE:replicateRegion:0", "DATA:WRITE:partitionRegion:0");
+      assertThat(authorizedOps.get("user2")).asList().containsExactlyInAnyOrder(
+          "DATA:WRITE:replicateRegion:1", "DATA:WRITE:partitionRegion:1");
+      Map<String, List<String>> unAuthorizedOps = ExpirableSecurityManager.getUnAuthorizedOps();
+      assertThat(unAuthorizedOps.get("user1")).asList()
+          .containsExactly("DATA:WRITE:replicateRegion:1");
+    });
+
+    // server2 performs no authorization checks
+    server2.invoke(() -> {
+      Map<String, List<String>> authorizedOps = ExpirableSecurityManager.getAuthorizedOps();
+      Map<String, List<String>> unAuthorizedOps = ExpirableSecurityManager.getUnAuthorizedOps();
+      assertThat(authorizedOps.size()).isEqualTo(0);
+      assertThat(unAuthorizedOps.size()).isEqualTo(0);
+    });
+
+    MemberVM.invokeInEveryMember(() -> {
+      InternalCache cache = ClusterStartupRule.getCache();
+      Region<Object, Object> serverRegion1 = cache.getRegion(REPLICATE_REGION);
+      assertThat(serverRegion1.size()).isEqualTo(2);
+      Region<Object, Object> serverRegion2 = cache.getRegion(PARTITION_REGION);
+      assertThat(serverRegion2.size()).isEqualTo(2);
+    }, server1, server2);
+
+    MemberVM.invokeInEveryMember(() -> {
+      ExpirableSecurityManager.reset();
+      UpdatableUserAuthInitialize.reset();
+    }, locator, server1, server2);
+  }
+
+  private void expireUserOnAllVms(String user) {
+    MemberVM.invokeInEveryMember(() -> {
+      ExpirableSecurityManager.addExpiredUser(user);
+    }, locator, server1, server2);
+  }
+
+
+}
diff --git a/geode-junit/src/main/java/org/apache/geode/security/ExpirableSecurityManager.java b/geode-junit/src/main/java/org/apache/geode/security/ExpirableSecurityManager.java
index 5c4d177..59a8b4cb 100644
--- a/geode-junit/src/main/java/org/apache/geode/security/ExpirableSecurityManager.java
+++ b/geode-junit/src/main/java/org/apache/geode/security/ExpirableSecurityManager.java
@@ -35,20 +35,18 @@ public class ExpirableSecurityManager extends SimpleSecurityManager {
   // use static field for ease of testing since there is only one instance of this in each VM
   // we only need ConcurrentHashSet here, but map is only construct available in the library
   private static final Set<String> EXPIRED_USERS = ConcurrentHashMap.newKeySet();
-  private static final Map<Object, List<ResourcePermission>> AUTHORIZED_OPS =
+  private static final Map<String, List<String>> AUTHORIZED_OPS =
+      new ConcurrentHashMap<>();
+  private static final Map<String, List<String>> UNAUTHORIZED_OPS =
       new ConcurrentHashMap<>();
 
   @Override
   public boolean authorize(Object principal, ResourcePermission permission) {
     if (EXPIRED_USERS.contains((String) principal)) {
+      addToMap(UNAUTHORIZED_OPS, principal, permission);
       throw new AuthenticationExpiredException("User authentication expired.");
     }
-    List<ResourcePermission> permissions = AUTHORIZED_OPS.get(principal);
-    if (permissions == null) {
-      permissions = new ArrayList<>();
-    }
-    permissions.add(permission);
-    AUTHORIZED_OPS.put(principal, permissions);
+    addToMap(AUTHORIZED_OPS, principal, permission);
 
     // always authorized
     return true;
@@ -62,12 +60,27 @@ public class ExpirableSecurityManager extends SimpleSecurityManager {
     return EXPIRED_USERS;
   }
 
-  public static Map<Object, List<ResourcePermission>> getAuthorizedOps() {
+  public static Map<String, List<String>> getAuthorizedOps() {
     return AUTHORIZED_OPS;
   }
 
+  public static Map<String, List<String>> getUnAuthorizedOps() {
+    return UNAUTHORIZED_OPS;
+  }
+
+  private static void addToMap(Map<String, List<String>> maps, Object user,
+      ResourcePermission permission) {
+    List<String> list = maps.get(user);
+    if (list == null) {
+      list = new ArrayList<>();
+    }
+    list.add(permission.toString());
+    maps.put(user.toString(), list);
+  }
+
   public static void reset() {
     EXPIRED_USERS.clear();
     AUTHORIZED_OPS.clear();
+    UNAUTHORIZED_OPS.clear();
   }
 }