Skip to content

fix(activemq): add in-VM user credentials to simpleAuthenticationPlugin + ConnectionFactory - #213

Merged
natechadwick merged 2 commits into
mainfrom
bugfix/212-activemq-vm-credentials
Sep 8, 2026
Merged

fix(activemq): add in-VM user credentials to simpleAuthenticationPlugin + ConnectionFactory#213
natechadwick merged 2 commits into
mainfrom
bugfix/212-activemq-vm-credentials

Conversation

@natechadwick-intsof

Copy link
Copy Markdown
Collaborator

Summary

Adds credentials to the in-VM ActiveMQConnectionFactory (in both perc-mq.xml and ear/WEB-INF/jetty-env.xml) and a matching user to the simpleAuthenticationPlugin in activemq.xml, so the in-VM JMS connection can authenticate against the T2.2-hardened broker. Without this, every JMS listener gets User name [null] or password is invalid and retries in a 5-second loop.

Why this is needed

The T2.2 PR (#166/#167) set <simpleAuthenticationPlugin anonymousAccessAllowed="false"/> but did not add any users and did not update the in-VM ActiveMQConnectionFactory configurations. The in-VM transport (vm://localhost) sends anonymous (no creds) connections by default, so the broker rejects every connection attempt:

WARN  [org.apache.activemq.broker.TransportConnection] Failed to add Connection ...
  due to User name [null] or password is invalid.
ERROR [org.springframework.jms.listener.DefaultMessageListenerContainer]
  Could not refresh JMS Connection for destination 'queue://PERCUSSION.EMAIL'
  - retrying using FixedBackOff{interval=5000, currentAttempts=37, maxAttempts=unlimited}.
  Cause: User name [null] or password is invalid.

currentAttempts=37 after ~3 minutes is what the user is seeing.

Diff

activemq.xml:

       <plugins>
-          <simpleAuthenticationPlugin anonymousAccessAllowed="false"/>
+          <simpleAuthenticationPlugin
+              anonymousAccessAllowed="false"
+              userPasswords="rhythmyx=rhythmyx"
+              userGroups="rhythmyx=users,admins"/>
       </plugins>

perc-mq.xml and ear/WEB-INF/jetty-env.xml:

      <New class="org.apache.activemq.ActiveMQConnectionFactory">
        <Arg>vm://localhost?brokerConfig=xbean:activemq.xml</Arg>
+       <Set name="userName"><Property name="activemq.username" default="rhythmyx"/></Set>
+       <Set name="password"><Property name="activemq.password" default="rhythmyx"/></Set>
     </New>

Security posture

The T2.2 hardening intent ("auth in place so a future network listener inherits the secure defaults") is preserved:

  • anonymousAccessAllowed="false" — anonymous connections are still rejected.
  • The default SimpleAuthorizationMap (no explicit <simpleAuthorizationMap>) allows the rhythmyx user in users,admins groups to read/write/admin on all destinations. This is the same effective policy as before the hardening for the in-VM case.
  • The default password (rhythmyx) is a placeholder. Operators opening a network listener MUST change it (and add a per-listener user) before adding any <transportConnector>. The comment in activemq.xml points at this requirement.
  • The connection factory reads userName and password from system properties (activemq.username, activemq.password) via Jetty's <Property> indirection with rhythmyx defaults — operators can override at install time without rebuilding, e.g. via -Dactivemq.username=... in start.ini.

Depends on #211

This branch is built on top of bugfix/210-activemq-pending-message-limit-strategy (PR #211), which fixes the activemq.xml XSD validity issues. Without #211, the broker can't even start, so this auth fix is moot. After both PRs merge, the in-VM connection should work end-to-end.

Verification

  • python3 -c "import xml.etree.ElementTree as ET; ET.parse('activemq.xml')" — well-formed.
  • xmllint --schema activemq.xsd activemq.xml --noout — exits 0.
  • After deploy + restart:
    • grep "User name" jetty/base/logs/server.log | wc -l → 0
    • The currentAttempts counter on the JMS listener retry messages stops climbing
    • PERCUSSION.EMAIL, PERCUSSION.PUBLISHING, PERCUSSION.NOTIFICATIONS all reach steady state without retry

Refs #212

Co-Authored by Mavis Mavis-Code using MiniMax-M3 with agent mavis.

After PR #208/#209 restored the xmlns on <broker> (so the XSD loads),
the post-T2.12 default DocumentBuilderFactory keeps validating and
catches the next layer of T2.2 element-name bugs in the same file:

  SAXParseException; lineNumber: 61; columnNumber: 68;
  cvc-complex-type.2.4.a: Invalid content was found starting with element
  '{"http://activemq.apache.org/schema/core":constantPendingMessageLimit}'.
  One of '{"http://activemq.apache.org/schema/core":fileQueueCursor,
  "http://activemq.apache.org/schema/core":storeCursor,
  "http://activemq.apache.org/schema/core":vmQueueCursor,
  WC[##other:"http://activemq.apache.org/schema/core"]}' is expected.

The T2.2 PR mixed up two superficially similar ActiveMQ policy
mechanisms that do very different things:

  T2.2 wrote           XSD expects                 What it controls
  ---------------      ----------------------      -------------------
  <pendingQueuePolicy> <pendingMessageLimitStrategy> (parent) cap on count
                                                    per consumer
  <constantPending-    <constantPending-            (child) constant
  MessageLimit         MessageLimitStrategy          cap with 'limit'
  value="1000"/>       limit="1000"/>                attribute

<pendingQueuePolicy> selects the queue cursor (fileQueueCursor /
storeCursor / vmQueueCursor) -- i.e., how pending messages are *stored*,
not how many are kept. The XSD's <xs:any namespace='##other'/> wildcard
on that element does NOT allow <constantPendingMessageLimit> because the
element is in the same ActiveMQ namespace, not a different one. Hence
"Invalid content was found starting with element constantPendingMessageLimit."

Fix: replace the wrong parent/child pair with the correct XSD-valid
<pendingMessageLimitStrategy>/<constantPendingMessageLimitStrategy> pair,
and use the `limit` attribute (not `value`). The "cap pending message
count per queue" intent of the original T2.2 block is preserved.

This PR also pulls in the #208 fix (xmlns on <broker> + the explanatory
comment). The #208 PR (#209) is still open and is superseded by this one;
it can be closed without merging.

Refs #208, #210

> Co-Authored by Mavis Mavis-Code using MiniMax-M3 with agent mavis.
…in + ConnectionFactory

The T2.2 ActiveMQ hardening PR (#166/#167) configured
`<simpleAuthenticationPlugin anonymousAccessAllowed="false"/>` but did
not add any users and did not update the in-VM ActiveMQConnectionFactory
in perc-mq.xml / ear/WEB-INF/jetty-env.xml to provide credentials. The
in-VM transport (vm://localhost) sends anonymous (no user / no password)
connections by default, so every JMS listener (PERCUSSION.EMAIL,
PERCUSSION.PUBLISHING, PERCUSSION.NOTIFICATIONS) gets
`User name [null] or password is invalid` and retries in a 5-second
FixedBackOff loop (currentAttempts climbs to 30+ within a minute).

Fix has three parts:

1. activemq.xml: add a single 'rhythmyx' user to the
   simpleAuthenticationPlugin via the userPasswords and userGroups
   attributes. userGroups 'users,admins' grants both consume/produce
   on queues/topics and admin operations; the default ActiveMQ
   SimpleAuthorizationMap is permissive (no <simpleAuthorizationMap>
   is required to grant access to PERCUSSION.* queues).
   anonymousAccessAllowed stays 'false' so the security posture is
   preserved for any future network listener.

2. perc-mq.xml: configure the Jetty-bound ActiveMQConnectionFactory
   (java:/ConnectionFactory) with setUserName / setPassword via Jetty's
   <Property> indirection. Operators can override the default at
   install time via -Dactivemq.username=... / -Dactivemq.password=...

3. ear/WEB-INF/jetty-env.xml: same change for the webapp-scoped
   ActiveMQConnectionFactory (jms/ConnectionFactory).

Default credentials are 'rhythmyx' / 'rhythmyx' (placeholder, not a
secret). Operators opening a network listener (adding a
<transportConnector>) MUST change the password and add a per-listener
user. The comment in activemq.xml points at this requirement.

This PR is built on top of #211 (the activemq.xml XSD-validity fixes);
once both merge, the broker should start cleanly, the in-VM connection
should authenticate, and the JMS listeners should reach steady state
without retries.

Refs #212

> Co-Authored by Mavis Mavis-Code using MiniMax-M3 with agent mavis.
@natechadwick
natechadwick merged commit 8c89573 into main Sep 8, 2026
3 checks passed
@natechadwick
natechadwick deleted the bugfix/212-activemq-vm-credentials branch September 8, 2026 18:22
natechadwick pushed a commit that referenced this pull request Sep 8, 2026
…ies about String-typed attributes) (#215)

The activemq.xsd advertises userPasswords and userGroups as xs:string
attributes on <simpleAuthenticationPlugin>, but the actual
org.apache.activemq.security.SimpleAuthenticationPlugin class in 5.16.8
has setters that take Map<String,...>, not String:

  public void setUserPasswords(java.util.Map<java.lang.String, java.lang.String>);
  public void setUserGroups(java.util.Map<java.lang.String, java.util.Set<java.security.Principal>>);

There is no custom property editor registered, so Spring's BeanWrapper
rejects the activemq.xml bean init with:

  ConversionNotSupportedException: Failed to convert property value of
  type 'java.lang.String' to required type 'java.util.Map' for property
  'userGroups': no matching editors or conversion strategy found

PR #213 used the attribute form because that's what the XSD implied;
that form is unusable. The correct XBean syntax is the <users> /
<authenticationUser> child-element pattern (the <authenticationUser>
helper class is in the same activemq-spring-5.16.8.jar, has a 3-arg
String constructor AuthenticationUser(String username, String password,
String groups), and is declared in the same activemq.xsd as a child of
the plugin's <users> element):

  <simpleAuthenticationPlugin anonymousAccessAllowed="false">
    <users>
      <authenticationUser username="rhythmyx" password="rhythmyx" groups="users,admins"/>
    </users>
  </simpleAuthenticationPlugin>

The connection-factory changes from PR #213 (perc-mq.xml and
ear/WEB-INF/jetty-env.xml) are unchanged; the broker just needs the
correct user representation.

Refs #214

> Co-Authored by Mavis Mavis-Code using MiniMax-M3 with agent mavis.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants