How can I configure JBoss EAP 7.1 so that EJB connections use 2-way SSL with PicketBox legacy security?

Solution Verified - Updated

Environment

  • Red Hat JBoss Enterprise Application Platform
    • 7.1

Issue

  • How can I configure JBoss EAP 7.1 so that EJB connections use 2-way SSL?

Resolution

Server side configuration

  1. Generate the keystore and truststores required for the 2-way SSL connection the standalone client and the JBoss server. If you don't already have certificates, you can generate self signed certificates by running the create_keystores_truststores.sh script (see below). This script creates keystores for the client and server as well as truststores for the client and server that correctly trust each other. For example, the client.truststore contains the public key from the server.keystore. Likewise, the server.truststore contains the public key from the client.keystore. These keystore/truststores are built this way to establish trust between the two servers. On the standalone client use the client.keystore and client.truststore. Copy the server.keystore and server.truststore to the configuration folder of the server (e. g. $JBOSS_HOME/standalone/configaution)

        #!/bin/sh
    
        # create_keystores_truststores.sh
        
        function create_keystore
        {
          KEY_FILE=$1
          ALIAS=$2
          DN=$3
          PASS=$4
          keytool -genkey -alias $ALIAS -keyalg RSA -keystore $KEY_FILE -storepass $PASS -keypass $PASS -dname $DN
        }
        
        function export_cert
        {
          KEY_FILE=$1
          ALIAS=$2
          EXPORT_FILE=$3
          PASS=$4
          keytool -export -alias $ALIAS -keystore $KEY_FILE -storepass $PASS -file $EXPORT_FILE
        }
        
        function import_cert
        {
          KEY_FILE=$1
          ALIAS=$2
          IMPORT_FILE=$3
          PASS=$4
          keytool -import -alias $ALIAS -keystore $KEY_FILE -storepass $PASS -file $IMPORT_FILE
        }
        
        PASSWORD="123456"
        
        create_keystore "server.keystore" "server" "CN=localhost" $PASSWORD
        create_keystore "client.keystore" "client" "CN=client" $PASSWORD
        
        export_cert "server.keystore" "server" "server_pub.key" $PASSWORD
        export_cert "client.keystore" "client" "client_pub.key" $PASSWORD
        
        import_cert "server.keystore" "client" "client_pub.key" $PASSWORD
        import_cert "client.keystore" "server" "server_pub.key" $PASSWORD
        
        import_cert "server.truststore" "client" "client_pub.key" $PASSWORD
        import_cert "client.truststore" "server" "server_pub.key" $PASSWORD
    
  2. Add a keystore and truststore to the ApplicationRealm, for example using the CLI on a standalone server like:

        [standalone@host.example.com:9990 /] /core-service=management/security-realm=ApplicationRealm/server-identity=ssl:remove()
    
        [standalone@host.example.com:9990 /] /core-service=management/security-realm=ApplicationRealm/server-identity=ssl:add(keystore-path=server.keystore, keystore-password=123456, keystore-relative-to=jboss.server.config.dir)
    
        [standalone@host.example.com:9990 /] /core-service=management/security-realm=ApplicationRealm/authentication=local:remove()
    
        [standalone@host.example.com:9990 /] /core-service=management/security-realm=ApplicationRealm/authentication=truststore:add(keystore-path=server.truststore, keystore-relative-to=jboss.server.config.dir, keystore-password=123456)
    

    XML:

        <security-realm name="ApplicationRealm">
            <server-identities>
                <ssl>
                    <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="123456"/>
                </ssl>
            </server-identities>
            <authentication>
                <truststore path="server.truststore" relative-to="jboss.server.config.dir" keystore-password="123456"/>
                <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>
    
    
  3. Configure the remoting http-connector to use https using the CLI on a standalone server like:

    [standalone@host.example.com:9990 /] /subsystem=remoting/http-connector=http-remoting-connector:write-attribute(name=connector-ref, value=https)
    

    XML:

    <subsystem xmlns="urn:jboss:domain:remoting:4.0">
        <endpoint/>
        <http-connector name="http-remoting-connector" connector-ref="https" security-realm="ApplicationRealm"/>
    </subsystem>
    
  4. Enable verify-client on the https listener using the CLI on a standalone server like:

    [standalone@host.example.com:9990 /] /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=verify-client, value=REQUIRED)
    

    XML:

    <subsystem xmlns="urn:jboss:domain:undertow:4.0">
        :
        <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" verify-client="REQUIRED" enable-http2="true"/>
            :
        </server>
        :
    </subsystem>
    

Client side configuration

  1. If you're implementing the client part as explained in How configure an EJB client in EAP 7.1 1, you need to change the PROVIDER_URL to use remote+https and the port configuration should be changed to the jboss.https.port which is 8443 by default, see:

        import org.jboss.ejb.client.EJBClient;
    
        public void callRemoteEjb() {
           HelloRemote remote = getInitialContext(host, port, user, pass).lookup("ejb:helloWorld/helloWorld-ejb/HelloWorldSLSB!org.jboss.examples.ejb.HelloRemote");
              remote.helloWorld();
        }
        public static Context getInitialContext(String host, Integer port, String username, String password) {
           Properties props = new Properties();
           props.put(Context.INITIAL_CONTEXT_FACTORY,  "org.wildfly.naming.client.WildFlyInitialContextFactory");
           props.put(Context.PROVIDER_URL, String.format("%s://%s:%d", "remote+https", host, port));
           if(username != null && password != null) {
              props.put(Context.SECURITY_PRINCIPAL, username);
              props.put(Context.SECURITY_CREDENTIALS, password);
           }
           return new InitialContext(props);
        }
    
  2. When running the standalone Java application the following system properties must be set (either directly in the code or as show below, as command line parameters):

    -Djavax.net.ssl.trustStore=${path.to}/client.truststore
    -Djavax.net.ssl.trustStorePassword=123456
    -Djavax.net.ssl.keyStore=${path.to}/client.keystore
    -Djavax.net.ssl.keyStorePassword=123456
    

Diagnostic Steps

Enable TRACE level logging on the following categories, reproduce the issue and upload the server.log file:

        <logger category="org.jboss.as.domain.management.security">
            <level name="TRACE"/>
        </logger>
        <logger category="org.jboss.remoting">
            <level name="TRACE"/>
        </logger>
        <logger category="org.jboss.sasl">
            <level name="TRACE"/>
        </logger>
        <logger category="org.jboss.as.security">
            <level name="TRACE"/>
        </logger>
        <logger category="org.jboss.security">
            <level name="TRACE"/>
        </logger>
        <logger category="org.undertow">
            <level name="TRACE"/>
        </logger>

Enable SSL/TLS debug logging by adding the following System Property to the JVM:

        - Djavax.net.debug=ssl:handshake
Category

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.