Programmatically add roles after authentication

前端 未结 2 578
星月不相逢
星月不相逢 2021-02-03 14:13

I have the following JSF 2.1 login form, running in Glassfish 3.1


        
            


        
相关标签:
2条回答
  • 2021-02-03 15:08

    I came up with the following solution to add roles programmatically after login, which works at least on GlassFish 3.1.2 build 23.

    import com.sun.enterprise.security.SecurityContext;
    import com.sun.enterprise.security.web.integration.PrincipalGroupFactory;
    import java.security.Principal;
    import java.util.Set;
    import javax.security.auth.Subject;
    import org.glassfish.security.common.Group;
    
    public class GlassFishUtils {
        public static void addGroupToCurrentUser(String groupName, String realmName) {
            Subject subject = SecurityContext.getCurrent().getSubject();
            Set<Principal> principals = subject.getPrincipals();
            Group group = PrincipalGroupFactory.getGroupInstance(groupName, realmName);
            if (!principals.contains(group))
                principals.add(group);
        }
    }
    

    You will need to add security.jar and common-util.jar from GlassFish to your project libraries.

    And don't forget to create a <security-role> section in your web.xml for the roles you wish to add.

    Note that I am using functionality which does not appear to be part of a published stable API, so there is no guarantee that this will keep working in future releases of GlassFish.

    I got the information on how to add roles from the source code of sun.appserv.security.AppservPasswordLoginModule.commit() of GlassFish. If a future GlassFish release breaks my code, this function would be a good place to start in order to find out how to fix it.

    0 讨论(0)
  • 2021-02-03 15:16

    OK, i have figured out a workaround, which is not 100% correct in my point of view but suggestions are welcome :)

    public void login() throws IOException, LoginException {
    
        log.debug("Trying to login with username " + username);
    
        try {
            getRequest().login(username, password);
    
            HttpSession session = getRequest().getSession(true);
            Subject subject = (Subject) session
                    .getAttribute("javax.security.auth.subject");
    
            if (subject == null) {
    
                log.debug("Subject is null, creating new one");
    
                subject = new Subject();
                subject.getPrincipals().add(new PlainRolePrincipal("USER"));
                subject.getPrincipals().add(new PlainRolePrincipal("ADMIN"));
    
            }
    
            log.debug("HAS USER " + getRequest().isUserInRole("USER"));
            log.debug("HAS ADMIN " + getRequest().isUserInRole("ADMIN"));
            log.debug("HAS REPORT " + getRequest().isUserInRole("REPORT"));
    
            session.setAttribute("javax.security.auth.subject", subject);
    
            log.debug("USER principal === " + getRequest().getUserPrincipal());
    
            FacesContext.getCurrentInstance().getExternalContext()
                    .redirect("pages/home.jsf");
    
        } catch (ServletException e) {
    
            FacesContext.getCurrentInstance().addMessage("Login",
                    new FacesMessage("Invalid Username/Password combination"));
    
            e.printStackTrace();
        }
    
    }
    

    Also I use the following info bean to retrieve the subject and check the principals.

     @ManagedBean(name = "userInfo")
     @SessionScoped
     public class UserInformation {
    
    /**
     * Fetches current logged in username.
     * 
     * @return
     */
    public String getUsername() {
    
        return FacesContext.getCurrentInstance().getExternalContext()
                .getRemoteUser();
    
    }
    
    
    
    public boolean isUserInRole(String roleName) {
        Subject subject = (Subject) getRequest().getSession().getAttribute(
                "javax.security.auth.subject");
    
        for (Principal p : subject.getPrincipals()) {
            if (p.getName().equals(roleName)) {
                return true;
            }
        }
    
        return false;
    }
    
    
    public static HttpServletRequest getRequest() {
        Object request = FacesContext.getCurrentInstance().getExternalContext()
                .getRequest();
        return request instanceof HttpServletRequest ? (HttpServletRequest) request
                : null;
    }
    

    }

    So I workaround the isUserInRole mechanism, the real isUserInRole method returns only true on USER, because that role is set when authenticating.

    From the JSF pages I can now do

    <p:menuitem value="Create" action="#{menuController.XXXXXCreate}"
                    ajax="false" helpText="Create new XXXXX"
                    disabled="#{!userInfo.isUserInRole('ADMIN')}" />
    

    Hope this helps other users, any improvement suggestions are welcome!

    0 讨论(0)
提交回复
热议问题