diff --git a/CHANGES.txt b/CHANGES.txt index baa7eee95c..3d372fce00 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,7 @@ * Equality check for Paxos.Electorate should not depend on collection types (CASSANDRA-19935) * Fix race condition in DecayingEstimatedHistogramReservoir during rescale (CASSANDRA-19365) Merged from 4.0: + * Tighten up permissions in dc authorizers (CASSANDRA-20225) * CBUtil serialization of UTF8 does not handle all UTF8 properly (CASSANDRA-20234) * Make hint expiry use request start time rather than timeout time for TTL (CASSANDRA-20014) * Do not attach rows and partitions to CheckForAbort when already attached (CASSANDRA-20135) diff --git a/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java b/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java index ccbaeb20a5..dbf514a35f 100644 --- a/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java @@ -83,6 +83,9 @@ public class AlterRoleStatement extends AuthenticationStatement if (opts.getSuperuser().isPresent() && !isSuper) throw new UnauthorizedException("Only superusers are allowed to alter superuser status"); + if (dcPermissions != null && !isSuper) + throw new UnauthorizedException("Only superusers are allowed to alter access to datacenters."); + // superusers can do whatever else they like if (isSuper) return; diff --git a/test/unit/org/apache/cassandra/auth/CassandraNetworkAuthorizerTest.java b/test/unit/org/apache/cassandra/auth/CassandraNetworkAuthorizerTest.java index 3a208f8f6b..b7fa4117f6 100644 --- a/test/unit/org/apache/cassandra/auth/CassandraNetworkAuthorizerTest.java +++ b/test/unit/org/apache/cassandra/auth/CassandraNetworkAuthorizerTest.java @@ -40,7 +40,9 @@ import org.apache.cassandra.cql3.statements.DropRoleStatement; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.UnauthorizedException; import org.apache.cassandra.service.ClientState; +import org.assertj.core.api.Assertions; import static org.apache.cassandra.auth.AuthKeyspace.NETWORK_PERMISSIONS; import static org.apache.cassandra.auth.AuthTestUtils.getRolesReadCount; @@ -111,7 +113,19 @@ public class CassandraNetworkAuthorizerTest return state; } + private static ClientState getClientState(String role) + { + ClientState state = ClientState.forInternalCalls(); + state.login(new AuthenticatedUser(role)); + return state; + } + private static void auth(String query, Object... args) + { + auth(query, getClientState(), args); + } + + private static void auth(String query, ClientState clientState, Object... args) { CQLStatement statement = QueryProcessor.parseStatement(String.format(query, args)).prepare(ClientState.forInternalCalls()); assert statement instanceof CreateRoleStatement @@ -121,7 +135,8 @@ public class CassandraNetworkAuthorizerTest // invalidate roles cache so that any changes to the underlying roles are picked up Roles.cache.invalidate(); - authStmt.execute(getClientState()); + authStmt.authorize(clientState); + authStmt.execute(clientState); } private static DCPermissions dcPerms(String username) @@ -168,6 +183,27 @@ public class CassandraNetworkAuthorizerTest assertDcPermRow(username); } + @Test + public void alterAsUser() + { + String username = createName(); + + assertNoDcPermRow(username); + auth("CREATE ROLE %s WITH PASSWORD = 'password' AND LOGIN = true AND ACCESS TO DATACENTERS {'dc1'}", username); + Assert.assertEquals(DCPermissions.subset("dc1"), dcPerms(username)); + assertDcPermRow(username, "dc1"); + + // try to alter as a user + ClientState userState = getClientState(username); + Assertions.assertThatThrownBy(() -> auth("ALTER ROLE %s WITH ACCESS TO DATACENTERS {'dc1', 'dc2'}", userState, username)) + .hasMessage("Only superusers are allowed to alter access to datacenters.") + .isInstanceOf(UnauthorizedException.class); + + // nothing changed + Assert.assertEquals(DCPermissions.subset("dc1"), dcPerms(username)); + assertDcPermRow(username, "dc1"); + } + @Test public void drop() {