You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ad...@apache.org on 2021/10/27 17:26:43 UTC

[cassandra] branch trunk updated (3783077 -> d21e0dd)

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

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


    from 3783077  Merge branch 'cassandra-4.0' into trunk
     new 969531a  Allow users to view permissions of the roles they created
     new 3d74cad  Merge branch 'cassandra-3.0' into cassandra-3.11
     new 6c9d5ab  Merge branch 'cassandra-3.11' into cassandra-4.0
     new d21e0dd  Merge branch 'cassandra-4.0' into trunk

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CHANGES.txt                                        |  1 +
 .../apache/cassandra/auth/CassandraAuthorizer.java | 16 ++--
 .../org/apache/cassandra/auth/RoleResource.java    |  3 +-
 .../cql3/statements/CreateRoleStatement.java       |  2 +-
 .../org/apache/cassandra/auth/AuthTestUtils.java   |  8 ++
 .../cassandra/auth/CassandraAuthorizerTest.java    | 93 ++++++++++++++++++++++
 test/unit/org/apache/cassandra/cql3/CQLTester.java |  5 ++
 7 files changed, 120 insertions(+), 8 deletions(-)
 create mode 100644 test/unit/org/apache/cassandra/auth/CassandraAuthorizerTest.java

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org


[cassandra] 01/01: Merge branch 'cassandra-4.0' into trunk

Posted by ad...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d21e0dd8461e7ab9ce41ad4ee58e75134dc918ab
Merge: 3783077 6c9d5ab
Author: Andrés de la Peña <a....@gmail.com>
AuthorDate: Wed Oct 27 18:19:11 2021 +0100

    Merge branch 'cassandra-4.0' into trunk

 CHANGES.txt                                        |  1 +
 .../apache/cassandra/auth/CassandraAuthorizer.java | 16 ++--
 .../org/apache/cassandra/auth/RoleResource.java    |  3 +-
 .../cql3/statements/CreateRoleStatement.java       |  2 +-
 .../org/apache/cassandra/auth/AuthTestUtils.java   |  8 ++
 .../cassandra/auth/CassandraAuthorizerTest.java    | 93 ++++++++++++++++++++++
 test/unit/org/apache/cassandra/cql3/CQLTester.java |  5 ++
 7 files changed, 120 insertions(+), 8 deletions(-)

diff --cc src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
index 60d5a1f,6397154..c808ebc
--- a/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
+++ b/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
@@@ -245,14 -236,13 +245,14 @@@ public class CassandraAuthorizer implem
                                SchemaConstants.AUTH_KEYSPACE_NAME,
                                AuthKeyspace.RESOURCE_ROLE_INDEX,
                                escape(resource.getName()),
 -                              escape(role.getRoleName())));
 +                              escape(role.getRoleName())),
 +                authWriteConsistencyLevel());
      }
  
-     // 'of' can be null - in that case everyone's permissions have been requested. Otherwise only single user's.
-     // If the user requesting 'LIST PERMISSIONS' is not a superuser OR their username doesn't match 'of', we
-     // throw UnauthorizedException. So only a superuser can view everybody's permissions. Regular users are only
-     // allowed to see their own permissions.
+     // 'grantee' can be null - in that case everyone's permissions have been requested. Otherwise, only single user's.
+     // If the 'performer' requesting 'LIST PERMISSIONS' is not a superuser OR their username doesn't match 'grantee' OR
+     // they have no permission to describe all roles OR they have no permission to describe 'grantee', then we throw
+     // UnauthorizedException.
      public Set<PermissionDetails> list(AuthenticatedUser performer,
                                         Set<Permission> permissions,
                                         IResource resource,
diff --cc test/unit/org/apache/cassandra/auth/AuthTestUtils.java
index 64daca5,0000000..83bdf71
mode 100644,000000..100644
--- a/test/unit/org/apache/cassandra/auth/AuthTestUtils.java
+++ b/test/unit/org/apache/cassandra/auth/AuthTestUtils.java
@@@ -1,150 -1,0 +1,158 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +package org.apache.cassandra.auth;
 +
 +import java.util.concurrent.Callable;
 +
 +import org.apache.cassandra.cql3.QueryOptions;
 +import org.apache.cassandra.cql3.QueryProcessor;
 +import org.apache.cassandra.cql3.UntypedResultSet;
 +import org.apache.cassandra.cql3.statements.BatchStatement;
 +import org.apache.cassandra.cql3.statements.SelectStatement;
 +import org.apache.cassandra.db.ColumnFamilyStore;
 +import org.apache.cassandra.db.ConsistencyLevel;
 +import org.apache.cassandra.db.Keyspace;
 +import org.apache.cassandra.exceptions.RequestExecutionException;
 +import org.apache.cassandra.schema.SchemaConstants;
 +import org.apache.cassandra.service.QueryState;
 +import org.apache.cassandra.transport.messages.ResultMessage;
 +
 +
 +public class AuthTestUtils
 +{
 +
 +    public static final RoleResource ROLE_A = RoleResource.role("role_a");
 +    public static final RoleResource ROLE_B = RoleResource.role("role_b");
 +    public static final RoleResource ROLE_B_1 = RoleResource.role("role_b_1");
 +    public static final RoleResource ROLE_B_2 = RoleResource.role("role_b_2");
 +    public static final RoleResource ROLE_B_3 = RoleResource.role("role_b_3");
 +    public static final RoleResource ROLE_C = RoleResource.role("role_c");
 +    public static final RoleResource ROLE_C_1 = RoleResource.role("role_c_1");
 +    public static final RoleResource ROLE_C_2 = RoleResource.role("role_c_2");
 +    public static final RoleResource ROLE_C_3 = RoleResource.role("role_c_3");
 +    public static final RoleResource[] ALL_ROLES  = new RoleResource[] {ROLE_A,
 +                                                                        ROLE_B, ROLE_B_1, ROLE_B_2, ROLE_B_3,
 +                                                                        ROLE_C, ROLE_C_1, ROLE_C_2, ROLE_C_3};
 +    /**
 +     * This just extends the internal IRoleManager implementation to ensure that
 +     * all access to underlying tables is made via
 +     * QueryProcessor.executeOnceInternal/CQLStatement.executeInternal and not
 +     * StorageProxy so that it can be used in unit tests.
 +     */
 +    public static class LocalCassandraRoleManager extends CassandraRoleManager
 +    {
++        @Override
 +        ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
 +        {
 +            return statement.executeLocally(QueryState.forInternalCalls(), options);
 +        }
 +
++        @Override
 +        UntypedResultSet process(String query, ConsistencyLevel consistencyLevel)
 +        {
 +            return QueryProcessor.executeInternal(query);
 +        }
 +
++        @Override
 +        protected void scheduleSetupTask(final Callable<Void> setupTask)
 +        {
 +            // skip data migration or setting up default role for tests
 +        }
 +    }
 +
 +    public static class LocalCassandraAuthorizer extends CassandraAuthorizer
 +    {
++        @Override
 +        ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
 +        {
 +            return statement.executeLocally(QueryState.forInternalCalls(), options);
 +        }
 +
++        @Override
 +        UntypedResultSet process(String query, ConsistencyLevel cl) throws RequestExecutionException
 +        {
 +            return QueryProcessor.executeInternal(query);
 +        }
 +
 +        @Override
 +        void processBatch(BatchStatement statement)
 +        {
 +            statement.executeLocally(QueryState.forInternalCalls(), QueryOptions.DEFAULT);
 +        }
 +    }
 +
 +    public static class LocalCassandraNetworkAuthorizer extends CassandraNetworkAuthorizer
 +    {
++        @Override
 +        ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
 +        {
 +            return statement.executeLocally(QueryState.forInternalCalls(), options);
 +        }
 +
++        @Override
 +        void process(String query)
 +        {
 +            QueryProcessor.executeInternal(query);
 +        }
 +    }
 +
 +    public static class LocalPasswordAuthenticator extends PasswordAuthenticator
 +    {
++        @Override
 +        ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
 +        {
 +            return statement.executeLocally(QueryState.forInternalCalls(), options);
 +        }
 +    }
 +
 +    public static void grantRolesTo(IRoleManager roleManager, RoleResource grantee, RoleResource...granted)
 +    {
 +        for(RoleResource toGrant : granted)
 +            roleManager.grantRole(AuthenticatedUser.ANONYMOUS_USER, toGrant, grantee);
 +    }
 +
 +    public static long getNetworkPermissionsReadCount()
 +    {
 +        ColumnFamilyStore networkPemissionsTable =
 +                Keyspace.open(SchemaConstants.AUTH_KEYSPACE_NAME).getColumnFamilyStore(AuthKeyspace.NETWORK_PERMISSIONS);
 +        return networkPemissionsTable.metric.readLatency.latency.getCount();
 +    }
 +
 +    public static long getRolePermissionsReadCount()
 +    {
 +        ColumnFamilyStore rolesPemissionsTable =
 +                Keyspace.open(SchemaConstants.AUTH_KEYSPACE_NAME).getColumnFamilyStore(AuthKeyspace.ROLE_PERMISSIONS);
 +        return rolesPemissionsTable.metric.readLatency.latency.getCount();
 +    }
 +
 +    public static long getRolesReadCount()
 +    {
 +        ColumnFamilyStore rolesTable = Keyspace.open(SchemaConstants.AUTH_KEYSPACE_NAME).getColumnFamilyStore(AuthKeyspace.ROLES);
 +        return rolesTable.metric.readLatency.latency.getCount();
 +    }
 +
 +    public static RoleOptions getLoginRoleOptions()
 +    {
 +        RoleOptions roleOptions = new RoleOptions();
 +        roleOptions.setOption(IRoleManager.Option.SUPERUSER, false);
 +        roleOptions.setOption(IRoleManager.Option.LOGIN, true);
 +        roleOptions.setOption(IRoleManager.Option.PASSWORD, "ignored");
 +        return roleOptions;
 +    }
 +}
diff --cc test/unit/org/apache/cassandra/auth/CassandraAuthorizerTest.java
index 0000000,61235d2..45f7e39
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/auth/CassandraAuthorizerTest.java
+++ b/test/unit/org/apache/cassandra/auth/CassandraAuthorizerTest.java
@@@ -1,0 -1,97 +1,93 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ package org.apache.cassandra.auth;
+ 
 -import java.util.Collections;
 -
+ import org.junit.BeforeClass;
+ import org.junit.Test;
+ 
 -import org.apache.cassandra.SchemaLoader;
 -import org.apache.cassandra.config.DatabaseDescriptor;
+ import org.apache.cassandra.cql3.CQLTester;
 -import org.apache.cassandra.cql3.QueryProcessor;
 -import org.apache.cassandra.cql3.UntypedResultSet;
 -import org.apache.cassandra.cql3.statements.CreateRoleStatement;
 -import org.apache.cassandra.cql3.statements.ListPermissionsStatement;
 -import org.apache.cassandra.exceptions.UnauthorizedException;
 -import org.apache.cassandra.service.ClientState;
 -import org.apache.cassandra.transport.messages.ResultMessage;
 -import org.assertj.core.api.Assertions;
+ 
 -import static org.apache.cassandra.auth.AuthenticatedUser.SYSTEM_USER;
++import static java.lang.String.format;
+ 
+ public class CassandraAuthorizerTest extends CQLTester
+ {
 -    private static final RoleResource PARENT_ROLE = RoleResource.role("parent");
 -    private static final RoleResource CHILD_ROLE = RoleResource.role("child");
 -    private static final RoleResource OTHER_ROLE = RoleResource.role("other");
++    private static final String PARENT = "parent";
++    private static final String CHILD = "child";
++    private static final String OTHER = "other";
++    private static final String PASSWORD = "secret";
+ 
+     @BeforeClass
+     public static void setupClass()
+     {
+         CQLTester.setUpClass();
 -        SchemaLoader.setupAuth(new RoleTestUtils.LocalCassandraRoleManager(),
 -                               new PasswordAuthenticator(),
 -                               new RoleTestUtils.LocalCassandraAuthorizer(),
 -                               new RoleTestUtils.LocalCassandraNetworkAuthorizer());
++        requireAuthentication();
++        requireNetwork();
+     }
+ 
+     @Test
 -    public void testListPermissionsOfChildByParent()
++    public void testListPermissionsOfChildByParent() throws Throwable
+     {
 -        // create parent role by system user
 -        DatabaseDescriptor.getRoleManager()
 -                          .createRole(SYSTEM_USER, PARENT_ROLE, RoleTestUtils.getLoginRoleOptions());
++        useSuperUser();
++
++        // create parent role by super user
++        executeNet(format("CREATE ROLE %s WITH login=true AND password='%s'", PARENT, PASSWORD));
++        executeNet(format("GRANT CREATE ON ALL ROLES TO %s", PARENT));
++        assertRowsNet(executeNet(format("LIST ALL PERMISSIONS OF %s", PARENT)),
++                      row(PARENT, PARENT, "<all roles>", "CREATE"));
++
++        // create other role by super user
++        executeNet(format("CREATE ROLE %s WITH login=true AND password='%s'", OTHER, PASSWORD));
++        assertRowsNet(executeNet(format("LIST ALL PERMISSIONS OF %s", OTHER)));
++
++        useUser(PARENT, PASSWORD);
+ 
+         // create child role by parent
 -        String createRoleQuery = String.format("CREATE ROLE %s", CHILD_ROLE.getRoleName());
 -        CreateRoleStatement createRoleStatement = (CreateRoleStatement) QueryProcessor.parseStatement(createRoleQuery)
 -                                                                                      .prepare(ClientState.forInternalCalls());
 -        createRoleStatement.execute(getClientState(PARENT_ROLE.getRoleName()));
 -
 -        // grant SELECT permission on ALL KEYSPACES to child
 -        DatabaseDescriptor.getAuthorizer()
 -                          .grant(SYSTEM_USER,
 -                                 Collections.singleton(Permission.SELECT),
 -                                 DataResource.root(),
 -                                 CHILD_ROLE);
 -
 -        // list child permissions by parent
 -        String listPermissionsQuery = String.format("LIST ALL PERMISSIONS OF %s", CHILD_ROLE.getRoleName());
 -        ListPermissionsStatement listPermissionsStatement = (ListPermissionsStatement) QueryProcessor.parseStatement(listPermissionsQuery)
 -                                                                                                     .prepare(ClientState.forInternalCalls());
 -        ResultMessage message = listPermissionsStatement.execute(getClientState(PARENT_ROLE.getRoleName()));
 -        assertRows(UntypedResultSet.create(((ResultMessage.Rows) message).result),
 -                   row("child", "child", "<all keyspaces>", "SELECT"));
 -
 -        // list child permissions by other user that is not their parent
 -        DatabaseDescriptor.getRoleManager().createRole(SYSTEM_USER, OTHER_ROLE, RoleTestUtils.getLoginRoleOptions());
 -        Assertions.assertThatThrownBy(() -> listPermissionsStatement.execute(getClientState(OTHER_ROLE.getRoleName())))
 -                  .isInstanceOf(UnauthorizedException.class)
 -                  .hasMessage("You are not authorized to view child's permissions");
 -    }
++        executeNet(format("CREATE ROLE %s WITH login = true AND password='%s'", CHILD, PASSWORD));
+ 
 -    private static ClientState getClientState(String username)
 -    {
 -        ClientState state = ClientState.forInternalCalls();
 -        state.login(new AuthenticatedUser(username));
 -        return state;
++        // list permissions by parent
++        assertRowsNet(executeNet(format("LIST ALL PERMISSIONS OF %s", PARENT)),
++                      row(PARENT, PARENT, "<all roles>", "CREATE"),
++                      row(PARENT, PARENT, "<role child>", "ALTER"),
++                      row(PARENT, PARENT, "<role child>", "DROP"),
++                      row(PARENT, PARENT, "<role child>", "AUTHORIZE"),
++                      row(PARENT, PARENT, "<role child>", "DESCRIBE"));
++        assertRowsNet(executeNet(format("LIST ALL PERMISSIONS OF %s", CHILD)));
++        assertInvalidMessageNet(format("You are not authorized to view %s's permissions", OTHER),
++                                format("LIST ALL PERMISSIONS OF %s", OTHER));
++
++        useUser(CHILD, PASSWORD);
++
++        // list permissions by child
++        assertInvalidMessageNet(format("You are not authorized to view %s's permissions", PARENT),
++                                format("LIST ALL PERMISSIONS OF %s", PARENT));
++        assertRowsNet(executeNet(format("LIST ALL PERMISSIONS OF %s", CHILD)));
++        assertInvalidMessageNet(format("You are not authorized to view %s's permissions", OTHER),
++                                format("LIST ALL PERMISSIONS OF %s", OTHER));
++
++        // try to create role by child
++        assertInvalidMessageNet(format("User %s does not have sufficient privileges to perform the requested operation", CHILD),
++                                format("CREATE ROLE %s WITH login=true AND password='%s'", "nope", PASSWORD));
++
++        useUser(PARENT, PASSWORD);
++
++        // alter child's role by parent
++        executeNet(format("ALTER ROLE %s WITH login = false", CHILD));
++        executeNet(format("DROP ROLE %s", CHILD));
+     }
+ }
diff --cc test/unit/org/apache/cassandra/cql3/CQLTester.java
index 049e5ab,59968fe..2ed4e26
--- a/test/unit/org/apache/cassandra/cql3/CQLTester.java
+++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java
@@@ -1523,6 -1410,6 +1523,11 @@@ public abstract class CQLTeste
          assertInvalidThrowMessage(errorMessage, null, query, values);
      }
  
++    protected void assertInvalidMessageNet(String errorMessage, String query, Object... values) throws Throwable
++    {
++        assertInvalidThrowMessage(Optional.of(ProtocolVersion.CURRENT), errorMessage, null, query, values);
++    }
++
      protected void assertInvalidThrow(Class<? extends Throwable> exception, String query, Object... values) throws Throwable
      {
          assertInvalidThrowMessage(null, exception, query, values);

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org