Chapter 7. Configuring Security 7.1. Securing Remote Connections 7.1.1. Using the Legacy Security Subsystem You can use the legacy security subsystem in JBoss EAP to secure the messaging-activemq subsystem. The legacy security subsystem uses legacy security realms and domains. See the JBoss EAP Security Architecture guide for more information on security realms and security domains . The messaging-activemq subsystem is pre-configured to use the security realm named ApplicationRealm and the security domain named other . Note The legacy security subsystem approach is the default configuration from JBoss EAP 7.0. The ApplicationRealm is defined near the top of the configuration file. <management> <security-realms> ... <security-realm name="ApplicationRealm"> <authentication> <local default-user="USDlocal" 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> </security-realms> ... </management> As its name implies, ApplicationRealm is the default security realm for all application-focused subsystems in JBoss EAP such as the messaging-activemq , undertow , and ejb3 subsystems. ApplicationRealm uses the local filesystem to store usernames and hashed passwords. For convenience JBoss EAP includes a script that you can use to add users to the ApplicationRealm . See Default User Configuration in the JBoss EAP How To Configure Server Security guide for details. The other security domain is the default security domain for the application-related subsystems like messaging-activemq . It is not explicitly declared in the configuration; however, you can confirm which security domain is used by the messaging-activemq subsystem with the following management CLI command: You can also update which security domain is used: The JBoss EAP How To Configure Server Security guide has more information on how to create new security realms and domains. For now, it is worth noting how the other domain appears in the configuration: <subsystem xmlns="urn:jboss:domain:security:2.0"> <security-domains> <security-domain name="other" cache-type="default"> <authentication> <login-module code="Remoting" flag="optional"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> <login-module code="RealmDirect" flag="required"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> </authentication> </security-domain> ... <security-domains> </subsystem> The 'other' domain uses two login-modules as its means of authentication. The first module, Remoting , authenticates remote Jakarta Enterprise Beans invocations, while the RealmDirect module uses the information store defined in a given realm to authenticate users. In this case the default realm ApplicationRealm is used, since no realm is declared. Each module has its password-stacking option set to useFirstPass , which tells the login-module to store the principal name and password of the authenticated user. See the JBoss EAP Login Module Reference for more details on the login modules and their options. Role-based access is configured at the address level, see Role Based Security for Addresses . 7.1.2. Using the Elytron Subsystem You can also use the elytron subsystem to secure the messaging-activemq subsystem. You can find more information on using the elytron subsystem and creating and Elytron security domains in the Elytron Subsystem section of How to Configure Identity Management guide. To use an Elytron security domain: Undefine the legacy security domain. Set an Elytron security domain. 7.1.2.1. Setting an Elytron Security Domain Using the Management Console To set an Elytron security domain using the management console: Access the management console. For more information, see Management Console in the JBoss EAP Configuration Guide. Navigate to Configuration Subsystems Messaging (ActiveMQ) Server default and click View . Navigate to the Security tab and click Edit . Add or edit the value of Elytron Domain . Click Save to save the changes. Reload the server for the changes to take effect. Note You can only define either security-domain or elytron-domain , but you cannot have both defined at the same time. If neither is defined, JBoss EAP will use the security-domain default value of other , which maps to the other legacy security domain. 7.1.3. Securing the Transport The default http-connector that comes bundled with JBoss EAP messaging is not secured by default. You can secure the message transport and enable web traffic for SSL/TLS by following the instructions to configure one-way and two-way SSL/TLS for applications in How to Configure Server Security for JBoss EAP. Note The above approach to secure a message transport also works for securing the http-acceptor . When you configure the transport as described above, you must perform the following additional steps. By default, all HTTP acceptors are configured to use the default http-listener , which listens on the HTTP port. You must configure HTTP acceptors to use the https-listener , which listens on the HTTPS port. The socket-binding element for all HTTP connectors must be updated to use https instead of http . Each http-connector that communicates through SSL/TLS must set the ssl-enabled parameter to true . If an HTTP connector is used to connect to another server, you must configure the related parameters such as trust-store and key-store . Securing the http-connector requires that you configure the same parameters as you do with a remote-connector , which is documented in Securing a Remote Connector . See Configuring the Messaging Transports for information about the configuring acceptors and connectors for messaging transports. 7.1.4. Securing a Remote Connector If you are not using the default http-connector and have instead created your own remote-connector and remote-acceptor for TCP communications, you can configure each for SSL/TLS by using the properties in the table below. The properties appear in the configuration as part of the child <param> elements of the acceptor or connector. Typically, a server owns its private SSL/TLS key and shares its public key with clients. In this scenario, the server defines the key-store-path and key-store-password parameters in a remote-acceptor . Since each client can have its truststore located at a different location, and be encrypted by a different password, specifying the trust-store-path and trust-store-password properties on the remote-connector is not recommended. Instead, configure these parameters on the client side using the system properties javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword . The parameters you need to configure for a remote-connector are ssl-enabled=true and useDefaultSslContext=true . However, if the server uses remote-connector to connect to another server, it makes sense in this case to set the trust-store-path and trust-store-password parameters of the remote-connector . In the above use case, the remote-acceptor would be created using the following management CLI command: To create the remote-connector from the above use case, use the following management CLI command: The management CLI also allows you to add a parameter to an already existing remote-acceptor or remote-connector as well: Note that the remote-acceptor and remote-connector both reference a socket-binding to declare the port to be used for communication. See the Overview of the Messaging Subsystem Configuration for more information on socket bindings and their relationship to acceptors and connectors. Table 7.1. SSL/TLS-related Configuration Properties for the NettyConnectorFactory Property Description enabled-cipher-suites Can be used to configure an acceptor or connector. This is a comma separated list of cipher suites used for SSL/TLS communication. The default value is null which means the JVM's default will be used. enabled-protocols Can be used to configure an acceptor or connector. This is a comma separated list of protocols used for SSL/TLS communication. The default value is null which means the JVM's default will be used. key-store-password When used on an acceptor, this is the password for the server-side keystore. When used on a connector, this is the password for the client-side keystore. This is only relevant for a connector if you are using two-way SSL/TLS. Although this value can be configured on the server, it is downloaded and used by the client. If the client needs to use a different password from that set on the server, it can override the server-side setting by either using the standard javax.net.ssl.keyStorePassword system property. Use the org.apache.activemq.ssl.keyStorePassword property if another component on the client is already making use of the standard system property. key-store-path When used on an acceptor, this is the path to the SSL/TLS keystore on the server which holds the server's certificates. Use for certificates either self-signed or signed by an authority. When used on a connector, this is the path to the client-side SSL/TLS keystore which holds the client certificates. This is only relevant for a connector if you are using two-way SSL/TLS. Although this value is configured on the server, it is downloaded and used by the client. If the client needs to use a different path from that set on the server, it can override the server-side setting by using the standard javax.net.ssl.keyStore system property. Use the org.apache.activemq.ssl.keyStore system property if another component on the client is already making use of the standard property. key-store-provider Defines the format of the file in which keys are stored, PKCS11 or PKCS12 for example. The accepted values are JDK specific. needs-client-auth This property is only for an acceptor. It tells a client connecting to this acceptor that two-way SSL/TLS is required. Valid values are true or false . Default is false . ssl-enabled Must be true to enable SSL/TLS. Default is false . trust-store-password When used on an acceptor, this is the password for the server-side truststore. This is only relevant for an acceptor if you are using two-way SSL/TLS. When used on a connector, this is the password for the client-side truststore. Although this value can be configured on the server, it is downloaded and used by the client. If the client needs to use a different password from that set on the server, it can override the server-side setting by using either the standard javax.net.ssl.trustStorePassword system property. Use the org.apache.activemq.ssl.trustStorePassword system property if another component on the client is already making use of the standard property. trust-store-path When used on an acceptor, this is the path to the server-side SSL/TLS keystore that holds the keys of all the clients that the server trusts. This is only relevant for an acceptor if you are using two-way SSL/TLS. When used on a connector, this is the path to the client-side SSL/TLS keystore which holds the public keys of all the servers that the client trusts. Although this value can be configured on the server, it is downloaded and used by the client. If the client needs to use a different path from that set on the server, it can override the server-side setting by using either the standard javax.net.ssl.trustStore system property. Use the org.apache.activemq.ssl.trustStore system property if another component on the client is already making use of the standard system property. trust-store-provider Defines the format of the file in which keys are stored, PKCS11 or PKCS12 for example. The accepted values are JDK specific. 7.2. Securing Destinations In addition to securing remote connections into the messaging server, you can also configure security around specific destinations. This is done by adding a security constraint using the security-setting configuration element. JBoss EAP messaging comes with a security-setting configured by default, as shown in the output from the following management CLI command: The security-setting option makes use of wildcards in the name field to handle which destinations to apply the security constraint. The value of a single # will match any address. For more information on using wildcards in security constraints, see Role Based Security for Addresses . 7.2.1. Role-Based Security for Addresses JBoss EAP messaging contains a flexible role-based security model for applying security to queues, based on their addresses. The core JBoss EAP messaging server consists mainly of sets of queues bound to addresses. When a message is sent to an address, the server first looks up the set of queues that are bound to that address and then routes the message to the bound queues. JBoss EAP messaging has a set of permissions that can be applied against queues based on their address. An exact string match on the address can be used or a wildcard match can be used using the wildcard characters # and * . See Address Settings for more information on how to use the wildcard syntax. You can create multiple roles for each security-setting , and there are 7 permission settings that can be applied to a role. Below is the complete list of the permissions available: create-durable-queue allows the role to create a durable queue under matching addresses. delete-durable-queue allows the role to delete a durable queue under matching addresses. create-non-durable-queue allows the role to create a non-durable queue under matching addresses. delete-non-durable-queue allows the role to delete a non-durable queue under matching addresses. send allows the role to send a message to matching addresses. consume allows the role to consume a message from a queue bound to matching addresses. manage allows the role to invoke management operations by sending management messages to the management address. Configuring Role-Based Security To start using role-based security for a security-setting , you first must create one. As an example, a security-setting of news.europe.# is created below. It would apply to any destination starting with news.europe. , such as news.europe.fr or news.europe.tech.uk . , you add a role to the security-setting you created and declare permissions for it. In the example below, the dev role is created and given permissions to consume from, and send to, queues, as well as to create and delete non-durable queues. Because the default is false , you have to tell JBoss EAP only about the permissions you want to switch on. To further illustrate the use of permissions, the example below creates an admin role and allows it to send management messages by switching on the manage permission. The permissions for creating and deleting durable queues are switched on as well: To confirm the configuration of a security-setting , use the management CLI. Remember to use the recursive=true option to get the full display of permissions: Above, the permissions for addresses that start with string news.europe. are displayed in full by the management CLI. To summarize, only users who have the admin role can create or delete durable queues, while only users with the dev role can create or delete non-durable queues. Furthermore, users with the dev role can send or consume messages, but admin users cannot. They can, however, send management messages since their manage permission is set to true . In cases where more than one match applies to a set of addresses the more specific match takes precedence. For example, the address news.europe.tech.uk.# is more specific than news.europe.tech.# . Because permissions are not inherited, you can effectively deny permissions in more specific security-setting blocks by simply not specifying them. Otherwise it would not be possible to deny permissions in sub-groups of addresses. The mapping between a user and what roles they have is handled by the security manager. JBoss EAP ships with a user manager that reads user credentials from a file on disk, and can also plug into JAAS or JBoss EAP security. For more information on configuring the security manager, see the JBoss EAP Security Architecture guide. 7.2.1.1. Granting Unauthenticated Clients the guest Role Using the Legacy Security Subsystem If you want JBoss EAP to automatically grant unauthenticated clients the guest role make the following two changes: Add a new module-option to the other security domain. The new option, unauthenticatedIdentity , will tell JBoss EAP to grant guest access to unauthenticated clients. The recommended way to do this is by using the management CLI: Note that the server requires a reload after issuing the command. You can confirm the new option by using the following management CLI command: Also, your server configuration file should look something like this after the command executes: <subsystem xmlns="urn:jboss:domain:security:2.0"> <security-domains> <security-domain name="other" cache-type="default"> <authentication> ... <login-module code="RealmDirect" flag="required"> ... <module-option name="unauthenticatedIdentity" value="guest"/> ... </login-module> ... </authentication> </security-domain> ... </security-domains> </subsystem> Uncomment the following line in the file application-roles.properties by deleting the # character. The file is located in EAP_HOME /standalone/configuration/ or EAP_HOME /domain/configuration/ , depending on whether you are using standalone servers or a domain controller respectively. Remote clients should now be able to access the server without needing to authenticate. They will be given the permissions associated with the guest role. 7.3. Controlling Jakarta Messaging ObjectMessage Deserialization Because an ObjectMessage can contain potentially dangerous objects, ActiveMQ Artemis provides a simple class filtering mechanism to control which packages and classes are to be trusted and which are not. You can add objects whose classes are from trusted packages to a white list to indicate they can be deserialized without a problem. You can add objects whose classes are from untrusted packages to a black list to prevent them from being deserialized. ActiveMQ Artemis filters objects for deserialization as follows. If both the white list and the black list are empty, which is the default, any serializable object is allowed to be deserialized. If an object's class or package matches one of the entries in the black list, it is not allowed to be deserialized. If an object's class or package matches an entry in the white list, it is allowed to be deserialized. If an object's class or package matches an entry in both the black list and the white list, the one in black list takes precedence, meaning it is not allowed to be deserialized. If an object's class or package matches neither the black list nor the white list, the object deserialization is denied, unless the white list is empty, meaning there is no white list specified. An object is considered a match if its full name exactly matches one of the entries in the list, if its package matches one of the entries in the list, or if it is a subpackage of one of the entries in the list. You can specify which objects can be deserialized on a connection-factory and on a pooled-connection-factory using the deserialization-white-list and deserialization-black-list attributes. The deserialization-white-list attribute is used to define the list of classes or packages that are allowed to be deserialized. The deserialization-black-list attribute is used to define the list of classes or packages that are not allowed to be deserialized. The following commands create a black list for the RemoteConnectionFactory connection factory and a white list for the activemq-ra pooled connection factory for the default server. /subsystem=messaging-activemq/server=default/connection-factory=RemoteConnectionFactory:write-attribute(name=deserialization-black-list,value=[my.untrusted.package,another.untrusted.package]) /subsystem=messaging-activemq/server=default/pooled-connection-factory=activemq-ra:write-attribute(name=deserialization-white-list,value=[my.trusted.package]) These commands generate the following configuration in the messaging-activemq subsystem. <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector" ha="true" block-on-acknowledge="true" reconnect-attempts="-1" deserialization-black-list="my.untrusted.package another.untrusted.package"/> <pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" deserialization-white-list="my.trusted.package" transaction="xa"/> For information about connection factories and pooled connection factories, see Configuring Connection Factories in this guide. You can also specify which objects can be deserialized in an MDB by configuring the activation properties. The deserializationWhiteList property is used to define the list of classes or packages that are allowed to be deserialized. The deserializationBlackList property is used to define the list of classes or packages that are not allowed to be deserialized. For more information about activation properties, see Configuring MDBs Using a Deployment Descriptor in Developing Jakarta Enterprise Beans Applications for JBoss EAP. 7.4. Authorization Invalidation Management The security-invalidation-interval attribute on the server in the messaging-activemq subsystem determines how long an authorization is cached before an action must be re-authorized. When the system authorizes a user to perform an action at an address, the authorization is cached. The time the same user performs the same action at the same address, the system uses the cached authorization for the action. For example, the user admin attempts to send a message to the address news . The system authorizes the action, and caches the authorization. The time admin attempts to send a message to news , the system uses the cached authorization. If the cached authorization is not used again within the time specified by the invalidation interval, the authorization is cleared from the cache. The system must re-authorize the user to perform the requested action at the requested address. After installation, JBoss EAP assumes a default value of 10000 milliseconds (10 seconds). The security-invalidation-interval attribute is configurable. For example, the following command updates the interval to 60000 milliseconds (60 seconds or one minute). You must reload the server for the modification of the configuration to take effect. Reading the attribute shows the new result.

Commands:
<management> <security-realms> <security-realm name="ApplicationRealm"> <authentication> <local default-user="USDlocal" 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> </security-realms> </management>
/subsystem=messaging-activemq/server=default:read-attribute(name=security-domain) { "outcome" => "success", "result" => "other" }
/subsystem=messaging-activemq/server=default:write-attribute(name=security-domain, value=mySecurityDomain)
<subsystem xmlns="urn:jboss:domain:security:2.0"> <security-domains> <security-domain name="other" cache-type="default"> <authentication> <login-module code="Remoting" flag="optional"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> <login-module code="RealmDirect" flag="required"> <module-option name="password-stacking" value="useFirstPass"/> </login-module> </authentication> </security-domain> <security-domains> </subsystem>
/subsystem=messaging-activemq/server=default:undefine-attribute(name=security-domain)
/subsystem=messaging-activemq/server=default:write-attribute(name=elytron-domain, value=myElytronSecurityDomain) reload
/subsystem=messaging-activemq/server=default/remote-acceptor=mySslAcceptor:add(socket-binding=netty,params={ssl-enabled=true, key-store-path= PATH/TO /server.jks, key-store-password=USD{VAULT::server-key::key-store-password::sharedKey}})
/subsystem=messaging-activemq/server=default/remote-connector=mySslConnector:add(socket-binding=netty,params={ssl-enabled=true, useDefaultSslContext=true})
/subsystem=messaging-activemq/server=default/remote-connector=myOtherSslConnector:map-put(name=params,key=ssl-enabled,value=true)
/subsystem=messaging-activemq/server=default:read-resource(recursive=true) { "outcome" => "success", "result" => { . "security-setting" => {"#" => {"role" => {"guest" => { "consume" => true, "create-durable-queue" => false, "create-non-durable-queue" => true, "delete-durable-queue" => false, "delete-non-durable-queue" => true, "manage" => false, "send" => true }}}} } }
/subsystem=messaging-activemq/server=default/security-setting=news.europe.#:add() {"outcome" => "success"}
/subsystem=messaging-activemq/server=default/security-setting=news.europe.#/role=dev:add(consume=true,delete-non-durable-queue=true,create-non-durable-queue=true,send=true) {"outcome" => "success"}
/subsystem=messaging-activemq/server=default/security-setting=news.europe.#/role=admin:add(manage=true,create-durable-queue=true,delete-durable-queue=true) {"outcome" => "success"}
/subsystem=messaging-activemq/server=default:read-children-resources(child-type=security-setting,recursive=true) { "outcome" => "success", "result" => { "#" => {"role" => {"guest" => { "consume" => true, "create-durable-queue" => false, "create-non-durable-queue" => true, "delete-durable-queue" => false, "delete-non-durable-queue" => true, "manage" => false, "send" => true }}}, "news.europe.#" => {"role" => { "dev" => { "consume" => true, "create-durable-queue" => false, "create-non-durable-queue" => true, "delete-durable-queue" => false, "delete-non-durable-queue" => true, "manage" => false, "send" => true }, "admin" => { "consume" => false, "create-durable-queue" => true, "create-non-durable-queue" => false, "delete-durable-queue" => true, "delete-non-durable-queue" => false, "manage" => true, "send" => false } }} }
/subsystem=security/security-domain=other/authentication=classic/login-module=RealmDirect:map-put(name=module-options,key=unauthenticatedIdentity,value=guest) { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } }
/subsystem=security/security-domain=other/authentication=classic/login-module=RealmDirect:read-resource() { "outcome" => "success", "result" => { "code" => "RealmDirect", "flag" => "required", "module" => undefined, "module-options" => { "password-stacking" => "useFirstPass", "unauthenticatedIdentity" => "guest" } } }
<subsystem xmlns="urn:jboss:domain:security:2.0"> <security-domains> <security-domain name="other" cache-type="default"> <authentication> <login-module code="RealmDirect" flag="required"> <module-option name="unauthenticatedIdentity" value="guest"/> </login-module> </authentication> </security-domain> </security-domains> </subsystem>
#guest=guest
/subsystem=messaging-activemq/server=default/connection-factory=RemoteConnectionFactory:write-attribute(name=deserialization-black-list,value=[my.untrusted.package,another.untrusted.package]) /subsystem=messaging-activemq/server=default/pooled-connection-factory=activemq-ra:write-attribute(name=deserialization-white-list,value=[my.trusted.package])
<connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector" ha="true" block-on-acknowledge="true" reconnect-attempts="-1" deserialization-black-list="my.untrusted.package another.untrusted.package"/> <pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" deserialization-white-list="my.trusted.package" transaction="xa"/>
/subsystem=messaging-activemq/server=default:read-attribute(name=security-invalidation-interval) { "outcome" => "success", "result" => 10000L }
/subsystem=messaging-activemq/server=default:write-attribute(name=security-invalidation-interval,value=60000) { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } }
/subsystem=messaging-activemq/server=default:read-attribute(name=security-invalidation-interval) { "outcome" => "success", "result" => 60000L }