Skip to content

system realm permissions #54

Description

@AAndersn

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);   // <-- bug

addStringPermission(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 = queue and topic and temp-queue and fusion and fusion (the commas fold into one part's value set), and
  • the remaining :-delimited parts come out garbled (*, *, *, read, *, write do 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:

  • GossLDAPRealmaddStringPermission("queue:*"), addStringPermission("temp-queue:*"), addStringPermission("topic:*") (three separate calls)
  • UnauthTokenBasedRealm — one addStringPermission(...) per concrete permission
  • GossAuthorizingRealm — uses the plural addStringPermissions(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

  1. Build the GridAPPS-D image using GOSS core 16.0.1
    (pnnl.goss.core.security-system-16.0.1.jar).
  2. Start the container and run ./run-gridappsd.sh.
  3. Observe the broker log:
    Subject [system] is not authorized to create destination: topic://ActiveMQ.Advisory.Connection.
  4. Observe that TCP port 61616 never becomes usable and the Docker healthcheck
    reports unhealthy.

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 STOMP 61613) open and stay open.
  • The Docker container healthcheck transitions to healthy.
  • GridAPPS-D manager components (LogManagerImpl, RoleManagerImpl,
    AppManagerImpl, SimulationManagerImpl, ConfigurationManagerImpl,
    TestManagerImpl) register and log as system.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions