Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get user roles in a JSP / Servlet

Is there any way to get a String[] with the roles a user has in the JSP or Servlet?

I know about request.isUserInRole("role1") but I also want to know all the roles of the user.

I searched the servlet source and it seems this is not possible, but this seems odd to me.

So... any ideas?

like image 418
AlfaTeK Avatar asked Dec 05 '08 15:12

AlfaTeK


3 Answers

Read in all the possible roles, or hardcode a list. Then iterate over it running the isUserInRole and build a list of roles the user is in and then convert the list to an array.

String[] allRoles = {"1","2","3"};
HttpServletRequest request = ... (or from method argument)
List userRoles = new ArrayList(allRoles.length);
for(String role : allRoles) {
 if(request.isUserInRole(role)) { 
  userRoles.add(role);
 }
}

// I forgot the exact syntax for list.toArray so this is prob wrong here
return userRoles.toArray(String[].class);
like image 93
Josh Avatar answered Oct 08 '22 02:10

Josh


On JACC-compliant application servers -- in theory every Full Java EE Platform implementation -- the Java SE Policy can be interrogated for (almost) portable evaluation of any type of declarative security constraint specified by Servlet and EJB. I say almost because neither JACC nor the Javadoc spec of Policy#getPermissions(ProtectionDomain) actually requires that the implementation compute all permissions on the fly, presumably due to performance considerations, as well as to accommodate for providers whose rendering of authorization statements depends on additional context (remote address, value of a certain HTTP GET parameter, etc.). Nonetheless, getPermissions should normally be safe to use with the typical pre-installed JACC provider.

The following example demonstrates Servlet role assignment testing:

package com.example;

import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Policy;
import java.security.Principal;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

import javax.security.auth.Subject;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebRoleRefPermission;

public final class Util {


    private static final Set<String> NO_ROLES = Collections.emptySet();
    private static final Permission DUMMY_WEB_ROLE_REF_PERM = new WebRoleRefPermission("", "dummy");

    /**
     * Retrieves the declared Servlet security roles that have been mapped to the {@code Principal}s of
     * the currently authenticated {@code Subject}, optionally limited to the scope of the Servlet
     * referenced by {@code servletName}.
     * 
     * @param servletName
     *            The scope; {@code null} indicates Servlet-context-wide matching.
     * @return the roles; empty {@code Set} iff:
     *         <ul>
     *         <li>the remote user is unauthenticated</li>
     *         <li>the remote user has not been associated with any roles declared within the search
     *         scope</li>
     *         <li>the method has not been called within a Servlet invocation context</li>
     *         </ul>
     */
    public static Set<String> getCallerWebRoles(String servletName) {
        // get current subject
        Subject subject = getSubject();
        if (subject == null) {
            // unauthenticated
            return NO_ROLES;
        }
        Set<Principal> principals = subject.getPrincipals();
        if (principals.isEmpty()) {
            // unauthenticated?
            return NO_ROLES;
        }
        // construct a domain for querying the policy; the code source shouldn't matter, as far as
        // JACC permissions are concerned
        ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), null, null,
                principals.toArray(new Principal[principals.size()]));
        // get all permissions accorded to those principals
        PermissionCollection pc = Policy.getPolicy().getPermissions(domain);
        // cause resolution of WebRoleRefPermissions, if any, in the collection, if still unresolved
        pc.implies(DUMMY_WEB_ROLE_REF_PERM);
        Enumeration<Permission> e = pc.elements();
        if (!e.hasMoreElements()) {
            // nothing granted, hence no roles
            return NO_ROLES;
        }
        Set<String> roleNames = NO_ROLES;
        // iterate over the collection and eliminate duplicates
        while (e.hasMoreElements()) {
            Permission p = e.nextElement();
            // only interested in Servlet container security-role(-ref) permissions
            if (p instanceof WebRoleRefPermission) {
                String candidateRoleName = p.getActions();
                // - ignore the "any-authenticated-user" role (only collect it if your
                // application has actually declared a role named "**")
                // - also restrict to the scope of the Servlet identified by the servletName
                // argument, unless null
                if (!"**".equals(candidateRoleName) && ((servletName == null) || servletName.equals(p.getName()))
                        && ((roleNames == NO_ROLES) || !roleNames.contains(candidateRoleName))) {
                    if (roleNames == NO_ROLES) {
                        roleNames = new HashSet<>();
                    }
                    roleNames.add(candidateRoleName);
                }
            }
        }
        return roleNames;
    }

    private static Subject getSubject() {
        return getFromJaccPolicyContext("javax.security.auth.Subject.container");
    }

    @SuppressWarnings("unchecked")
    private static <T> T getFromJaccPolicyContext(String key) {
        try {
            return (T) PolicyContext.getContext(key);
        }
        catch (PolicyContextException | IllegalArgumentException e) {
            return null;
        }
    }

    private Util() {
    }

}

References:

  • JSR-115 / JACC specification
  • Using JACC to determine a caller's roles
  • How Java EE translates web.xml constraints to Permission instances
like image 40
Uux Avatar answered Oct 08 '22 01:10

Uux


The answer is messy.

First you need to find out what type request.getUserPrincipal() returns in your webapp.

    System.out.println("type = " + request.getUserPrincipal().getClass());

Let's say that returns org.apache.catalina.realm.GenericPrincipal.

Then cast the result of getUserPrincipal() to that type and use the methods it provides.

    final Principal userPrincipal = request.getUserPrincipal();
    GenericPrincipal genericPrincipal = (GenericPrincipal) userPrincipal;
    final String[] roles = genericPrincipal.getRoles();

I said it was going to be messy. It's not very portable either.

like image 31
Steve McLeod Avatar answered Oct 08 '22 01:10

Steve McLeod