Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong redirect after logging in (Java EE w/ JSF)

Developing web application in Java EE with JSF. All pages are secured from viewing by authentication form with action 'j_security_check' and inputs 'j_username' and 'j_password'.

After successful log in, however, I am redirected not to the page I wanted to access but to this URL

/faces/javax.faces.resource/jsf.js?ln=javax.faces&stage=Development

So I'm looking at the script file jsf.js with all the JS code instead of the page I wanted to view. It doesn't matter if I access the web root or any other page, I'm being redirected to this URL every time. Then I change the URL to any page, it loads it fine and I am logged in.

I have to say I already had this problem which magically went away so it redirected me correctly. After few weeks it got broken again but I don't if it was my fault, and if it was I don't know the cause. I wasn't messing with redirect or navigational rules at all.

Good to mention that I'm also using PrettyFaces.

EDIT:

<security-constraint>
    <display-name>secured</display-name>
    <web-resource-collection>
        <web-resource-name>all</web-resource-name>
        <description/>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <description/>
        <role-name>admin</role-name>
        <role-name>teacher</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
    <display-name>secured for admins</display-name>
    <web-resource-collection>
        <web-resource-name>admin pages</web-resource-name>
        <description/>
        <url-pattern>/admin/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <description/>
        <role-name>admin</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
    <display-name>unsecured</display-name>
    <web-resource-collection>
        <web-resource-name>css</web-resource-name>
        <description/>
        <url-pattern>/css/*</url-pattern>
    </web-resource-collection>
    <web-resource-collection>
        <web-resource-name>js</web-resource-name>
        <description/>
        <url-pattern>/js/*</url-pattern>
    </web-resource-collection>
    <web-resource-collection>
        <web-resource-name>img</web-resource-name>
        <description/>
        <url-pattern>/img/*</url-pattern>
    </web-resource-collection>
</security-constraint>
<login-config>
    <auth-method>FORM</auth-method>
    <realm-name>wetk-security</realm-name>
    <form-login-config>
        <form-login-page>/faces/login.xhtml</form-login-page>
        <form-error-page>/faces/login.xhtml</form-error-page>
    </form-login-config>
</login-config>
like image 258
redhead Avatar asked Jun 05 '12 18:06

redhead


1 Answers

The container managed security will redirect to the last HTTP request which triggered the authentication check. In your case it's apparently the auto-included JSF ajax API JavaScript file. That can happen if the browser has loaded the to-be-authenticated page fully from the browser cache, while the browser has loaded the JS file fully from the server side, or have tested the cache validity of the JavaScript file by a conditional GET request.

You'd like to exclude the JSF resources (<h:outputScript>, <h:outputStylesheet> and <h:graphicImage> from authentication checks. You could do that by excluding the common URL pattern /javax.faces.resource/*. You may only want to add the /faces prefix pattern as you're apparently using it instead of the *.xhtml suffix pattern.

You also need to instruct the browser to not cache restricted pages to prevent the browser loading it from the cache (e.g. by pressing back button after logout). Map the following filter on the same URL pattern as the one of your <security-constraint>.

@WebFilter("/secured/*") // Use the same URL pattern as <security-constraint>
public class NoCacheFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpReq = (HttpServletRequest) request;
        HttpServletResponse httpRes = (HttpServletResponse) response;

        if (!httpReq.getRequestURI().startsWith(httpReq.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
            httpRes.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
            httpRes.setHeader("Pragma", "no-cache"); // HTTP 1.0.
            httpRes.setDateHeader("Expires", 0); // Proxies.
        }

        chain.doFilter(request, response);
    }

    // ...
}
like image 172
BalusC Avatar answered Nov 14 '22 00:11

BalusC