Why do I get an invalid-session redirect after a Spring Security logout? - spring

I have a Spring MVC project which uses Spring Security. I am wondering how j_spring_security_logout works. I have a logout link defined in a view like this:
Logout
In my spring-security.xml I have defined this:
<form-login login-page="/login" default-target-url="/wellcome" authentication-failure-url="/loginfailed" />
<logout logout-success-url="/logout" logout-url="/j_spring_security_logout" />
<session-management invalid-session-url="/invalidsession" />
I expected that clicking logout should redirect me to /logout, but instead I get redirected to the invalid-session-url, namely /invalidsession. The logout-success-url is ignored.
However when I delete session-management, logging out does indeed redirect me to /logout.

This is explained in the Spring Security reference manual.
You can't really use the session-expiry facility unless the session cookie is deleted when you log out.

Use just this one and it should work (without logout-url):
<logout logout-success-url="/logout" />
I think you may experience problems by using both logout and session management invalid session url because once you've logged out your session is no longer valid.
Update per your additional question, how about this :
<security:logout logout-success-url="/logout?displayLogout=1" />
<security:session-management invalid-session-url="/logout?displayLogout=0" />
And then in your view :
<c:if test="${param.displayLogout == 0}">
<h2>Your session has timed out.</h2>
</c:if>
Update #2, just tried it locally, when you logout your session is invalid and you get redirected to invalid-session-url location you specified in the session-management configuration.
Really interested in the solution now.

Related

Spring Security cannot request URL with jessionid

I am developing a web application using Spring 5.3.20, Spring Security 5.7.1 and Tomcat 9.0.62.
Here is my Spring Security settings:
<form-login login-page="/home" />
<logout logout-url="/logout"
logout-success-url="/login?logout"
delete-cookies="JSESSIONID"/>
<session-management invalid-session-url="/main?timeout" session-authentication-error-url="/main?error"
session-fixation-protection="newSession">
<concurrency-control max-sessions="1" expired-url="/mail"
error-if-maximum-exceeded="true" session-registry-alias="sessionRegistry" />
</session-management>
The problem is when user logged out, the JSESSIONID cookies is deleted and the URL Rewriting kicked in.
As as result, the CSS, JS URLs become something like this.
http://localhost:8080/bookstore/resources/css/bootstrap.min-7184d3edc008c1890deb0a71e4348267.css;jsessionid=5052769FD8FEB8D2901C8CCB2B6A0C66
http://localhost:8080/bookstore/resources/js/jquery-1.12.3.min-2b6294333db8eeb65bc7717144357d23.js;jsessionid=5052769FD8FEB8D2901C8CCB2B6A0C66
The JESSIONID and semicolon are appended to the URLs which is a problem because according to those links below, the Spring Security will reject URLs that contain semicolons.
Spring getting The request was rejected because the URL contained a potentially malicious String ";"
https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/firewall/StrictHttpFirewall.html
There are two ways to solve this problem.
Not deleting the JSESSIONID cookies when logged out by removing delete-cookies="JSESSIONID"
<logout logout-url="/logout"
logout-success-url="/login?logout"/>
Forcing Spring Security to allow semicolons in URL by using setAllowSemicolon(true)
But from best security practices perspectives I think both of those solution above are not really good.
Can you guys elaborate in real world web application how people handle such a situation?

Spring security logout after session timeout

I'm having a problem logging out of the application after the session times out. I've configured the logout url:
<security:logout logout-url="/logout" logout-success-url="/" delete-cookies="JESSIONID"/>
and I have the logout form:
<form action="#" th:action="#{/logout}" method="POST">
<input type="submit" th:value="#{btn.logout}"/>
</form>
The form tag adds the csrf parameter and logging out works well as long as the session is still active. But if I log in the application, leave it open long enough for the session to expire and then hit the logout button I get the error:
HTTP Status 405 - Request method 'POST' not supported
I'd still like to keep the csrf validation and make it work as a POST request.
I found the solution in the documentation:
In your spring security configuration you have to add the following line:
<session-management invalid-session-url="/login" />
An example:
<form-login
login-page="/login"
default-target-url="/"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<session-management invalid-session-url="/login" />
<form-login login-processing-url="/login" login-page="/login"/>
<logout logout-success-url="/" logout-url="/logout"/>
I hope it will help you.
Set the Refresh HTTP header for just after session expiry. This will cause the page to reload itself just after the session expires, essentially logging you out.
It is due to the fact that when session expires, the csrf token with the login form is no longer valid. And making a post request with invalid csrf token causes spring to give a 405 i.e. Method Not Supported Error.
Solution:
Add the following configuration in Http Security Configuration.
For Java Config:
.and().sessionManagement().invalidSessionUrl("/login")
For XML Config:
> <session-management invalid-session-url="/login" />

Spring Security Remember Me Redirect after RequireFully Authorized

All,
I am trying to implement Remember Me functionality
I have two protected urls.
/operation/fully (user must be fully authenticated no remember me allowed)
and
/operation/authenticated (remember me ok)
If I have no remember me cookie and I visit either URL I am prompted for my credentials and redirected to the original URL life is good.
If I am in remember me mode, I can navigate to /operation/authenticated no problem. If I navigate to /operation/fully I am redirected to the login page. I then authenticate and am taken back to "/" I want to go back to my original target /operation/fully.
<http auto-config="true" use-expressions="true" access-denied-page="/login">
<form-login login-page="/login"
login-processing-url="/static/j_spring_security_check"
authentication-failure-url="/login" />
<logout logout-url="/j_spring_security_logout" logout-success-url="/logout"/>
<intercept-url pattern="/favicon.ico" access="permitAll" />
<intercept-url pattern="/operations/fully" access="hasRole('ROLE_USER') and isFullyAuthenticated()"/>
<intercept-url pattern="/operations/authenticated" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/login" />
<remember-me key="myKey"
token-validity-seconds="2419200" />
</http>
Somehow I need to get the user back to the original requested URL when they aren't fully authenticated. Any ideas on the best approach to do this?
I have come up with one solution, however it makes me cringe as it seems like it is more work than should be necessary.
In my scenario the ExceptionTranslationFilter is not invoking the login process and thus is not storing off the original URL.
The following line isn't called
requestCache.saveRequest(request, response);
instead a 403 is generated which I was catching via configuration and sending the user to the login page. In my case the user should be treated as if it they were anonymous and a 403 not be generated and the login process should begin.
The easiest way I found to change this behavior was to change the AuthenticationTrustResolverImpl
public boolean isAnonymous(Authentication authentication) {
if ((anonymousClass == null) || (authentication == null)) {
return false;
}
//if this is a RememberMe me situation, the user should be treated as
//if they were anonymous
if (this.isRememberMe(authentication)){
return true;
}
return anonymousClass.isAssignableFrom(authentication.getClass());
}
This seems to do exactly what I want, however since you can't get access to the ExceptionTranslationFilter when using the http namespace I had to do a lot of messy manual configuration.
Is there a more elegant way to do this?
There's a PR scheduled for Spring Security 4.2.0 M1 to address this need. Its associated commit probably gives hints to implement the same thing in previous versions of Spring Security.

how to delete remember me cookie in spring security

I was wondering how to the remove the remember me cookie when using spring remember me services.
I am using the default remember me cookie name
I came across the following documentation in spring to delete the JSESSION.
<http>
<logout delete-cookies="JSESSIONID" />
</http>
But is it possible to do something like below to delete the remember me cookie as well
I don't have a logout controller and i have the following configuration in the spring xml.
<http use-expressions="true">
<!-- Authentication policy -->
<form-login login-page="/signin" login-processing-url="/signin/authenticate" authentication-failure-url="/signin?param.error=bad_credentials" />
<logout logout-url="/signout" delete-cookies="JSESSIONID" />
....................
I don't think you have to manually delete the remember-me cookie. The AbstractRememberMeServices implements the LogoutHandler interface, so it will receive a call-back from the LogoutFilter, and makes sure the remember-me cookie is cancelled on logout.

Spring Security: Redirect to invalid-session-url instead of logout-success-url on successful logout

I have implemented a login-logout system with Spring Security 3.0.2, everything is fine but for this one thing: after I added a session-management tag with invalid-session-url attribute, on logout Spring would always redirect me on the invalid-session-url instead of the logout-success-url (which it correctly did before).
Is there a way to avoid this behaviour?
This is my configuration:
<http use-expressions="true" auto-config="true">
[...some intercept-url's...]
<form-login login-page="/login" authentication-failure-url="/login?error=true"
login-processing-url="/login-submit" default-target-url="/home"
always-use-default-target="true" />
<logout logout-success-url="/home?logout=true" logout-url="/login-logout" />
<session-management invalid-session-url="/home?invalid=true" />
</http>
Thanks a lot.
By default, the logout process will first invalidate the session, hence triggering the session management to redirect to the invalid session page. By specifying invalidate-session="false" will fix this behavior.
<sec:logout logout-success-url="/logout" invalidate-session="false"
delete-cookies="JSESSIONID" />
Do not confuse the logout-url attribute in the logout tag with the invalid-session-url attribute from session-management.
The latter is the URL to execute the action of logging out while the former is the URL being forwarded to upon a logout action.
To put it in other words, when creating a logout button, the URL for that button would be the logout-url value.
Now when the logout is done, spring security, be default, will render the main application's root app path, i.e.: http://yourserver:yourport/yourwebapp/. This path is overridden by invalid-session-url. So upon logout, you will be forwarded there.
To sum up, if you don't want the behavior you're asking for, then do not use invalid-session-url attribute.
Hope that helps.

Resources