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

markt pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/10.1.x by this push:
     new ae3c73ad81 Don't create multiple GenericPrincipals per Subject
ae3c73ad81 is described below

commit ae3c73ad818fa892e8a815d6c1b2c078a80046bb
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Sep 18 21:48:33 2024 +0100

    Don't create multiple GenericPrincipals per Subject
---
 .../authenticator/jaspic/CallbackHandlerImpl.java  | 74 ++++++++++++++--------
 webapps/docs/changelog.xml                         |  7 +-
 2 files changed, 52 insertions(+), 29 deletions(-)

diff --git 
a/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java 
b/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
index 17d97c683c..e95654c4bc 100644
--- a/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
+++ b/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
@@ -18,9 +18,11 @@ package org.apache.catalina.authenticator.jaspic;
 
 import java.io.IOException;
 import java.security.Principal;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 import javax.security.auth.Subject;
 import javax.security.auth.callback.Callback;
@@ -58,9 +60,11 @@ public class CallbackHandlerImpl implements CallbackHandler, 
Contained {
         String[] groups = null;
 
         if (callbacks != null) {
-            // Need to combine data from multiple callbacks so use this to hold
-            // the data
-            // Process the callbacks
+            /*
+             * There may be multiple callbacks passed to this method and/or 
multiple calls to this method. The Jakarta
+             * Authentication specification recommends that this class does 
not maintain state for individual requests
+             * and that the Subject is used to maintain state.
+             */
             for (Callback callback : callbacks) {
                 if (callback instanceof CallerPrincipalCallback) {
                     CallerPrincipalCallback cpc = (CallerPrincipalCallback) 
callback;
@@ -88,36 +92,50 @@ public class CallbackHandlerImpl implements 
CallbackHandler, Contained {
                 }
             }
 
-            // Create the GenericPrincipal
-            Principal gp = getPrincipal(principal, name, groups);
-            if (subject != null && gp != null) {
-                subject.getPrivateCredentials().add(gp);
-            }
-        }
-    }
+            // If subject is null, there is nothing to do
+            if (subject != null) {
 
+                // Need a name to create a Principal
+                if (name == null && principal != null) {
+                    name = principal.getName();
+                }
 
-    private Principal getPrincipal(Principal principal, String name, String[] 
groups) {
-        // If the Principal is cached in the session JASPIC may simply return 
it
-        if (principal instanceof GenericPrincipal) {
-            return principal;
-        }
-        if (name == null && principal != null) {
-            name = principal.getName();
-        }
-        if (name == null) {
-            return null;
-        }
-        List<String> roles;
-        if (groups == null || groups.length == 0) {
-            roles = Collections.emptyList();
-        } else {
-            roles = Arrays.asList(groups);
+                if (name != null) {
+                    // If the Principal has been cached in the session, just 
return it.
+                    if (principal instanceof GenericPrincipal) {
+                        // Duplicates are unlikely and will be handled in 
AuthenticatorBase.getPrincipal()
+                        subject.getPrivateCredentials().add(principal);
+                    } else {
+                        /*
+                         * There should only be a single GenericPrincipal in 
the private credentials for the Subject. If
+                         * one is already present, merge the groups to create 
a new GenericPrincipal. The code assumes
+                         * that the name and principal (if any) will be the 
same.
+                         */
+                        List<String> mergedRoles = new ArrayList<>();
+
+                        Set<GenericPrincipal> gps = 
subject.getPrivateCredentials(GenericPrincipal.class);
+                        if (!gps.isEmpty()) {
+                            GenericPrincipal gp = gps.iterator().next();
+                            mergedRoles.addAll(Arrays.asList(gp.getRoles()));
+                            // Remove the existing GenericPrincipal
+                            subject.getPrivateCredentials().remove(gp);
+                        }
+                        if (groups != null) {
+                            mergedRoles.addAll(Arrays.asList(groups));
+                        }
+
+                        if (mergedRoles.size() == 0) {
+                            mergedRoles = Collections.emptyList();
+                        }
+
+                        subject.getPrivateCredentials().add(new 
GenericPrincipal(name, mergedRoles, principal));
+                    }
+                }
+            }
         }
-
-        return new GenericPrincipal(name, roles, principal);
     }
 
+
     // Contained interface methods
     @Override
     public Container getContainer() {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 7b09500918..2367fb89a6 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -109,7 +109,12 @@
     <changelog>
       <fix>
         Ensure that <code>ServerAuthModule.initialize()</code> is called when
-        the module is configured via <code>registerServerAuthModule()</code>.
+        a Jakarta Authentication module is configured via
+        <code>registerServerAuthModule()</code>. (markt)
+      </fix>
+      <fix>
+        Ensure that the Jakarta Authentication <code>CallbackHandler</code> 
only
+        creates one <code>GenericPrincipal</code> in the <code>Subject</code>.
         (markt)
       </fix>
     </changelog>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to