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 <m...@apache.org> Authored: Wed Mar 7 13:07:21 2018 +1100 Committer: Mick Semb Wever <m...@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-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org