Reputation: 27286
Posted in JBoss forums as well: https://developer.jboss.org/thread/280195
update 2019-06-26 apparently this is now confirmed as a bug in Undertow, with a pull request submitted here.
This is a SSCCE.
I have a very simple Servlet that does nothing except print the value of a parameter:
public class TestServlet extends HttpServlet{
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
final String URL = req.getParameter("url");
System.out.printf("url parameter read as: [%s]\n", URL);
}
}
My application's web.xml is configured so as to automatically redirect http
access to https
:
<web-app>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>SECURE</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
</web-app>
… and I also have (in my standalone-full.xml
configuration file) the redirect-socket
attribute set in the definition of the http-listener
:
<http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
If I deploy to JBoss EAP 7.1 and enter the following URL in my browser (where the url
parameter carries the URL-encoded value of "http://www.google.com"):
http://localhost:8082/get-parameter-test/min?url=http%3A%2F%2Fwww.google.com
… this is what I see in the developer console:
As a result, after the automatic redirect, my code fails to obtain the correct value of the url
parameter and I see in the log files:
url parameter read as: [http%3A%2F%2Fwww.google.com]
However, if I deploy to JBoss EAP 6.2 and do the same, the URL is not mangled in the redirect and everything works fine:
this answer suggests that the decode-url
parameter in the configuration of the http-listener
and https-listener
in the undertow system in the JBoss configuration file (standalong-full.xml
) may have something to do with this. This is wrong. I tried all four combinations:
decode-url
="false" and https-listener: decode-url
="false"decode-url
="false" and https-listener: decode-url
="true"decode-url
="true" and https-listener: decode-url
="false"decode-url
="true" and https-listener: decode-url
="true"In all cases, the 302 response that's effecting the redirect from http to https has the following header:
Location: https://localhost:8445/get-parameter-test?url=http%253A%252F%252Fwww.google.com
That is in all cases, the URL is mangled (call it re-encoded it if you like, it's mangled AFAIAC). There's no reason for this behavior at all and it is not what EAP 6.2 does. The value of the decode-url
parameter only affects the behavior of the HttpServletRequest#getRequest
method inside your servlet, it has no effect whatsoever in the redirected URL.
Upvotes: 1
Views: 3951
Reputation: 27286
update 2019-06-26 Apparently this is now confirmed as a bug in Undertow, with a pull request submitted here
Here's what ultimately worked for me.
First of all, I removed from my web.xml
the entire <security-constraint>
element as it is not needed for the solution I implemented.
I also removed the redirect-socket="https"
from the <http-listener>
configuration. That too, is also not needed. So here's what my <http-listener>
and <https-listener>
look like:
<http-listener name="default" socket-binding="http" enable-http2="true"/>
<https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
I think the above is exactly what you get in JBoss EAP 7.1 out of the box, so no need to change that.
I then created a filter and added it in the <filters>
element of the undertow subsystem:
<rewrite name="http-to-https" redirect="true" target="https://%h:8445%U%q"/>
%h
is the remote host name%U
is the requested URL path%q
is the query string (automatically prepended with ?
if it exists)I found the above codes here - I am sure there's a more normative reference somewhere else but they seem to work.
Finally, I added a reference to the filter, along with a predicate, in the <server>/<host>
element (also in the undertow subsystem):
<server name="default-server">
<http-listener name="default" socket-binding="http" enable-http2="true"/>
<https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<filter-ref name="server-header"/>
<filter-ref name="x-powered-by-header"/>
<filter-ref name="http-to-https" predicate="equals(%p, 8082)"/>
<http-invoker security-realm="ApplicationRealm"/>
</host>
</server>
With the above configuration the request gets redirected without re-encoding the URL:
$ curl -I -L -k http://localhost:8082/get-parameter-test?url=http%3A%2F%2Fwww.google.com
HTTP/1.1 302 Found
Connection: keep-alive
Server: JBoss-EAP/7
Location: https://127.0.0.1:8445/get-parameter-test?url=http%3A%2F%2Fwww.google.com
Content-Length: 0
Date: Tue, 11 Jun 2019 17:43:23 GMT
HTTP/1.1 200 OK
Connection: keep-alive
X-Powered-By: Undertow/1
Server: JBoss-EAP/7
Content-Length: 0
Date: Tue, 11 Jun 2019 17:43:23 GMT
… and the parameter is correctly read from Java:
url parameter read as: [http://www.google.com]
There is no need to set decode-url="true"
in the http/https listeners as that's the default value.
NB: The above causes JBoss EAP 7.1 to send a 302 redirect. I have no idea how to configure a 303 or 307 redirect.
The obvious alternative to the above is to do the redirect programmatically from your application's code using HttpServletRequest#sendRedirect. In that case too, you do not need redirect-socket="https"
in your http-listener
.
Apparently, the redirect-socket
attribute is only necessary in conjunction with the <security-constraint>
element in your application's web.xml. That's because otherwise (i.e. if you have the <security-constraint>
in your web.xml
but no redirect-socket
in your http-listener
), you get hit with:
ERROR [io.undertow.request] (default task-14) UT005001: An exception occurred processing the request: java.lang.IllegalStateException: UT010053: No confidential port is available to redirect the current request.
).
However if you have both the <security-constraint>
and the redirect-socket
, the query String is needlessly re-URL-encoded (and thus mangled) in the redirected URL as explained in the question. So it's not clear to me what's the use of <security-constraint>
in JBoss EAP 7.1.
Upvotes: 2
Reputation: 4309
You are URL is not getting mangled its getting re-encoded. The issue is of re-encoding or URL while redirecting from http to https. You are passing encoded url parameter to http
i.e. http%3A%2F%2Fwww.google.com.
http://www.google.com --encode--> http%3A%2F%2Fwww.google.com --re-encode--> http%253A%252F%252Fwww.google.com
In you re-encode url, '%' is getting encoded to '%25'.
To disable this behaviour, you need to make changes in your listners. There is one attribute called decode-url which can be used to disable/enable this behaviour.
decode-url
: If the URL should be decoded. If this is not set to true then percent encoded characters in the URL will be left as is.
Refer following link for more information on Undertow subsystem. https://docs.jboss.org/author/display/WFLY/Undertow+subsystem+configuration
Note: This functionality may have worked on JBoss 6.2 because in JBoss 6.2 subsystem for this configuration is called WEB which is replaced by Undertow in JBoss EAP 7+
Upvotes: 0