Servlet redirection protocol on the WebLogic
In web development, the browser automatically redirects when it receives a response with a "Location" header for some
HTTP status codes. Codes that trigger automatic redirection start with 3. When using a Java Servlet API, i.e., javax.servlet.http.HttpServletResponse.sendRedirect(String)
, it will
usually be a 302.
When you migrate your servlet application from something like Tomcat to the WebLogic, you might come across a quirk that causes "Location" header to evaluate to an absolute URL. Unfortunately, it might not play well with a reverse-proxy that terminates SSL and connects to the WebLogic on the HTTP port.
WebLogic absolute URL redirect
The servlet on the WebLogic may redirect to a Location with HTTP protocol even though you connect through an HTTPS
reverse proxy (regardless of the forwarded headers).
Suppose we send a POST to the https://example.com/app/foo, which would be a WebLogic servlet invoking sendRedirect("bar")
from behind a reverse-proxy:
# Request headers (with unrelated headers skipped for brevity)
POST /app/foo HTTP/1.1
Host: example.com
Origin: https://example.com
Referer: https://example.com/bar
Request from the reverse-proxy:
POST /app/foo HTTP/1.1
Host: [example.com]
X-forwarded-host: [example.com]
Upgrade-insecure-requests: [1]
X-forwarded-server: [example.com]
X-forwarded-for: [192.168.0.100]
X-forwarded-proto: [https]
X-forwarded-ssl: [on]
Even though the forwarded headers are present, WebLogic responds with an HTTP location instead of HTTPS:
HTTP/1.1 302 Moved Temporarily
Location: http://example.com/app/bar
Mixed-content redirect solutions
You can find various solutions to this:
- Rewrite the response header on the proxy.
- Implement a custom filter that will rewrite the response header.
- Turn on "WebLogic Plugin Enabled" option in the WebLogic console and add the "WL-Proxy-SSL: ON" request header on the proxy.
- Add WL front end host and port in the WebLogic console.
However, after examining the contents of the provided servlet library, I realized that the safest and simplest solution was to disable the absolute URL evaluation during the redirection.
To debug this, I put a breakpoint on
sendRedirect()
method, executed arbitrarygetClass().getProtectionDomain().getCodeSource().getLocation()
. Given the location of theHttpServletResponse
implementation I added it to the classpath in my IDE: /u01/oracle/wlserver/modules/com.oracle.weblogic.servlet.jar!/weblogic/servlet/internal/ServletResponseImpl.class (from the official 12.1.2.4 image docker).
Turns out you can do this in the WEB-INF/weblogic.xml
web application descriptor, like so (swap the 1.9
XSD version with a version
compatible with your WebLogic):
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
http://xmlns.oracle.com/weblogic/weblogic-web-app/1.9/weblogic-web-app.xsd">
<context-root>/app</context-root>
<container-descriptor>
<redirect-with-absolute-url>false</redirect-with-absolute-url>
</container-descriptor>
</weblogic-web-app>
Comment from the XSD file: If the redirect-with-absolute-url element is set to false, then the servlet container will not convert the relative url to the absolute url in the location header in a redirect.