I have a Spring MVC application secured with Spring Security. The majority of the application uses simple HTTP to save resources, but a small part processes more confidentia
Spring Boot makes it dead simple (at least with embedded Tomcat).
1. Add the following lines to your application.properties:
server.forward-headers-strategy=native
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto
2. Do the following trick with your HttpSecurity
configuration.
// final HttpSecurity http = ...
// Probably it will be in your `WebSecurityConfigurerAdapter.configure()`
http.requiresChannel()
.anyRequest().requiresSecure()
Source is Spring Boot reference guide
84.3 Enable HTTPS When Running behind a Proxy Server
Please also check the answer below for a specifics related to Spring Boot 2.2
Kind of a followup to NeilMcGuigan's answer that showed that the solution was servlet container side.
Tomcat is even better. There is a valve dedicated to masking the side effects of a reverse proxy. Extract from Tomcat documentation for Remote IP Valve:
Another feature of this valve is to replace the apparent scheme (http/https), server port and request.secure with the scheme presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto").
Example of the valve configuration :
<Valve className="org.apache.catalina.valves.RemoteIpValve"
internalProxies="192\.168\.0\.10|192\.168\.0\.11"
remoteIpHeader="x-forwarded-for" proxiesHeader="x-forwarded-by"
protocolHeader="x-forwarded-proto" />
That way with no other configuration of the application itself, the call to Request.isSecure()
will return true if the request contains a header field of X-Forwarded-Proto=https
.
I had thought of two other possibilities, but definitively prefere that one :
ChannelProcessingFilter
to wrap the request with a HttpServletRequestWrapper
overriding isSecure()
to process a X-Forwarded-Proto
header - need writing and testing the filter and the wrapperBeanPostProcessor
to look for a ChannelProcessingFilter
and manually inject a ChannelDecisionManager
able to consider the X-Forwarded-Proto
header - really too low levelIf your site is HTTPS and you're running Apache Tomcat behind another system that's handling TLS termination, you can tell Tomcat to "pretend" that it's handling the TLS termination.
This makes request.isSecure()
return true
;
To do so, you need to add secure="true"
to your Connector config in server.xml
.
https://tomcat.apache.org/tomcat-7.0-doc/config/http.html
See also the scheme
attribute.