{"record":{"id":"a33552c5c981230f","repo":"apache/pulsar","slug":"original-principal-not-authorized-for-super-user-o","errorCode":null,"errorMessage":"Original principal not authorized for super-user operation (original:%s)","messagePattern":"Original principal not authorized for super-user operation \\(original:(.+?)\\)","errorType":"http","errorClass":"RestException","httpStatus":401,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java","lineNumber":246,"sourceCode":"        } catch (RestException e) {\n            return FutureUtil.failedFuture(e);\n        }\n\n        if (pulsar.getConfiguration().getProxyRoles().contains(appId)) {\n            BrokerService brokerService = pulsar.getBrokerService();\n            return brokerService.getAuthorizationService().isSuperUser(appId, clientAuthData())\n                    .thenCompose(proxyAuthorizationSuccess -> {\n                        if (!proxyAuthorizationSuccess){\n                            throw new RestException(Status.UNAUTHORIZED,\n                                    String.format(\"Proxy not authorized for super-user \"\n                                            + \"operation (proxy:%s)\", appId));\n                        }\n                        return pulsar.getBrokerService()\n                                .getAuthorizationService()\n                                .isSuperUser(originalPrincipal, clientAuthData());\n                    }).thenAccept(originalPrincipalAuthorizationSuccess -> {\n                        if (!originalPrincipalAuthorizationSuccess){\n                            throw new RestException(Status.UNAUTHORIZED,\n                                    String.format(\"Original principal not authorized for super-user operation \"\n                                                    + \"(original:%s)\", originalPrincipal));\n                        }\n                            log.debug()\n                                    .attr(\"authorized\", originalPrincipal)\n                                    .attr(\"proxyAppId\", appId)\n                                    .log(\"Successfully authorized as super-user\");\n                                            });\n        } else {\n            return pulsar.getBrokerService()\n                    .getAuthorizationService()\n                    .isSuperUser(appId, clientAuthData())\n                    .thenAccept(proxyAuthorizationSuccess -> {\n                        if (!proxyAuthorizationSuccess) {\n                            throw new RestException(Status.UNAUTHORIZED,\n                                    \"This operation requires super-user access\");\n                        }\n                    });","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java#L228-L264","documentation":"For proxied requests whose proxy role passes the super-user check, validateSuperUserAccessAsync then verifies the forwarded original principal is also a super-user. If isSuperUser(originalPrincipal) is false, the request fails with HTTP 401 even though the proxy itself was authorized.","triggerScenarios":"A super-user proxy forwards a request whose X-Original-Principal is a non-super-user role (or an empty/unknown role); end-user role changed/removed from superUserRoles while the proxy remains super-user.","commonSituations":"Clients connecting through an authorized proxy with their own (non-super) credentials hitting super-user-only endpoints; stale role names after IAM/kerberos changes; typo in the original principal header.","solutions":["Grant the original principal super-user access (add to superUserRoles or your AuthorizationProvider) if it legitimately needs the operation","Use a non-super-user endpoint appropriate for the original principal's actual permissions","Verify the X-Original-Principal value exactly matches the authenticated role in the authorization provider","If the proxy shouldn't forward other identities, call the broker directly with the super-user credentials"],"exampleFix":"// before (broker.conf)\nsuperUserRoles=[admin,proxy]  # original principal 'app-a' missing\n// after\nsuperUserRoles=[admin,proxy,app-a]","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    admin.clusters().getClusters();\n} catch (PulsarAdminException e) {\n    if (e.getStatusCode() == 401 && e.getMessage().contains(\"Original principal not authorized\")) {\n        // grant the original principal super-user or use a scoped API\n    }\n    throw e;\n}","preventionTips":["Ensure the forwarded original principal is also a super-user for super-user operations","Verify X-Original-Principal matches the role known to the authorization provider","Prefer tenant/namespace-scoped admin APIs for non-super-user identities"],"tags":["authorization","proxy","superuser","rest-api","pulsar"],"backgroundTag":"unauthorized-principal","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}