You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sa...@apache.org on 2019/07/05 18:11:06 UTC
[cassandra-dtest] branch master updated: Verify that auth handle
unavailable system_auth keyspace.
This is an automated email from the ASF dual-hosted git repository.
samt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cassandra-dtest.git
The following commit(s) were added to refs/heads/master by this push:
new ef5f2f5 Verify that auth handle unavailable system_auth keyspace.
ef5f2f5 is described below
commit ef5f2f52f83ae2592555a627ce3534daa8a0a3a5
Author: Per Otterström <pe...@gmail.com>
AuthorDate: Thu May 16 18:57:15 2019 +0200
Verify that auth handle unavailable system_auth keyspace.
Patch by Per Otterström; reviewed by Sam Tunnicliffe for CASSANDRA-15041
closes #52
---
auth_test.py | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 321 insertions(+), 1 deletion(-)
diff --git a/auth_test.py b/auth_test.py
index 4244487..93e6d9b 100644
--- a/auth_test.py
+++ b/auth_test.py
@@ -8,7 +8,7 @@ import re
import pytest
import logging
-from cassandra import AuthenticationFailed, InvalidRequest, Unauthorized
+from cassandra import AuthenticationFailed, InvalidRequest, Unauthorized, Unavailable
from cassandra.cluster import NoHostAvailable
from cassandra.protocol import ServerError, SyntaxException
@@ -2708,6 +2708,326 @@ class TestAuthRoles(Tester):
assert list(session.execute(query)) == []
+@since('2.2')
+class TestAuthUnavailable(Tester):
+ """
+ * These tests verify behavior when backends for authentication & authorization are unable to pull data from the
+ * system_auth keyspace. Failure scenarios are simulated based on the assumption that internal queries for role
+ * hierarchies and role properties of the "cassandra" super-user get CL=QUORUM (other roles get CL=LOCAL_ONE). And so
+ * we expect these internal queries to fail when one of two nodes are down and system_auth have RF=2. Though the
+ * permissions cache is used in these tests, it is always populated by permissions derived from the super-user status
+ * (all applicable to resource) of the "cassandra" user. The network_authorizer is always disabled to make sure the
+ * queries utilize the role/permissions cache only.
+ """
+
+ def test_authentication_handle_unavailable(self):
+ """
+ * Launch a two node cluster with role/permissions cache disabled
+ * Connect as default super user
+ * Increase the system_auth RF to 2
+ * Run repair
+ * Stop one of the nodes
+ * Verify that attempt to login fail with AuthenticationFailed
+
+ @jira_ticket CASSANDRA-15041
+ """
+ self.prepare(nodes=2)
+ logger.debug("Nodes started")
+
+ node0, node1 = self.cluster.nodelist()
+
+ cassandra = self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ self.set_rf2_on_system_auth(cassandra)
+
+ node1.stop()
+
+ try:
+ self.patient_exclusive_cql_connection(node0, timeout=2, user='cassandra', password='cassandra')
+ self.fail("Expected login attempt to raise an exception.")
+ except NoHostAvailable as e:
+ # From driver
+ assert isinstance(list(e.errors.values())[0], AuthenticationFailed)
+ # AuthenticationFailed from server
+ assert re.search("code=0100", str(e))
+ # Message from server
+ assert re.search("Unable to perform authentication:.* Cannot achieve consistency level QUORUM", str(e))
+
+ def test_authentication_through_cache_handle_unavailable(self):
+ """
+ * Launch a two node cluster with role/permissions cache enabled
+ * Connect as default super user
+ * Increase the system_auth RF to 2
+ * Run repair
+ * Stop one of the nodes
+ * Verify that attempt to login fail with AuthenticationFailed
+
+ @jira_ticket CASSANDRA-15041
+ """
+ self.prepare(nodes=2, cache_validity=500, cache_update_interval=500)
+ logger.debug("Nodes started")
+
+ node0, node1 = self.cluster.nodelist()
+
+ cassandra = self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ self.set_rf2_on_system_auth(cassandra)
+
+ # Warm up cache
+ self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ node1.stop()
+
+ # Wait for cache to timeout
+ time.sleep(1)
+
+ try:
+ self.patient_exclusive_cql_connection(node0, timeout=2, user='cassandra', password='cassandra')
+ self.fail("Expected login attempt to raise an exception.")
+ except NoHostAvailable as e:
+ # From driver
+ assert isinstance(list(e.errors.values())[0], AuthenticationFailed)
+ # AuthenticationFailed from server
+ assert re.search("code=0100", str(e))
+ # Message from server
+ assert re.search("Unable to perform authentication:.* Cannot achieve consistency level QUORUM", str(e))
+
+ @since('4.0')
+ def test_authentication_from_cache_while_unavailable(self):
+ """
+ * Launch a two node cluster with role/permissions cache enabled
+ * Connect as default super user
+ * Increase the system_auth RF to 2
+ * Run repair
+ * Stop one of the nodes
+ * Verify that login is successful from cached entries
+
+ @jira_ticket CASSANDRA-15041
+ """
+ self.prepare(nodes=2, cache_validity=60000, cache_update_interval=60000)
+ logger.debug("Nodes started")
+
+ node0, node1 = self.cluster.nodelist()
+
+ cassandra = self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ self.set_rf2_on_system_auth(cassandra)
+
+ # Warm up cache
+ self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ node1.stop()
+
+ self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ @since('4.0')
+ def test_credentials_cache_background_reload_handle_unavailable(self):
+ """
+ * Launch a two node cluster with role/permissions cache update interval at a fraction of validity time
+ * Connect as default super user
+ * Increase the system_auth RF to 2
+ * Run repair
+ * Stop one of the nodes
+ * Wait for cache update interval to expire
+ * Trigger async update of cache
+
+ @jira_ticket CASSANDRA-15041
+ """
+ self.prepare(nodes=2, cache_validity=60000, cache_update_interval=10)
+ logger.debug("Nodes started")
+
+ node0, node1 = self.cluster.nodelist()
+
+ cassandra = self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ self.set_rf2_on_system_auth(cassandra)
+
+ # Warm up cache
+ self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ node1.stop()
+
+ # Trigger async update of role/permissions cache
+ time.sleep(0.5)
+ self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ # Give background update operation time to fail and check logs
+ time.sleep(6)
+ assert not self.check_logs_for_errors()
+
+ def test_authorization_handle_unavailable(self):
+ """
+ * Launch a two node cluster with role/permissions cache disabled
+ * Connect as default super user
+ * Increase the system_auth RF to 2
+ * Run repair
+ * Create dummy ks/table
+ * Stop one of the nodes
+ * Verify that attempt to select on table fail with Unauthorized
+
+ @jira_ticket CASSANDRA-15041
+ """
+ self.prepare(nodes=2)
+ logger.debug("Nodes started")
+
+ node0, node1 = self.cluster.nodelist()
+
+ cassandra = self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ self.set_rf2_on_system_auth(cassandra)
+
+ cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':2}")
+ cassandra.execute("CREATE TABLE ks.cf (id int primary key)")
+
+ node1.stop()
+
+ assert_exception(cassandra, "SELECT * from ks.cf", matching="Unable to perform authorization of super-user permission: Cannot achieve consistency level QUORUM", expected=Unauthorized)
+
+ def test_authorization_through_cache_handle_unavailable(self):
+ """
+ * Launch a two node cluster with role/permissions cache enabled
+ * Connect as default super user
+ * Increase the system_auth RF to 2
+ * Run repair
+ * Create dummy ks/table
+ * Stop one of the nodes
+ * Verify that attempt to select on table fail with Unauthorized
+
+ @jira_ticket CASSANDRA-15041
+ """
+ self.prepare(nodes=2, cache_validity=500, cache_update_interval=500)
+ logger.debug("Nodes started")
+
+ node0, node1 = self.cluster.nodelist()
+
+ cassandra = self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ self.set_rf2_on_system_auth(cassandra)
+
+ cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':2}")
+ cassandra.execute("CREATE TABLE ks.cf (id int primary key)")
+
+ # Warm up cache
+ cassandra.execute("SELECT * from ks.cf")
+
+ node1.stop()
+
+ # Wait for cache to timeout
+ time.sleep(1)
+
+ assert_exception(cassandra, "SELECT * from ks.cf", matching="Unable to perform authorization of super-user permission: Cannot achieve consistency level QUORUM", expected=Unauthorized)
+
+ def test_authorization_from_cache_while_unavailable(self):
+ """
+ * Launch a two node cluster with role/permissions cache enabled
+ * Connect as default super user
+ * Increase the system_auth RF to 2
+ * Run repair
+ * Create dummy ks/table
+ * Stop one of the nodes
+ * Verify that select on table is authorized from cached entries
+
+ @jira_ticket CASSANDRA-15041
+ """
+ self.prepare(nodes=2, cache_validity=60000, cache_update_interval=60000)
+ logger.debug("Nodes started")
+
+ node0, node1 = self.cluster.nodelist()
+
+ cassandra = self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ self.set_rf2_on_system_auth(cassandra)
+
+ cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':2}")
+ cassandra.execute("CREATE TABLE ks.cf (id int primary key)")
+
+ # Warm up cache
+ cassandra.execute("SELECT * from ks.cf")
+
+ node1.stop()
+
+ # Authorized from cache
+ cassandra.execute("SELECT * from ks.cf")
+
+ def test_permission_cache_background_reload_handle_unavailable(self):
+ """
+ * Launch a two node cluster with role/permissions cache update interval at a fraction of validity time
+ * Connect as default super user
+ * Increase the system_auth RF to 2
+ * Run repair
+ * Create dummy ks/table
+ * Stop one of the nodes
+ * Wait for cache update interval to expire
+ * Trigger async update of cache
+ * Verify that background update don't log errors
+
+ @jira_ticket CASSANDRA-15041
+ """
+ self.prepare(nodes=2, cache_validity=60000, cache_update_interval=10)
+ logger.debug("Nodes started")
+
+ node0, node1 = self.cluster.nodelist()
+
+ cassandra = self.patient_exclusive_cql_connection(node0, user='cassandra', password='cassandra')
+
+ self.set_rf2_on_system_auth(cassandra)
+
+ cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':2}")
+ cassandra.execute("CREATE TABLE ks.cf (id int primary key)")
+
+ # Warm up cache
+ cassandra.execute("SELECT * from ks.cf")
+
+ node1.stop()
+
+ # Trigger async update of role/permissions cache
+ time.sleep(0.5)
+ cassandra.execute("SELECT * from ks.cf")
+
+ # Give background update operation time to fail and check logs
+ time.sleep(6)
+ assert not self.check_logs_for_errors()
+
+ def set_rf2_on_system_auth(self, session):
+ """
+ Set RF=2 on system_auth and repair
+ @param session The session used to alter keyspace
+ """
+ session.execute("""
+ ALTER KEYSPACE system_auth
+ WITH replication = {'class':'SimpleStrategy', 'replication_factor':2};
+ """)
+
+ logger.debug("Repairing after altering RF")
+ self.cluster.repair()
+
+ def prepare(self, nodes=1, cache_validity=0, cache_update_interval=-1):
+ """
+ Sets up and launches C* cluster.
+ Always set same cache validity and update-interval on roles, permissions and credentials to overcome differences
+ in cache strategies between 4.0 and pre-4.0.
+ @param nodes Number of nodes in the cluster. Default is 1
+ @param cache_validity The timeout for the roles/permissions/credentials cache in ms. Default is 0.
+ @param cache_update_interval The update interval for the roles/permissions/credentials cache in ms. Default is -1.
+ """
+ config = {'authenticator': 'org.apache.cassandra.auth.PasswordAuthenticator',
+ 'authorizer': 'org.apache.cassandra.auth.CassandraAuthorizer',
+ 'permissions_validity_in_ms': cache_validity,
+ 'permissions_update_interval_in_ms': cache_update_interval,
+ 'roles_validity_in_ms': cache_validity,
+ 'roles_update_interval_in_ms': cache_update_interval}
+ if self.dtest_config.cassandra_version_from_build >= '3.0':
+ config['enable_materialized_views'] = 'true'
+ if self.dtest_config.cassandra_version_from_build >= '3.4':
+ config['credentials_validity_in_ms'] = cache_validity
+ config['credentials_update_interval_in_ms'] = cache_update_interval
+ self.cluster.set_configuration_options(values=config)
+ self.cluster.populate(nodes).start()
+
+ n = self.cluster.wait_for_any_log('Created default superuser', 25)
+ logger.debug("Default role created by " + n.name)
+
+
@since('4.0')
class TestNetworkAuth(Tester):
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org