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:
127.0.0.1:6379> hkeys spring:session:sessions:7c1858d1-0ea7-4a7a-8523-2abf89137771
127.0.0.1:6379> hkeys spring:session:sessions:58a584d3-625e-4e0a-bef5-3aaff485ad93
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.