This is an automated email from the ASF dual-hosted git repository. remm pushed a commit to branch 8.5.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/8.5.x by this push: new d20637f Refactor principal handling for UserDatabaseRealm d20637f is described below commit d20637fbee3c4acd388841831382e0fc35bd4841 Author: remm <r...@apache.org> AuthorDate: Wed Jun 2 17:28:23 2021 +0200 Refactor principal handling for UserDatabaseRealm Now extends GenericPrincipal for easier integration in the rest of Tomcat. --- .../apache/catalina/realm/UserDatabaseRealm.java | 164 +++++++++------------ .../catalina/realm/TestGenericPrincipal.java | 7 + webapps/docs/changelog.xml | 4 + 3 files changed, 82 insertions(+), 93 deletions(-) diff --git a/java/org/apache/catalina/realm/UserDatabaseRealm.java b/java/org/apache/catalina/realm/UserDatabaseRealm.java index b6b2e9a..76757da 100644 --- a/java/org/apache/catalina/realm/UserDatabaseRealm.java +++ b/java/org/apache/catalina/realm/UserDatabaseRealm.java @@ -17,9 +17,10 @@ package org.apache.catalina.realm; import java.security.Principal; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; -import java.util.List; +import java.util.Set; import javax.naming.Context; @@ -28,7 +29,6 @@ import org.apache.catalina.LifecycleException; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.catalina.UserDatabase; -import org.apache.catalina.Wrapper; import org.apache.catalina.users.MemoryUserDatabase; import org.apache.naming.ContextBindings; import org.apache.tomcat.util.ExceptionUtils; @@ -121,69 +121,6 @@ public class UserDatabaseRealm extends RealmBase { } - // --------------------------------------------------------- Public Methods - - /** - * Return <code>true</code> if the specified Principal has the specified - * security role, within the context of this Realm; otherwise return - * <code>false</code>. This implementation returns <code>true</code> if the - * <code>User</code> has the role, or if any <code>Group</code> that the - * <code>User</code> is a member of has the role. - * - * @param principal Principal for whom the role is to be checked - * @param role Security role to be checked - */ - @Override - public boolean hasRole(Wrapper wrapper, Principal principal, String role) { - - UserDatabase database = getUserDatabase(); - if (database == null) { - return false; - } - - // Check for a role alias defined in a <security-role-ref> element - if (wrapper != null) { - String realRole = wrapper.findSecurityReference(role); - if (realRole != null) { - role = realRole; - } - } - if (principal instanceof GenericPrincipal) { - GenericPrincipal gp = (GenericPrincipal) principal; - if (gp.getUserPrincipal() instanceof User) { - principal = gp.getUserPrincipal(); - } - } - if (!(principal instanceof User)) { - // Play nice with SSO and mixed Realms - // No need to pass the wrapper here because role mapping has been - // performed already a few lines above - return super.hasRole(null, principal, role); - } - if ("*".equals(role)) { - return true; - } else if (role == null) { - return false; - } - User user = (User) principal; - Role dbrole = database.findRole(role); - if (dbrole == null) { - return false; - } - if (user.isInRole(dbrole)) { - return true; - } - Iterator<Group> groups = user.getGroups(); - while (groups.hasNext()) { - Group group = groups.next(); - if (group.isInRole(dbrole)) { - return true; - } - } - return false; - } - - // ------------------------------------------------------ Protected Methods @Override @@ -227,32 +164,7 @@ public class UserDatabaseRealm extends RealmBase { */ @Override protected Principal getPrincipal(String username) { - UserDatabase database = getUserDatabase(); - if (database == null) { - return null; - } - - User user = database.findUser(username); - if (user == null) { - return null; - } - - List<String> roles = new ArrayList<>(); - Iterator<Role> uroles = user.getRoles(); - while (uroles.hasNext()) { - Role role = uroles.next(); - roles.add(role.getName()); - } - Iterator<Group> groups = user.getGroups(); - while (groups.hasNext()) { - Group group = groups.next(); - uroles = group.getRoles(); - while (uroles.hasNext()) { - Role role = uroles.next(); - roles.add(role.getName()); - } - } - return new GenericPrincipal(username, user.getPassword(), roles, user); + return new UserDatabasePrincipal(username); } @@ -276,7 +188,9 @@ public class UserDatabaseRealm extends RealmBase { database = (UserDatabase) context.lookup(resourceName); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); - containerLog.error(sm.getString("userDatabaseRealm.lookup", resourceName), e); + if (containerLog != null) { + containerLog.error(sm.getString("userDatabaseRealm.lookup", resourceName), e); + } database = null; } } @@ -321,4 +235,68 @@ public class UserDatabaseRealm extends RealmBase { // Release reference to our user database database = null; } + + + public final class UserDatabasePrincipal extends GenericPrincipal { + private static final long serialVersionUID = 1L; + private final User user; + + public UserDatabasePrincipal(String username) { + super(username, null, null); + UserDatabase database = getUserDatabase(); + if (database == null) { + user = null; + } else { + user = database.findUser(username); + } + } + + @Override + public String[] getRoles() { + if (user == null) { + return super.getRoles(); + } + Set<String> roles = new HashSet<>(); + Iterator<Role> uroles = user.getRoles(); + while (uroles.hasNext()) { + Role role = uroles.next(); + roles.add(role.getName()); + } + Iterator<Group> groups = user.getGroups(); + while (groups.hasNext()) { + Group group = groups.next(); + uroles = group.getRoles(); + while (uroles.hasNext()) { + Role role = uroles.next(); + roles.add(role.getName()); + } + } + return roles.toArray(new String[0]); + } + + @Override + public boolean hasRole(String role) { + if ("*".equals(role)) { + return true; + } else if (role == null) { + return false; + } + UserDatabase database = getUserDatabase(); + if (user == null || database == null) { + return super.hasRole(role); + } + Role dbrole = database.findRole(role); + if (dbrole == null) { + return false; + } + return user.isInRole(dbrole); + } + + private Object writeReplace() { + // Replace with a static principal disconnected from the database + return new GenericPrincipal(getName(), null, Arrays.asList(getRoles())); + } + + } + } diff --git a/test/org/apache/catalina/realm/TestGenericPrincipal.java b/test/org/apache/catalina/realm/TestGenericPrincipal.java index c1507de..9cd2e04 100644 --- a/test/org/apache/catalina/realm/TestGenericPrincipal.java +++ b/test/org/apache/catalina/realm/TestGenericPrincipal.java @@ -57,6 +57,13 @@ public class TestGenericPrincipal { doTest(gpIn); } + @Test + public void testSerialize04() throws ClassNotFoundException, IOException { + UserDatabaseRealm realm = new UserDatabaseRealm(); + GenericPrincipal gpIn = realm.new UserDatabasePrincipal(USER); + doTest(gpIn); + } + private void doTest(GenericPrincipal gpIn) throws ClassNotFoundException, IOException { GenericPrincipal gpOut = serializeAndDeserialize(gpIn); diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 061575c..9cd71f5 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -148,6 +148,10 @@ AprLifecycleListener does not show dev version suffix for libtcnative and libapr. (michaelo) </fix> + <update> + Refactor principal handling in <code>UserDatabaseRealm</code> using + an inner class that extends <code>GenericPrincipal</code>. (remm) + </update> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org