Skip to content

fix(activemq): use <users>/<authenticationUser> child elements - #215

Merged
natechadwick merged 1 commit into
mainfrom
bugfix/214-activemq-users-child-element
Sep 8, 2026
Merged

fix(activemq): use <users>/<authenticationUser> child elements#215
natechadwick merged 1 commit into
mainfrom
bugfix/214-activemq-users-child-element

Conversation

@natechadwick-intsof

Copy link
Copy Markdown
Collaborator

Summary

The activemq.xsd says userPasswords and userGroups are xs:string attributes on <simpleAuthenticationPlugin>, but the actual SimpleAuthenticationPlugin class in 5.16.8 has setters that take Map<String, ...>, not String. There is no custom property editor registered, so Spring's BeanWrapper rejects the bean init with ConversionNotSupportedException. The fix is to use the <users> / <authenticationUser> child-element pattern that the same XSD declares, and that PR #213 should have used originally.

The actual error from the install

ERROR [org.apache.activemq.xbean.XBeanBrokerFactory] Failed to load:
  class path resource [activemq.xml], reason: Error creating bean with name
  'org.apache.activemq.xbean.XBeanBrokerService#...' defined in class path
  resource [activemq.xml]: Cannot create inner bean
  'simpleAuthenticationPlugin#...' ... nested exception is
  org.springframework.beans.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

The XSD is misleading. From javap on the class in activemq-broker-5.16.8.jar:

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

— the XSD's xs:string attribute type is just wrong. The XSD needs a different element form.

The fix

Use the <users> / <authenticationUser> child-element pattern from the same activemq.xsd:

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

<authenticationUser> is the helper class org.apache.activemq.security.AuthenticationUser (3-arg String constructor and matching setters), declared in activemq.xsd as a child of the plugin's <users> element. XBean/Spring constructs the List<AuthenticationUser> from the child elements and passes it to setUsers(List<?>).

The perc-mq.xml and ear/WEB-INF/jetty-env.xml changes from PR #213 are unchanged — the broker just needs the user expressed in a form it can actually parse.

Why the XSD is wrong

Looking at the activemq.xsd in 5.16.8, both forms are declared:

<xs:element name='simpleAuthenticationPlugin'>
  <xs:complexType>
    <xs:choice minOccurs="0" maxOccurs="unbounded">
      <xs:element name='userGroups' .../>
      <xs:element name='userPasswords' .../>
      <xs:element name='users' .../>
      ...
    </xs:choice>
    <xs:attribute name='userPasswords' type='xs:string'/>  <!-- lies -->
    <xs:attribute name='userGroups' type='xs:string'/>      <!-- lies -->
    ...
  </xs:complexType>
</xs:element>

The attributes are declared as xs:string but the corresponding Java setters take Map. There is no XBean custom editor to bridge the two. The attribute form is documented as supported but isn't actually implemented in 5.16.8. The child-element form (<users> / <authenticationUser>) is the one that actually works.

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 -c "Failed to convert property value" jetty/base/logs/server.log — 0
    • grep -c "Failed to load: class path resource \[activemq.xml\]" ... — 0
    • grep -c "User name \[null\] or password is invalid" ... — 0
    • JMS listeners reach steady state without retry.

Refs #214

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

…ies about String-typed attributes)

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.
@natechadwick
natechadwick merged commit 023f4d4 into main Sep 8, 2026
3 checks passed
@natechadwick
natechadwick deleted the bugfix/214-activemq-users-child-element branch September 8, 2026 19:22
natechadwick pushed a commit that referenced this pull request Sep 9, 2026
…tional) (#217)

activemq-broker-5.16.8.pom declares activemq-jaas as <optional>true</optional>,
so Maven never pulls it in transitively. The org.apache.activemq.jaas.GroupPrincipal
class lives in activemq-jaas-5.16.8.jar (not in activemq-broker-5.16.8.jar),
so as soon as the SimpleAuthenticationPlugin(List<?>) constructor is exercised,
the JVM throws:

  NoClassDefFoundError: org/apache/activemq/jaas/GroupPrincipal

This was a latent issue under the T2.2 hardening (#166). The
<simpleAuthenticationPlugin anonymousAccessAllowed="false"/> block did not
call the List ctor (it constructed the plugin with the no-arg ctor, which
doesn't reference GroupPrincipal), so the missing class was never observed.
PR #215 changed the config to <users><authenticationUser .../></users>, which
forces the List ctor, which surfaces the missing class.

The WebUI module's pom declares dependencies on activemq-broker,
activemq-client, activemq-kahadb-store, activemq-spring, activemq-jms-pool
-- but not activemq-jaas. The root pom's dependencyManagement block is
missing activemq-jaas too. Maven respects <optional>true</optional> and
does not transitively include optional deps, so the jar is never resolved,
downloaded, or copied to WEB-INF/lib/.

Fix has two parts:
1. Add activemq-jaas to the root pom's dependencyManagement (with
   version pinned to ${activemq.version} to match the other 5.16.8
   entries).
2. Add activemq-jaas to WebUI/pom.xml as a runtime dependency.

activemq-jaas-5.16.8.jar is ~38KB; the runtime cost is negligible.

Refs #216

> 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