Wildfly 9 http to https

2019-01-08 10:13发布

问题:

I want to redirect the request from HTTP to HTTPS. I am using wildfly 9. After a google search I found the following, but it is not working. I hope somebody

<subsystem xmlns="urn:jboss:domain:undertow:2.0">
    <buffer-cache name="default"/>
    <server name="default-server">
        <http-listener name="default" socket-binding="http" redirect-socket="https"/>
        <https-listener name="https" socket-binding="https" security-realm="SSLRealm"/>
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content"/>
            <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="welcome-content" path="${jboss.home.dir}/welcome-content"/>
    </handlers>
    <filters>
        <response-header name="server-header" header-name="Server" header-value="WildFly/9"/>
        <response-header name="x-powered-by-header" header-name="X-Powered-By" header-value="Undertow/1"/>
    </filters>
</subsystem>

回答1:

First, I am basing this off of WildFly 9.0.1.Final and I am assuming you're merely trying to enable SSL via HTTPS and am not worried about authentication. I just spent about a day figuring this all out. Work off this documentation:

https://docs.jboss.org/author/display/WFLY9/Admin+Guide

The first thing you want to do is create your keystore as outlined in the documentation.

https://docs.jboss.org/author/display/WFLY9/Admin+Guide#AdminGuide-EnableSSL

The really important question to answer correctly is the one asking for your first and last name. In there, you need to put the hostname of the application server (e.g. localhost). Open a terminal window in the folder {jboss.home}/standalone/configuration and enter the following command:

keytool -genkey -alias MY_ALIAS -keyalg RSA -keystore MY_KEYSTORE_FILENAME -validity 365`

NOTE:, MY_ALIAS, MY_KEYSTORE_FILENAME, and MY_PASSWORD are arbitrary and you can set them as you wish.

The next step is to modify the standalone-XXX.xml file in the same {jboss.home}/standalone/configuration directory. I am using the standalone-full.xml file, however I believe this will work for the others as well.

The next step in the documentation I linked to above tells us to put the SSL keystore reference in the ManagementRealm. This can lead to a good deal of confusion. For the purposes of this response, I am trying to get WildFly to enable SSL over port 8443 for access to my applications. While I also enabled SSL for the management console (via port 9993), that's for later.

I suggest putting the keystore information in the ApplicationRealm as follows:

<security-realm name="ApplicationRealm">
    <server-identities>
        <ssl>
            <keystore path="MY_KEYSTORE_FILENAME" relative-to="jboss.server.config.dir" keystore-password="MY_PASSWORD" alias="MY_ALIAS" key-password="MY_PASSWORD"/>
        </ssl>
    </server-identities>
    <authentication>
        <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
        <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
    </authentication>
    <authorization>
        <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
    </authorization>
</security-realm>

NOTE:, the only changes to the default file in this section should be the server-identities tag. The authentication tag should be left alone unless you have other reasons to modify it).

NOTE:, MY_KEYSTORE_FILENAME, MY_ALIAS and MY_PASSWORD must match the values you provided when creating the key.

Now, the documentation gets a bit tricky. You now need to scroll down a bit to do the next step, though unfortunately it doesn't tell you to do so. Now that you have the keystore installed in Wildfly and configured within the appropriate security realm, you need to install the HTTPS listener and link it to the keystore.

https://docs.jboss.org/author/display/WFLY9/Admin+Guide#AdminGuide-HTTPSlistener

HTTPS listener

Https listener provides secure access to the server. The most important configuration option is security realm which defines SSL secure context.

Unfortunately, the documentation does not remain consistent with the security-realm attribute (previously installing the keystore in ManagementRealm and here referencing it in the ssl-realm). Since I put the keystore in the ApplicationRealm, we need to reference it as such.

Additionally, just to clarify, you need to put this within the undertow subsystem. Here is what I inserted, right underneath the http-listener tag:

<https-listener name="httpsServer" socket-binding="https" security-realm="ApplicationRealm"/>

Below is the full body of the undertow subsystem.

<subsystem xmlns="urn:jboss:domain:undertow:2.0">
    <buffer-cache name="default"/>
    <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"/>
            <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="welcome-content" path="${jboss.home.dir}/welcome-content"/>
    </handlers>
    <filters>
        <response-header name="server-header" header-name="Server" header-value="WildFly/9"/>
        <response-header name="x-powered-by-header" header-name="X-Powered-By" header-value="Undertow/1"/>
    </filters>
</subsystem>

And also, the socket-binding-group tag which defines the ports themselves:

<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="iiop" interface="unsecure" port="3528"/>
    <socket-binding name="iiop-ssl" interface="unsecure" port="3529"/>
    <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>

NOTE:, you will notice in the HTTPS listener we referenced name="httpsServer" (this value 'httpServer' is arbitrary and can be set to whatever you wish), socket-binding="https" (this value 'https' must match the https socket listed in the socket-binding group) and security-realm="ApplicationRealm" (this value 'ApplicationRealm' must be whatever security realm you installed the keystore in).

With this configuration, you should find that ports 8443 (secure) and 8080 (unsecure) both work for accessing WildFly's application service. Port 9990 (unsecure) still works for accessing the web administration UI, however 9993 (secure admin UI) does not.

SECURE ADMIN CONSOLE

I found these instructions and they worked perfectly.

http://www.mastertheboss.com/jboss-server/jboss-security/securing-access-to-jboss-wildfly-management-console

First step is to create the SSL key:

keytool -genkeypair -alias serverkey -keyalg RSA -keysize 2048 -validity 7360 -keystore server.keystore -keypass mypassword -storepass mypassword

NOTE: Remember, your server name should be used when it asks for first name / last name.

Next, configure the ManagementRealm in the standalone-XXX.xml to include the keystore. Add in the server-identities tag below:

<server-identities>
    <ssl>
        <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="mypassword" alias="serverkey" key-password="mypassword"/>
    </ssl>
</server-identities>

Below is what the full ManagementRealm looks like:

<security-realm name="ManagementRealm">
    <server-identities>
        <ssl>
            <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="mypassword" alias="serverkey" key-password="mypassword"/>
        </ssl>
    </server-identities>
    <authentication>
        <local default-user="$local" skip-group-loading="true"/>
        <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
    </authentication>
    <authorization map-groups-to-roles="false">
        <properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
    </authorization>
</security-realm>

Next, the management-interfaces section of the standalone-XXX.xml file uses an HTTP socket binding and we want to bind it to the HTTPS socket (specifically, the management-https socket).

<management-interfaces>
    <http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
              <socket-binding https="management-https"/>
    </http-interface>
</management-interfaces>

NOTE: see how the interface references the ManagementRealm security-realm. I tried it by just referencing the ApplicationRealm, without creating a separate keystore and it still worked somehow. It's probably best practice to not reuse that code for both purposes.

NOTE: below is the management-https socket definition referenced in the management-interface.

<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>

NOTE: for any of the socket definitions, you can (if needed) change the port number.

REDIRECT HTTP to HTTPS

In your web.xml file, insert the following chunk of code within the web-app tag.

<security-constraint>
    <web-resource-collection>
        <web-resource-name>WEB_APPLICATION_NAME</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

NOTE: You need to put the name of your application where it says WEB_APPLICATION_NAME. I can't be sure of what that would be in all scenarios, but for me, if the war file being deployed is MyApp.war, then I put MyApp there.

You can use either CONFIDENTIAL, INTEGRAL or NONE for the transport-guarantee. Note the below URL: https://docs.oracle.com/cd/E19798-01/821-1841/bncbk/index.html which will describe the differences, however it also states that CONFIDENTIAL and INTEGRAL are effectively the same.

Once that code is installed, you're done. Go ahead and test it out using https via port 8443 and then using http via port 8080. You will notice that when you use http/8080, it replies and your browser switches to https/8443. If you are like me and didn't trust it, you can curl it.

curl -vv -k -L -X GET http://localhost:8080/MyApp/rest/endpoint

You will see output similar to the following, demonstrating the redirect is working:

Hostname was NOT found in DNS cache
Trying 127.0.0.1...
Connected to localhost (127.0.0.1) port 8080 (#0)
GET /MyApp/rest/endpoint HTTP/1.1
User-Agent: curl/7.35.0
Host: localhost:8080
Accept: /

HTTP/1.1 302 Found
Connection: keep-alive
X-Powered-By: Undertow/1
Server WildFly/9 is not blacklisted
Server: WildFly/9
Location: https://localhost:8443/MyApp/rest/endpoint
Content-Length: 0
Date: Fri, 04 Sep 2015 18:42:08 GMT

Connection #0 to host localhost left intact
Issue another request to this URL: 'https://localhost:8443/MyApp/rest/endpoint'
Found bundle for host localhost: 0x8d68f0
Hostname was NOT found in DNS cache
Trying 127.0.0.1...
Connected to localhost (127.0.0.1) port 8443 (#1)
successfully set certificate verify locations:
CAfile: none
CApath: /etc/ssl/certs
SSLv3, TLS handshake, Client hello (1):
SSLv3, TLS handshake, Server hello (2):
SSLv3, TLS handshake, CERT (11):
SSLv3, TLS handshake, Server key exchange (12):
SSLv3, TLS handshake, Server finished (14):
SSLv3, TLS handshake, Client key exchange (16):
SSLv3, TLS change cipher, Client hello (1):
SSLv3, TLS handshake, Finished (20):
SSLv3, TLS change cipher, Client hello (1):
SSLv3, TLS handshake, Finished (20):
SSL connection using ECDHE-RSA-DES-CBC3-SHA
Server certificate:
subject: C=US; ST=Unknown; L=Unknown; O=Org; OU=Unknown; CN=localhost
start date: 2015-09-04 15:23:06 GMT
expire date: 2016-09-03 15:23:06 GMT
issuer: C=US; ST=Unknown; L=Unknown; O=Org; OU=Unknown; CN=localhost
SSL certificate verify result: self signed certificate (18), continuing anyway.
GET /MyApp/rest/endpoint HTTP/1.1
User-Agent: curl/7.35.0
Host: localhost:8443
Accept: /

HTTP/1.1 200 Forbidden
Connection: keep-alive
X-Powered-By: Undertow/1
Server WildFly/9 is not blacklisted
Server: WildFly/9
Content-Type: application/json
Content-Length: 42
Date: Fri, 04 Sep 2015 18:42:08 GMT

Connection #1 to host localhost left intact



回答2:

UPDATE FOR Wildfly 10

In Wildlfy 10 it is even easier to secure the management interface. First two steps are the same:

1) Prepare a key, e.g. with keytool (or you can use openSSL as well)

keytool -genkeypair -alias serverkey -keyalg RSA -keysize 2048 -validity 7360 -keystore server.keystore -keypass mypassword -storepass mypasswor

2) Add SSL into you ManagementRealm. E.g.:

<security-realm name="ManagementRealm">
    <server-identities>
        <ssl>
            <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="mypassword" alias="serverkey" key-password="mypassword"/>
        </ssl>
    </server-identities>
    <authentication>
        <local default-user="$local" skip-group-loading="true"/>
...

THE IMPORTANT DIFFERENCE IS AS FOLLOWS:

In http-interface, instead of socket-binding you have just socket.

In default it could look e.g. like the following:

        <http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
            <socket interface="management" port="${jboss.management.http.port:9990}"/>
        </http-interface>

Just change port to secure-port and the job is done.

        <http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
            <socket interface="management" secure-port="${jboss.management.http.port:9990}"/>
        </http-interface>