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

rzo1 pushed a commit to branch tomee-10.x
in repository https://gitbox.apache.org/repos/asf/tomee.git

commit f7855760838823a3722a008d44baf2624dd59a3f
Author: Richard Zowalla <[email protected]>
AuthorDate: Tue Oct 13 08:47:30 2026 +0200

    Do not map the caller principal to a role by name in getLogicalRoles (#3070)
    
    Realm-authenticated callers get roles from the realm only; group principals 
still map by name.
    
    (cherry picked from commit 6dbc78217a476843e587c4695f0730421dd9b133)
---
 .../tomee/catalina/TomcatSecurityService.java      |  13 ++-
 .../TomcatSecurityServiceLogicalRolesTest.java     | 104 +++++++++++++++++++++
 2 files changed, 116 insertions(+), 1 deletion(-)

diff --git 
a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java
 
b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java
index 92262daa2e..3575688363 100644
--- 
a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java
+++ 
b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java
@@ -144,6 +144,17 @@ public class TomcatSecurityService extends 
AbstractSecurityService {
 
     @Override
     public Set<String> getLogicalRoles(final Principal[] principals, final 
Set<String> logicalRoles) {
+        // the caller's own principals are resolved through the realm only, 
never by name
+        final Set<Principal> callerPrincipals = new HashSet<>();
+        for (final Principal principal : principals) {
+            if (principal instanceof TomcatUser user) {
+                callerPrincipals.add(user.getTomcatPrincipal());
+                if (user.getTomcatPrincipal() instanceof GenericPrincipal 
genericPrincipal) {
+                    callerPrincipals.add(genericPrincipal.getUserPrincipal());
+                }
+            }
+        }
+
         final Set<String> roles = new LinkedHashSet<>(logicalRoles.size());
         for (final String logicalRole : logicalRoles) {
             for (final Principal principal : principals) {
@@ -152,7 +163,7 @@ public class TomcatSecurityService extends 
AbstractSecurityService {
                         roles.add(logicalRole);
                         break;
                     }
-                } else if (principal != null) {
+                } else if (principal != null && 
!callerPrincipals.contains(principal)) {
                     final String name = principal.getName();
                     if (logicalRole.equals(name)) {
                         roles.add(logicalRole);
diff --git 
a/tomee/tomee-catalina/src/test/java/org/apache/tomee/catalina/TomcatSecurityServiceLogicalRolesTest.java
 
b/tomee/tomee-catalina/src/test/java/org/apache/tomee/catalina/TomcatSecurityServiceLogicalRolesTest.java
new file mode 100644
index 0000000000..0e86f59baf
--- /dev/null
+++ 
b/tomee/tomee-catalina/src/test/java/org/apache/tomee/catalina/TomcatSecurityServiceLogicalRolesTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.tomee.catalina;
+
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.realm.RealmBase;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.security.Principal;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+public class TomcatSecurityServiceLogicalRolesTest {
+
+    // getLogicalRoles uses no instance state, skip the constructor which 
needs a running server
+    private final TomcatSecurityService service =
+            Mockito.mock(TomcatSecurityService.class, 
Mockito.CALLS_REAL_METHODS);
+
+    @Test
+    public void userNamedLikeRoleIsNotGrantedThatRole() {
+        final GenericPrincipal generic = new GenericPrincipal("admin", 
List.of("user"), new NamedPrincipal("admin"));
+        final Principal[] principals = {
+                generic,
+                new TomcatSecurityService.TomcatUser(new UserRoleRealm(), 
generic),
+                generic.getUserPrincipal()
+        };
+
+        assertEquals(Set.of("user"), service.getLogicalRoles(principals, 
Set.of("admin", "user")));
+    }
+
+    @Test
+    public void groupPrincipalIsMappedToRoleByName() {
+        final GenericPrincipal generic = new GenericPrincipal("bob", 
List.of("user"), new NamedPrincipal("bob"));
+        final Principal[] principals = {
+                generic,
+                new TomcatSecurityService.TomcatUser(new UserRoleRealm(), 
generic),
+                generic.getUserPrincipal(),
+                new GroupPrincipal("admin")
+        };
+
+        assertEquals(Set.of("admin", "user"), 
service.getLogicalRoles(principals, Set.of("admin", "user")));
+    }
+
+    @Test
+    public void groupPrincipalWithoutRealmIsMappedToRoleByName() {
+        final Principal[] principals = {new GroupPrincipal("admin")};
+
+        assertEquals(Set.of("admin"), service.getLogicalRoles(principals, 
Set.of("admin", "user")));
+    }
+
+    private static class NamedPrincipal implements Principal {
+        private final String name;
+
+        NamedPrincipal(final String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+
+    private static class GroupPrincipal extends NamedPrincipal {
+        GroupPrincipal(final String name) {
+            super(name);
+        }
+    }
+
+    public static class UserRoleRealm extends RealmBase {
+        @Override
+        public boolean hasRole(final Wrapper wrapper, final Principal 
principal, final String role) {
+            return "user".equals(role);
+        }
+
+        @Override
+        protected String getPassword(final String username) {
+            return null;
+        }
+
+        @Override
+        protected Principal getPrincipal(final String username) {
+            return null;
+        }
+    }
+}

Reply via email to