Как получить роли пользователя в JSP/Servlet

Есть ли способ получить String [] с ролями, которые пользователь имеет в JSP или Servlet?

Я знаю о request.isUserInRole( "role1" ), но также хочу знать все роли пользователя.

Я искал источник сервлетов, и кажется, что это невозможно, но мне это кажется странным.

Итак... любые идеи?

Ответ 1

Прочитайте все возможные роли или введите код жесткого кода. Затем перейдите к нему, запустив isUserInRole и создайте список ролей, в котором находится пользователь, а затем преобразуйте список в массив.

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);

Ответ 2

Ответ грязный.

Сначала вам нужно выяснить, какой тип request.getUserPrincipal() возвращается в вашем webapp.

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

Скажем, что возвращает org.apache.catalina.realm.GenericPrincipal.

Затем передайте результат getUserPrincipal() в этот тип и используйте методы, которые он предоставляет.

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

Я сказал, что это будет грязно. Это не очень портативно.

Ответ 3

В WebLogic вы можете сделать это с помощью

import weblogic.security.Security;
import weblogic.security.SubjectUtils;
...
private List<String> getUserRoles()  {
    return Arrays.asList(SubjectUtils.getPrincipalNames(Security.getCurrentSubject()).split("/"));
}

Обратите внимание, что первым элементом в списке является имя пользователя.

Ответ 4

На серверах приложений, совместимых с JACC, - в теории каждой реализации полной Java EE Platform - Java SE Policy может быть опрошено для оценки любого типа декларативного ограничения безопасности, заданного Servlet и EJB.

Следующий пример демонстрирует тестирование назначения ролей:

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() {
    }

}

Литература: