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

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


The following commit(s) were added to refs/heads/main by this push:
     new ae8778ec5e ARTEMIS-5902 optimize authn cache key creation
ae8778ec5e is described below

commit ae8778ec5efcdea543e219467d39c7441f328b5d
Author: Justin Bertram <[email protected]>
AuthorDate: Sat Feb 14 13:30:54 2026 -0600

    ARTEMIS-5902 optimize authn cache key creation
    
    Eliminate unnecessary calls to j.s.MessageDigest#getInstance(String) as
    well as unnecessary bytes in hash.
    
    Existing tests should suffice for validation.
---
 .../core/security/impl/SecurityStoreImpl.java      | 41 ++++++++++++++++++++--
 .../artemis/core/server/ActiveMQServerLogger.java  |  3 ++
 .../activemq/artemis/utils/CertificateUtil.java    |  8 +++--
 .../core/security/impl/SecurityStoreImplTest.java  | 12 +++++++
 4 files changed, 59 insertions(+), 5 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 c0bb9d2874..c07d7bafef 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
@@ -63,6 +63,8 @@ import 
org.apache.activemq.artemis.utils.sm.SecurityManagerShim;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static 
org.apache.activemq.artemis.utils.CertificateUtil.CERT_SUBJECT_DN_UNAVAILABLE;
+
 /**
  * The Apache Artemis SecurityStore implementation
  */
@@ -70,6 +72,8 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
 
    private static final Logger logger = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
+   private static final byte[] CACHE_KEY_SEPARATOR = new byte[]{0};
+
    private final HierarchicalRepository<Set<Role>> securityRepository;
 
    private final ActiveMQSecurityManager securityManager;
@@ -95,6 +99,8 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
    private static final AtomicLongFieldUpdater<SecurityStoreImpl> 
AUTHORIZATION_FAILURE_COUNT_UPDATER = 
AtomicLongFieldUpdater.newUpdater(SecurityStoreImpl.class, 
"authorizationFailureCount");
    private volatile long authorizationFailureCount;
 
+   private static final MessageDigest SHA256 = getDigestInstance();
+   private static volatile boolean messageDigestCnsLogged = false;
 
    /**
     * @param notificationService can be {@code null}
@@ -568,10 +574,41 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
       return granted;
    }
 
-   private String createAuthenticationCacheKey(String username, String 
password, RemotingConnection connection) {
+   protected String createAuthenticationCacheKey(String username, String 
password, RemotingConnection connection) {
+      MessageDigest md = getDigestClone();
+      if (username != null) {
+         md.update(username.getBytes(StandardCharsets.UTF_8));
+      }
+      md.update(CACHE_KEY_SEPARATOR);
+      if (password != null) {
+         md.update(password.getBytes(StandardCharsets.UTF_8));
+      }
+      md.update(CACHE_KEY_SEPARATOR);
+      String certSubjectDN = CertificateUtil.getCertSubjectDN(connection);
+      if (!CERT_SUBJECT_DN_UNAVAILABLE.equals(certSubjectDN)) {
+         md.update(certSubjectDN.getBytes(StandardCharsets.UTF_8));
+      }
+      return ByteUtil.bytesToHex(md.digest());
+   }
+
+   private static MessageDigest getDigestClone() {
+      try {
+         return (MessageDigest) SHA256.clone();
+      } catch (CloneNotSupportedException cns) {
+         // This should never happen, but just in case log it and fail safely.
+         if (!messageDigestCnsLogged) {
+            ActiveMQServerLogger.LOGGER.sha256CloneNotSupported(cns);
+            messageDigestCnsLogged = true;
+         }
+         return getDigestInstance();
+      }
+   }
+
+   private static MessageDigest getDigestInstance() {
       try {
-         return 
ByteUtil.bytesToHex(MessageDigest.getInstance("SHA-256").digest((username + 
password + 
CertificateUtil.getCertSubjectDN(connection)).getBytes(StandardCharsets.UTF_8)));
+         return MessageDigest.getInstance("SHA-256");
       } catch (NoSuchAlgorithmException e) {
+         // This should never happen. The JavaDoc for MessageDigest states 
that SHA-256 is always available.
          throw new RuntimeException(e);
       }
    }
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
index 95542dd4d9..efe46e0746 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
@@ -1529,4 +1529,7 @@ public interface ActiveMQServerLogger {
 
    @LogMessage(id = 224158, value = "The operation {} on queue {} cannot read 
more data from paging into memory and will be interrupted.", level = 
LogMessage.Level.INFO)
    void preventQueueManagementToFloodMemory(String operation, String queue);
+
+   @LogMessage(id = 224159, value = "Failed to clone SHA256 MessageDigest, 
falling back to getInstance", level = LogMessage.Level.INFO)
+   void sha256CloneNotSupported(CloneNotSupportedException cns);
 }
\ No newline at end of file
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/utils/CertificateUtil.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/utils/CertificateUtil.java
index 6e6be8aa08..9cf59b824c 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/utils/CertificateUtil.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/utils/CertificateUtil.java
@@ -40,13 +40,15 @@ public class CertificateUtil {
 
    private static final String SSL_HANDLER_NAME = "ssl";
 
+   public static final String CERT_SUBJECT_DN_UNAVAILABLE = "unavailable";
+
    public static String getCertSubjectDN(RemotingConnection connection) {
-      String certSubjectDN = "unavailable";
       X509Certificate[] certs = getCertsFromConnection(connection);
       if (certs != null && certs.length > 0 && certs[0] != null) {
-         certSubjectDN = certs[0].getSubjectDN().getName();
+         return certs[0].getSubjectDN().getName();
+      } else {
+         return CERT_SUBJECT_DN_UNAVAILABLE;
       }
-      return certSubjectDN;
    }
 
    public static X509Certificate[] getCertsFromConnection(RemotingConnection 
remotingConnection) {
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
index afd7ec0a96..153d12c6cb 100644
--- 
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
@@ -28,6 +28,7 @@ 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.logs.AssertionLoggerHandler;
 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.RolePrincipal;
@@ -39,6 +40,7 @@ import org.mockito.ArgumentMatchers;
 import org.mockito.Mockito;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -216,4 +218,14 @@ public class SecurityStoreImplTest {
       assertEquals(1, securityStore.getAuthenticationFailureCount());
       assertEquals(0, securityStore.getAuthenticationCacheSize());
    }
+
+   @Test
+   public void testCacheAlgorithm() throws Exception {
+      final String user = RandomUtil.randomUUIDString();
+      SecurityStoreImpl securityStore = new SecurityStoreImpl(new 
HierarchicalObjectRepository<>(), securityManager, 999, true, "", null, null, 
0, 0);
+      try (AssertionLoggerHandler handler = new AssertionLoggerHandler()) {
+         securityStore.createAuthenticationCacheKey(user, 
RandomUtil.randomUUIDString(), null);
+         assertFalse(handler.findText("AMQ224159"));
+      }
+   }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to