3

I'm trying to implement a redirect after login, which means I can't use glassfish built-in form authentication settings anymore that handles such things automatically. So first thing's first, I need to take control over redirecting to a login page when requesting a protected page. As I understand, this is done with a filter. Can this method be combined with security-constraints in web-xml? As it is, my filter is not called at all since glassfish just takes over and throws a basic loginbox at the user and ignores all filters even when no login configuration is set. Basicly, I have not managed to get a filter called before a user has logged in when security constraints are configured in glassfish.

Do I really need to take over security completly manually in a filter for this to work? If that's the case, the implementation seems horrible.

Using glassfish 3.1 with JSF 2 and a custom loginpage logging in manually with request.login.

web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value><!--Production-->Development</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.expressionFactory</param-name>
        <param-value>de.odysseus.el.ExpressionFactoryImpl</param-value>
    </context-param>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>com.xdin.competence.jsf.util.LoginFilter</filter-class>
    </filter>
    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsf</welcome-file>
    </welcome-file-list>
    <!--<error-page>
        <exception-type>javax.faces.application.ViewExpiredException</exception-type>
        <location>/viewExpired.jsf</location>
    </error-page>-->
    <security-constraint>
        <display-name>ManagerArea</display-name>
        <web-resource-collection>
            <web-resource-name>ManagerArea</web-resource-name>
            <description/>
            <url-pattern>/manager/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>Manager-role</role-name>
            <role-name>Admin-role</role-name>
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <display-name>EmployeeArea</display-name>
        <web-resource-collection>
            <web-resource-name>EmployeeConstraint</web-resource-name>
            <description/>
            <url-pattern>/user/Overview.jsf</url-pattern>
            <url-pattern>/user/PrepareReport.jsf</url-pattern>
            <url-pattern>/user/Search.jsf</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>Employee-role</role-name>
            <role-name>Admin-role</role-name>
            <role-name>Manager-role</role-name>
            <role-name>OKIF-role</role-name>
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <display-name>AdminArea</display-name>
        <web-resource-collection>
            <web-resource-name>AdminCompetence</web-resource-name>
            <description/>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>Admin-role</role-name>
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <display-name>UserArea</display-name>
        <web-resource-collection>
            <web-resource-name>UserConstraint</web-resource-name>
            <description/>
            <url-pattern>/index.jsf</url-pattern>
            <url-pattern>/template.jsf</url-pattern>
            <url-pattern>/user/UserDetail.jsf</url-pattern>
            <url-pattern>/user/UserInformation.jsf</url-pattern>
            <url-pattern>/print/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>Employee-role</role-name>
            <role-name>Admin-role</role-name>
            <role-name>Manager-role</role-name>
            <role-name>OKIF-role</role-name>
        </auth-constraint>
    </security-constraint>
    <!--<login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login.jsf</form-login-page>
            <form-error-page>/login.jsf</form-error-page>
        </form-login-config>
    </login-config>-->
    <security-role>
        <description/>
        <role-name>Employee-role</role-name>
    </security-role>
    <security-role>
        <description/>
        <role-name>Admin-role</role-name>
    </security-role>
    <security-role>
        <description/>
        <role-name>Manager-role</role-name>
    </security-role>
    <security-role>
        <description/>
        <role-name>OKIF-role</role-name>
    </security-role>
</web-app>

And my filter:

public class LoginFilter implements Filter {

    private FilterConfig filterConfig = null;

    public LoginFilter() {
    } 

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
        if (req.getUserPrincipal() == null) {
            req.getSession().setAttribute("from", req.getRequestURI());
            res.sendRedirect("/login.jsf");
        } else {
            chain.doFilter(request, response);
        }

    }

    @Override
    public void destroy() { 
    }

    @Override
    public void init(FilterConfig filterConfig) { 
        this.filterConfig = filterConfig;
    }

}
Rasmus Franke
  • 4,434
  • 8
  • 45
  • 62
  • *"I'm trying to implement a redirect after login"*, doesn't j_security_check handle that automatically? It should do it. – BalusC Apr 28 '11 at 13:24
  • I'm using a customized form-based login, with manual request.login, and thus are not using j_security_check. – Rasmus Franke Apr 28 '11 at 14:41

1 Answers1

5

In your customized login form, add the following hidden field:

<input type="hidden" name="from" value="#{requestScope['javax.servlet.forward.request_uri']}" />

which you set in JSF as follows

@ManagedProperty(value="#{param.from}")
private String from;

and redirect as follows in login action method

if (from != null) {
    externalContext.redirect(from);
}

No need for a Filter.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Is it possible to use it in a session scoped managed bean somehow? I have my login function in the same class as where i store who is logged in. – Rasmus Franke Apr 28 '11 at 15:01
  • Ah ok, get it by `externalContext.getRequestParameterMap().get("from")` instead. – BalusC Apr 28 '11 at 15:02
  • Hmm didnt work at first try, will try more tomorrow. Thank you. – Rasmus Franke Apr 28 '11 at 15:05
  • That line needs to be put in the login method. Also the `` needs to be put in the `` and the submit must include the field value as hidden parameter (take this into account when using ajax). Of course the login page needs to be opened by the servletcontainer when the client opens the restricted page, not the login page itself directly. – BalusC Apr 28 '11 at 15:06
  • Debugged it and the problem was just that the application name was part of the url and I returned it from an action method which resulted in /appname/appname/page.jsf being returned, causing it to redirect to the login page again. Is it possible to just get the relevant part of the url? Also on a side note, can you get the parameters of the url aswell? Some kind of list of what the requestScope map contains would be really appreciated. – Rasmus Franke Apr 29 '11 at 06:38
  • Nevermind, found it at http://stackoverflow.com/questions/1256562/java-httpservletrequest-get-url-in-browsers-url-bar . I should be able to get this working perfectly now, thanks for the help! – Rasmus Franke Apr 29 '11 at 06:46
  • @BalusC I don't know what we'd do without you. Any hints on how to make this solution survive a failed login attempt? If user types in a wrong password it seems to lose the "from" value... – Kevin Pauli Mar 09 '12 at 22:36