Securing EJBs with SSL on Wildfly 18

Wildfly has a new security framework called Elytron, which brings significant changes to how you configure Wildfly to make use of SSL for EJB connections. This post details the configuration required and shows a simple client and EJB project to demonstrate the steps needed to secure your EJB calls.

Securing EJBs with SSL on Wildfly 18

The most recent versions of Wildfly bring with them a new security framework called Elytron, which brings significant changes to how you configure Wildfly to make use of SSL for EJB connections.

This post details the configuration required and shows a simple client and EJB project to demonstrate the steps needed to secure your EJB calls.

First create the Server and Client keystore and truststore files using the script below.

#!/bin/sh
# script for re-generating the keystores and truststores needed for SSL connector

# Create server keystore - file server.keystore
keytool -genkey -v -alias jbossalias -keyalg RSA -keysize 1024 -keystore server.keystore -validity 3650 -keypass 123456 -storepass 123456 -dname "cn=Server Administrator,o=Acme,c=GB" 

# Export Server's Public Key - file server.cer
keytool -export -keystore server.keystore -alias jbossalias -file server.cer -keypass 123456 -storepass 123456

# Export Client Key Store - file client.keystore
keytool -genkey -v -alias clientalias -keyalg RSA -keysize 1024 -keystore client.keystore -validity 3650 -keypass abcdef -storepass abcdef -dname "cn=Server Administrator,o=Acme,c=GB" 

# Exporting Client's Public Key - file client.cer
keytool -export -keystore client.keystore -alias clientalias -file client.cer -keypass abcdef -storepass abcdef

# Importing Client's Public key into server's truststore
keytool -import -v -trustcacerts -alias clientalias -file client.cer -keystore server.truststore -keypass 123456 -storepass 123456

# Importing Server's Public key into client's truststore
keytool -import -v -trustcacerts -alias jbossalias -file server.cer -keystore client.truststore -keypass abcdef -storepass abcdef
Generate Keypairs

Then copy the server.keystore and server.truststore files to the Wildfly configuration directory, such as /wildfly-18.0.1.Final/standalone/configuration.

Then in the Wildfly CLI run the following commands to add the server keystore and trust manager.

#Script to create Elytron keystore-trust-manager-server-ssl-context using the default ApplicationDomain that ships with Wildfly
connect

/subsystem=elytron/key-store=server-key-store:add(path=server.keystore, relative-to=jboss.server.config.dir, credential-reference={clear-text=123456}, type=JKS)
/subsystem=elytron/key-store=server-trust-store:add(path=server.truststore, relative-to=jboss.server.config.dir, credential-reference={clear-text=123456}, type=JKS)
/subsystem=elytron/key-manager=example-key-manager:add(key-store=server-key-store, credential-reference={clear-text=123456})
/subsystem=elytron/trust-manager=example-trust-manager:add(key-store=server-trust-store)
/subsystem=elytron/server-ssl-context=example-ssl-context:add(trust-manager=example-trust-manager, key-manager=example-key-manager, need-client-auth=true, want-client-auth=true)

batch

/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=example-ssl-context)

run-batch

reload
Add server keystore & SSL context

Then in the Wildfly configuration file, we need to add a new remoting connector to make use of the https connection.

<subsystem xmlns="urn:jboss:domain:remoting:4.0">
  <http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
  <http-connector name="https-remoting-connector" connector-ref="https" security-realm="ApplicationRealm"/>
</subsystem>
Remoting connector configuration

Finally, we need to add a user to Wildfly for the EJB connection and authentication.

$ ./add-user.sh -a -u 'sslUser' -p 'sslUserPass123!'
Add wildfly user

That's it for the Widlfly server setup.

In your EJB project, create a basic EJB like the following.

package org.slsltest;

import javax.ejb.Remote;

@Remote
public interface Calculator {

	float calculateInterest(long money);

}
Calculator.java
package org.slsltest;

import javax.ejb.Stateless;

/**
 * Session Bean implementation class CalculatorEJB
 */
@Stateless
public class CalculatorEJB implements Calculator {

	float interest = 5;

	@Override
	public float calculateInterest(long money) {
		return money * (1 + (interest / 100));
	}

}
CalculatorEJB.java

Package the EJB project in an EAR or similar and deploy to your Wildfly server.

In your client project, copy the client.keystore and client.truststore files you created back at the start to the root directory. Then in a resources/META-INF directory, create the following wildfly-config.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<authentication-client xmlns="urn:elytron:1.0">
		<authentication-rules>
			<rule use-configuration="default" />
		</authentication-rules>
		<authentication-configurations>
			<configuration name="default">
				<sasl-mechanism-selector
					selector="DIGEST-MD5" />
				<set-user-name name="sslUser" />
				<credentials>
					<clear-password password="sslUserPass123!" />
				</credentials>
			</configuration>
		</authentication-configurations>
		<key-stores>
			<key-store name="client-keystore" type="JKS">
				<file name="./client.keystore" />
				<key-store-clear-password password="abcdef" />
			</key-store>
			<key-store name="client-truststore" type="JKS">
				<file name="./client.truststore" />
			</key-store>
		</key-stores>
		<ssl-contexts>
			<ssl-context name="client-ssl-context">
				<trust-store key-store-name="client-truststore" />
				<key-store-ssl-certificate
					key-store-name="client-keystore" alias="clientalias">
					<key-store-clear-password
						password="abcdef" />
				</key-store-ssl-certificate>
			</ssl-context>
		</ssl-contexts>
		<ssl-context-rules>
			<rule use-ssl-context="client-ssl-context" />
		</ssl-context-rules>
	</authentication-client>
	<jboss-ejb-client
		xmlns="urn:jboss:wildfly-client-ejb:3.0">
		<connections>
			<connection uri="remote+https://127.0.0.1:8443" />
		</connections>
	</jboss-ejb-client>
</configuration>
wildfly-config.xml

Then add the jboss-client.jar to your project's classpath (found in /wildfly-18.0.1.Final/bin/client).

Finally create a class like the below.

package org.ssltest;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.slsltest.Calculator;

public class SslTest {

	public static void main(String[] args) throws Exception {
		Calculator calculator = lookupCalculatorEJB();
		final long amount = 1000L;
		System.out.println("Calculating interest on " + amount);
		float total = calculator.calculateInterest(amount);
		System.out.println("Final amount = " + total);
	}

	private static Calculator lookupCalculatorEJB() throws NamingException {
		final Hashtable<String, String> jndiProperties = new Hashtable<>();
		jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
		final Context context = new InitialContext(jndiProperties);

		return (Calculator) context.lookup("ejb:SslTestEar/SslTestEjb/CalculatorEJB!org.slsltest.Calculator");
	}
}
SslTest.java

And that's it. Just run your project.