Spring Security - Remember me cookie doesn't survive restart - spring-security

I have a spring boot application (2.1.6) with spring security.
I added a capability of "remember me", but unfortunatelly - after server restart the app doesn't remember the user.
my configuration looks like this:
.and().rememberMe().key("*****").tokenValiditySeconds(15768000)
I debug TokenBasedRememberMeServices , and I saw there is a signature that doesn't much between the cookie and the calculation after restart.
The reason the signatures are different is because they are based on passwords, and the passwords are retrieved differently between setting the remember me cookie and reading the cookie.
I'm not sure why.
All my users are defined in-memory:
authBuilder.inMemoryAuthentication()
.withUser("david")
.password("{noop}mypassword").authorities("ROLE_USER")
Can you please help me understand why the remember me doesn't survive server restarts?

Related

Spring Saml2 and Spring Session - SavedRequest not retrieved (cannot redirect to requested page after authentication / InResponseTo exception)

I am trying to use Spring Boot SAML2 + Spring Session to secure my web application (to be deployed on K8S). Everything is fine without spring-session-data-rest or spring-session-hazelcast. It can authenticate with Okta and redirect back to the requested page after authentication. Also, I can use either opensaml3 or opensaml4.
However, when I tried to use either spring-session-data-rest or spring-session-hazelcast (just 1 instance, no cluster yet), it would not redirect back to the requested page. Also, it'd fail with opensaml4 with exception: "The response contained an InResponseTo attribute [] but no saved authentication request was found". There's some mentioning about opensaml3 going EOL so I want to make it work with opensaml4.
Here's a sample application to demonstrate my case https://github.com/simonckw/redis-saml2/tree/redis. Have I missed anything? Have anyone got a working sample with this setup? Help is much appreciated.
p.s. I've traced into HttpSessionRequestCache.java, invoked from SavedRequestAwareWarpper.java. Without spring-session-data-rest or spring-session-hazelcast, the saved request can be retrieved but not when either spring-session-data-rest or spring-session-hazelcast is enabled. It also seems to me that the InResponseTo exception could be related too. My Redis setup should be fine. Here's the session data written into Redis:
"spring:session:sessions:expires:7c1858d1-0ea7-4a7a-8523-2abf89137771"
"spring:session:expirations:1654439580000"
"spring:session:sessions:expires:58a584d3-625e-4e0a-bef5-3aaff485ad93"
"spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:abc#xyz.com"
"spring:session:sessions:7c1858d1-0ea7-4a7a-8523-2abf89137771"
"spring:session:sessions:58a584d3-625e-4e0a-bef5-3aaff485ad93"
127.0.0.1:6379> hkeys spring:session:sessions:7c1858d1-0ea7-4a7a-8523-2abf89137771
"sessionAttr:SPRING_SECURITY_SAVED_REQUEST"
"lastAccessedTime"
"maxInactiveInterval"
"creationTime"
"sessionAttr:org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository.SAML2_AUTHN_REQUEST"
127.0.0.1:6379> hkeys spring:session:sessions:58a584d3-625e-4e0a-bef5-3aaff485ad93
"maxInactiveInterval"
"creationTime"
"lastAccessedTime"
"sessionAttr:SPRING_SECURITY_CONTEXT"
"sessionAttr:SPRING_SECURITY_LAST_EXCEPTION"
The problem is that Spring Session is setting SameSite=Lax for its SESSION cookie. Your servlet container isn't setting that on JSESSIONID (when you're not using Spring Session).
Because the SAML response is being POSTed from Okta's page, the browser will not send the cookie, so Spring doesn't think it has a session in which to find the authentication request. It uses that saved request to reconcile the InResponseTo attribute.
You can work around this by removing SameSite from the cookie. Create a bean like this:
#Bean
public DefaultCookieSerializerCustomizer cookieSerializerCustomizer() {
return cookieSerializer -> {
cookieSerializer.setSameSite(null);
};
}
Alternatively, you could explicitly specify None, but then you would have to also set the Secure attribute.
Note: Chrome is supposed to default to Lax where SameSite isn't specified. In reality, it doesn't do that if HttpOnly is set. Safari and Firefox don't even seem to care about HttpOnly.
This problem is discussed here.

JSESSIONID use existing session cookies

Spring Session uses a different format for its session cookies than Tomcat does. So if you implement Spring Session, even if you would name the session cookie JSESSIONID, all the users have to login again.
This is a point where you potentially lose users, because nobody likes to login. Perhaps this is an edge case, and certainly it's not worth a huge amount of trouble, but I'm curious if it's possible for existing users to use their already stored Tomcat session cookies?
You can implement your own org.springframework.session.web.http.CookieSerializer that matches Tomcat's default cookie serialization and register it as a bean.
Spring Session configuration will then pick it up and use it - see org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration#setCookieSerializer for more details.

Spring "Remember Me" not working with jetty and session replication

I am using Jetty 8 and currently have two instances set up and running behind a round robin load balancer. I have configured it use session replication via MongoDB. My application uses spring security. It is working great with two exceptions. I will include one here, and the other in another question.
Spring Security's "Remember Me" does not work correctly. If a user logs in and requests "Remember me", then it will work fine, assuming the users future authentication requests hit the particular node that was hit during the original login. However, if a future auth request hits a different node, that node appears to be ignorant of the "Remember me" request and therefore prompts the user for credentials.
Does anyone have any suggestions? I'm about to start digging into the implementation of spring security's remember me code and jetty-nosql, but would love it if someone could save me some time.
Additionally, I have tried both the cookie hash-based "remember me" token as well as the db persisted "remember me" token approach, and both have the same issue.
The solution is to use the db persisted "remember me" token approach. In our situation, we used org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices.
It turns out that our first attempt at using the db persisted token approach was simply implemented in error. When we did it correctly, it worked fine and solved our remember me problem.

Redirect after Session timeout (Grails, Spring Security Core, Tomcat)

I have an application developed in Grails (v1.3.7) and we used Spring Security Core (v1.2.6) plugin for authentication. After building .war file, I have deployed the application in a standard tomcat server (v7.0.22). The application runs fine.
I know that I can configure Session timeout period in web.xml either before building the application or in the tomcat server itself. But, I want (additionally) to redirect any page to the log-in page automatically whenever the Session is timed out. Because, if the Session times out and users click on any links or simply refresh the current page, they get a tomcat error.
Can anyone suggest a way to resolve it easily? Is there any configuration (like expired-session-url) in Tomcat or Spring Security Core that does the job?
I have search in the plugin doc site, plugin blog site but nothing found. This site suggest that I would require to add a listener in code and I would hate to do that and would like to use a simple configuration like this. Can anyone guide anything?
Thanks in anticipation
Http is stateless protocol, and session is just a marker stored on client cookies (+ local db), and you can't handle this as an event. 'new client' and 'session expired' is the exactly same, it just means that you can't identify browser for current request. For most cases it means also that user is not authenticated (for raw Spring Security Core, at least)
For you case, you already have session expired handler, it's when you're getting this tomcat error. Just handle this error, and redirect user to login page.
Btw, if you have proper Spring Security configuration, it must redirect all non-authorized users to login page. And seems that you have made something wrong with your app architecture, if you have authenticated user, but still having some user datails in standard tomcat session. There at least two ways: avoid your own user session, or make some kind of session-based Spring Security authentication config.

User is not prompted to authenticate after restarting the server

Spring security has been used for our application. Spring security has been configured in bean declaration way.
The problem is : I logged into the application, browsed few pages, and restarted the server(but didn't close the browser). After restarting the server I could successfully move to other pages. I am sure it is not the browser cache as I delete all the cookies before I start go through other pages.
Why does it happen like this ? Is this the default behavior ? How can I enforce the authentication after restarting the server ?
We use Tomcat 6, and it is the default behavior of the tomcat which serializes sessions before server shutdown and de-serializes next time the server is restarted thus it maintains the session.
If we don't want this default behavior then uncomment the 'Manager' element section in the context.xml.

Resources