{"record":{"id":"ce670777f1069417","repo":"apache/pulsar","slug":"unauthorized-to-validatebothsuperuserandbrokeroper","errorCode":null,"errorMessage":"Unauthorized to validateBothSuperuserAndBrokerOperation for originalPrincipal [${principal}] and clientAppId [${clientAppId}] about operation [${operation}] on broker [${brokerId}]","messagePattern":"Unauthorized to validateBothSuperuserAndBrokerOperation for originalPrincipal \\[(.+?)\\] and clientAppId \\[(.+?)\\] about operation \\[(.+?)\\] on broker \\[(.+?)\\]","errorType":"http","errorClass":"RestException","httpStatus":401,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java","lineNumber":571,"sourceCode":"                    Throwable superUserValidationException = null;\n                    try {\n                        superUserAccessValidation.join();\n                    } catch (Throwable ex) {\n                        superUserValidationException = FutureUtil.unwrapCompletionException(ex);\n                    }\n                    Throwable brokerOperationValidationException = null;\n                    try {\n                        brokerOperationValidation.join();\n                    } catch (Throwable ex) {\n                        brokerOperationValidationException = FutureUtil.unwrapCompletionException(ex);\n                    }\n                    log.debug().attr(\"originalPrincipal\", originalPrincipal())\n                            .attr(\"operation\", operation.toString())\n                            .attr(\"broker\", brokerId)\n                            .attr(\"superuserValidationError\", superUserValidationException)\n                            .attr(\"brokerOperationValidationError\", brokerOperationValidationException)\n                            .log(\"validateBothSuperuserAndBrokerOperation failed\");\n                    throw new RestException(Status.UNAUTHORIZED,\n                            String.format(\"Unauthorized to validateBothSuperuserAndBrokerOperation for\"\n                                          + \" originalPrincipal [%s] and clientAppId [%s] \"\n                                          + \"about operation [%s] on broker [%s]\",\n                                    originalPrincipal(), clientAppId(), operation.toString(), brokerId));\n                });\n    }\n\n    private CompletableFuture<Void> validateBrokerOperationAsync(String cluster, String brokerId,\n                                                                 BrokerOperation operation) {\n        final var pulsar = pulsar();\n        if (pulsar.getBrokerService().isAuthenticationEnabled()\n            && pulsar.getBrokerService().isAuthorizationEnabled()) {\n            return pulsar.getBrokerService().getAuthorizationService()\n                    .allowBrokerOperationAsync(cluster, brokerId, operation, originalPrincipal(),\n                            clientAppId(), clientAuthData())\n                    .thenAccept(isAuthorized -> {\n                        if (!isAuthorized) {\n                            throw new RestException(Status.UNAUTHORIZED,","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java#L553-L589","documentation":"BrokersBase.validateBothSuperuserAndBrokerOperation requires the caller to pass EITHER superuser validation OR broker-operation authorization. When both fail (originalPrincipal is not a superuser and the AuthorizationService denies the broker operation), it throws HTTP 401 UNAUTHORIZED with this message listing the principal, clientAppId, operation, and brokerId.","triggerScenarios":"Any of getActiveBrokers, getLeaderBroker, getOwnedNamespaces, updateDynamicConfiguration, deleteDynamicConfiguration, getAllDynamicConfigurations when: (1) authorization is enabled, (2) the original principal is not in the list of superusers, and (3) the authorization provider's allowBrokerOperationAsync returns false for the requested BrokerOperation on the target cluster/broker.","commonSituations":"Non-superuser operators hitting /admin/v2/brokers/configuration or dynamic-config endpoints; authorization provider misconfigured (role not granted broker-level permissions in the external authz store); token/client credentials not conveying the expected role; cluster name mismatch so the provider cannot match the broker.","solutions":["Add the principal/role to the broker's superUserRoles (broker.conf or standalone.conf) if it should have unrestricted admin access, and restart/reload.","If superuser is not appropriate, grant the role broker-operation permission in the AuthorizationService provider (e.g. allow the role the specific BrokerOperation on the cluster) so one of the two checks passes.","Verify the client is authenticating as the intended role (check originalPrincipal and clientAppId in the message) — often a stale or wrong auth token is being used.","Confirm authorizationEnabled and the configured authorizationProvider on the broker match your access-control setup, and that any wildcard role rules cover this principal."],"exampleFix":"// before: broker.conf with wrong superuser role\nsuperUserRoles=admin\n// after: include the role the admin client authenticates as\nsuperUserRoles=admin,ops-bot","handlingStrategy":"validation","validationCode":"// verify role is a superuser before invoking broker admin ops\nSet<String> superUsers = admin.brokers().getDynamicConfiguration(\"superUserRoles\") == null\n        ? Set.of() : parseRoles(admin.brokers().getDynamicConfiguration(\"superUserRoles\"));\nif (!superUsers.contains(myRole)) {\n    // ensure authz provider grants the BrokerOperation, or use a superuser client\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.brokers().getActiveBrokers(cluster);\n} catch (PulsarAdminException.NotAuthorizedException e) {\n    log.warn(\"Denied broker admin op for {} on {}\", clientRole, cluster, e);\n}","preventionTips":["Keep broker superUserRoles in sync with the roles your admin tooling authenticates as.","Test broker admin endpoints with the exact role/token your automation uses.","Grant broker-operation permissions in the AuthorizationProvider for non-superuser operators.","Rotate tokens/certs carefully so the role claim (originalPrincipal) stays correct."],"tags":["pulsar","authorization","http-401","superuser","admin-api"],"backgroundTag":"unauthorized-admin-operation","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}