Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect to https on tomcat behind ELB

I have following setup on AWS

ELB (terminates SSL) -> nginx receives http on 80 and forwards to -> tomcat on 8080

But when i do a response.sendRedirect("/somepath") in my servlet then the browser is receiving it as 302 http://example.com/somepath

But I want the browser to get https://example.com/somepath, how do I achieve this in tomcat or nginx without setting up SSL on them.

like image 600
Rahul Avatar asked Mar 17 '23 14:03

Rahul


1 Answers

This is because of response.sendRedirect();

SSL Offloading servers actually cause this problem of https URLs getting converted into http URLs in case of sendRedirect. Let's try to understand how it all happens. When an https URL reaches an intermediate SSL Offloading server, the request is decoded (to offload the decoding task which would have been done by the actual target server otherwise) into an http request and the SSL Offloader now sends that decoded http request to the actual target server (it may go through few other intermediary servers for other purposes as well). Now, the target server has no clue whether it was originally an https request or not and it treats it as an http request only. This is the reason why a servlet calling sendRedirect on the target server will result into an http URL for the redirected resource (having a relative URL)and the same http URL is sent back to the client browser. Remember, no SSL Offloading server will come into picture for this URL as it's an http request and not an https request. If the redirected resource is an absolute https URL then also an intermediate SSL Offloader may convert that https request into an http request before it reaches to the client browser.

The solution to the problem is implementing a Filter and override sendRedirect in HttpServletResponseWrapper.

Filter.

public class AbsoluteSendRedirectFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException { }
    public void destroy() { }
    public void doFilter(ServletRequest request,
            ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        //continue the request
        chain.doFilter(request, new SendRedirectOverloadedResponse(request, response));
    }
}

HttpServletResponseWrapper

public class SendRedirectOverloadedResponse extends HttpServletResponseWrapper {

    private HttpServletRequest m_request;
    private String prefix = null;

    public SendRedirectOverloadedResponse(HttpServletRequest inRequest,
            HttpServletResponse response) {
        super(response);
        m_request = inRequest;
        prefix = getPrefix(inRequest);
    }

    public void sendRedirect(String location) throws IOException {
        String finalurl = null;
        if (isUrlAbsolute(location)) {
            finalurl = location;
        } else {
            finalurl = fixForScheme(prefix + location);
        }
        super.sendRedirect(finalurl);
    }

    public boolean isUrlAbsolute(String url) {
        return url.toLowerCase().startsWith("http");
    }

    public String fixForScheme(String url) {
        //alter the url here if you were to change the scheme return url;
    }

    public String getPrefix(HttpServletRequest request) {
        StringBuffer str = request.getRequestURL();
        String url = str.toString();
        String uri = request.getRequestURI();
        int offset = url.indexOf(uri);
        String prefix = url.substring(0,offset);
    }
}

Resources came from here:
http://www.hoitikwong.com/2013/03/the-mystery-case-of-https-becoming-http.html and
http://geekexplains.blogspot.in/2008/06/https-becoming-http-in-case-of.html

like image 161
Ken de Guzman Avatar answered Mar 20 '23 04:03

Ken de Guzman