Generate JMS admin password of the broker on first run (fixes CVE-2026-22886) - #26148
Generate JMS admin password of the broker on first run (fixes CVE-2026-22886)#26148OndroMih wants to merge 4 commits into
Conversation
Generates the password for both the client and in the broker configuration to keep them in synch.
8ac385a to
a6e2bf7
Compare
If the password is generated lazily and jms-ping is the initiator of this (nothing else connected to the JMS broker before), the jms-ping command has no way to know the generated password. it first uses the default password, fails, and retries if the password was generated and is now different from the previous (default) password.
Using admin was a hack and doesn't work anymore as admin's password is generated. The test needs to create a new test user and use it for JMS resources. The create-jms-user mechanism in build.xml is a copy of a similar mechanism in the varhome test
e79c13f to
30e0ed5
Compare
|
@pzygielo , do you think it's worth porting this directly to the OpenMQ resource adapter? My new GlassFishResourceAdapter doesn't use any GlassFish-specific features, it only relies on the value of the "AdminPassword" property and updated the admin password in the broker config when the broker is created. It could also accept a property toggle, e.g. "UpdateAdminPassword" and only upadte the admin password if it's true. |
There was a problem hiding this comment.
Pull request overview
This PR mitigates CVE-2026-22886 by ensuring managed (Embedded/Local) OpenMQ brokers do not retain the well-known default admin password on first creation, and aligns docs/tests with the new behavior.
Changes:
- Generate and persist a randomized OpenMQ admin password in GlassFish config when a managed broker is created for the first time, and synchronize the broker’s password repository accordingly.
- Update
jms-pingto handle the “lazy broker creation + password generation” timing by retrying with the updated credentials. - Adjust devtests and add an integration test to ensure default OpenMQ admin credentials can no longer access the admin service; update documentation to explain how to retrieve/change the generated password.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/administration-guide/src/main/asciidoc/jms.adoc | Documents autogenerated admin password behavior and how to retrieve/change it. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/servlet/Servlet.java | Switches devtest connection factories off admin/admin to a dedicated test user. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/ejb/HelloStatefulEJB.java | Switches devtest connection factories off admin/admin to a dedicated test user. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/ejb/HelloEJB.java | Switches devtest connection factories off admin/admin to a dedicated test user. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/descriptor/web.xml | Updates descriptor-defined JMS CF credentials to use the dedicated test user. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/descriptor/ejb-jar.xml | Updates descriptor-defined JMS CF credentials to use the dedicated test user. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/descriptor/application.xml | Updates descriptor-defined JMS CF credentials to use the dedicated test user. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/descriptor/application-client.xml | Updates descriptor-defined JMS CF credentials to use the dedicated test user. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/client/Client.java | Switches appclient-side JMS CF credentials to the dedicated test user. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/build.xml | Ensures broker exists and creates the dedicated JMS test user during setup. |
| appserver/tests/appserv-tests/devtests/connector/v3/jms-connection-factory-definition/build.properties | Defines dedicated JMS test user credentials for the devtest. |
| appserver/tests/application/src/test/java/org/glassfish/main/test/app/jms/OpenMqAdminServiceDefaultCredentialsTest.java | Adds an integration test ensuring default admin credentials can’t access OpenMQ admin service. |
| appserver/jms/pom.xml | Adds the new jmsra-ext module to the JMS build. |
| appserver/jms/jmsra/pom.xml | Packages the extension and replaces RA class in ra.xml to use the GlassFish adapter. |
| appserver/jms/jmsra-ext/src/main/java/org/glassfish/main/jms/ra/GlassFishResourceAdapter.java | Implements OpenMQ RA extension to synchronize the admin password repository on first broker creation. |
| appserver/jms/jmsra-ext/pom.xml | Introduces the new extension module and its OpenMQ dependencies. |
| appserver/jms/jms-core/src/main/java/com/sun/enterprise/connectors/jms/system/ActiveJmsResourceAdapter.java | Generates a random admin password in config on first use for managed brokers. |
| appserver/jms/admin/src/main/java/org/glassfish/jms/admin/cli/JMSPing.java | Retries ping with regenerated credentials and includes formatting cleanups. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| String adminUserName = jmsHost.getAdminUserName(); | ||
| String adminPassword = JmsRaUtil.getUnAliasedPwd(jmsHost.getAdminPassword()); | ||
| boolean usesDefaultAdminCredentials = isDefaultAdminCredentials(adminUserName, adminPassword); | ||
| List<Property> jmsHostProps= getJmsService().getProperty(); |
| try { | ||
| value = pingConnectionPool(SimpleJndiName.of(tmpJMSResource + JNDINAME_APPENDER)); | ||
| } catch (ResourceException e) { | ||
| if (!oldPassword.equals(defaultJmsHost.getAdminPassword())) { | ||
| // Retry in case the password was lazily autogenerated on first access. | ||
| // We need to recreate the resource with the generated password, which was meanwhile updated in | ||
| // the default JMS host config | ||
| deleteJMSResource(subReport, tmpJMSResource, context.getSubject()); | ||
| createJMSResource(defaultJmsHost, subReport, tmpJMSResource, context.getSubject()); | ||
| } | ||
| value = pingConnectionPool(SimpleJndiName.of(tmpJMSResource + JNDINAME_APPENDER)); | ||
| } |
| report.setMessage(localStrings.getLocalString("jms-ping.pingConnectionPoolException", | ||
| "An exception occured while trying to ping the JMS Host.", e.getMessage())); | ||
| "An exception occured while trying to ping the JMS Host.", e.getMessage())); | ||
| report.setActionExitCode(ActionReport.ExitCode.FAILURE); |
| boolean finished = process.waitFor(Duration.ofSeconds(30).toMillis(), java.util.concurrent.TimeUnit.MILLISECONDS); | ||
| assertTrue(finished, "imqcmd command timed out"); | ||
|
|
| <replace | ||
| file="${project.build.outputDirectory}/glassfish/lib/install/applications/jmsra/META-INF/ra.xml" | ||
| token="com.sun.messaging.jms.ra.ResourceAdapter" | ||
| value="org.glassfish.main.jms.ra.GlassFishResourceAdapter" | ||
| /> |
| ways: | ||
|
|
||
| * Read the `admin-password` attribute of the JMS host in | ||
| domain-dir``/config/domain.xml``. |
Fixes CVE-2026-22886.
When the default JMS broker instance is created, this generates a random password for both the client and in the broker configuration to keep them in synch.
WARNING: If upgrading an existing Glassfish installation, the existing JMS broker configuration isn't changed. It's recommended to change the default JMS admin password manually, as described in the GlassFish Administration guide.
The generated password can be retrieved from the GlassFish configuration if needed:
get configs.config.config-name.jms-service.jms-host.jms-host-name.admin-passwordKnowing the generated password, it's possible to change the password to a custom value, as described in the guide.
Why
Currently, by default the OpenMQ broker's admin interface is protected by the default well-known password. This allows anybody to access the admin interface if they have access to the JMS port.
It's possible to disable the admin interface but it's needed for several Glassfish commands, which would be broken without access to the OpenMQ admin interface. I chose the solution to generate the password because it doesn't break anything and should be safe as the default setup.
How
The EMBEDDED and LOCAL type of the broker are initialized from the JMS resource adapter. The EMBEDDED is initialized lazily, the LOCAL is initialized immediately after GlassFish starts if it's not created yet.
The resource adapter provided by OpenMQ doesn't support providing the admin password to initialize the new broker instance with, and always uses the default admin password. That's why I extended it in the new GlassFishResourceAdapter class, which waits until the new broker instance is created in the filesystem and then modifies the admin password to a generated password and updates the admin password in the jms host in GlassFish configuration to match it.
A few more changes were required to align with this: