How to secure JMS destinations in WildFly

Ensuring the security of JMS destinations is key to protect sensitive data and prevent unauthorized access. In this article, we will explore how to secure JMS destinations with roles in the WildFly application server.

The default Security Domain of Messaging Subsystem

By default the embedded Artemis MQ in WildFly uses a Security Domain to protect the access of JMS Destinations using a Role Based Access Control. You can verify the current (Elytron) Security Domain of an Artemis Server with the following CLI command:

/subsystem=messaging-activemq/server=default:read-attribute(name=elytron-domain)
{
    "outcome" => "success",
    "result" => "ApplicationDomain"
}

On the other hand, older WildFly releases configure the (Legacy) Security Domain with the attribute “security-domain”.

/subsystem=messaging-activemq/server=default:read-attribute(name=security-domain)
{
    "outcome" => "success",
    "result" => "other"
}

Within this article we will be using Elytron as Security Infrastructure, therefore by default our Security Domain is “ApplicationDomain”.

To add an user into the ApplicationDomain you can use the add-user.sh script which stores Identities into the ApplicationDomain.

For example, to add an user “demouser” with “password” as password into the “guest” Group, you can use the following command:

./add-user.sh -a -u demouser -p password -g guest

Messaging Security Settings

By default, the messaging-activemq subsystem uses a single security-settings element which secures all destinations:

 <subsystem xmlns="urn:jboss:domain:messaging-activemq:15.0">
            <server name="default">
                <security elytron-domain="ApplicationDomain"/>
                <statistics enabled="${wildfly.messaging-activemq.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
                <security-setting name="#">
                    <role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
                </security-setting>

As you can see, the default “guest” Role has permission to:

  • send messages
  • consume messages
  • create non durable queues
  • delete non durable queues

Since our Application User belongs to the “guest” Role, we will use it to test sending messages from a remote JMS Client to WIldFly.

Testing Messaging Security

Start WildFly application Server using a full (or full-ha) profile. For example:

./standalone.sh -c standalone-full.xml

For testing purposes, you can use a JMS Client available in the WIldFly quickstarts: https://github.com/wildfly/quickstart/tree/main/helloworld-jms

This example requires creating a JMS destination on the server. You can use the CLI for this purpose:

jms-queue add --queue-address=testQueue --entries=queue/test,java:jboss/exported/jms/queue/test

Then, compile and run the quickstart as follows:

mvn clean install -Dusername=demouser -Dpassword=password exec:java

You should be able to verify that a JMS Messages successfully receives the destination:

wildfly secure destinations

Creating fine grained Security Settings

The value of a single # will match any address available in a JMS Server. This is often not ideal as you might want to have different settings for your destinations.

For example, to define a configuration that is valid only for the “jms.queue.testQueue” Destination you can use the following security-setting:

<security-setting name="jms.queue.testQueue">
    <role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
</security-setting>

As you can see from the above configuration, the security-setting name is generated by adding a prefix to the destination object name. The prefixes are:

  • jms.queue. for jms-queue objects, that is, JMS Queue resources.
  • jms.topic. for jms-topic objects, that is, JMS Topic resources.

Finally, if multiple security-setting objects match the same destination, the most specific one overrides the generic ones

Changing the default Security Domain

In Production system you will probably use a more advanced Elytron Security Realm (such as LDAP or Database) to protect your resources. When you define your custom Elytron Security Domain you can apply it to your JMS Server by setting the elytrond-domain attribute. For example:

/subsystem=messaging-activemq/server=default:write-attribute(name=elytron-domain, value=myElytronSecurityDomain)

reload

To learn more about configuring Elytron Realms and Security Domain refer to this article: Creating an Elytron Security Realm for WildFly

Conclusion

This article was a walkthrough the Security Settings of WildFly JMS Destinations. We have discussed how to secure the send/receive of JMS messages using the default Security Domain and how to apply fine-grained JMS Security Settings