jsfjsf-2authorizationservlet-filtersphaselistener

Limitations of using a PhaseListener instead of a Servlet Filter for authorization


I'm currently using a PhaseListener as below to perform user authorization.

private PhaseId phaseId = PhaseId.RESTORE_VIEW;

@Override
public void afterPhase(PhaseEvent event) {

    FacesContext fc = event.getFacesContext();
    boolean isOnAllowedPage = false;
    String[] allowedPages = choseRightPages(); // chose pages for role

    for (String s : allowedPages) {
        if (fc.getViewRoot().getViewId().lastIndexOf(s) > -1) {
            isOnAllowedPage = true;
            break;
        }
    }

    if (!isOnAllowedPage) {
        NavigationHandler nh = fc.getApplication().getNavigationHandler();
        nh.handleNavigation(fc, null, "prohibited");
    }
}

It does what I want, however I don't see it being listed in How to handle authentication/authorization with users in a database? and this Coderanch topic titled "authorization with phaselistener problem" also mentions the following:

You shouldn't couple authorization that tight with JSF. Better make use of container managed authentication and/or a simple filter acting on an url-pattern covering the protected pages.

I don't exactly understand the limitations of using a PhaseListener instead of a Filter when performing user authorization. Can someone explain it to me?


Solution

  • A PhaseListener is only fired on a JSF request (i.e. a HTTP request which invoked the FacesServlet). It's not fired when a non-JSF request is executed and thus exposes a potential security leak on non-JSF requests. A servlet Filter can be fired on every single HTTP request, regardless of the target servlet.

    In other words: HTTP request authorization should not be tied to having the FacesContext available, but to the ServletRequest available. Always try to authorize as "low level" as possible.