2

I'm using form based authentication.

I have a logout link which looks like:

<h:commandLink action="#{loginBean.logout}">
    <h:outputText value="logout" />
</h:commandLink></div>

And the corresponding logout method:

public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().invalidateSession();

    return "/view/index?faces-redirect=true"; // Redirect added as per BalusC's suggestion.
}

After hitting the logout link I'm returned to the front page, but seemingly without CSS. When I hit a button to run a search I get the following error:

javax.faces.application.ViewExpiredException: viewId:/view/index.jsf - View /view/index.jsf could not be restored.

And yet the CSS is actually under /resources which shouldn't require authentication as I understand my web.xml:

    <security-constraint>
    <web-resource-collection>
        <web-resource-name>fizio</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
</security-constraint>

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Unprotected area</web-resource-name>
        <url-pattern>/resources/*</url-pattern>
    </web-resource-collection>
</security-constraint>

From this state I seem to be able to login again and see some data between occasional view-could-not-be-restored errors, but no CSS. It's all a bit broken really. Any suggestions would be appreciated.

ETA: Login form:

<form method="POST" action="j_security_check">
    <label for="j_password">Username:</label> <input type="text" name="j_username" />
    <br />
    <label for="j_password">Password:</label> <input type="password" name="j_password" /> <input type="submit" value="Login" />
</form>
rich
  • 18,987
  • 11
  • 75
  • 101

1 Answers1

4

You need to redirect after invalidate. Otherwise the page is been shown in midst of the "invalidated" session. Add faces-redirect=true to the outcome to trigger the redirect.

public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    return "/index?faces-redirect=true";
}

The redirect will cause the webbrowser to fire a new GET request after the POST response and in turn cause the server to create a brand new session. This way the views will work as intended.

As to the CSS resources, they apparently still need a login. The "Unprotected area" constraint which you have there is not going to work. Remove it and change the URL-pattern of your main security constraint to for example /app/* or whatever a common path of the secured area is.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks. That seems to have made a subtle difference - on hitting logout now I see the login page, complete with CSS. But if I actually hit login I'm returned to my app in the invalidated session state. Perhaps a further problem with my login form? – rich Aug 22 '11 at 14:07
  • Can you please describe "I'm returned to my app in the invalidated session state" problem in more detail? Try to view to the problem from developer's perspective, not from enduser's perspective. E.g. is the session cookie there? Is there means of a change in session ID? Etc. – BalusC Aug 22 '11 at 14:10
  • Oh, is there any chance that you're just looking to a page from the browser cache? Try creating a filter as suggested in the following answer: http://stackoverflow.com/questions/3642919/javax-faces-application-viewexpiredexception-view-could-not-be-restored/3642969#3642969 You can check with help of for example Firebug if you're looking to a page from browser cache or not. Another (layman's) test is to press Ctrl+F5 after logout and then retry the action. – BalusC Aug 22 '11 at 14:18
  • There appears to be a session cookie associated with the context root, which remains after hitting log out and again after hitting log in. It maintains the same JSESSIONID value throughout unless I manually navigate to the context root when I get a new JSESSIONID value. – rich Aug 22 '11 at 14:26
  • Did you exclude the browser cache from being the culprit? See the previous comment. You should definitely get a new session cookie after logout (but only if the page is served by server, not from browser cache). – BalusC Aug 22 '11 at 14:27
  • I've now added the filter. I put a breakpoint in which gets hit, regularly. But it doesn't seem to have altered the behaviour. – rich Aug 22 '11 at 14:47
  • This is really odd. Do you see a `Set-Cookie` header on the response of the redirected request? Does the filter set the proper `Cache-Control` header and others on all JSF requests? Did you clear the browser cache before testing? What servletcontainer are you using? I recall similar session cookie issues on Resin. – BalusC Aug 22 '11 at 14:50
  • There's a 302 POST to index.jsf, followed by a 200 GET also for index.jsf which has a Set-Cookie with a JSESSIONID value that's different than the one in the Cookie for the 302. I didn't clear the browser cache, I'll try that now. I'm using JBoss AS7. – rich Aug 22 '11 at 15:01
  • OK, that part looks fine. When you submit a form in the index.jsf, is the same `Cookie` set in the request as it was obtained in the `Set-Cookie` of the redirected GET response? – BalusC Aug 22 '11 at 15:03
  • Yes it is using the Set-Cookie value when submitting the login form afterwards. Clearing the browser cache doesn't seem to have resolved anything. I am seeing the filter set cache-related headers coming back. – rich Aug 22 '11 at 15:08
  • Okay, that part looks fine as well. What exactly happens when you submit the login afterwards? You said "I end up in invalidated session state", but didn't describe the precise symptoms and behaviour. Do you get logged in or did you get a `ViewExpiredException`? Or is CSS/JS broken? Etc. – BalusC Aug 22 '11 at 15:11
  • The stylesheets aren't attached. It was also that on then trying to do certain tasks, like search, I was getting the ViewExpiredException though it looks like something done above _has_ fixed that. Firebug shows the stylesheets are coming back as the login form page rather than CSS. Also the logout link then doesn't seem to have any effect - it doesn't redirect. – rich Aug 22 '11 at 15:15
  • Oh OK, you should really have made that clear from the beginning on :) Are the CSS resources downloaded or not? Check it with Firebug and check the response data. – BalusC Aug 22 '11 at 15:17
  • The stylesheet requests get a 200 OK but the response data is the HTML for the login form, not the CSS. – rich Aug 22 '11 at 15:22
  • Yes, your security constraint doesn't work that way. I updated the answer. – BalusC Aug 22 '11 at 15:23
  • If I remove the unprotected resource section and change the URL pattern of the other to /jsf-web/* then when I first access the app it doesn't redirect to the login page and I get an NPE within my app when it tries to retrieve the logged in user. – rich Aug 22 '11 at 15:54
  • Then the URL pattern simply does not match. It look like that you specified the context path instead of a real folder in the webapp context. the URL pattern needs to be context-relative. – BalusC Aug 22 '11 at 15:57
  • Ah. Adding three url-patterns for index.jsp, /view/* and /edit/* it seems to work with. Thanks for persisting! – rich Aug 22 '11 at 16:04