{"record":{"id":"860f565327789ee5","repo":"apache/pulsar","slug":"unauthorized-to-validatebothtenantoperationandsupe","errorCode":null,"errorMessage":"Unauthorized to validateBothTenantOperationAndSuperUser for originalPrincipal [${originalPrincipal}] and clientAppId [${clientAppId}] about operation [${operation}] ","messagePattern":"Unauthorized to validateBothTenantOperationAndSuperUser for originalPrincipal \\[(.+?)\\] and clientAppId \\[(.+?)\\] about operation \\[(.+?)\\] ","errorType":"http","errorClass":"RestException","httpStatus":401,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java","lineNumber":370,"sourceCode":"                    }\n                    Throwable superUserValidationException = null;\n                    try {\n                        superUserValidationFuture.join();\n                    } catch (Throwable ex) {\n                        superUserValidationException = FutureUtil.unwrapCompletionException(ex);\n                    }\n                    Throwable tenantOperationValidationException = null;\n                    try {\n                        tenantOperationValidationFuture.join();\n                    } catch (Throwable ex) {\n                        tenantOperationValidationException = FutureUtil.unwrapCompletionException(ex);\n                    }\n                    log.debug().attr(\"originalPrincipal\", originalPrincipal())\n                            .attr(\"operation\", operation.toString())\n                            .attr(\"superuserValidationError\", superUserValidationException)\n                            .attr(\"tenantOperationValidationError\", tenantOperationValidationException)\n                            .log(\"validateBothTenantOperationAndSuperUser failed\");\n                    throw new RestException(Status.UNAUTHORIZED,\n                            String.format(\"Unauthorized to validateBothTenantOperationAndSuperUser for\"\n                                          + \" originalPrincipal [%s] and clientAppId [%s] \"\n                                          + \"about operation [%s] \",\n                                    originalPrincipal(), clientAppId(), operation.toString()));\n                });\n    }\n}\n","sourceCodeStart":352,"sourceCodeEnd":378,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java#L352-L378","documentation":"HTTP 401 UNAUTHORIZED raised by validateBothSuperUserAndTenantOperation when the caller is neither a superuser (originalPrincipal fails superuser validation) nor authorized for the requested tenant operation (tenant admin role check fails). Both validation paths failed, so the tenancy API call is denied.","triggerScenarios":"GET/PUT/DELETE /admin/v2/tenants* endpoints (getTenants, getTenantAdmin, createTenant, updateTenant, deleteTenant) invoked by a principal lacking superuser role and not listed in the tenant's adminRoles; common with authenticated clients whose role is not mapped in superUserRoles or the tenant policy.","commonSituations":"Client authenticated with a role certificate/token but superUserRoles in broker.conf doesn't include it; tenant adminRoles not updated after team changes; proxy/stripped original principal (originalPrincipal not propagated through proxy authentication); use of admin API key without tenant-level grants.","solutions":["Grant the role: add it to superUserRoles in broker.conf (restart or dynamic config) for cluster-wide admin, or","Add the role to the tenant's adminRoles via PUT /admin/v2/tenants/{tenant} if it should only manage this tenant.","Verify authentication is mapping the expected role: check clientAppId/originalPrincipal in the message against the credentials presented.","If behind a proxy, ensure the proxy forwards the original principal (authenticateOriginalAuthData=true) so authorization evaluates the right user.","Confirm the operation name in the message matches what the client intends; a wrong endpoint may require higher privileges."],"exampleFix":"// broker.conf before\nsuperUserRoles=admin\n// after: grant the client role\nsuperUserRoles=admin,my-admin-client\n// or, tenant-scoped:\n// after\nTenantInfo info = admin.tenants().getTenant(\"my-tenant\");\ninfo.getAdminRoles().add(\"my-tenant-admin\");\nadmin.tenants().updateTenant(\"my-tenant\", info);","handlingStrategy":"try-catch","validationCode":"// Caller-side pre-check\nboolean isSuperUser = brokerConfig.getSuperUserRoles().contains(myRole);\nboolean isTenantAdmin = tenantInfo.getAdminRoles().contains(myRole);\nif (!isSuperUser && !isTenantAdmin) {\n    throw new SecurityException(\"Role \" + myRole + \" cannot perform tenant operation\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.tenants().getTenants();\n} catch (PulsarAdminException e) {\n    if (e.getStatusCode() == 401) {\n        // insufficient privileges: request superuser role or tenant adminRoles grant\n        throw new SecurityException(\"Not authorized for tenant operation; need superuser or adminRoles\", e);\n    }\n    throw e;\n}","preventionTips":["Keep superUserRoles and tenant adminRoles in sync with your team's access grants.","When using a proxy, enable authenticateOriginalAuthData so the real principal is authorized.","Use a dedicated admin role for tenancy APIs and verify it's present in broker config.","Test authorization with the exact credentials used in production automation."],"tags":["authorization","security","rest-api","tenant"],"backgroundTag":"insufficient-role-privileges","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"}