javajakarta-eejbosssecurityjaspic

How to apply Filter before security constraint in JBoss EAP6/AS7


Edit: For some context, I am using a custom security-domain and manually calling request.login. I am not using the standard FORM authentication.

Edit: It seems like what I am really looking for is a way to replicate the <login-config> functionality using a custom <security-domain> configured in jboss instead of j_security_check.

I need to be able to do two distinct things in my web app. First, I need to be able to determine if a user is authenticated, and if they are not I want to redirect them to the login page. I am using a Filter for this. Secondly, I need to determine whether a user has the right role in order to view certain pages in my webapp. It seems like the security-constraint tag in the web.xml file would be the proper tool for this job, but this rule is always applied first, before any filter. This means that the user is never given the opportunity to log in before being denied access to a page because he lacks the proper role.

The only solution I have been able to think of is to manually inspect the user roles in a Filter instead of using the security-constraint, but this does not feel like a good solution. I am wondering if there is something I am missing here, as it seems like this would be a pretty common use case. For reference, my Filter and a sample security constraint are pasted below.

Edit: The reason I am using a Filter to check for authorization is because you can only define one error page for a particular error (in this case, 403 access denied). For example, somebody with the role "customer" attempts to access the searchCustomer page. My security-constraint restricts that page to users with role "admin" or "user", and so a 403 error is generated and the user is redirected to the configured error page, error.xhtml. A second user who is NOT logged in attempts to visit main.xhtml. Because he is not logged in, he lacks one of the 3 allowed roles, and so he also receives a 403 error and is redirected to error.xhtml. However, because he is not logged in, I would prefer to redirect him to a login page instead. I do not see any way to distinguish between these two use cases using the security-constraint and error-page.

<security-constraint>
    <display-name>SecureApplicationConstraint</display-name>
    <web-resource-collection>
        <web-resource-name>SecureApplication</web-resource-name>
        <description>SecureApplication</description>
        <url-pattern>/main.xhtml</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
        <role-name>user</role-name>
        <role-name>customer</role-name>
    </auth-constraint>
</security-constraint>
    <security-constraint>
    <display-name>SearchCustomerPage</display-name>
    <web-resource-collection>
        <web-resource-name>SecureApplication</web-resource-name>
        <description>SecureApplication</description>
        <url-pattern>/searchCustomer.xhtml</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
        <role-name>user</role-name>
    </auth-constraint>
</security-constraint>
<error-page>
    <error-code>403</error-code>
    <location>/error.xhtml</location>
</error-page>

Filter:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) request;   
    String uri = req.getRequestURI();

    if ((null != req.getUserPrincipal()) 
            || uri.endsWith("login.xhtml")
            || uri.endsWith("error.xhtml")
            || uri.contains(ResourceHandler.RESOURCE_IDENTIFIER)) {
        chain.doFilter(request, response);
    } else {
        HttpServletResponse res = (HttpServletResponse) response;
        res.sendRedirect(req.getContextPath() + "/login.xhtml?from=" + URLEncoder.encode(uri, "UTF-8"));
        return;
    }
}

Solution

  • You can do this using the JASPI/JASPIC API in Java EE 6.

    For some reason or the other JBoss requires you to activate this API first, but they have a wiki page up on how to do this.