diff --git a/java/org/apache/catalina/realm/UserDatabaseRealm.java b/java/org/apache/catalina/realm/UserDatabaseRealm.java
index bffb978a90e0..9d69540931c6 100644
--- a/java/org/apache/catalina/realm/UserDatabaseRealm.java
+++ b/java/org/apache/catalina/realm/UserDatabaseRealm.java
@@ -17,7 +17,7 @@
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.Set;
@@ -29,7 +29,6 @@
import org.apache.catalina.Role;
import org.apache.catalina.User;
import org.apache.catalina.UserDatabase;
-import org.apache.catalina.Wrapper;
import org.apache.naming.ContextBindings;
import org.apache.tomcat.util.ExceptionUtils;
@@ -113,69 +112,6 @@ public void setLocalJndiResource(boolean localJndiResource) {
}
- // --------------------------------------------------------- Public Methods
-
- /**
- * Return true
if the specified Principal has the specified
- * security role, within the context of this Realm; otherwise return
- * false
. This implementation returns true
if the
- * User
has the role, or if any Group
that the
- * User
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 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 UserDatabasePrincipal) {
- principal = database.findUser(gp.getName());
- }
- }
- 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 groups = user.getGroups();
- while (groups.hasNext()) {
- Group group = groups.next();
- if (group.isInRole(dbrole)) {
- return true;
- }
- }
- return false;
- }
-
-
// ------------------------------------------------------ Protected Methods
@Override
@@ -212,32 +148,7 @@ protected String getPassword(String username) {
*/
@Override
protected Principal getPrincipal(String username) {
- UserDatabase database = getUserDatabase();
- if (database == null) {
- return null;
- }
-
- User user = database.findUser(username);
- if (user == null) {
- return null;
- }
-
- Set roles = new HashSet<>();
- Iterator uroles = user.getRoles();
- while (uroles.hasNext()) {
- Role role = uroles.next();
- roles.add(role.getName());
- }
- Iterator 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, new ArrayList<>(roles), new UserDatabasePrincipal(username));
+ return new UserDatabasePrincipal(username);
}
@@ -261,7 +172,9 @@ private UserDatabase getUserDatabase() {
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;
}
}
@@ -308,14 +221,65 @@ protected void stopInternal() throws LifecycleException {
}
- private static class UserDatabasePrincipal implements Principal {
- private final String name;
- private UserDatabasePrincipal(String name) {
- this.name = name;
+ public final class UserDatabasePrincipal extends GenericPrincipal {
+ private static final long serialVersionUID = 1L;
+ private final User user;
+
+ public UserDatabasePrincipal(String username) {
+ super(username);
+ UserDatabase database = getUserDatabase();
+ if (database == null) {
+ user = null;
+ } else {
+ user = database.findUser(username);
+ }
+ }
+
+ @Override
+ public String[] getRoles() {
+ if (user == null) {
+ return super.getRoles();
+ }
+ Set roles = new HashSet<>();
+ Iterator uroles = user.getRoles();
+ while (uroles.hasNext()) {
+ Role role = uroles.next();
+ roles.add(role.getName());
+ }
+ Iterator 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 String getName() {
- return name;
+ public boolean hasRole(String role) {
+ if (user == null) {
+ return super.hasRole(role);
+ }
+ if ("*".equals(role)) {
+ return true;
+ } else if (role == null) {
+ return false;
+ }
+ 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(), Arrays.asList(getRoles()));
+ }
+
}
+
}
diff --git a/test/org/apache/catalina/realm/TestGenericPrincipal.java b/test/org/apache/catalina/realm/TestGenericPrincipal.java
index 5a994156e6fa..b2ac92feddb8 100644
--- a/test/org/apache/catalina/realm/TestGenericPrincipal.java
+++ b/test/org/apache/catalina/realm/TestGenericPrincipal.java
@@ -56,6 +56,13 @@ public void testSerialize03() throws ClassNotFoundException, IOException {
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 a26cc8c438de..993e0b76d3c0 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -160,6 +160,10 @@
AprLifecycleListener does not show dev version suffix for libtcnative
and libapr. (michaelo)
+
+ Refactor principal handling in UserDatabaseRealm
using
+ an inner class that extends GenericPrincipal
. (remm)
+
Ignore duplicates when collecting the effective roles list from Roles
and Groups in UserDatabaseRealm.getPrincipal(String)
.