Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UserDatabaseRealm does not rely on cached roles only #420

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 5 additions & 81 deletions java/org/apache/catalina/realm/UserDatabaseRealm.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@

import java.security.Principal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.naming.Context;

Expand All @@ -28,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;

Expand Down Expand Up @@ -112,69 +112,6 @@ public void setLocalJndiResource(boolean localJndiResource) {
}


// --------------------------------------------------------- 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 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<Group> groups = user.getGroups();
while (groups.hasNext()) {
Group group = groups.next();
if (group.isInRole(dbrole)) {
return true;
}
}
return false;
}


// ------------------------------------------------------ Protected Methods

@Override
Expand Down Expand Up @@ -221,7 +158,7 @@ protected Principal getPrincipal(String username) {
return null;
}

List<String> roles = new ArrayList<>();
Set<String> roles = new HashSet<>();
Iterator<Role> uroles = user.getRoles();
while (uroles.hasNext()) {
Role role = uroles.next();
Expand All @@ -235,9 +172,8 @@ protected Principal getPrincipal(String username) {
Role role = uroles.next();
roles.add(role.getName());
}
}
return new GenericPrincipal(username, roles,
new UserDatabasePrincipal(username));
}
return new GenericPrincipal(username, new ArrayList<String>(roles));
}


Expand Down Expand Up @@ -306,16 +242,4 @@ protected void stopInternal() throws LifecycleException {
// Release reference to our user database
database = null;
}


private static class UserDatabasePrincipal implements Principal {
private final String name;
private UserDatabasePrincipal(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
}
11 changes: 11 additions & 0 deletions webapps/docs/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,17 @@
AprLifecycleListener does not show dev version suffix for libtcnative
and libapr. (michaelo)
</fix>
<update>
Remove class <code>UserDatabasePrincipal</code> and the <code>hasRole</code>
override from class <code>UserDatabaseRealm</code> in order to make the
Realm work with cached roles only during a user's login (according to the
documentation).
</update>
<update>
Ignore duplicates when collecting the effective roles list from Roles and
Groups in <code>UserDatabaseRealm.getPrincipal(String)</code> by using a
<code>HashSet</code> instead of an <code>ArrayList</code>.
</update>
</changelog>
</subsection>
<subsection name="Coyote">
Expand Down