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

1

7

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>
Ouachita answered 5/6, 2012 at 18:44 Comment(1)
What is in the <security-constraint> elements of your web.xml file?Ilka
B
9

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);
    }

    // ...
}
Betrothal answered 5/6, 2012 at 18:51 Comment(3)
So I tried your code and in the login process (the first request and after form submit) the filter never receives the requested page. It only receives it when I change the URL again. So, not working again, I still see the JS script.Ouachita
Got it working finally. I just needed to exclude /faces/javax.faces.resource/* from the security. No need for filter. I should have tried it before digging into the filter. Thanks!Ouachita
The filter is however mandatory as it may otherwise result in unintuitive browser behaviour, e.g. pressing back button after logout would otherwise still show the restricted page.Betrothal

© 2022 - 2024 — McMap. All rights reserved.