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]
