Repository navigation
Description
Bug: SystemBasedRealm grants the system principal a single malformed permission, breaking broker authorization
Component: pnnl.goss.core — bundle pnnl.goss.core.security-system
File: pnnl.goss.core/src/pnnl/goss/core/security/system/SystemBasedRealm.java
Method: loadSystemAccount()
Affected versions: GOSS core 16.0.1 (the security-system bundle shipped in the GridAPPS-D 16.x release cache)
Severity: High — the embedded ActiveMQ broker rejects the system principal, so GridAPPS-D cannot start.
Summary
SystemBasedRealm.loadSystemAccount() builds the system account's permissions by
passing the entire comma-joined permission list to Shiro's singular
SimpleAccount.addStringPermission(String):
private static final String SYSTEM_PERMISSIONS =
"queue:*,topic:*,temp-queue:*,fusion:*:read,fusion:*:write";
...
SimpleAccount account = new SimpleAccount(managerUser, managerPassword, getName());
account.addStringPermission(SYSTEM_PERMISSIONS); // <-- bugaddStringPermission(String) treats its argument as one WildcardPermission.
In a Shiro wildcard permission, : separates parts and , separates
sub-values within a single part — it does not separate independent
permissions. So the string above is parsed as a single permission whose:
- part 1 =
queueandtopicandtemp-queueandfusionandfusion(the commas fold into one part's value set), and - the remaining
:-delimited parts come out garbled (*,*,*,read,*,writedo not line up as intended).
The result is a permission that does not imply the concrete permissions the
ActiveMQ Shiro plugin checks at runtime, e.g.
topic:ActiveMQ.Advisory.Connection:create. The broker therefore throws:
org.apache.shiro.authz.UnauthorizedException:
Subject [system] is not authorized to create destination: topic://ActiveMQ.Advisory.Connection
and the OpenWire connector never becomes usable, which in the Docker image
leaves the healthcheck (/dev/tcp/localhost/61616) failing and the container
unhealthy.
Root cause
The intent is to grant five separate permissions. Every other realm in the
same package grants permissions one per addStringPermission call — the
singular method is only ever correct for a single permission string:
GossLDAPRealm—addStringPermission("queue:*"),addStringPermission("temp-queue:*"),addStringPermission("topic:*")(three separate calls)UnauthTokenBasedRealm— oneaddStringPermission(...)per concrete permissionGossAuthorizingRealm— uses the pluraladdStringPermissions(Collection<String>)with a collection of role permissions
Only SystemBasedRealm collapses the whole list into one string and hands it to
the singular method.
There is a second, related consequence: the same malformed single-string blob
was also stored in userPermissions:
Set<String> perms = new HashSet<>();
perms.add(SYSTEM_PERMISSIONS); // set contains ONE element: the whole joined string
userPermissions.put(managerUser, perms);so getPermissions("system") (part of the GossRealm/PermissionAdapter
contract) returns a set with a single malformed entry rather than the five
intended permissions.
Fix
Split the constant on , into individual permission strings and grant them with
the plural addStringPermissions(Collection<String>). Store the same split
set in userPermissions so getPermissions() is also correct:
Set<String> perms = new HashSet<>(Arrays.asList(SYSTEM_PERMISSIONS.split(",")));
SimpleAccount account = new SimpleAccount(managerUser, managerPassword, getName());
account.addStringPermissions(perms);
userMap.put(managerUser, account);
userPermissions.put(managerUser, perms);(Add import java.util.Arrays;.)
This makes SystemBasedRealm consistent with GossAuthorizingRealm, which
already uses addStringPermissions(Collection<String>).
Diff
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ loadSystemAccount()
- SimpleAccount account = new SimpleAccount(managerUser, managerPassword, getName());
- account.addStringPermission(SYSTEM_PERMISSIONS);
-
- Set<String> perms = new HashSet<>();
- perms.add(SYSTEM_PERMISSIONS);
+ Set<String> perms = new HashSet<>(Arrays.asList(SYSTEM_PERMISSIONS.split(",")));
+
+ SimpleAccount account = new SimpleAccount(managerUser, managerPassword, getName());
+ account.addStringPermissions(perms);Reproduction
- Build the GridAPPS-D image using GOSS core
16.0.1
(pnnl.goss.core.security-system-16.0.1.jar). - Start the container and run
./run-gridappsd.sh. - Observe the broker log:
Subject [system] is not authorized to create destination: topic://ActiveMQ.Advisory.Connection. - Observe that TCP port
61616never becomes usable and the Docker healthcheck
reportsunhealthy.
Verification of the fix
After rebuilding the security-system bundle with the fix and deploying it in
place of 16.0.1:
SystemBasedRealm loaded the system account for manager user 'system'on
activation (permissions now split correctly).- Zero
Subject [system] is not authorized ...errors on a clean startup. - OpenWire port
61616(and STOMP61613) open and stay open. - The Docker container healthcheck transitions to
healthy. - GridAPPS-D manager components (
LogManagerImpl,RoleManagerImpl,
AppManagerImpl,SimulationManagerImpl,ConfigurationManagerImpl,
TestManagerImpl) register and log assystem.
Scope note (not part of this bug)
A separate set of Subject [app_user] is not authorized to create destination: topic://ActiveMQ.Advisory.Topic warnings remain for the app_user STOMP
client. app_user is served by a different realm (property-file / JWT), not by
SystemBasedRealm, and these warnings are non-fatal — the broker stays up
and the healthcheck stays healthy. They are unrelated to the
SystemBasedRealm fix above and, if undesired, should be tracked separately.
Activity
craigpnnl commentedon Sep 10, 2026
Closed via #55