This is an automated email from the ASF dual-hosted git repository.

frankgh pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 5bd164477f681b85cde36ba2595db9db04edaaab
Merge: 07885ef317 b584a43597
Author: Francisco Guerrero <[email protected]>
AuthorDate: Mon Mar 16 13:33:21 2026 -0700

    Merge branch 'cassandra-5.0' into trunk
    
    * cassandra-5.0:
      Disallow binding an identity to a superuser when the user is a regular 
user

 .../cql3/statements/AddIdentityStatement.java      |  8 ++-
 .../cql3/statements/DropIdentityStatement.java     | 25 +++++++-
 .../apache/cassandra/auth/GrantAndRevokeTest.java  | 73 ++++++++++++++++++++++
 .../cql3/statements/AddIdentityStatementTest.java  |  2 +-
 4 files changed, 104 insertions(+), 4 deletions(-)

diff --cc test/unit/org/apache/cassandra/auth/GrantAndRevokeTest.java
index 2c81d61635,719c713555..f0060dae93
--- a/test/unit/org/apache/cassandra/auth/GrantAndRevokeTest.java
+++ b/test/unit/org/apache/cassandra/auth/GrantAndRevokeTest.java
@@@ -578,46 -487,79 +578,119 @@@ public class GrantAndRevokeTest extend
          executeNet(ProtocolVersion.CURRENT, format("REVOKE SELECT PERMISSION 
ON KEYSPACE system_views FROM %s", user));
      }
  
 +    @Test
 +    public void testCheckPermissionsAfterAuthorize() throws Throwable
 +    {
 +        useSuperUser();
 +
 +        executeNet("CREATE KEYSPACE check_permissions WITH replication = 
{'class': 'SimpleStrategy', 'replication_factor': '1'}");
 +        executeNet("CREATE TABLE check_permissions.t1 (k int PRIMARY KEY)");
 +        executeNet("INSERT INTO check_permissions.t1 (k) VALUES (1)");
 +
 +        executeNet(String.format("CREATE ROLE %s WITH LOGIN = TRUE AND 
password='%s'", user, pass));
 +
 +        final String simple_user = "simple_user";
 +        executeNet(String.format("CREATE ROLE %s WITH LOGIN = TRUE AND 
password='%s'", simple_user, simple_user));
 +        executeNet("GRANT AUTHORIZE ON check_permissions.t1 TO " + 
simple_user);
 +
 +        useUser(user, pass);
 +        assertUnauthorizedQuery("User user has no SELECT permission on <table 
check_permissions.t1> or any of its parents",
 +                                "SELECT * FROM check_permissions.t1");
 +
 +        useUser(simple_user, simple_user);
 +        assertUnauthorizedQuery("User simple_user has no SELECT permission on 
<table check_permissions.t1> or any of its parents",
 +                                "SELECT * FROM check_permissions.t1");
 +        assertUnauthorizedQuery("User simple_user has no SELECT permission on 
<table check_permissions.t1> or any of its parents",
 +                                "GRANT SELECT ON check_permissions.t1 TO " + 
user);
 +
 +        useUser(user, pass);
 +        assertUnauthorizedQuery("User user has no SELECT permission on <table 
check_permissions.t1> or any of its parents",
 +                                "SELECT * FROM check_permissions.t1");
 +
 +        useSuperUser();
 +        executeNet("GRANT SELECT ON check_permissions.t1 TO " + simple_user);
 +
 +        useUser(simple_user, simple_user);
 +        executeNet("SELECT * FROM check_permissions.t1");
 +        executeNet("GRANT SELECT ON check_permissions.t1 TO " + user);
 +
 +        useUser(user, pass);
 +        executeNet("SELECT * FROM check_permissions.t1");
 +    }
 +
+     @Test
+     public void testAddIdentityPermissions() throws Throwable
+     {
+         useSuperUser();
+ 
+         executeNet(String.format("CREATE ROLE %s WITH LOGIN = TRUE AND 
password='%s'", user, pass));
+         executeNet(String.format("GRANT CREATE ON ALL ROLES TO %s", user));
+ 
+         useUser(user, pass);
+         executeNet(String.format("ADD IDENTITY 'id1' TO ROLE '%s'", user));
+ 
+         // Should disallow binding an identity to a superuser role for 
regular users
+         assertUnauthorizedQuery("Only superusers can bind identities to a 
role with superuser status",
+                                 "ADD IDENTITY 'adminId' TO ROLE 'cassandra'");
+     }
+ 
+     @Test
+     public void testRemoveIdentityPermissionsWithSpecificRolePermission() 
throws Throwable
+     {
+         useSuperUser();
+ 
+         String simpleUser = "user_1";
+         executeNet(String.format("CREATE ROLE %s WITH LOGIN = TRUE AND 
password='%s'", user, pass));
+         executeNet(String.format("CREATE ROLE %s WITH LOGIN = TRUE AND 
password='%s'", simpleUser, pass));
+         executeNet(String.format("ADD IDENTITY 'userId' TO ROLE '%s'", user));
+         executeNet(String.format("ADD IDENTITY 'simpleUserId' TO ROLE '%s'", 
simpleUser));
+         // allows user to drop simpleUser (including identity to role 
mappings)
+         executeNet(String.format("GRANT DROP ON ROLE %s TO %s", simpleUser, 
user));
+ 
+         useUser(user, pass);
+         executeNet("DROP IDENTITY 'simpleUserId'");
+         // We should not be able to drop identities mapped for role "user"
+         assertUnauthorizedQuery("User user does not have sufficient 
privileges to perform the requested operation",
+                                 "DROP IDENTITY 'userId'");
+         // Finally drop the "simpleUser" role
+         executeNet(String.format("DROP ROLE '%s'", simpleUser));
+     }
+ 
+     @Test
+     public void testRemoveIdentityPermissions()
+     {
+         useSuperUser();
+ 
+         executeNet(String.format("CREATE ROLE %s WITH LOGIN = TRUE AND 
password='%s'", user, pass));
+         executeNet(String.format("GRANT DROP ON ALL ROLES TO %s", user));
+         // Bind an identity to a superuser role
+         executeNet("ADD IDENTITY 'adminId' TO ROLE 'cassandra'");
+ 
+         useUser(user, pass);
+ 
+         // Spin assert for effective auth changes.
+         Util.spinAssertEquals(false, () -> {
+             try
+             {
+                 // Should disallow regular users from removing an identity 
binding from a superuser role
+                 assertUnauthorizedQuery("Only superusers can remove identity 
bindings from a role with superuser status",
+                                         "DROP IDENTITY 'adminId'");
+             }
+             catch (Throwable e)
+             {
+                 return true;
+             }
+             return false;
+         }, 10);
+ 
+         useSuperUser();
+         // superusers can drop identities bound to superusers
+         executeNet("DROP IDENTITY 'adminId'");
+ 
+         // Should also be able to run an IF EXISTS query with a non-existent 
identity
+         executeNet("DROP IDENTITY IF EXISTS 'nonExistentUserId'");
+     }
+ 
      private void maybeReadSystemTables(boolean superuser) throws Throwable
      {
          if (superuser)


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to