1

I'm having troubles in setting an Authorization Listener (that implements PhaseListener) to manage authentication and autorization.

More specifically, I set a session scoped bean called SessionBean:

@ManagedBean
@SessionScoped
public class SessionBean{

   private String loggedUser;

   public SessionBean(){
    logger.info("Sono nel costruttore di SessionBean()");
   }
   public String login(){
       ....
   }
   ...
}

And in my sun-web.xml:

  <managed-bean>
    <managed-bean-name>SessionBean</managed-bean-name>
    <managed-bean-class>it.uniroma3.acme.auction.bean.SessionBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>

In login() I make controls on username/password and if successful I set "loggedUser".

My AuthorizationListener is:

public class AuthorizationListener implements PhaseListener {

    private String currentUser;

    private SessionBean sessionBean;

    public void afterPhase(PhaseEvent event) {
        SessionBean sessionBean = (SessionBean)event.getFacesContext().getExternalContext().getSessionMap().get("SessionBean");
        String currentUser = sessionBean.getLoggedUser();

        if (sessionBean != null) {
            ...
               String currentUser = sessionBean.getLoggedUser();
        }
            else {
                 ...
            }
    }

    ...
}

And in the sun-web.xml:

 <!-- Authentication and authorization block starting -->
    <lifecycle>
        <phase-listener>AuthorizationListener</phase-listener>
    </lifecycle>
    <navigation-rule>
        <from-view-id>/*</from-view-id>
        <navigation-case>
            <from-outcome>loginPage</from-outcome>
            <to-view-id>login.jsf</to-view-id>
        </navigation-case>
    </navigation-rule>
  <!-- Authentication and authorization block ending -->

But I receive a null pointe sessionBean.getLoggedUser(). So, the SessionBean is still not created when the AuthorizationListener check the user. This is why I added a "if SessionBean doesn't exists, create it and put it in SessionMap", but still not working.

I'm not forced to use this approach for authentication and authorization, but what I need is to avoid "session.setAttribute("username", username). So any other strategy would be really apreciated. Thanks, Andrea

EDIT: as BalusC suggested, I edited the afterPhase method. Still having troubles with always null SessionBean.

andreaxi
  • 931
  • 5
  • 15
  • 28

2 Answers2

3

The @ManagedProperty works in @ManagedBean classes only. Your PhaseListener isn't.

You need to manually get it from the session map.

SessionBean sessionBean = (SessionBean) event.getFacesContext()
    .getExternalContext().getSessionMap().get("SessionBean");

Note that it can be still null on the very first HTTP request.

The common approach, however, is to use a servlet Filter for the job, not a PhaseListener. The session scoped managed bean is available as a session attribute.

SessionBean sessionBean = (SessionBean) session.getAttribute("sessionBean");
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks, BalusC. I'm however having troubles with an **always** null "SessionBean" (I updated the question, after your suggestion): in the first hit I expect a null value, but when the listener allows me to fulfill the login form, the bean beside it (SessionBean) should be istantiated. BTW, I'm interesten also on the Filter approach, can you suggest me some link or resource where to lear it? Thanks, Andrea – andreaxi Sep 16 '12 at 07:39
  • 1
    BalusC, I'm following [this steps] (http://stackoverflow.com/questions/7979839/how-do-a-web-filter-in-jsf-2) and accessing the session. But, when I am in a bean and I need to redirect to a page using FacesContext.getCurrentInstance().getExternalContext().redirect(...) from an actionListener method it causes request parameters to be lost. How can I redirect saving the request/response/session (more than redirect, I need a forward)?Thanks, Andrea – andreaxi Sep 16 '12 at 09:49
  • 1
    Thanks to your contribute [here] (http://stackoverflow.com/questions/3888710/jsf-1-2-difference-between-exception-in-action-and-actionlistener) solved the question: I don't need an actionListener, cause I have to use a action (it involves business tasks). – andreaxi Sep 16 '12 at 09:56
  • @BalsusC What is the advantage of a `Filter` over a `PhaseListener`? A `PhaseListener` is IMO better suited for this job as it allows more direct control over the jsf lifecycle which might be required in order to perform business logic correctly. Also a `Filter` looks pretty low-level to me, more related to networking as to abstract logics. – Sebastian Hoffmann Apr 04 '13 at 14:35
  • @Paranaix: the phase listener doesn't run on non-JSF requests. The business requirement in question doesn't require involvement of JSF lifecycle. It's a simple check whether the HTTP request is allowed or not. – BalusC Apr 04 '13 at 14:36
  • @BalsusC Thank you for your response. Another question I have is related to your statement `Note that it can be still null on the very first HTTP request.`. In the doc of `getSessionMap()` it says `Accessing attributes via this Map must cause the creation of a session associated with the current request, if such a session does not already exist.` Shouldnt the creation of a `Session` also trigger the creation of `@SessionScoped` beans? What solutions exists if i need that bean on the very first request? – Sebastian Hoffmann Apr 04 '13 at 14:41
  • 1
    @Paranaix: the bean, not the map. The session bean is only created when an EL expression referencing it is evaluated for the first time. For future questions, please press `Ask Question`. – BalusC Apr 04 '13 at 14:42
  • I am using JSF 2.2 and the session is not null on the first request. – abbas Jan 05 '16 at 06:57
  • @BalusC: Hey.. can you please check https://stackoverflow.com/q/54500560/887235 .. Since this is not working, as a workaround, I am trying to set an attribute in HttpSession inside the PhaseListener and then try to read the attribute in normal Filter and set a cookie based on that.. But I am not sure if this is a cleaner approach.. thanks! – Vicky Feb 11 '19 at 01:17
0

Here in your code, in your phaseListener, you did not tell in which Phase exactly you would implement the code and you should call your managed bean. You should do this in RESTORE_VIEW Phase in AuthorizationListener override method getPhaseId(). See the following:

public PhaseId getPhaseId() {

        return PhaseId.RESTORE_VIEW;

    }

If your managed bean is still null, remove managed bean annotations, register it in faces_config, and use this helper method in phase listener to call the managed bean:

public static Object resolveExpression(String expression) {
    FacesContext ctx = FacesContext.getCurrentInstance();
    Application app = ctx.getApplication();
    ValueBinding bind = app.createValueBinding(expression);
    return bind.getValue(ctx);
}

To call it in after phase method, use:

public void afterPhase(PhaseEvent event) {

SessionBean sessionBean =(SessionBean)resolveExpression("#{SessionBean}");
String currentUser = sessionBean.getLoggedUser();      
Asciiom
  • 9,867
  • 7
  • 38
  • 57