1
+ import random
2
+ import string
1
3
import pytest
2
4
import logging
3
5
from distutils .version import LooseVersion
12
14
13
15
@since ('3.6' )
14
16
class TestJMXAuth (Tester ):
17
+ """
18
+ Uses nodetool as a means of exercising the JMX interface as JolokiaAgent
19
+ exposes its own connector which bypasses the in-built security features
20
+ """
15
21
16
22
def test_basic_auth (self ):
17
23
"""
18
24
Some basic smoke testing of JMX authentication and authorization.
19
- Uses nodetool as a means of exercising the JMX interface as JolokiaAgent
20
- exposes its own connector which bypasses the in-built security features
21
25
@jira_ticket CASSANDRA-10091
22
26
"""
23
27
self .prepare ()
@@ -55,6 +59,42 @@ def test_basic_auth(self):
55
59
# superuser status applies to JMX authz too
56
60
node .nodetool ('-u cassandra -pw cassandra gossipinfo' )
57
61
62
+ @since ('4.1' )
63
+ def test_revoked_jmx_access (self ):
64
+ """
65
+ if a user's access to a JMX MBean is revoked while they're connected,
66
+ all of their requests should fail once the cache is cleared.
67
+ @jira_ticket CASSANDRA-16404
68
+ """
69
+ self .prepare (permissions_validity = 60000 )
70
+ [node ] = self .cluster .nodelist ()
71
+
72
+ def test_revoked_access (cache_name ):
73
+ logger .debug ('Testing with cache name: %s' % cache_name )
74
+ username = self .username ()
75
+ session = self .patient_cql_connection (node , user = 'cassandra' , password = 'cassandra' )
76
+ session .execute ("CREATE ROLE %s WITH LOGIN=true AND PASSWORD='abc123'" % username )
77
+ session .execute ("GRANT SELECT ON MBEAN 'org.apache.cassandra.net:type=FailureDetector' TO %s" % username )
78
+ session .execute ("GRANT DESCRIBE ON ALL MBEANS TO %s" % username )
79
+
80
+ # works fine
81
+ node .nodetool ('-u %s -pw abc123 gossipinfo' % username )
82
+
83
+ session .execute ("REVOKE SELECT ON MBEAN 'org.apache.cassandra.net:type=FailureDetector' FROM %s" % username )
84
+ # works fine because the JMX permission is cached
85
+ node .nodetool ('-u %s -pw abc123 gossipinfo' % username )
86
+
87
+ node .nodetool ('-u cassandra -pw cassandra invalidatejmxpermissionscache' )
88
+ # the user has no permissions to the JMX resource anymore
89
+ with pytest .raises (ToolError , match = 'Access Denied' ):
90
+ node .nodetool ('-u %s -pw abc123 gossipinfo' % username )
91
+
92
+ test_revoked_access ("JmxPermissionsCache" )
93
+
94
+ # deprecated cache name, scheduled for removal in 5.0
95
+ if self .dtest_config .cassandra_version_from_build < '5.0' :
96
+ test_revoked_access ("JMXPermissionsCache" )
97
+
58
98
def prepare (self , nodes = 1 , permissions_validity = 0 ):
59
99
config = {'authenticator' : 'org.apache.cassandra.auth.PasswordAuthenticator' ,
60
100
'authorizer' : 'org.apache.cassandra.auth.CassandraAuthorizer' ,
@@ -69,3 +109,6 @@ def prepare(self, nodes=1, permissions_validity=0):
69
109
def authentication_fail_message (self , node , username ):
70
110
return "Provided username {user} and/or password are incorrect" .format (user = username ) \
71
111
if node .cluster .version () >= LooseVersion ('3.10' ) else "Username and/or password are incorrect"
112
+
113
+ def username (self ):
114
+ return '' .join (random .choice (string .ascii_lowercase ) for _ in range (8 ))
0 commit comments