I'm having loads of trouble getting my Java web app working on Heroku.
This is what I have:
A Java web app (standard war file) using Spring Security with a security-constraint section in my web.xml that looks like this:
<security-constraint>
<web-resource-collection>
<web-resource-name>SSL URLs</web-resource-name>
<url-pattern>/j_spring_security_check</url-pattern>
<url-pattern>/secure/account/create</url-pattern>
<url-pattern>/register</url-pattern>
<url-pattern>/login/*</url-pattern>
<url-pattern>/</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
When I deploy my WAR file to Heroku (using the Heroku deploy plugin for Atlassian Bamboo) and the app starts up, I end up getting a 'too many redirects' error in my browser - it looks like it has something to do with flicking between https and http but I can't figure out what I need to do to fix it.
I just want to use the piggyback SSL for now, as the SSL add-on is quite pricey for my hobby project (at $20 a month).
I solved a similar problem by using a combination of requires-channel in my Spring Security configuration and Tomcat's RemoteIpValve. If you are not using Spring Security, configuring RemoteIpValve should be sufficient (the following assumes you are using the excellent webapp-runner as your container) I imagine there is an equivalent for jetty-runner, but I don't know it...
The issue is that Heroku's web/routing tier handles the SSL, and proxies the request to your webapp as plain HTTP. So Tomcat doesn't know the request is secured elsewhere (SSL offloading) RemoteIpValve essentially over-rides the protocol, port and IP address that Tomcat sees (and, in turn, how request.isSecure() is evaluated) by looking at HTTP headers set by the proxying server that handled the SSL.
Create a context.xml with the following:
<Context>
<Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="x-forwarded-for" protocolHeader="x-forwarded-proto" portHeader="x-forwarded-port"/>
</Context>
Those three headers (x-forwarded-for, x-forwarded-proto, and x-forwarded-port) are automatically sent by Heroku's routing tier.
Next, ensure that the file gets copied somewhere in your maven target dir (I put it in the same dir as webapp-runner itself). In pom.xml:
<resources>
<resource>
<directory>${basedir}/src/main/resources/META-INF</directory>
<includes>
<include>context.xml</include>
</includes>
<targetPath>${project.build.directory}/dependency</targetPath>
</resource>
</resources>
Finally, make sure webapp-runner points to the context.xml (e.g., using webapp-runner 7.0.30.1, which supports the context-xml argument). In your Procfile:
web: java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --context-xml target/dependency/context.xml ...etc...
As a final note, I use of Spring Security requires-channel on <sec:intercept-url> to toggle back and forth between HTTP and HTTPS by flipping an environment variable - unset on my local dev box for easy configuration, set on Heroku (via heroku config) to selectively force SSL in different environments.
Hope this works for you...
I was facing the exact same problem using webapp-runner and fixed it by simply using the --proxy-base-url https://example.com, as described here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With