apache/cassandra · error · UnauthorizedException

Only superusers can bind identities to a role with…

Error message

Only superusers can bind identities to a role with superuser status

What it means

An authorization check in AddIdentityStatement.authorize: a non-superuser attempting to CREATE an identity bound to a role that currently has superuser status is rejected with UnauthorizedException. This prevents privilege escalation by letting ordinary users attach credentials/identities to superuser roles.

Solutions

  1. Run the statement as a superuser
  2. Remove superuser status from the target role first (as a superuser), then add the identity
  3. Pick a different, non-superuser role to bind the identity to

Example fix

// before (as non-super user)
CREATE IDENTITY cert1 FOR 'superadmin';
// after: run as superuser, or
CREATE IDENTITY cert1 FOR 'app_role';  -- non-superuser role
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check before issuing CREATE IDENTITY
boolean targetIsSuper = roleManager.isSuper(RoleResource.role(roleName));
boolean iAmSuper = clientUser.isSuper();
if (targetIsSuper && !iAmSuper) throw new IllegalStateException("Need superuser to bind identity to superuser role " + roleName);

Try / catch

try { session.execute(createIdentity); } catch (UnauthorizedException e) { if (e.getMessage().contains("Only superusers can bind identities")) { /* escalate credentials or target non-super role */ } else throw e; }

Prevention

When it happens

Trigger: CREATE IDENTITY ... FOR role 'x' (or equivalent AddIdentityStatement execution) where the authenticated user is not a superuser and DatabaseDescriptor.getRoleManager().isSuper(RoleResource.role(role)) returns true for the target role.

Common situations: Admin delegation setups where a lesser admin manages identities but tries to add one for the built-in superuser or another superuser role; scripts running under non-super credentials that previously worked against non-super roles.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/59c1a6b9d35559d2. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/AddIdentityStatement.java:58

{
    final String identity;
    final String role;
    final boolean ifNotExists;

    public AddIdentityStatement(String identity, String role, boolean ifNotExists)
    {
        this.role = role;
        this.identity = identity;
        this.ifNotExists = ifNotExists;
    }

    @Override
    public void authorize(ClientState state)
    {
        checkPermission(state, Permission.CREATE, RoleResource.root());

        if (!state.getUser().isSuper() && DatabaseDescriptor.getRoleManager().isSuper(RoleResource.role(role)))
            throw new UnauthorizedException("Only superusers can bind identities to a role with superuser status");
    }

    @Override
    public void validate(ClientState state)
    {
        state.ensureNotAnonymous();

        if (!DatabaseDescriptor.getRoleManager().isExistingRole(RoleResource.role(role)))
        {
            throw new InvalidRequestException(String.format("Can not add identity for non-existent role '%s'", role));
        }

        if (!ifNotExists && DatabaseDescriptor.getRoleManager().isExistingIdentity(identity))
            throw new InvalidRequestException(String.format("%s already exists", identity));
    }

    @Override
    public AuditLogContext getAuditLogContext()

View on GitHub (pinned to 88fd0f6a0e)