Direct Audit Information to a JMS Broker

This sample shows how to configure a Java Message Service (JMS) audit event handler to direct audit information to a JMS broker.

JMS is an API that supports Java-based peer-to-peer messages between clients. The JMS API can create, send, receive, and read messages, reliably and asynchronously. You can set up a JMS audit event handler to publish messages that comply with the Java Message Service Specification Final Release 1.1.

This sample demonstrates the use of the JMS audit event handler. In the sample you will set up communication between IDM and an external JMS Message Broker, as well as Apache Active MQ as the JMS provider and message broker.

Note

JMS topics are not related to ForgeRock audit event topics. The ForgeRock implementation of JMS topics uses the publish/subscribe messaging domain to direct messages to the JMS audit event handler. In contrast, ForgeRock audit event topics specify categories of events.

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:

  1. Unpack the ActiveMQ archive. For example:

    tar -zxvf ~/Downloads/apache-activemq-5.16.1-bin.tar
  2. 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/
  3. Create an OSGi bundle as follows:

    1. 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
    2. 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
  4. Copy the resulting activemq-client-5.16.1-osgi.jar file to the openidm/bundle directory:

    cp activemq-client-5.16.1-osgi.jar /path/to/openidm/bundle/
  5. 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.

  1. 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 an ssl <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).

  2. 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
  3. 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 using localhost to connect to the broker, you must specify localhost when keytool prompts you for the first and last name. If the CN is not the same as the hostname, the server certificate validation will fail.

  4. 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>
  5. 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/audit-jms/conf/audit.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/bundle/ directory, you can start the ActiveMQ message broker, then start IDM with the configuration for this sample.

  1. 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')
  2. Start IDM with the sample configuration:

    cd /path/to/openidm/
    ./startup.sh -p samples/audit-jms
  3. Go to the ActiveMQ Console at http://localhost:8161/admin/topics.jsp, and verify audit messages are being created and sent to the forgerock.idm.audit audit topic.

Note

If you see the following error in the OSGi console, make sure that you have installed all the required dependencies and that you have started the ActiveMQ broker.

SEVERE: Unable to create JmsAuditEventHandler 'jms': null

Configure and Use a JMS Consumer Application

To take advantage of the Apache ActiveMQ event broker, the JMS audit sample includes a Java consumer in the following directory: /path/to/openidm/samples/audit-jms/consumer/

Assuming you have Apache Maven installed on the local system, you can compile that sample consumer with the following commands:

cd /path/to/openidm/samples/audit-jms/consumer/
mvn clean install

When the build process is complete, you'll see a BUILD SUCCESS message:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 22.852 s
[INFO] Finished at: 2017-02-17T17:21:35+02:00
[INFO] Final Memory: 18M/148M
[INFO] ------------------------------------------------------------------------

Note

You might see [WARNING] messages during the build. As long as the messages end with BUILD SUCCESS, you can proceed with the JMS consumer application.

When the consumer is compiled, run the following command in the same directory to output audit messages related to IDM actions:

mvn \
exec:java \
-Dexec.mainClass="consumer.src.main.java.SimpleConsumer" \
-Dexec.args="tcp://localhost:61616"
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building SimpleConsumer 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.5.0:java (default-cli) @ SimpleConsumer ---
Downloading: https://repo.maven.apache.org/maven2/org/apache/commons/commons-exec/...
Downloaded: https://repo.maven.apache.org/maven2/org/apache/commons/commons-exec/...
Downloading: https://repo.maven.apache.org/maven2/org/apache/commons/commons-exec/...
Downloaded: https://repo.maven.apache.org/maven2/org/apache/commons/commons-exec/...
Connection factory=org.apache.activemq.ActiveMQConnectionFactory
READY, listening for messages. (Press 'Enter' to exit)

Look for the message READY, listening for messages.

If you've configured ActiveMQ on a secure port, run this command:

MAVEN_OPTS="-Djavax.net.ssl.trustStore=/path/to/openidm/security/truststore" \
mvn \
exec:java \
-Dexec.mainClass="consumer.src.main.java.SimpleConsumer" \
-Dexec.args="ssl://localhost:61617?daemon=true"

Try some actions on IDM, either in a different console or in the Admin UI. Watch the output in the SimpleConsumer console. For example, you might see output similar to the following when you run a reconciliation on the data in this sample:

{
  "auditTopic": "recon",
  "event" :{
    "transactionId": "f3e108a9-eb75-4ec8-96c5-9dc2f5137d51-176",
    "timestamp": "2017-02-17T15:25:34.899Z",
    "eventName": "recon",
    "userId": "openidm-admin",
    "exception": null,
    "linkQualifier": null,
    "mapping": "systemCsvfileAccounts_managedUser",
    "message": "SOURCE_IGNORED: 0 UNASSIGNED: 0 AMBIGUOUS: 0 CONFIRMED: ...",
    "messageDetail": {
      "_id": "f3e108a9-eb75-4ec8-96c5-9dc2f5137d51-176",
      "mapping": "systemCsvfileAccounts_managedUser",
      "state": "SUCCESS",
      "stage": "COMPLETED_SUCCESS",
      "stageDescription": "reconciliation completed.",
      "progress": {
        "source": {
          "existing": {
            "processed": "2",
            "total": "2"
          }
        }
      }
    }
  }
}
Read a different version of :