I am having issues disabling the httpOnly flag on the set-cookie header. This is mainly an issue on login when the JSESSIONID is being sent back in the response. Note that this is on a tomcat server deployed on AWS EBS.
Any of the configs below work fine locally but no on deployment.
I have tried the following solutions, none seem to work
application.yml config
server:
servlet:
session:
cookie:
http-only: false
Servlet Context Initializer
@Bean
open fun servletContextInitializer(): ServletContextInitializer {
return ServletContextInitializer { servletContext ->
servletContext.setSessionTrackingModes(setOf(SessionTrackingMode.COOKIE))
val sessionCookieConfig = servletContext.sessionCookieConfig
sessionCookieConfig.isHttpOnly = false
}
WebServerFactoryCustomizer
@Bean
open fun tomcatCustomizer(): WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
return WebServerFactoryCustomizer { tomcat ->
tomcat
.addContextCustomizers(TomcatContextCustomizer { context -> context.useHttpOnly = false })
}
web.xml
<session-config>
<cookie-config>
<http-only>false</http-only>
</cookie-config>
</session-config>
Sample Request Header
Host:
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer:
Authorization: Bearer null
Content-Type: application/json
Content-Length: 58
Origin:
Connection: keep-alive
TE: Trailers
Sample Response Header
HTTP/2.0 200 OK
date: Sat, 16 Mar 2019 14:11:58 GMT
set-cookie: AWSALB=qBpX9uFjtkP4H7gyJ3EXL8na0a7aARiEN/twi0cc2sPywvbysKXXaNfQbe8HaS5hcC6VRnkp09VYj0pGcXiHbWRod9OithDlQ0ZIvHSbY7B5xiJT1r8N+lcRdCcp; Expires=Sat, 23 Mar 2019 14:11:57 GMT; Path=/
server: Apache/2.4.37 (Amazon) OpenSSL/1.0.2k-fips
vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers
access-control-allow-origin:
access-control-allow-credentials: true
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0
strict-transport-security: max-age=31536000 ; includeSubDomains
x-frame-options: DENY
set-cookie: JSESSIONID=70F12355ABFDD0F42292D9F6CEAA22BF; Path=/; Secure; HttpOnly
X-Firefox-Spdy: h2
I was finally able to resolve it by creating a Filter that runs as part of Spring Security. The filter executes before the SecurityContextPersistenceFilter, thus waiting until the set-cookie header is added then updates the headers (before in the chain, gets last call after doFilter() executes).
Filter Implementation
package com.zambezii.app.security.filter
import org.springframework.web.filter.GenericFilterBean
import java.io.IOException
import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class SessionFilter : GenericFilterBean() {
@Throws(IOException::class, ServletException::class)
override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
val req = request as HttpServletRequest
val res = response as HttpServletResponse
chain.doFilter(req, res)
removeHttpOnlyFlag(res)
}
private fun removeHttpOnlyFlag(res: HttpServletResponse) {
val setCookieHeaderName = "set-cookie"
var setCookieHeader = res.getHeader(setCookieHeaderName)
if (setCookieHeader != null) {
setCookieHeader = setCookieHeader.replace("; HttpOnly", "")
res.setHeader(setCookieHeaderName, setCookieHeader)
}
}
}
Security Config
open class WebSecurityConfig() : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
...
.authenticated()
.and()
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter::class.java)
.addFilterBefore(SessionFilter(), SecurityContextPersistenceFilter::class.java)