1

We have a Java servlet, running with embedded Jetty, deployed to Heroku using the "SSL Endpoint" add-on. I have the requirement that all pages in the app be served over HTTPS, regardless of whether the user navigates to our app with http or https.

The application recognizes requests made over https, but it also accepts http requests without redirecting (which it should not do). Also, if the user starts with an https connection, then whenever a form is posted and redirected to a "GET" request, any https connection is reverted to http.

I tried adding a URL filter that simply changed "http://" to "https://" and do a redirect using the following code (imports removed for brevity):

public class UrlFilter implements Filter
{
  protected FilterConfig filterConfig;

  @Override
  public void destroy(){}

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
  {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    String incomingUrl = httpRequest.getRequestURL().toString();
    if ( (!httpRequest.isSecure()) && incomingUrl.contains(".webapps.stjude.org")  )
    {
      String newUrl = incomingUrl.replace("http://", "https://");
      httpResponse.sendRedirect(newUrl);
    }
    chain.doFilter(request, response);
  }

  @Override
  public void init(FilterConfig filterConfig) throws ServletException
  {
    this.filterConfig = filterConfig;
  }
}

Then, I added this to my web.xml file:

<filter>
  <filter-name>urlFilter</filter-name>
  <filter-class>org.stjude.radio.ui.filters.UrlFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>urlFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

The problem with this approach is that the app returns a "too many redirects" error (redirect loop).

I'm sure this question has been addressed, but I can't for the life of me find exactly what I need to do to make this work.

BTW, I tried adding the following to web.xml also, but this simply caused requests to fail.

<security-constraint>
  <web-resource-collection>
    <web-resource-name>SSL Pages</web-resource-name>
    <url-pattern>/*</url-pattern>
    <http-method>GET</http-method>
    <http-method>PUT</http-method>
    <http-method>POST</http-method>
  </web-resource-collection>
  <user-data-constraint>
    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
  </user-data-constraint>
</security-constraint>

Any help would be greatly appreciated.

pconrey
  • 5,805
  • 7
  • 29
  • 38
  • The `getRequestURL()` used in the filter doesn't include the query portion of the original URL so this would be lost on redirect. One should also check if `getQueryString()` is non-null and append that (with a preceding '?') is so. – George Hawkins Feb 10 '15 at 18:13

2 Answers2

3

You need to check the x-forwarded-proto header to see if the request was secure:

Boolean secure = false;
if (request.headers.get("x-forwarded-proto") != null) {
  secure = request.headers.get("x-forwarded-proto").values.contains("https");
}
System.out.println("secure = " + secure);
James Ward
  • 29,283
  • 9
  • 49
  • 85
  • James, is this specific to Heroku? – pconrey Jul 24 '12 at 19:14
  • The `x-forwarded-proto` is a de-facto standard for load balancers to let the backing server know what the protocol was for the request into the load balancer. – James Ward Jul 24 '12 at 21:01
  • Good tip! This solves the issue I had on AWS Elastic Beanstalk. – Douglas Patriarche Sep 03 '12 at 02:08
  • 2
    Jetty can automatically handle the `x-forwarded` attributes - this is done with `ForwardedRequestCustomizer` (as described in the Jetty "[configuring connectors](http://eclipse.org/jetty/documentation/current/configuring-connectors.html#d0e4471)" documentation page). This avoids lots of other `x-forwarded` related issues, e.g. redirects in servlets always redirecting to http resources and issues when using authentication. – George Hawkins Feb 10 '15 at 18:04
0

I have checked with Heroku (maybe I miss here a version, and buildpack ,and so on ) but definitely you got none of this information:

  • a X-Forwarded-Proto point to http
  • a HttpServletRequest#scheme returns a http
  • a HttpServletRequest#secure return false ....
maryoush
  • 173
  • 1
  • 12