Subscribe to JMS Messages
IDM can subscribe to Java Messaging Service (JMS) messages using the Messaging Service's JMS Subscriber. In an event-driven architecture, also known as a message-driven architecture, there are publishers and subscribers. When a publisher sends a message over JMS, that message is broadcast. All active and subscribed clients receive that message. This sample shows how IDM can act as a JMS message subscriber, using the ActiveMQ JMS message broker.
Note
For more information on how IDM can publish JMS messages using the JMS Audit Event Handler, see Direct Audit Information to a JMS Broker
Sample Overview
With the scripted message handler shown in this sample, you can configure scripts to parse the contents of JMS messages, and act on that content.
The script in this sample, crudpaqTextMessageHandler.js
, shows how JMS can handle ForgeRock REST operations. If you customize a script to manage JMS messages, you must also modify the conf/messaging.json
file.
This sample uses ActiveMQ, a JMS message broker. With the ActiveMQ UI, you can act as the JMS message provider. This sample demonstrates how you can input REST payloads through the ActiveMQ UI.
Dependencies for JMS Messaging
The JMS audit event handler requires ActiveMQ, and a number of dependencies, that are bundled with the ActiveMQ delivery. This section lists the dependencies, and where they must be installed in the IDM instance. If you use a different ActiveMQ version, you might need to download the corresponding dependencies separately.
Download the following files:
ActiveMQ. This sample was tested with ActiveMQ Classic 5.16.1.
The most recent
bnd
JAR file from https://repo1.maven.org/maven2/biz/aQute/bnd/biz.aQute.bnd/. The bnd utility lets you create OSGi bundles for libraries that do not yet support OSGi.
Unpack the ActiveMQ archive. For example:
tar -zxvf ~/Downloads/apache-activemq-5.16.1-bin.tar
Create a temporary directory, move the ActiveMQ Client, and
bnd
JAR files to that directory, then change to that directory:mkdir ~/Downloads/tmp mv ~/Downloads/apache-activemq-5.16.1/lib/activemq-client-5.16.1.jar ~/Downloads/tmp/ mv biz.aQute.bnd-version.jar ~/Downloads/tmp/ cd ~/Downloads/tmp/
Create an OSGi bundle as follows:
In a text editor, create a BND file named
activemq.bnd
and save it to the current directory. The file should have the following contents:version=5.16.1 Export-Package: *;version=${version} Bundle-Name: ActiveMQ :: Client Bundle-SymbolicName: org.apache.activemq Bundle-Version: ${version}
Your
tmp/
directory should now contain the following files:ls ~/Downloads/tmp/
activemq-client-5.16.1.jar activemq.bnd biz.aQute.bnd-version.jar
In that same directory, create the OSGi bundle archive file as follows:
java -jar biz.aQute.bnd-version.jar \ wrap --properties activemq.bnd \ --output activemq-client-5.16.1-osgi.jar \ activemq-client-5.16.1.jar
Copy the resulting
activemq-client-5.16.1-osgi.jar
file to theopenidm/bundle
directory:cp activemq-client-5.16.1-osgi.jar /path/to/openidm/bundle/
Copy the required dependencies from the extracted ActiveMQ archive to the
openidm/bundle
directory:cp ~/Downloads/apache-activemq-5.16.1/lib/geronimo-j2ee-management_1.1_spec-1.0.1.jar /path/to/openidm/bundle/ cp ~/Downloads/apache-activemq-5.16.1/lib/hawtbuf-1.11.jar /path/to/openidm/bundle/ cp ~/Downloads/apache-activemq-5.16.1/lib/optional/jmdns-3.4.1.jar /path/to/openidm/bundle cp ~/Downloads/apache-activemq-5.16.1/lib/optional/commons-net-3.7.2.jar /path/to/openidm/bundle
Configure SSL for ActiveMQ
This configuration provides a connection to the ActiveMQ server instance with TLSv1.3.
In the directory where you unpacked ActiveMQ, edit the
conf/activemq.xml
file as follows:In the
<brokers>
element, add an<sslContext>
:<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}"> ... <sslContext> <sslContext keyStore="file:${activemq.conf}/broker.ks" keyStorePassword="password"/> </sslContext> ... </broker>
In the
<transportConnectors>
element, add anssl
<transportConnector>
:<transportConnectors> ... <transportConnector name="ssl" uri="ssl://0.0.0.0:61617?transport.needClientAuth=false"/> </transportConnectors>
Note
To enable mutual authentication, set
transport.needClientAuth=true
, and import the IDM server certificate into the ActiveMQ truststore (conf/broker.ts
).
Delete the existing self-signed server certificate from the ActiveMQ keystore and truststore:
keytool \ -delete \ -keystore /path/to/activeMQ/conf/broker.ts \ -alias broker-localhost
Enter keystore password:
password keytool \ -delete \ -keystore /path/to/activeMQ/conf/broker.ks \ -alias broker-localhost
Enter keystore password:
password
Generate a new self-signed server certificate for ActiveMQ:
keytool \ -genkey \ -keyalg RSA \ -alias broker-localhost \ -keystore /path/to/activeMQ/conf/broker.ks \ -storepass password \ -validity 360 \ -keysize 2048
Important
The
CN
in the generated self-signed certificate must match the hostname that you specify in the IDM JMS provider URL. If you are usinglocalhost
to connect to the broker, you must specifylocalhost
when keytool prompts you for thefirst and last name
. If theCN
is not the same as the hostname, the server certificate validation will fail.Export the ActiveMQ server certificate:
keytool \ -export \ -alias broker-localhost \ -file broker-localhost.key \ -keystore /path/to/activeMQ/conf/broker.ks
Enter keystore password:
password
Certificate stored in file <broker-localhost.key>
Import the ActiveMQ server certificate into the IDM truststore:
keytool \ -import \ -alias activemq \ -keystore /path/to/openidm/security/truststore \ -file broker-localhost.key
Enter keystore password:
changeit
Owner: CN=localhost, OU=Unknown, O=example.com, L=Unknown, ST=Unknown, C=Unknown Issuer: CN=localhost, OU=Unknown, O=example.com, L=Unknown, ST=Unknown, C=Unknown ... Trust this certificate? [no]:
yes
Certificate was added to keystore
Configure a Secure Port for JMS Messages
Edit /path/to/openidm/samples/scripted-jms-subscriber/conf/messaging.json
, as follows:
"java.naming.provider.url" : "ssl://localhost:61617?daemon=true"
Start the ActiveMQ Broker and IDM
With the appropriate bundles in the /path/to/openidm/bundles
directory, you're ready to start the ActiveMQ message broker, as well as IDM with the JMS Audit Sample.
Navigate to the directory where you unpacked the ActiveMQ binary and run the following command to start the ActiveMQ broker:
cd ~/Downloads/apache-activemq-5.16.1 bin/activemq start
INFO: Loading '/path/to/Downloads/apache-activemq-5.16.1/bin/env' INFO: Using java '/usr/bin/java' INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details INFO: pidfile created : '/path/to/Downloads/apache-activemq-5.16.1/data/activemq.pid' (pid '69627')
Start IDM, with the configuration for this sample:
cd /path/to/openidm/ ./startup.sh -p samples/scripted-jms-subscriber
Go to the ActiveMQ Console at
http://localhost:8161/admin/topics.jsp
, and verify audit messages are being created and sent to theforgerock.idm.audit
audit topic.
Access the REST Interface Using the ActiveMQ UI
In this section, you will run REST calls through the ActiveMQ UI. This assumes you started ActiveMQ and IDM in "Start the ActiveMQ Broker and IDM".
Access the ActiveMQ web console, at
http://localhost:8161/admin
. Log in as an administrator; the default administrative user and password areadmin
andadmin
.In the ActiveMQ web console, in the Queue Name text box, enter the value of
idmQ
from theconf/messaging.json
file. The default value forqueue.idmQ
anddestinationName
isidmQ
. Enter that value and select Create.In the Queues window for the
idmQ
queue, select theSend To
link under Operations.You should see a
Send a JMS Message
window, with aMessage body
text box towards the bottom.Copy the following text, a payload to create a new user with a user ID of
mgr1
, to theMessage body
text box:{ "operation" : "CREATE", "resourceName" : "/managed/user", "newResourceId" : "mgr1", "content" : { "mail" : "mgr1@example.com", "sn" : "Sanchez", "givenName" : "Jane", "password" : "Password1", "employeenumber" : 100, "accountStatus" : "active", "roles" : [ ], "userName" : "mgr1" }, "params" : {}, "fields" : [ "*", "*_ref" ] }
For comparison, note the following equivalent REST call to create the same user:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "mail" : "mgr1@example.com", "sn" : "Sanchez", "givenName" : "Jane", "password" : "Password1", "employeenumber" : 100, "accountStatus" : "active", "roles" : [ ], "userName" : "mgr1", "params" : {}, "fields" : [ "*", "*_ref" ] }' \ "http://localhost:8080/openidm/managed/user?_action=create"
Observe the OSGi console. You should see output in two parts. The first part starts with:
*****request received****** Parsed JMS JSON = ...
The first part should include a JSON-formatted replay of the request that you entered in the
Message body
text box.The second part of the output includes information for that same user, as written to the managed user repository.
Confirm that user either in the Admin UI, or using the following REST call:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request GET \ "http://localhost:8080/openidm/managed/user/mgr1"
Repeat the process to create additional users. Try a different REST function. For example, you can enter the following payload in the ActiveMQ UI
Message body
text box, to change the first name (givenName
) of themgr1
user to Donna:{ "operation": "PATCH", "resourceName": "/managed/user/mgr1", "value": [ { "operation": "replace", "field": "/givenName", "value": "Donna" } ] }
Customize the Scripted JMS Sample
If you set up a custom script to parse and process JMS messages, store that script in the script/
subdirectory. Assume that script is named myCustomScript.js
.
Edit the messaging.json
file in the conf/
subdirectory, and point it to that file:
{ "subscribers" : [ { "name" : "IDM CREST Queue Subscriber", "instanceCount": 3, "enabled" : true, "type" : "JMS", "handler" : { "type" : "SCRIPTED", "properties" : { "script" : { "type" : "text/javascript", "file" : "myCustomScript.js" } } }, "properties" : { "sessionMode" : "CLIENT", "jndi" : { "contextProperties" : { "java.naming.factory.initial" : "org.apache.activemq.jndi.ActiveMQInitialContextFactory", "java.naming.provider.url" : "tcp://127.0.0.1:61616?daemon=true", "queue.idmQ" : "idmQ" }, "destinationName" : "idmQ", "connectionFactoryName" : "ConnectionFactory" } } } ] }
You'll find some of these properties in "JMS Audit Event Handler Properties". Despite the name of the table and the different configuration file, the properties are the same.
Other properties of interest in the messaging.json
file are shown in the following table:
messaging.json
Configuration Propertiesmessaging.json File Label | Description |
---|---|
subscribers | Needed to subscribe to incoming JMS message requests. |
name | Arbitrary name for the subscriber. |
instanceCount | Each instanceCount manages a single connection between IDM and the messaging channel. Supports multithreading throughput. If subscribing to a queue, such as queue.idmQ , the message is handled by a single instance. If subscribing to a topic, all instances receive and handle the same message. |
handler | Parses the JMS message, then processes it, possibly through a script. |
queue.idmQ | One of the JNDI context properties. Name of the JMS queue in the ActiveMQ UI. |
destinationName | JNDI lookup name for message delivery. |