Forcing HTTPS redirect on Wildfly 10.0 directs to https://localhost:8443 - https

I am having a very challenging time forcing HTTPS on a Bitnami Ubutnu Wildfly 10 install.
The HTTPS works fine (e.g. https://example.com works great)
I have tried many different things with no result. Here are some highlights of what I've done:
I modified my web.xml to add this (note MYWEBNAME was replaced with my war file name):
<security-constraint>
<web-resource-collection>
<web-resource-name>MYWEBNAME</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
I modified /opt/bitnami/apache2/conf/bitnami/bitnami.conf (as per https://docs.bitnami.com/aws/components/apache/):
<VirtualHost _default_:80>
DocumentRoot /opt/bitnami/apache2/htdocs"
ADD: RewriteEngine On
ADD: RewriteCond %{HTTPS} !=on
ADD: RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R,L]
...
</VirtualHost>
I modified standalone.xml
<management-interfaces>
<http-interface security-realm="ApplicationRealm" http-upgrade-enabled="true">
<socket-binding https="management-https"/>
</http-interface>
</management-interfaces>
I modified my root index.html to redirect to:
<SCRIPT>document.location="https://example.com";</SCRIPT>
As per Wildfly 9 http to https, I tried this:
<http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
<socket interface="management" secure-port="${jboss.management.http.port:9990}"/>
</http-interface>
this resulted in a 503 error and wildfly to die, so I removed it.
What I have now, is http://example.com redirecting to https://localhost:8443
So I think it's close, I just cannot figure out how to make it redirect to https://example.com:8443 instead

I m not using Apache proxing Wildfly. But in my setup, all request on port 80 or 8080 (http://example.com or http://example.com:8080) is redirected to port 443 (https://example.com).
It is done making iptables to redirect traffic from 80 to 8080 and 443 to 8443 and than wildfly redirects CONFIDENTIAL transport requests to port 443 instead 8443.
Please see if it is helpful: make wildfly listen on port 443 not 8443
By the way, use javascript or any other client side script to redirect to SSL is not safe enough once the responsability of the redirection is in the client side.

For others looking for a solution, here's a summary of what I did - all in one spot. This is a summary of the links located in this thread, so h/t to those authors who answered the question. The credit belongs to them, this is just a summary of what worked for me.
1. Add an IPTABLES routing rule to route port 443 to 8443.
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
Hint: to see what rules you already have in place, use:
sudo iptables -t nat -L -n -v
2. Add a Rewrite Filter and a Predicate to the configuration. Add the entries shown on line 10 and 24 of the snippet.
<subsystem xmlns="urn:jboss:domain:undertow:3.0">
<buffer-cache name="default"/>
<server name="default-server">
<http-listener name="default" socket-binding="http" redirect-socket="https"/>
<https-listener name="default-ssl" security-realm="ApplicationRealm" socket-binding="https"/>
<host name="default-host" default-web-module="YOURWARFILENAMEHERE.war" 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,8080)"/>
<!-- ADD THE filter-ref ENTRY ABOVE -->
</host>
</server>
<servlet-container name="default">
<jsp-config/>
<websockets/>
</servlet-container>
<handlers>
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>
<filters>
<response-header name="server-header" header-name="Server" header-value="WildFly/10"/>
<response-header name="x-powered-by-header" header-name="X-Powered-By" header-value="Undertow/1"/>
<rewrite name="http-to-https" redirect="true" target="https://DOMAINNAMEHERE:8443%U"/>
<!-- ADD THE rewrite ENTRY ABOVE, BE SURE TO SUBSTITUTE YOUR DOMAIN NAME -->
</filters>
</subsystem>
Note: I wondered if adding an iptables reroute from 8080 to 8443 using the command in step 1 would be sufficient and eliminate the need for step 2. But step 2 worked for me so I went with it. I'll leave trying that option up to the reader if they want.
3. Modify The Management Interfaces section of the standalone.xml.
<management-interfaces>
<http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
<socket-binding https="management-https"/>
</http-interface>
</management-interfaces>
Note that this replaced the binding to http. Also note this step may not be directly related to the forwarding of HTTP to HTTPS but rather just a step in the HTTPS setup.
4. Restart your Wildfly instance.

Related

Pentaho j_spring_security_check mixed content. HTTPS to HTTP

I have installed Pentaho (9.x) on Tomcat 8.5 and OpenJDK 1.8 as required.
In front of it there is Apache 2.4 with mod_proxy_http.
My website is served with HTTPS and I have these Proxy rules:
RequestHeader set X-Forwarded-Proto "https"
ProxyPreserveHost on
ProxyPass "/pentaho" "http://tomcat_host_ip:8080/pentaho"
ProxyPassReverse "/pentaho" "http://tomcat_host_ip:8080/pentaho"
ProxyPass "/pentaho/" "http://tomcat_host_ip:8080/pentaho/"
ProxyPassReverse "/pentaho/" "http://tomcat_host_ip:8080/pentaho/"
ProxyPass "/pentaho/Login" "http://tomcat_host_ip:8080/pentaho/Login"
ProxyPassReverse "/pentaho/Login" "http://tomcat_host_ip:8080/pentaho/Login"
When I try to log in a get an error during the POST:
https://pentaho.mywebsite.org/pentaho/j_spring_security_check
The application try to responde with HTTP protocol instead HTTPS.
In the request header I have the correct Referer and Origin:
Origin: https://pentaho.mywebsite.org
Referer: https://pentaho.mywebsite.org/pentaho/Login
But the response header reply with HTTP and NOT https:
Location http://pentaho.mywebsite.org/pentaho/
I solved the problem just adding proxyPort="443" and scheme="https" to my http connector in Tomcat.
The rule
RequestHeader set X-Forwarded-Proto "https"
on Apache was unusefull. This is my correct Apache configuration
ProxyPreserveHost on
ProxyPass "/pentaho" "http://tomcat_host_ip:8080/pentaho"
ProxyPassReverse "/pentaho" "http://tomcat_host_ip:8080/pentaho"
ProxyPass "/pentaho/" "http://tomcat_host_ip:8080/pentaho/"
ProxyPassReverse "/pentaho/" "http://tomcat_host_ip:8080/pentaho/"
And this is my Tomcat HTTP connector
<Connector URIEncoding="UTF-8"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
proxyPort="443"
scheme="https"
redirectPort="8443"
relaxedPathChars="[]|"
relaxedQueryChars="^{}[]|&"
maxHttpHeaderSize="65536"
/>
Servlet applications use the scheme, serverName and serverPort properties of a ServletRequest to generate hyperlinks. Usually Tomcat gets the latter two from the Host request header, while scheme depends on the connector.
If you use a reverse proxy, the above logic may not be enough. You have two solution:
Setting scheme statically
In your case the proxy uses HTTPS, while Tomcat uses HTTP, so you must override the scheme and secure properties:
<Connector
port="8080"
scheme="https"
secure="true"
...
while the Apache HTTP Server configuration can be shortened to:
ProxyPreserveHost on
ProxyPass "/pentaho" "http://tomcat_host_ip:8080/pentaho"
ProxyPassReverse "/pentaho" "http://tomcat_host_ip:8080/pentaho"
Remark that in your answer you didn't set the secure attribute: this attribute decides whether the transport is confidential. If you don't set it to true, Tomcat will automatically redirect the browser to redirectPort whenever the application asks for a confidential transport (cf. Securing Web Applications).
This solution only works correctly, if your proxy forwards only HTTPS requests to Tomcat.
Setting scheme dynamically
If you forward both HTTP and HTTPS requests to Tomcat, the server needs a way to distinguish between them. Therefore you need to add a RemoteIpValve to your Tomcat configuration:
<Valve className="org.apache.catalina.valves.RemoteIpValve" />
<Connector
port="8080"
redirectPort="443"
...
and ask Apache HTTP Server to add an X-Forwarded-Proto header:
RequestHeader set X-Forwarded-Proto "expr=%{REQUEST_SCHEME}"
ProxyPreserveHost on
ProxyPass "/pentaho" "http://tomcat_host_ip:8080/pentaho"
ProxyPassReverse "/pentaho" "http://tomcat_host_ip:8080/pentaho"
This solution has also the advantage to set the client's remoteHost and remoteAddr instead of those of the proxy.

Configure Tomcat8 behind Apache with HTTPS

I have Tomcat 8 installed in my server in port 8080 that I am exposing with a secured Apache (using Proxy Pass).
Here is my Apache configuration:
<VirtualHost *:443>
ServerName myserver.com
ProxyRequests Off
ProxyPreserveHost On
ProxyPass /odata/ http://172.31.36.251:8080/
ProxyPassReverse /odata/ http://172.31.36.251:8080/
<Proxy *>
allow from all
</Proxy>
RequestHeader set X-Forwarded-Port 443
RequestHeader set X-Forwarded-Scheme https
</VirtualHost>
Here is the Tomcat server.xml configuration
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
address="172.31.36.251"
proxyName="myserver.com"
scheme="https" proxyPort="443" />
All works well until here. If I call my application:
https://myserver.com/odata/D3a1593adae89/odata.svc/
I get:
<service xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xml:base="https://myserver.com:443/D3a1593adae89/odata.svc/">
<workspace>
<atom:title>Default</atom:title>
<collection href="Maintables">
<atom:title>Maintables</atom:title>
</collection>
</workspace>
</service>
The problem: If you see the attribute xml:base in the result, Tomcat decorates the address with the port and I really don't know how to remove it. Also the address is wrong: It should be https://myserver.com:443/odata/D3a1593adae89/odata.svc/ . I been looking around and trying things like setting proxyPort to blank but nothing. I think this is related to broken links when using a reverse proxy as described at https://cwiki.apache.org/confluence/display/HTTPD/TomcatModProxyHTML . I tried some rewrites like:
ProxyHTMLURLMap http://172.31.33.105:8080 /odata
RewriteEngine On
RewriteRule ^/odata$ https://myserver.com/odata/ [R,L]
But I just cannot make it work. The xml:base should be https://myserver.com/odata/D3a1593adae89/odata.svc/
Any idea is appreciated
For the port thing, as you use ProxyPreserveHost On and you set X-Forwarded-* headers, you can use the RemoteIpValve:
<Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="X-Forwarded-For" protocolHeader="X-Forwarded-Proto" />
The connector will be simply:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443"
address="172.31.33.105"
/>
The valve detect the proto and will assume the connection is secured with the default port number (https://xxxxx/yyy).
For the location, you should deploy your application in the odata context so that you can use
ProxyPass /odata http://172.31.33.105:8080/odata
modifying the context on the proxy pass (from /odata/ to /) is somehow tricky as you would need to filter all text coming from your backend server to fix some url path. It can be really painful ( should I replace all "/xxx" with "/odata/xxx" ? )

How can i set a placeholder when redirecting my url with wildfly standalone handlers?

I'm trying to redirect my URL with the following settings in the standalone.xml:
<server name="default-server">
<http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
<https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/en/" handler="en"/>
<location name="/de/" handler="de"/>
<location name="/" handler="de"/>
<filter-ref name="server-header"/>
<filter-ref name="x-powered-by-header"/>
</host>
</server>
<servlet-container name="default">
<jsp-config/>
<websockets/>
</servlet-container>
<handlers>
<file name="en" path="${jboss.home.dir}/standalone/deployments/en"/>
<file name="de" path="${jboss.home.dir}/standalone/deployments/de"/>
</handlers>
My handlers point on to the matching angular frontend-projects in the deployments folder of my wildfly-server, where also my EAR-file is deployed.
This works fine except for one case: If i refresh my detail-page, which looks like this: localhost:8080/en/details/1234 i get an error
404 - Page not found
I already tried <location name="/en/details/1234" handler="en"/> which works, but obviously only for that specific id.
In my understanding this could be solved by adding something like
<location name="/en/details/(.*)" handler="en"/>
My problem is that I can't figure out how to put a placeholder like a regular expression after "details/". Is that even possible? Or is there a better way of handling this redirection/rewriting problem?
I already gave undertow-handlers.conf a shot, but it felt like it never really triggered the rewrite rules I implemented there.

Configuring Liberty with httpProxyRedirect

I am attempting to redirect traffic on insecure port to secure port as described here:
https://www.ibm.com/support/knowledgecenter/en/SSD28V_9.0.0/com.ibm.websphere.liberty.autogen.core.doc/ae/rwlp_config_httpProxyRedirect.html
Instead both ports are available and I see nothing in the logs. It's as if the httpProxyRedirect isn't being configured at all.
<?xml version="1.0" encoding="UTF-8"?>
<server description="CAST Liberty Server">
<!-- Enable features -->
<featureManager>
<feature>webProfile-7.0</feature>
</featureManager>
<application id="app" context-root="/" type="war" location="${war.name}">
<classloader apiTypeVisibility="spec, ibm-api, api, third-party" />
</application>
<httpProxyRedirect id="defaultHttpProxyRedirect" httpPort="${http.port}" httpsPort="${https.port}" />
<keyStore id="defaultKeyStore" password="pass" />
<httpEndpoint host="*" httpPort="${http.port}" httpsPort="${https.port}" id="defaultHttpEndpoint" />
<applicationMonitor updateTrigger="mbean" />
</server>
Most likely, you are missing the security-constraints in the web.xml. This configuration tells the server which URLs need to be accessed over a secure transport and then re-directs qualifying requests from the non-secure port to the secure port. This tutorial may help: https://docs.oracle.com/cd/E19798-01/821-1841/bncbk/index.html
Also, keep in mind that the httpProxyRedirect configuration in the server.xml is intended for redirecting when you have a proxy server in front of your application server. For example, you may have your proxy server on the main "www.ibm.com" host - listening on HTTP port 80 and HTTPS port 443. But that host may route some requests to your Liberty application server on some other host (like "app1host.internal.ibm.com") that listens on different ports (i.e. HTTP port 9080 and HTTPS port 9443). In that case, just using the security-constraints in the web.xml would attempt to redirect the client request on the Liberty server from 9080 to 9443 but on the www.ibm.com host - where nothing is listening on those ports. In this case, you should configure httpProxyRedirect like this:
<httpProxyRedirect httpPort="80" httpsPort="443" host="www.ibm.com" />
With the configuration, a client HTTP request to a secured URL will get redirected to www.ibm.com on port 443, where the proxy server will forward the request to app1host.internal.ibm.com port 9443.
Hope this helps,
Andy
This is the security constraint that i am using in my web.xml and it works well for both Tomcat and IBM Websphere 8.5.5.15:
<security-constraint>
<web-resource-collection>
<web-resource-name>Entire Application</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Note: make sure that you put it after your <servlet-mapping>.

make wildfly listen on port 443 not 8443

so I have added a SSL certificate to my wildfly 9 and it's working, but I want to configure my standalone.xml to listen to https on port 443 not on port 8443 as the default configuration, so when I update the value ${jboss.https.port:8443} to ${jboss.https.port:443} it generate an error.
this what I have in my standalone.xml :
<server name="default-server">
<http-listener name="default" socket-binding="http" redirect-socket="https"/>
<https-listener name="httpsServer" socket-binding="https" security-realm="ApplicationRealm"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<location name="/images" handler="ImagesDirHandler"/>
<filter-ref name="server-header"/>
<filter-ref name="x-powered-by-header"/>
</host>
</server>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="localhost" port="25"/>
</outbound-socket-binding>
</socket-binding-group>
Please, provide more accurate details about your environment and errors.
I had similar needs like you. The users access our system trough a network where the only requests availables are on port 80 or 443. Than, when a costumer calls the system on port 80, wildfly redirects to port 8443 and the user cannot connect to the system. The solution was to make wildfly redirect to port 443 instead 8443. Follow some instruction for all looking for help in this issue:
In case of a linux based operational system, ports up to 1024 are
available to bind only with root privilegies.
It isn't a great idea run wildfly or any other web/app server with root privilegies in a production oriented server.
In other hands, try to run wildfly with a 'regular' user directly bind to port 443 or 80 generates permission denied like errors.
The solution for the problem I described above was to bind wildfly to ports 8080/8443 (without root privilegies) and ask the operational system to redirect traffic from port 80 to port 8080 and port 443 to port 8443. After it, config wildfly to redirect http requests to https requests on port 443 instead 8443.
So, assuming wildfly is working with http on port 8080 and https on port 8443 in a Linux based OS as service:
1) Stop wildfly: sudo service wildfly stop
2) Add iptables commands in the startup /etc/init.d/wildfly script like:
if [ $launched -eq 0 ]; then
log_warning_msg "$DESC hasn't started within the timeout allowed"
log_warning_msg "please review file \"$JBOSS_CONSOLE_LOG\" to see the status of the service"
else
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8443
fi
PS: You add a rule on a table called "nat", from man pages of iptables:
nat:
This table is consulted when a packet that creates a new connection is encountered.
So, if you have requested https://localhost:443 before the rule creation, the connection wal already created, so the nat table is not applied. Try from a new device.
Where $launched is a bash variable to represent the state of wildfly
2) In the standalone.xml, create an additional socket-binding entry:
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="https-external" port="443"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
...
</socket-binding-group>
Take attention to new tag entry <socket-binding name="https-external" port="443"/>
3) Change the http-listener to redirect to https-external instead https:
<http-listener name="default" socket-binding="http" redirect-socket="https-external" max-header-size=...
Where the change is redirect-socket="https-external"
4) Restart wildfly: sudo service wildfly start
After wildfly starts, verify the console.log file to see any errors report.
Thus, if your web.xml section assure confidential transport:
....
<security-constraint>
...
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
...
Wildfly will redirect the requests on port 80 or 8080 to directly to port 443 instead 8443.
Obs: It is a good idea to make backup copies of your /etc/init.d/wildfly script and standalone.xml file configuration before make any changes on them.

Resources