Программно добавлять роли после аутентификации - PullRequest
6 голосов
/ 31 января 2012

У меня есть следующая форма входа в JSF 2.1, запущенная в Glassfish 3.1

<h:form id="loginForm">
        <h:panelGrid columns="2" cellspacing="5">
            <h:outputText value="Username" />
            <h:inputText value="#{loginHandler.username}" />
            <h:outputText value="Password:" />
            <h:inputText value="#{loginHandler.password}" />
            <h:outputLabel value="" />
            <h:commandButton value="Login" action="#{loginHandler.login}" />
        </h:panelGrid>
    </h:form>

и следующий компонент поддержки.

public String login() throws IOException, LoginException {

    log.debug("Trying to login with username " + username);

    HttpSession session = getRequest().getSession(true);

    try {
        getRequest().login(username, password);

        // if OK, add Roles
                    ????????
                    ...................

    } catch (ServletException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


    log.debug("USER principal === " + getRequest().getUserPrincipal());

    return "home";
}

Вопрос в том, как программно добавить ролив UserPrincipal после успешного входа в систему?

Обновление 1: я пытался получить тему, используя следующий код, но subject == null.

Subject thisSubject = Subject.getSubject(AccessController
                .getContext());

Спасибо, Coen

Ответы [ 2 ]

5 голосов
/ 11 июля 2012

Я придумал следующее решение для программного добавления ролей после входа в систему, которое работает по крайней мере в 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);
    }
}

Вам потребуется добавить security.jar и common-util.jar из GlassFish в библиотеки вашего проекта.

И не забудьте создать в своем web.xml раздел <security-role> для ролей, которые вы хотите добавить.

Обратите внимание, что я использую функциональность, которая, по-видимому, не является частью опубликованного стабильного API, поэтому нет гарантии, что она будет работать в будущих выпусках GlassFish.

Я получил информацию о том, как добавлять роли из исходного кода sun.appserv.security.AppservPasswordLoginModule.commit() GlassFish. Если в будущем выпуске GlassFish будет нарушен мой код, эта функция будет хорошей отправной точкой, чтобы узнать, как ее исправить.

3 голосов
/ 01 февраля 2012

ОК, я нашел обходной путь, который не является на 100% правильным с моей точки зрения, но предложения приветствуются:)

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

}

Также я использую следующий информационный компонент для получения объекта ипроверьте принципалы.

 @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;
}

}

Поэтому, чтобы обойти механизм isUserInRole, реальный метод isUserInRole возвращает только значение true для USER, поскольку эта роль устанавливается при аутентификации.

Со страниц JSF, которые я теперь могу сделать

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

Надеюсь, это поможет другим пользователям, любые предложения по улучшению приветствуются!

...