Late answer, but an alternative, configuration-driven approach is to use Spring Security with requires-channel="https"
on the various <sec:intercept-url>
tags, in conjunction with Tomcat RemoteIpValve
, which handles the same proxy headers (x-forwarded-proto
, etc.) mentioned in the prior answer. The valve changes the behavior of HttpServletRequest.isSecure()
based on the proxy headers to reflect the protocol reported by the proxy, not the protocol the connector actually received - so any frameworks like Spring that rely on isSecure()
to Do the Right Thing will behave properly when SSL is offloaded.
SSL redirects in Heroku has instruction on configuring the valve for use with webapp-runner and Heroku.
Additionally, I suggest using PropertyPlaceholderConfigurer
to let the value be environment over-ridable. E.g., in your Spring Security configuration:
<sec:intercept-url pattern="/api/**" requires-channel="${REQUIRES_CHANNEL}" access="..."/>
The relevant application-config.xml
would include something like this:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="properties" ref="applicationProperties"/>
</bean>
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:/application-config.properties</value>
</list>
</property>
</bean>
The application-config.properties
file would include REQUIRES_CHANNEL=http
as a default, then when deployed to Heroku, you set heroku config:set REQUIRES_CHANNEL=https
to override.