You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by mc...@apache.org on 2018/03/07 02:15:55 UTC

cassandra-dtest git commit: New test for CASSANDRA-11381: Node running with join_ring=false and authentication can not serve requests

Repository: cassandra-dtest
Updated Branches:
  refs/heads/master 8fa87f63d -> 7f5d9c0f3


New test for CASSANDRA-11381: Node running with join_ring=false and authentication can not serve requests

Patch by Mick Semb Wever; Reviewed by Philip Thompson; for CASSANDRA-11381


Project: http://git-wip-us.apache.org/repos/asf/cassandra-dtest/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra-dtest/commit/7f5d9c0f
Tree: http://git-wip-us.apache.org/repos/asf/cassandra-dtest/tree/7f5d9c0f
Diff: http://git-wip-us.apache.org/repos/asf/cassandra-dtest/diff/7f5d9c0f

Branch: refs/heads/master
Commit: 7f5d9c0f34f782aa8fa041e6408400152d64e533
Parents: 8fa87f6
Author: Mick Semb Wever <mc...@apache.org>
Authored: Wed Mar 7 13:07:21 2018 +1100
Committer: Mick Semb Wever <mc...@apache.org>
Committed: Wed Mar 7 13:07:21 2018 +1100

----------------------------------------------------------------------
 auth_join_ring_false_test.py | 212 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 212 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra-dtest/blob/7f5d9c0f/auth_join_ring_false_test.py
----------------------------------------------------------------------
diff --git a/auth_join_ring_false_test.py b/auth_join_ring_false_test.py
new file mode 100644
index 0000000..34e2b4b
--- /dev/null
+++ b/auth_join_ring_false_test.py
@@ -0,0 +1,212 @@
+import pytest
+
+from cassandra import AuthenticationFailed, Unauthorized
+from cassandra.cluster import NoHostAvailable
+
+from dtest import Tester
+
+
+class TestAuth(Tester):
+
+
+    def test_login_existing_node(self):
+        """
+        * Launch a three node cluster
+        * Restart the third node in `join_ring=false` mode
+        * Connect as the default user/password
+        * Verify that default user w/ bad password gives AuthenticationFailed exception
+        * Verify that bad user gives AuthenticationFailed exception
+        """
+        # also tests default user creation (cassandra/cassandra)
+        self.prepare(nodes=3)
+        node1, node2, node3 = self.cluster.nodelist()
+        node3.stop(wait_other_notice=True)
+        node3.start(join_ring=False, wait_other_notice=False, wait_for_binary_proto=True)
+
+        self.patient_exclusive_cql_connection(node=node3, user='cassandra', password='cassandra')
+        try:
+            self.patient_exclusive_cql_connection(node=node3, user='cassandra', password='badpassword')
+        except NoHostAvailable as e:
+            assert isinstance(list(e.errors.values())[0], AuthenticationFailed)
+        try:
+            self.patient_exclusive_cql_connection(node=node3, user='doesntexist', password='doesntmatter')
+        except NoHostAvailable as e:
+            assert isinstance(list(e.errors.values())[0], AuthenticationFailed)
+
+    def test_login_new_node(self):
+        """
+        * Launch a two node cluster
+        * Add a third node in `join_ring=false` mode
+        * Connect as the default user/password
+        * Verify that default user w/ bad password gives AuthenticationFailed exception
+        * Verify that bad user gives AuthenticationFailed exception
+        """
+        # also tests default user creation (cassandra/cassandra)
+        self.prepare(nodes=2)
+
+        node3 = self.cluster.create_node('node3', False,
+                                    ('127.0.0.3', 9160),
+                                    ('127.0.0.3', 7000),
+                                    '7300', '2002', None,
+                                    binary_interface=('127.0.0.3', 9042))
+
+        self.cluster.add(node3, False)
+        node3.start(join_ring=False, wait_other_notice=False, wait_for_binary_proto=True)
+
+        self.patient_exclusive_cql_connection(node=node3, user='cassandra', password='cassandra')
+        try:
+            self.patient_exclusive_cql_connection(node=node3, user='cassandra', password='badpassword')
+        except NoHostAvailable as e:
+            assert isinstance(list(e.errors.values())[0], AuthenticationFailed)
+        try:
+            self.patient_exclusive_cql_connection(node=node3, user='doesntexist', password='doesntmatter')
+        except NoHostAvailable as e:
+            assert isinstance(list(e.errors.values())[0], AuthenticationFailed)
+
+    def test_list_users(self):
+        """
+        * Launch a one node cluster
+        * Connect as the default superuser
+        * Create two new users, and two new superusers.
+        * Verify that LIST USERS shows all five users.
+        * Verify that the correct users are listed as super users.
+        * Add a second node in `join_ring=false` mode
+        * Connect (through the non-ring node) as one of the new users, and check that the LIST USERS behavior is also correct there.
+        """
+        self.prepare()
+
+        session = self.get_session(user='cassandra', password='cassandra')
+        session.execute("CREATE USER alex WITH PASSWORD '12345' NOSUPERUSER")
+        session.execute("CREATE USER bob WITH PASSWORD '12345' SUPERUSER")
+        session.execute("CREATE USER cathy WITH PASSWORD '12345' NOSUPERUSER")
+        session.execute("CREATE USER dave WITH PASSWORD '12345' SUPERUSER")
+
+        node2 = self.cluster.create_node('node2', False,
+                                    ('127.0.0.2', 9160),
+                                    ('127.0.0.2', 7000),
+                                    '7200', '2001', None,
+                                    binary_interface=('127.0.0.2', 9042))
+                                    
+        self.cluster.add(node2, False)
+        node2.start(join_ring=False, wait_other_notice=False, wait_for_binary_proto=True)
+
+        self.patient_exclusive_cql_connection(node=node2, user='cassandra', password='cassandra')
+        session = self.get_session(user='cassandra', password='cassandra')
+
+        rows = list(session.execute("LIST USERS"))
+        assert 5 == len(rows)
+        # {username: isSuperuser} dict.
+        users = dict([(r[0], r[1]) for r in rows])
+
+        assert users['cassandra']
+        assert not users['alex']
+        assert users['bob']
+        assert not users['cathy']
+        assert users['dave']
+
+        self.get_session(node_idx=1, user='dave', password='12345')
+        rows = list(session.execute("LIST USERS"))
+        assert 5 == len(rows)
+        # {username: isSuperuser} dict.
+        users = dict([(r[0], r[1]) for r in rows])
+
+        assert users['cassandra']
+        assert not users['alex']
+        assert users['bob']
+        assert not users['cathy']
+        assert users['dave']
+
+    def test_modify_and_select_auth(self):
+        self.prepare()
+
+        cassandra = self.get_session(user='cassandra', password='cassandra')
+        cassandra.execute("CREATE USER cathy WITH PASSWORD '12345'")
+        cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':3}")
+        cassandra.execute("CREATE TABLE ks.cf (id int primary key, val int)")
+
+        node2 = self.cluster.create_node('node2', False,
+                                    ('127.0.0.2', 9160),
+                                    ('127.0.0.2', 7000),
+                                    '7200', '2001', None,
+                                    binary_interface=('127.0.0.2', 9042))
+
+        self.cluster.add(node2, False)
+        node2.start(join_ring=False, wait_other_notice=False, wait_for_binary_proto=True)
+
+        cathy = self.get_session(node_idx=1, user='cathy', password='12345')
+
+        self.assert_unauthorized("User cathy has no SELECT permission on <table ks.cf> or any of its parents",
+                                cathy, "SELECT * FROM ks.cf")
+
+        node2.stop()
+
+        cassandra = self.get_session(user='cassandra', password='cassandra')
+        cassandra.execute("GRANT SELECT ON ks.cf TO cathy")
+
+        node2.start(join_ring=False, wait_other_notice=False, wait_for_binary_proto=True)
+        cathy = self.get_session(node_idx=1, user='cathy', password='12345')
+
+        rows = list(cathy.execute("SELECT * FROM ks.cf"))
+        assert 0 == len(rows)
+
+        self.assert_unauthorized("User cathy has no MODIFY permission on <table ks.cf> or any of its parents",
+                                cathy, "INSERT INTO ks.cf (id, val) VALUES (0, 0)")
+
+        self.assert_unauthorized("User cathy has no MODIFY permission on <table ks.cf> or any of its parents",
+                                cathy, "UPDATE ks.cf SET val = 1 WHERE id = 1")
+
+        self.assert_unauthorized("User cathy has no MODIFY permission on <table ks.cf> or any of its parents",
+                                cathy, "DELETE FROM ks.cf WHERE id = 1")
+
+        self.assert_unauthorized("User cathy has no MODIFY permission on <table ks.cf> or any of its parents",
+                                cathy, "TRUNCATE ks.cf")
+
+        node2.stop()
+
+        cassandra = self.get_session(user='cassandra', password='cassandra')
+        cassandra.execute("GRANT MODIFY ON ks.cf TO cathy")
+
+        node2.start(join_ring=False, wait_other_notice=False, wait_for_binary_proto=True)
+        cathy = self.get_session(node_idx=1, user='cathy', password='12345')
+
+        cathy.execute("INSERT INTO ks.cf (id, val) VALUES (0, 0)")
+        cathy.execute("UPDATE ks.cf SET val = 1 WHERE id = 1")
+        rows = list(cathy.execute("SELECT * FROM ks.cf"))
+        assert 2 == len(rows)
+
+        cathy.execute("DELETE FROM ks.cf WHERE id = 1")
+        rows = list(cathy.execute("SELECT * FROM ks.cf"))
+        assert 1 == len(rows)
+
+        rows = list(cathy.execute("TRUNCATE ks.cf"))
+        assert len(rows) == 0
+
+
+    def assert_unauthorized(self, message, session, query):
+        with pytest.raises(Unauthorized) as cm:
+            session.execute(query)
+            assert_regexp_matches(repr(cm._excinfo[1]), message)
+            
+    def get_session(self, node_idx=0, user=None, password=None):
+        """
+        Connect with a set of credentials to a given node. Connection is not exclusive to that node.
+        @param node_idx Initial node to connect to
+        @param user User to connect as
+        @param password Password to use
+        @return Session as user, to specified node
+        """
+        node = self.cluster.nodelist()[node_idx]
+        session = self.patient_cql_connection(node, user=user, password=password)
+        return session
+
+    def prepare(self, nodes=1, roles_expiry=0):
+        config = {'authenticator': 'org.apache.cassandra.auth.PasswordAuthenticator',
+                  'authorizer': 'org.apache.cassandra.auth.CassandraAuthorizer',
+                  'role_manager': 'org.apache.cassandra.auth.CassandraRoleManager',
+                  'permissions_validity_in_ms': 0,
+                  'roles_validity_in_ms': roles_expiry}
+        self.cluster.set_configuration_options(values=config)
+        self.cluster.populate(nodes).start(wait_for_binary_proto=True)
+
+        self.cluster.wait_for_any_log('Created default superuser', 25)
+


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