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

robbie pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/main by this push:
     new 29fafb5fed ARTEMIS-4399 fix disabled authn/z cache
29fafb5fed is described below

commit 29fafb5fed78788851273491f6f49638cbff828b
Author: Justin Bertram <[email protected]>
AuthorDate: Wed Aug 23 14:43:14 2023 -0500

    ARTEMIS-4399 fix disabled authn/z cache
---
 .../core/security/impl/SecurityStoreImpl.java      | 101 +++++++++++++++++----
 .../core/security/impl/SecurityStoreImplTest.java  |  94 +++++++++++++++++++
 2 files changed, 176 insertions(+), 19 deletions(-)

diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
index 14c393d032..35c4c87417 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
@@ -98,14 +98,22 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
       this.managementClusterUser = managementClusterUser;
       this.managementClusterPassword = managementClusterPassword;
       this.notificationService = notificationService;
-      authenticationCache = CacheBuilder.newBuilder()
-                                        .maximumSize(authenticationCacheSize)
-                                        
.expireAfterWrite(invalidationInterval, TimeUnit.MILLISECONDS)
-                                        .build();
-      authorizationCache = CacheBuilder.newBuilder()
-                                       .maximumSize(authorizationCacheSize)
-                                       .expireAfterWrite(invalidationInterval, 
TimeUnit.MILLISECONDS)
-                                       .build();
+      if (authenticationCacheSize == 0) {
+         authenticationCache = null;
+      } else {
+         authenticationCache = CacheBuilder.newBuilder()
+                                           
.maximumSize(authenticationCacheSize)
+                                           
.expireAfterWrite(invalidationInterval, TimeUnit.MILLISECONDS)
+                                           .build();
+      }
+      if (authorizationCacheSize == 0) {
+         authorizationCache = null;
+      } else {
+         authorizationCache = CacheBuilder.newBuilder()
+                                          .maximumSize(authorizationCacheSize)
+                                          
.expireAfterWrite(invalidationInterval, TimeUnit.MILLISECONDS)
+                                          .build();
+      }
       this.securityRepository.registerListener(this);
    }
 
@@ -159,7 +167,7 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
          boolean check = true;
 
          Subject subject = null;
-         Pair<Boolean, Subject> cacheEntry = 
authenticationCache.getIfPresent(createAuthenticationCacheKey(user, password, 
connection));
+         Pair<Boolean, Subject> cacheEntry = getAuthenticationCacheEntry(user, 
password, connection);
          if (cacheEntry != null) {
             if (!cacheEntry.getA()) {
                // cached authentication failed previously so don't check again
@@ -186,7 +194,7 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
             if (securityManager instanceof ActiveMQSecurityManager5) {
                try {
                   subject = ((ActiveMQSecurityManager5) 
securityManager).authenticate(user, password, connection, securityDomain);
-                  authenticationCache.put(createAuthenticationCacheKey(user, 
password, connection), new Pair<>(subject != null, subject));
+                  putAuthenticationCacheEntry(user, password, connection, 
subject);
                   validatedUser = getUserFromSubject(subject);
                } catch (NoCacheLoginException e) {
                   handleNoCacheLoginException(e);
@@ -313,12 +321,12 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
          // if we get here we're granted, add to the cache
          ConcurrentHashSet<SimpleString> set;
          String key = createAuthorizationCacheKey(user, checkType);
-         ConcurrentHashSet<SimpleString> act = 
authorizationCache.getIfPresent(key);
+         ConcurrentHashSet<SimpleString> act = getAuthorizationCacheEntry(key);
          if (act != null) {
             set = act;
          } else {
             set = new ConcurrentHashSet<>();
-            authorizationCache.put(key, set);
+            putAuthorizationCacheEntry(set, key);
          }
          set.add(fqqn != null ? fqqn : bareAddress);
       }
@@ -394,7 +402,7 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
     * @return the authenticated Subject with all associated role principals
     */
    private Subject getSubjectForAuthorization(SecurityAuth auth, 
ActiveMQSecurityManager5 securityManager) {
-      Pair<Boolean, Subject> cached = 
authenticationCache.getIfPresent(createAuthenticationCacheKey(auth.getUsername(),
 auth.getPassword(), auth.getRemotingConnection()));
+      Pair<Boolean, Subject> cached = 
getAuthenticationCacheEntry(auth.getUsername(), auth.getPassword(), 
auth.getRemotingConnection());
 
       if (cached == null && auth.getUsername() == null && auth.getPassword() 
== null && auth.getRemotingConnection() instanceof 
ManagementRemotingConnection) {
          AccessControlContext accessControlContext = 
AccessController.getContext();
@@ -410,7 +418,7 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
       if (cached == null) {
          try {
             Subject subject = securityManager.authenticate(auth.getUsername(), 
auth.getPassword(), auth.getRemotingConnection(), auth.getSecurityDomain());
-            
authenticationCache.put(createAuthenticationCacheKey(auth.getUsername(), 
auth.getPassword(), auth.getRemotingConnection()), new Pair<>(subject != null, 
subject));
+            putAuthenticationCacheEntry(auth.getUsername(), 
auth.getPassword(), auth.getRemotingConnection(), subject);
             return subject;
          } catch (NoCacheLoginException e) {
             handleNoCacheLoginException(e);
@@ -424,26 +432,71 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
       logger.debug("Skipping authentication cache due to exception: {}", 
e.getMessage());
    }
 
+   private void putAuthenticationCacheEntry(String user,
+                                            String password,
+                                            RemotingConnection connection,
+                                            Subject subject) {
+      if (authenticationCache != null) {
+         authenticationCache.put(createAuthenticationCacheKey(user, password, 
connection), new Pair<>(subject != null, subject));
+      }
+   }
+
+   private Pair<Boolean, Subject> getAuthenticationCacheEntry(String user,
+                                                              String password,
+                                                              
RemotingConnection connection) {
+      if (authenticationCache == null) {
+         return null;
+      } else {
+         return 
authenticationCache.getIfPresent(createAuthenticationCacheKey(user, password, 
connection));
+      }
+   }
+
+   private void putAuthorizationCacheEntry(ConcurrentHashSet<SimpleString> 
set, String key) {
+      if (authorizationCache != null) {
+         authorizationCache.put(key, set);
+      }
+   }
+
+   private ConcurrentHashSet<SimpleString> getAuthorizationCacheEntry(String 
key) {
+      if (authorizationCache == null) {
+         return null;
+      } else {
+         return authorizationCache.getIfPresent(key);
+      }
+   }
+
    public void invalidateAuthorizationCache() {
-      authorizationCache.invalidateAll();
+      if (authorizationCache != null) {
+         authorizationCache.invalidateAll();
+      }
    }
 
    public void invalidateAuthenticationCache() {
-      authenticationCache.invalidateAll();
+      if (authenticationCache != null) {
+         authenticationCache.invalidateAll();
+      }
    }
 
    public long getAuthenticationCacheSize() {
-      return authenticationCache.size();
+      if (authenticationCache == null) {
+         return 0;
+      } else {
+         return authenticationCache.size();
+      }
    }
 
    public long getAuthorizationCacheSize() {
-      return authorizationCache.size();
+      if (authorizationCache == null) {
+         return 0;
+      } else {
+         return authorizationCache.size();
+      }
    }
 
    private boolean checkAuthorizationCache(final SimpleString dest, final 
String user, final CheckType checkType) {
       boolean granted = false;
 
-      ConcurrentHashSet<SimpleString> act = 
authorizationCache.getIfPresent(createAuthorizationCacheKey(user, checkType));
+      ConcurrentHashSet<SimpleString> act = 
getAuthorizationCacheEntry(createAuthorizationCacheKey(user, checkType));
       if (act != null) {
          granted = act.contains(dest);
       }
@@ -458,4 +511,14 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
    private String createAuthorizationCacheKey(String user, CheckType 
checkType) {
       return user + "." + checkType.name();
    }
+
+   // for testing
+   protected Cache<String, Pair<Boolean, Subject>> getAuthenticationCache() {
+      return authenticationCache;
+   }
+
+   // for testing
+   protected Cache<String, ConcurrentHashSet<SimpleString>> 
getAuthorizationCache() {
+      return authorizationCache;
+   }
 }
diff --git 
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImplTest.java
 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImplTest.java
new file mode 100644
index 0000000000..ae22d1b812
--- /dev/null
+++ 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImplTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.activemq.artemis.core.security.impl;
+
+import javax.security.auth.Subject;
+import java.util.Set;
+
+import org.apache.activemq.artemis.core.security.CheckType;
+import org.apache.activemq.artemis.core.security.Role;
+import org.apache.activemq.artemis.core.security.SecurityAuth;
+import 
org.apache.activemq.artemis.core.settings.impl.HierarchicalObjectRepository;
+import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
+import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5;
+import 
org.apache.activemq.artemis.spi.core.security.jaas.NoCacheLoginException;
+import org.apache.activemq.artemis.utils.RandomUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class SecurityStoreImplTest {
+
+   @Test
+   public void zeroCacheSizeTest() throws Exception {
+      ActiveMQSecurityManager5 securityManager = new 
ActiveMQSecurityManager5() {
+         @Override
+         public Subject authenticate(String user,
+                                     String password,
+                                     RemotingConnection remotingConnection,
+                                     String securityDomain) throws 
NoCacheLoginException {
+            return new Subject();
+         }
+
+         @Override
+         public boolean authorize(Subject subject, Set<Role> roles, CheckType 
checkType, String address) {
+            return true;
+         }
+
+         @Override
+         public boolean validateUser(String user, String password) {
+            return false;
+         }
+
+         @Override
+         public boolean validateUserAndRole(String user, String password, 
Set<Role> roles, CheckType checkType) {
+            return false;
+         }
+      };
+      SecurityStoreImpl securityStore = new SecurityStoreImpl(new 
HierarchicalObjectRepository<>(), securityManager, 999, true, "", null, null, 
0, 0);
+      assertNull(securityStore.getAuthenticationCache());
+      securityStore.authenticate(RandomUtil.randomString(), 
RandomUtil.randomString(), null);
+      assertEquals(0, securityStore.getAuthenticationCacheSize());
+      securityStore.invalidateAuthenticationCache(); // ensure this doesn't 
throw an NPE
+
+      assertNull(securityStore.getAuthorizationCache());
+      securityStore.check(RandomUtil.randomSimpleString(), CheckType.SEND, new 
SecurityAuth() {
+         @Override
+         public String getUsername() {
+            return RandomUtil.randomString();
+         }
+
+         @Override
+         public String getPassword() {
+            return RandomUtil.randomString();
+         }
+
+         @Override
+         public RemotingConnection getRemotingConnection() {
+            return null;
+         }
+
+         @Override
+         public String getSecurityDomain() {
+            return null;
+         }
+      });
+      assertEquals(0, securityStore.getAuthorizationCacheSize());
+      securityStore.invalidateAuthorizationCache(); // ensure this doesn't 
throw an NPE
+   }
+}
\ No newline at end of file

Reply via email to