forked from thepaul/cassandra-dtest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauth_roles_test.py
1202 lines (1040 loc) · 67.2 KB
/
auth_roles_test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import os
import re
import time
from ccmlib.common import get_version_from_build
from cassandra import AuthenticationFailed, Unauthorized, InvalidRequest
from cassandra.cluster import NoHostAvailable
from cassandra.protocol import SyntaxException
from auth_test import data_resource_creator_permissions, role_creator_permissions, function_resource_creator_permissions
from dtest import Tester
from assertions import assert_one, assert_all, assert_invalid
from tools import since
# Second value is superuser status
# Third value is login status, See #7653 for explanation.
mike_role = ['mike', False, True, {}]
role1_role = ['role1', False, False, {}]
role2_role = ['role2', False, False, {}]
cassandra_role = ['cassandra', True, True, {}]
@since('2.2')
class TestAuthRoles(Tester):
def __init__(self, *args, **kwargs):
CASSANDRA_DIR = os.environ.get('CASSANDRA_DIR')
if get_version_from_build(CASSANDRA_DIR) >= '3.0':
kwargs['cluster_options'] = {'enable_user_defined_functions': 'true',
'enable_scripted_user_defined_functions': 'true'}
else:
kwargs['cluster_options'] = {'enable_user_defined_functions': 'true'}
Tester.__init__(self, *args, **kwargs)
def create_drop_role_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
assert_one(cassandra, 'LIST ROLES', cassandra_role)
cassandra.execute("CREATE ROLE role1")
assert_all(cassandra, "LIST ROLES", [cassandra_role, role1_role])
cassandra.execute("DROP ROLE role1")
assert_one(cassandra, "LIST ROLES", cassandra_role)
def conditional_create_drop_role_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
assert_one(cassandra, "LIST ROLES", cassandra_role)
cassandra.execute("CREATE ROLE IF NOT EXISTS role1")
cassandra.execute("CREATE ROLE IF NOT EXISTS role1")
assert_all(cassandra, "LIST ROLES", [cassandra_role, role1_role])
cassandra.execute("DROP ROLE IF EXISTS role1")
cassandra.execute("DROP ROLE IF EXISTS role1")
assert_one(cassandra, "LIST ROLES", cassandra_role)
def create_drop_role_validation_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
mike = self.get_session(user='mike', password='12345')
assert_invalid(mike,
"CREATE ROLE role2",
"User mike does not have sufficient privileges to perform the requested operation",
Unauthorized)
cassandra.execute("CREATE ROLE role1")
assert_invalid(mike,
"DROP ROLE role1",
"User mike does not have sufficient privileges to perform the requested operation",
Unauthorized)
assert_invalid(cassandra, "CREATE ROLE role1", "role1 already exists")
cassandra.execute("DROP ROLE role1")
assert_invalid(cassandra, "DROP ROLE role1", "role1 doesn't exist")
def role_admin_validation_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE administrator WITH SUPERUSER = false AND LOGIN = false")
cassandra.execute("GRANT ALL ON ALL ROLES TO administrator")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("GRANT administrator TO mike")
cassandra.execute("CREATE ROLE klaus WITH PASSWORD = '54321' AND SUPERUSER = false AND LOGIN = true")
mike = self.get_session(user='mike', password='12345')
klaus = self.get_session(user='klaus', password='54321')
# roles with CREATE on ALL ROLES can create roles
mike.execute("CREATE ROLE role1 WITH PASSWORD = '11111' AND LOGIN = false")
# require ALTER on ALL ROLES or a SPECIFIC ROLE to modify
self.assert_unauthenticated('role1 is not permitted to log in', 'role1', '11111')
cassandra.execute("GRANT ALTER on ROLE role1 TO klaus")
klaus.execute("ALTER ROLE role1 WITH LOGIN = true")
mike.execute("ALTER ROLE role1 WITH PASSWORD = '22222'")
role1 = self.get_session(user='role1', password='22222')
# only superusers can set superuser status
assert_invalid(mike, "ALTER ROLE role1 WITH SUPERUSER = true",
"Only superusers are allowed to alter superuser status",
Unauthorized)
assert_invalid(mike, "ALTER ROLE mike WITH SUPERUSER = true",
"You aren't allowed to alter your own superuser status or that of a role granted to you",
Unauthorized)
# roles without necessary permissions cannot create, drop or alter roles except themselves
assert_invalid(role1, "CREATE ROLE role2 WITH LOGIN = false",
"User role1 does not have sufficient privileges to perform the requested operation",
Unauthorized)
assert_invalid(role1, "ALTER ROLE mike WITH LOGIN = false",
"User role1 does not have sufficient privileges to perform the requested operation",
Unauthorized)
assert_invalid(role1, "DROP ROLE mike",
"User role1 does not have sufficient privileges to perform the requested operation",
Unauthorized)
role1.execute("ALTER ROLE role1 WITH PASSWORD = '33333'")
# roles with roleadmin can drop roles
mike.execute("DROP ROLE role1")
assert_all(cassandra, "LIST ROLES", [['administrator', False, False, {}],
cassandra_role,
['klaus', False, True, {}],
mike_role])
# revoking role admin removes its privileges
cassandra.execute("REVOKE administrator FROM mike")
assert_invalid(mike, "CREATE ROLE role3 WITH LOGIN = false",
"User mike does not have sufficient privileges to perform the requested operation",
Unauthorized)
def creator_of_db_resource_granted_all_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("GRANT CREATE ON ALL KEYSPACES TO mike")
cassandra.execute("GRANT CREATE ON ALL ROLES TO mike")
mike = self.get_session(user='mike', password='12345')
# mike should automatically be granted permissions on any resource he creates, i.e. tables or roles
mike.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}")
mike.execute("CREATE TABLE ks.cf (id int primary key, val int)")
mike.execute("CREATE ROLE role1 WITH PASSWORD = '11111' AND SUPERUSER = false AND LOGIN = true")
mike.execute("""CREATE FUNCTION ks.state_function_1(a int, b int)
CALLED ON NULL INPUT
RETURNS int
LANGUAGE javascript
AS ' a + b'""")
mike.execute("""CREATE AGGREGATE ks.simple_aggregate_1(int)
SFUNC state_function_1
STYPE int
INITCOND 0""")
cassandra_permissions = role_creator_permissions('cassandra', '<role mike>')
mike_permissions = [('mike', '<all roles>', 'CREATE'),
('mike', '<all keyspaces>', 'CREATE')]
mike_permissions.extend(role_creator_permissions('mike', '<role role1>'))
mike_permissions.extend(data_resource_creator_permissions('mike', '<keyspace ks>'))
mike_permissions.extend(data_resource_creator_permissions('mike', '<table ks.cf>'))
mike_permissions.extend(function_resource_creator_permissions('mike', '<function ks.state_function_1(int, int)>'))
mike_permissions.extend(function_resource_creator_permissions('mike', '<function ks.simple_aggregate_1(int)>'))
self.assert_permissions_listed(cassandra_permissions + mike_permissions,
cassandra,
"LIST ALL PERMISSIONS")
def create_and_grant_roles_with_superuser_status_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE another_superuser WITH SUPERUSER = true AND LOGIN = false")
cassandra.execute("CREATE ROLE non_superuser WITH SUPERUSER = false AND LOGIN = false")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
# mike can create and grant any role, except superusers
cassandra.execute("GRANT CREATE ON ALL ROLES TO mike")
cassandra.execute("GRANT AUTHORIZE ON ALL ROLES TO mike")
# mike can create roles, but not with superuser status
# and can grant any role, including those with superuser status
mike = self.get_session(user='mike', password='12345')
mike.execute("CREATE ROLE role1 WITH SUPERUSER = false")
mike.execute("GRANT non_superuser TO role1")
mike.execute("GRANT another_superuser TO role1")
assert_invalid(mike, "CREATE ROLE role2 WITH SUPERUSER = true",
"Only superusers can create a role with superuser status",
Unauthorized)
assert_all(cassandra, "LIST ROLES OF role1", [['another_superuser', True, False, {}],
['non_superuser', False, False, {}],
['role1', False, False, {}]])
def drop_and_revoke_roles_with_superuser_status_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE another_superuser WITH SUPERUSER = true AND LOGIN = false")
cassandra.execute("CREATE ROLE non_superuser WITH SUPERUSER = false AND LOGIN = false")
cassandra.execute("CREATE ROLE role1 WITH SUPERUSER = false")
cassandra.execute("GRANT another_superuser TO role1")
cassandra.execute("GRANT non_superuser TO role1")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("GRANT DROP ON ALL ROLES TO mike")
cassandra.execute("GRANT AUTHORIZE ON ALL ROLES TO mike")
# mike can drop and revoke any role, including superusers
mike = self.get_session(user='mike', password='12345')
mike.execute("REVOKE another_superuser FROM role1")
mike.execute("REVOKE non_superuser FROM role1")
mike.execute("DROP ROLE non_superuser")
mike.execute("DROP ROLE role1")
def drop_role_removes_memberships_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE role1")
cassandra.execute("CREATE ROLE role2")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("GRANT role2 TO role1")
cassandra.execute("GRANT role1 TO mike")
assert_all(cassandra, "LIST ROLES OF mike", [mike_role, role1_role, role2_role])
# drop the role indirectly granted
cassandra.execute("DROP ROLE role2")
assert_all(cassandra, "LIST ROLES OF mike", [mike_role, role1_role])
cassandra.execute("CREATE ROLE role2")
cassandra.execute("GRANT role2 to role1")
assert_all(cassandra, "LIST ROLES OF mike", [mike_role, role1_role, role2_role])
# drop the directly granted role
cassandra.execute("DROP ROLE role1")
assert_one(cassandra, "LIST ROLES OF mike", mike_role)
assert_all(cassandra, "LIST ROLES", [cassandra_role, mike_role, role2_role])
def drop_role_revokes_permissions_granted_on_it_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE role1")
cassandra.execute("CREATE ROLE role2")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("GRANT ALTER ON ROLE role1 TO mike")
cassandra.execute("GRANT AUTHORIZE ON ROLE role2 TO mike")
self.assert_permissions_listed([("mike", "<role role1>", "ALTER"),
("mike", "<role role2>", "AUTHORIZE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("DROP ROLE role1")
cassandra.execute("DROP ROLE role2")
assert cassandra.execute("LIST ALL PERMISSIONS OF mike") is None
def grant_revoke_roles_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE role1")
cassandra.execute("CREATE ROLE role2")
cassandra.execute("GRANT role1 TO role2")
cassandra.execute("GRANT role2 TO mike")
assert_all(cassandra, "LIST ROLES OF role2", [role1_role, role2_role])
assert_all(cassandra, "LIST ROLES OF mike", [mike_role, role1_role, role2_role])
assert_all(cassandra, "LIST ROLES OF mike NORECURSIVE", [mike_role, role2_role])
cassandra.execute("REVOKE role2 FROM mike")
assert_one(cassandra, "LIST ROLES OF mike", mike_role)
cassandra.execute("REVOKE role1 FROM role2")
assert_one(cassandra, "LIST ROLES OF role2", role2_role)
def grant_revoke_role_validation_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
mike = self.get_session(user='mike', password='12345')
assert_invalid(cassandra, "GRANT role1 TO mike", "role1 doesn't exist")
cassandra.execute("CREATE ROLE role1")
assert_invalid(cassandra, "GRANT role1 TO john", "john doesn't exist")
assert_invalid(cassandra, "GRANT role2 TO john", "role2 doesn't exist")
cassandra.execute("CREATE ROLE john WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE role2")
assert_invalid(mike,
"GRANT role2 TO john",
"User mike does not have sufficient privileges to perform the requested operation",
Unauthorized)
# superusers can always grant roles
cassandra.execute("GRANT role1 TO john")
# but regular users need AUTHORIZE permission on the granted role
cassandra.execute("GRANT AUTHORIZE ON ROLE role2 TO mike")
mike.execute("GRANT role2 TO john")
# same applies to REVOKEing roles
assert_invalid(mike,
"REVOKE role1 FROM john",
"User mike does not have sufficient privileges to perform the requested operation",
Unauthorized)
cassandra.execute("REVOKE role1 FROM john")
mike.execute("REVOKE role2 from john")
def list_roles_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE role1")
cassandra.execute("CREATE ROLE role2")
assert_all(cassandra, "LIST ROLES", [cassandra_role, mike_role, role1_role, role2_role])
cassandra.execute("GRANT role1 TO role2")
cassandra.execute("GRANT role2 TO mike")
assert_all(cassandra, "LIST ROLES OF role2", [role1_role, role2_role])
assert_all(cassandra, "LIST ROLES OF mike", [mike_role, role1_role, role2_role])
assert_all(cassandra, "LIST ROLES OF mike NORECURSIVE", [mike_role, role2_role])
mike = self.get_session(user='mike', password='12345')
assert_invalid(mike,
"LIST ROLES OF cassandra",
"You are not authorized to view roles granted to cassandra",
Unauthorized)
assert_all(mike, "LIST ROLES", [mike_role, role1_role, role2_role])
assert_all(mike, "LIST ROLES OF mike", [mike_role, role1_role, role2_role])
assert_all(mike, "LIST ROLES OF mike NORECURSIVE", [mike_role, role2_role])
assert_all(mike, "LIST ROLES OF role2", [role1_role, role2_role])
# without SELECT permission on the root level roles resource, LIST ROLES with no OF
# returns only the roles granted to the user. With it, it includes all roles.
assert_all(mike, "LIST ROLES", [mike_role, role1_role, role2_role])
cassandra.execute("GRANT DESCRIBE ON ALL ROLES TO mike")
assert_all(mike, "LIST ROLES", [cassandra_role, mike_role, role1_role, role2_role])
def grant_revoke_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}")
cassandra.execute("CREATE TABLE ks.cf (id int primary key, val int)")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE role1")
cassandra.execute("GRANT ALL ON table ks.cf TO role1")
cassandra.execute("GRANT role1 TO mike")
mike = self.get_session(user='mike', password='12345')
mike.execute("INSERT INTO ks.cf (id, val) VALUES (0, 0)")
assert_one(mike, "SELECT * FROM ks.cf", [0, 0])
cassandra.execute("REVOKE role1 FROM mike")
assert_invalid(mike,
"INSERT INTO ks.cf (id, val) VALUES (0, 0)",
"mike has no MODIFY permission on <table ks.cf> or any of its parents",
Unauthorized)
cassandra.execute("GRANT role1 TO mike")
cassandra.execute("REVOKE ALL ON ks.cf FROM role1")
assert_invalid(mike,
"INSERT INTO ks.cf (id, val) VALUES (0, 0)",
"mike has no MODIFY permission on <table ks.cf> or any of its parents",
Unauthorized)
def filter_granted_permissions_by_resource_type_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}")
cassandra.execute("CREATE TABLE ks.cf (id int primary key, val int)")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE role1 WITH SUPERUSER = false AND LOGIN = false")
cassandra.execute("CREATE FUNCTION ks.state_func(a int, b int) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'a+b'")
cassandra.execute("CREATE AGGREGATE ks.agg_func(int) SFUNC state_func STYPE int")
# GRANT ALL ON ALL KEYSPACES grants Permission.ALL_DATA
# GRANT ALL ON KEYSPACE grants Permission.ALL_DATA
cassandra.execute("GRANT ALL ON KEYSPACE ks TO mike")
self.assert_permissions_listed([("mike", "<keyspace ks>", "CREATE"),
("mike", "<keyspace ks>", "ALTER"),
("mike", "<keyspace ks>", "DROP"),
("mike", "<keyspace ks>", "SELECT"),
("mike", "<keyspace ks>", "MODIFY"),
("mike", "<keyspace ks>", "AUTHORIZE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE ALL ON KEYSPACE ks FROM mike")
# GRANT ALL ON TABLE does not include CREATE (because the table must already be created before the GRANT)
cassandra.execute("GRANT ALL ON ks.cf TO MIKE")
self.assert_permissions_listed([("mike", "<table ks.cf>", "ALTER"),
("mike", "<table ks.cf>", "DROP"),
("mike", "<table ks.cf>", "SELECT"),
("mike", "<table ks.cf>", "MODIFY"),
("mike", "<table ks.cf>", "AUTHORIZE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE ALL ON ks.cf FROM mike")
assert_invalid(cassandra,
"GRANT CREATE ON ks.cf TO MIKE",
"Resource type DataResource does not support any of the requested permissions",
SyntaxException)
# GRANT ALL ON ALL ROLES includes SELECT & CREATE on the root level roles resource
cassandra.execute("GRANT ALL ON ALL ROLES TO mike")
self.assert_permissions_listed([("mike", "<all roles>", "CREATE"),
("mike", "<all roles>", "ALTER"),
("mike", "<all roles>", "DROP"),
("mike", "<all roles>", "DESCRIBE"),
("mike", "<all roles>", "AUTHORIZE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE ALL ON ALL ROLES FROM mike")
assert_invalid(cassandra,
"GRANT SELECT ON ALL ROLES TO MIKE",
"Resource type RoleResource does not support any of the requested permissions",
SyntaxException)
# GRANT ALL ON ROLE does not include CREATE (because the role must already be created before the GRANT)
cassandra.execute("GRANT ALL ON ROLE role1 TO mike")
self.assert_permissions_listed([("mike", "<role role1>", "ALTER"),
("mike", "<role role1>", "DROP"),
("mike", "<role role1>", "AUTHORIZE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
assert_invalid(cassandra,
"GRANT CREATE ON ROLE role1 TO MIKE",
"Resource type RoleResource does not support any of the requested permissions",
SyntaxException)
cassandra.execute("REVOKE ALL ON ROLE role1 FROM mike")
# GRANT ALL ON ALL FUNCTIONS or on all functions for a single keyspace includes AUTHORIZE, EXECUTE and USAGE
cassandra.execute("GRANT ALL ON ALL FUNCTIONS TO mike")
self.assert_permissions_listed([("mike", "<all functions>", "CREATE"),
("mike", "<all functions>", "ALTER"),
("mike", "<all functions>", "DROP"),
("mike", "<all functions>", "AUTHORIZE"),
("mike", "<all functions>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE ALL ON ALL FUNCTIONS FROM mike")
cassandra.execute("GRANT ALL ON ALL FUNCTIONS IN KEYSPACE ks TO mike")
self.assert_permissions_listed([("mike", "<all functions in ks>", "CREATE"),
("mike", "<all functions in ks>", "ALTER"),
("mike", "<all functions in ks>", "DROP"),
("mike", "<all functions in ks>", "AUTHORIZE"),
("mike", "<all functions in ks>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE ALL ON ALL FUNCTIONS IN KEYSPACE ks FROM mike")
# GRANT ALL ON FUNCTION includes AUTHORIZE, EXECUTE and USAGE for scalar functions and
# AUTHORIZE and EXECUTE for aggregates
cassandra.execute("GRANT ALL ON FUNCTION ks.state_func(int, int) TO mike")
self.assert_permissions_listed([("mike", "<function ks.state_func(int, int)>", "ALTER"),
("mike", "<function ks.state_func(int, int)>", "DROP"),
("mike", "<function ks.state_func(int, int)>", "AUTHORIZE"),
("mike", "<function ks.state_func(int, int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE ALL ON FUNCTION ks.state_func(int, int) FROM mike")
cassandra.execute("GRANT ALL ON FUNCTION ks.agg_func(int) TO mike")
self.assert_permissions_listed([("mike", "<function ks.agg_func(int)>", "ALTER"),
("mike", "<function ks.agg_func(int)>", "DROP"),
("mike", "<function ks.agg_func(int)>", "AUTHORIZE"),
("mike", "<function ks.agg_func(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE ALL ON FUNCTION ks.agg_func(int) FROM mike")
def list_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}")
cassandra.execute("CREATE TABLE ks.cf (id int primary key, val int)")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE role1")
cassandra.execute("CREATE ROLE role2")
cassandra.execute("GRANT SELECT ON table ks.cf TO role1")
cassandra.execute("GRANT ALTER ON table ks.cf TO role2")
cassandra.execute("GRANT MODIFY ON table ks.cf TO mike")
cassandra.execute("GRANT ALTER ON ROLE role1 TO role2")
cassandra.execute("GRANT role1 TO role2")
cassandra.execute("GRANT role2 TO mike")
expected_permissions = [("mike", "<table ks.cf>", "MODIFY"),
("role1", "<table ks.cf>", "SELECT"),
("role2", "<table ks.cf>", "ALTER"),
("role2", "<role role1>", "ALTER")]
expected_permissions.extend(data_resource_creator_permissions('cassandra', '<keyspace ks>'))
expected_permissions.extend(data_resource_creator_permissions('cassandra', '<table ks.cf>'))
expected_permissions.extend(role_creator_permissions('cassandra', '<role mike>'))
expected_permissions.extend(role_creator_permissions('cassandra', '<role role1>'))
expected_permissions.extend(role_creator_permissions('cassandra', '<role role2>'))
self.assert_permissions_listed(expected_permissions, cassandra, "LIST ALL PERMISSIONS")
self.assert_permissions_listed([("role1", "<table ks.cf>", "SELECT")],
cassandra,
"LIST ALL PERMISSIONS OF role1")
self.assert_permissions_listed([("role1", "<table ks.cf>", "SELECT"),
("role2", "<table ks.cf>", "ALTER"),
("role2", "<role role1>", "ALTER")],
cassandra,
"LIST ALL PERMISSIONS OF role2")
self.assert_permissions_listed([("cassandra", "<role role1>", "ALTER"),
("cassandra", "<role role1>", "DROP"),
("cassandra", "<role role1>", "AUTHORIZE"),
("role2", "<role role1>", "ALTER")],
cassandra,
"LIST ALL PERMISSIONS ON ROLE role1")
# we didn't specifically grant DROP on role1, so only it's creator should have it
self.assert_permissions_listed([("cassandra", "<role role1>", "DROP")],
cassandra,
"LIST DROP PERMISSION ON ROLE role1")
# but we did specifically grant ALTER role1 to role2
# so that should be listed whether we include an OF clause or not
self.assert_permissions_listed([("cassandra", "<role role1>", "ALTER"),
("role2", "<role role1>", "ALTER")],
cassandra,
"LIST ALTER PERMISSION ON ROLE role1")
self.assert_permissions_listed([("role2", "<role role1>", "ALTER")],
cassandra,
"LIST ALTER PERMISSION ON ROLE role1 OF role2")
# make sure ALTER on role2 is excluded properly when OF is for another role
cassandra.execute("CREATE ROLE role3 WITH SUPERUSER = false AND LOGIN = false")
assert cassandra.execute("LIST ALTER PERMISSION ON ROLE role1 OF role3") is None
# now check users can list their own permissions
mike = self.get_session(user='mike', password='12345')
self.assert_permissions_listed([("mike", "<table ks.cf>", "MODIFY"),
("role1", "<table ks.cf>", "SELECT"),
("role2", "<table ks.cf>", "ALTER"),
("role2", "<role role1>", "ALTER")],
mike,
"LIST ALL PERMISSIONS OF mike")
def list_permissions_validation_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}")
cassandra.execute("CREATE TABLE ks.cf (id int primary key, val int)")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE john WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE role1")
cassandra.execute("CREATE ROLE role2")
cassandra.execute("GRANT SELECT ON table ks.cf TO role1")
cassandra.execute("GRANT ALTER ON table ks.cf TO role2")
cassandra.execute("GRANT MODIFY ON table ks.cf TO john")
cassandra.execute("GRANT role1 TO role2")
cassandra.execute("GRANT role2 TO mike")
mike = self.get_session(user='mike', password='12345')
self.assert_permissions_listed([("role1", "<table ks.cf>", "SELECT"),
("role2", "<table ks.cf>", "ALTER")],
mike,
"LIST ALL PERMISSIONS OF role2")
self.assert_permissions_listed([("role1", "<table ks.cf>", "SELECT")],
mike,
"LIST ALL PERMISSIONS OF role1")
assert_invalid(mike,
"LIST ALL PERMISSIONS",
"You are not authorized to view everyone's permissions",
Unauthorized)
assert_invalid(mike,
"LIST ALL PERMISSIONS OF john",
"You are not authorized to view john's permissions",
Unauthorized)
def role_caching_authenticated_user_test(self):
# This test is to show that the role caching in AuthenticatedUser
# works correctly and revokes the roles from a logged in user
self.prepare(roles_expiry=2000)
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}")
cassandra.execute("CREATE TABLE ks.cf (id int primary key, val int)")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE role1")
cassandra.execute("GRANT ALL ON table ks.cf TO role1")
cassandra.execute("GRANT role1 TO mike")
mike = self.get_session(user='mike', password='12345')
mike.execute("INSERT INTO ks.cf (id, val) VALUES (0, 0)")
assert_one(mike, "SELECT * FROM ks.cf", [0, 0])
cassandra.execute("REVOKE role1 FROM mike")
# mike should retain permissions until the cache expires
unauthorized = None
cnt = 0
while not unauthorized and cnt < 20:
try:
mike.execute("SELECT * FROM ks.cf")
cnt += 1
time.sleep(.5)
except Unauthorized as e:
unauthorized = e
assert unauthorized is not None
def drop_non_existent_role_should_not_update_cache(self):
# The su status check during DROP ROLE IF EXISTS <role>
# should not cause a non-existent role to be cached (CASSANDRA-9189)
self.prepare(roles_expiry=10000)
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}")
cassandra.execute("CREATE TABLE ks.cf (id int primary key, val int)")
# Dropping a role which doesn't exist should be a no-op. If we cache the fact
# that the role doesn't exist though, subsequent authz attempts which should
# succeed will fail due to the erroneous cache entry
cassandra.execute("DROP ROLE IF EXISTS mike")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
cassandra.execute("GRANT ALL ON ks.cf TO mike")
mike = self.get_session(user='mike', password='12345')
mike.execute("SELECT * FROM ks.cf")
def prevent_circular_grants_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike")
cassandra.execute("CREATE ROLE role1")
cassandra.execute("CREATE ROLE role2")
cassandra.execute("GRANT role2 to role1")
cassandra.execute("GRANT role1 TO mike")
assert_invalid(cassandra,
"GRANT mike TO role1",
"mike is a member of role1",
InvalidRequest)
assert_invalid(cassandra,
"GRANT mike TO role2",
"mike is a member of role2",
InvalidRequest)
def create_user_as_alias_for_create_role_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE USER mike WITH PASSWORD '12345' NOSUPERUSER")
assert_one(cassandra, "LIST ROLES OF mike", mike_role)
cassandra.execute("CREATE USER super_user WITH PASSWORD '12345' SUPERUSER")
assert_one(cassandra, "LIST ROLES OF super_user", ["super_user", True, True, {}])
def role_requires_login_privilege_to_authenticate_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
assert_one(cassandra, "LIST ROLES OF mike", mike_role)
self.get_session(user='mike', password='12345')
cassandra.execute("ALTER ROLE mike WITH LOGIN = false")
assert_one(cassandra, "LIST ROLES OF mike", ["mike", False, False, {}])
self.assert_unauthenticated('mike is not permitted to log in', 'mike', '12345')
cassandra.execute("ALTER ROLE mike WITH LOGIN = true")
assert_one(cassandra, "LIST ROLES OF mike", ["mike", False, True, {}])
self.get_session(user='mike', password='12345')
def roles_do_not_inherit_login_privilege_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = false")
cassandra.execute("CREATE ROLE with_login WITH PASSWORD = '54321' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("GRANT with_login to mike")
assert_all(cassandra, "LIST ROLES OF mike", [["mike", False, False, {}],
["with_login", False, True, {}]])
assert_one(cassandra, "LIST ROLES OF with_login", ["with_login", False, True, {}])
self.assert_unauthenticated("mike is not permitted to log in", "mike", "12345")
def role_requires_password_to_login_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH SUPERUSER = false AND LOGIN = true")
self.assert_unauthenticated("Username and/or password are incorrect", 'mike', None)
cassandra.execute("ALTER ROLE mike WITH PASSWORD = '12345'")
self.get_session(user='mike', password='12345')
def superuser_status_is_inherited_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("CREATE ROLE db_admin WITH SUPERUSER = true")
mike = self.get_session(user='mike', password='12345')
assert_invalid(mike,
"CREATE ROLE another_role WITH SUPERUSER = false AND LOGIN = false",
"User mike does not have sufficient privileges to perform the requested operation",
Unauthorized)
cassandra.execute("GRANT db_admin TO mike")
mike.execute("CREATE ROLE another_role WITH SUPERUSER = false AND LOGIN = false")
assert_all(mike, "LIST ROLES", [["another_role", False, False, {}],
cassandra_role,
["db_admin", True, False, {}],
mike_role])
def list_users_considers_inherited_superuser_status_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
cassandra.execute("CREATE ROLE db_admin WITH SUPERUSER = true")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true")
cassandra.execute("GRANT db_admin TO mike")
assert_all(cassandra, "LIST USERS", [['cassandra', True],
["mike", True]])
# UDF permissions tests TODO move to separate fixture & refactor this + auth_test.py
def grant_revoke_udf_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
self.setup_table(cassandra)
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
cassandra.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
cassandra.execute("CREATE FUNCTION ks.\"plusOne\" ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
# grant / revoke on a specific function
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO mike")
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.\"plusOne\"(int) TO mike")
self.assert_permissions_listed([("mike", "<function ks.plus_one(int)>", "EXECUTE"),
("mike", "<function ks.plusOne(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE ALL PERMISSIONS ON FUNCTION ks.plus_one(int) FROM mike")
self.assert_permissions_listed([("mike", "<function ks.plusOne(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE EXECUTE PERMISSION ON FUNCTION ks.\"plusOne\"(int) FROM mike")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
# grant / revoke on all functions in a given keyspace
cassandra.execute("GRANT EXECUTE PERMISSION ON ALL FUNCTIONS IN KEYSPACE ks TO mike")
self.assert_permissions_listed([("mike", "<all functions in ks>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE EXECUTE PERMISSION ON ALL FUNCTIONS IN KEYSPACE ks FROM mike")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
# grant / revoke on all (non-builtin) functions
cassandra.execute("GRANT EXECUTE PERMISSION ON ALL FUNCTIONS TO mike")
self.assert_permissions_listed([("mike", "<all functions>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE EXECUTE PERMISSION ON ALL FUNCTIONS FROM mike")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
def grant_revoke_are_idempotent_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
self.setup_table(cassandra)
cassandra.execute("CREATE ROLE mike")
cassandra.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO mike")
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO mike")
self.assert_permissions_listed([("mike", "<function ks.plus_one(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE EXECUTE ON FUNCTION ks.plus_one(int) FROM mike")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
cassandra.execute("REVOKE EXECUTE ON FUNCTION ks.plus_one(int) FROM mike")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
def function_resource_hierarchy_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
self.setup_table(cassandra)
cassandra.execute("INSERT INTO ks.t1 (k,v) values (1,1)")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
cassandra.execute("GRANT SELECT ON ks.t1 TO mike")
cassandra.execute("CREATE FUNCTION ks.func_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
cassandra.execute("CREATE FUNCTION ks.func_two ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
mike = self.get_session(user='mike', password='12345')
select_one = "SELECT k, v, ks.func_one(v) FROM ks.t1 WHERE k = 1"
select_two = "SELECT k, v, ks.func_two(v) FROM ks.t1 WHERE k = 1"
# grant EXECUTE on only one of the two functions
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.func_one(int) TO mike")
mike.execute(select_one)
assert_invalid(mike, select_two,
"User mike has no EXECUTE permission on <function ks.func_two\(int\)> or any of its parents",
Unauthorized)
# granting EXECUTE on all of the parent keyspace's should enable mike to use both functions
cassandra.execute("GRANT EXECUTE ON ALL FUNCTIONS IN KEYSPACE ks TO mike")
mike.execute(select_one)
mike.execute(select_two)
# revoke the keyspace level privilege and verify that the function specific perms are unaffected
cassandra.execute("REVOKE EXECUTE ON ALL FUNCTIONS IN KEYSPACE ks FROM mike")
mike.execute(select_one)
assert_invalid(mike, select_two,
"User mike has no EXECUTE permission on <function ks.func_two\(int\)> or any of its parents",
Unauthorized)
# now check that EXECUTE on ALL FUNCTIONS works in the same way
cassandra.execute("GRANT EXECUTE ON ALL FUNCTIONS TO mike")
mike.execute(select_one)
mike.execute(select_two)
cassandra.execute("REVOKE EXECUTE ON ALL FUNCTIONS FROM mike")
mike.execute(select_one)
assert_invalid(mike, select_two,
"User mike has no EXECUTE permission on <function ks.func_two\(int\)> or any of its parents",
Unauthorized)
# finally, check that revoking function level permissions doesn't affect root/keyspace level perms
cassandra.execute("GRANT EXECUTE ON ALL FUNCTIONS IN KEYSPACE ks TO mike")
cassandra.execute("REVOKE EXECUTE ON FUNCTION ks.func_one(int) FROM mike")
mike.execute(select_one)
mike.execute(select_two)
cassandra.execute("REVOKE EXECUTE ON ALL FUNCTIONS IN KEYSPACE ks FROM mike")
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.func_one(int) TO mike")
cassandra.execute("GRANT EXECUTE ON ALL FUNCTIONS TO mike")
mike.execute(select_one)
mike.execute(select_two)
cassandra.execute("REVOKE EXECUTE ON FUNCTION ks.func_one(int) FROM mike")
mike.execute(select_one)
mike.execute(select_two)
def udf_permissions_validation_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
self.setup_table(cassandra)
cassandra.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
mike = self.get_session(user='mike', password='12345')
# can't replace an existing function without ALTER permission on the parent ks
cql = "CREATE OR REPLACE FUNCTION ks.plus_one( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript as '1 + input'"
assert_invalid(mike, cql,
"User mike has no ALTER permission on <function ks.plus_one\(int\)> or any of its parents",
Unauthorized)
cassandra.execute("GRANT ALTER ON FUNCTION ks.plus_one(int) TO mike")
mike.execute(cql)
# can't grant permissions on a function without AUTHORIZE (and without the grantor having EXECUTE themself)
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO mike")
cassandra.execute("CREATE ROLE role1")
cql = "GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO role1"
assert_invalid(mike, cql,
"User mike has no AUTHORIZE permission on <function ks.plus_one\(int\)> or any of its parents",
Unauthorized)
cassandra.execute("GRANT AUTHORIZE ON FUNCTION ks.plus_one(int) TO mike")
mike.execute(cql)
# now revoke AUTHORIZE from mike
cassandra.execute("REVOKE AUTHORIZE ON FUNCTION ks.plus_one(int) FROM mike")
cql = "REVOKE EXECUTE ON FUNCTION ks.plus_one(int) FROM role1"
assert_invalid(mike, cql,
"User mike has no AUTHORIZE permission on <function ks.plus_one\(int\)> or any of its parents",
Unauthorized)
cassandra.execute("GRANT AUTHORIZE ON FUNCTION ks.plus_one(int) TO mike")
mike.execute(cql)
# can't drop a function without DROP
cql = "DROP FUNCTION ks.plus_one(int)"
assert_invalid(mike, cql,
"User mike has no DROP permission on <function ks.plus_one\(int\)> or any of its parents",
Unauthorized)
cassandra.execute("GRANT DROP ON FUNCTION ks.plus_one(int) TO mike")
mike.execute(cql)
# DROP IF EXISTS on a non-existent function should return silently, DROP on a non-existent function
# behaves like DROP TABLE and returns an "Unconfigured XXX" error
cql = "DROP FUNCTION IF EXISTS ks.no_such_function(int,int)"
mike.execute(cql)
cql = "DROP FUNCTION ks.no_such_function(int,int)"
assert_invalid(mike, cql,
"Unconfigured function ks.no_such_function\(int,int\)",
InvalidRequest)
# can't create a new function without CREATE on the parent keyspace's collection of functions
cql = "CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'"
assert_invalid(mike, cql,
"User mike has no CREATE permission on <all functions in ks> or any of its parents",
Unauthorized)
cassandra.execute("GRANT CREATE ON ALL FUNCTIONS IN KEYSPACE ks TO mike")
mike.execute(cql)
def drop_role_cleans_up_udf_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
self.setup_table(cassandra)
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
cassandra.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO mike")
cassandra.execute("GRANT EXECUTE ON ALL FUNCTIONS IN KEYSPACE ks TO mike")
cassandra.execute("GRANT EXECUTE ON ALL FUNCTIONS TO mike")
self.assert_permissions_listed([("mike", "<all functions>", "EXECUTE"),
("mike", "<all functions in ks>", "EXECUTE"),
("mike", "<function ks.plus_one(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
# drop and recreate the role to ensure permissions are cleared
cassandra.execute("DROP ROLE mike")
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
def drop_function_and_keyspace_cleans_up_udf_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
self.setup_table(cassandra)
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
cassandra.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO mike")
cassandra.execute("GRANT EXECUTE ON ALL FUNCTIONS IN KEYSPACE ks TO mike")
self.assert_permissions_listed([("mike", "<all functions in ks>", "EXECUTE"),
("mike", "<function ks.plus_one(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
# drop the function
cassandra.execute("DROP FUNCTION ks.plus_one")
self.assert_permissions_listed([("mike", "<all functions in ks>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
# drop the keyspace
cassandra.execute("DROP KEYSPACE ks")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
def udf_with_overloads_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
self.setup_table(cassandra)
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
cassandra.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
cassandra.execute("CREATE FUNCTION ks.plus_one ( input double ) CALLED ON NULL INPUT RETURNS double LANGUAGE javascript AS 'input + 1'")
# grant execute on one variant
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO mike")
self.assert_permissions_listed([("mike", "<function ks.plus_one(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
# and now on the other
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(double) TO mike")
self.assert_permissions_listed([("mike", "<function ks.plus_one(int)>", "EXECUTE"),
("mike", "<function ks.plus_one(double)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
# revoke permissions on one of the functions only
cassandra.execute("REVOKE EXECUTE ON FUNCTION ks.plus_one(double) FROM mike")
self.assert_permissions_listed([("mike", "<function ks.plus_one(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
# drop the function that the role has no permissions on
cassandra.execute("DROP FUNCTION ks.plus_one(double)")
self.assert_permissions_listed([("mike", "<function ks.plus_one(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
# finally, drop the function that the role does have permissions on
cassandra.execute("DROP FUNCTION ks.plus_one(int)")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
def drop_keyspace_cleans_up_function_level_permissions_test(self):
self.prepare()
cassandra = self.get_session(user='cassandra', password='cassandra')
self.setup_table(cassandra)
cassandra.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true")
cassandra.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'")
cassandra.execute("GRANT EXECUTE ON FUNCTION ks.plus_one(int) TO mike")
self.assert_permissions_listed([("mike", "<function ks.plus_one(int)>", "EXECUTE")],
cassandra,
"LIST ALL PERMISSIONS OF mike")
# drop the keyspace
cassandra.execute("DROP KEYSPACE ks")
self.assert_no_permissions(cassandra, "LIST ALL PERMISSIONS OF mike")
def udf_permissions_in_selection_test(self):
self.verify_udf_permissions("SELECT k, v, ks.plus_one(v) FROM ks.t1 WHERE k = 1")
def udf_permissions_in_select_where_clause_test(self):
self.verify_udf_permissions("SELECT k, v FROM ks.t1 WHERE k = ks.plus_one(0)")
def udf_permissions_in_insert_test(self):
self.verify_udf_permissions("INSERT INTO ks.t1 (k, v) VALUES (1, ks.plus_one(1))")
def udf_permissions_in_update_test(self):
self.verify_udf_permissions("UPDATE ks.t1 SET v = ks.plus_one(2) WHERE k = ks.plus_one(0)")
def udf_permissions_in_delete_test(self):
self.verify_udf_permissions("DELETE FROM ks.t1 WHERE k = ks.plus_one(0)")
def verify_udf_permissions(self, cql):
self.prepare()