20
20
import java .net .InetSocketAddress ;
21
21
import java .net .SocketAddress ;
22
22
import java .util .Arrays ;
23
- import java .util .HashSet ;
23
+ import java .util .List ;
24
24
import java .util .Set ;
25
25
import java .util .concurrent .atomic .AtomicLong ;
26
26
27
+ import com .google .common .collect .ImmutableSet ;
27
28
import org .slf4j .Logger ;
28
29
import org .slf4j .LoggerFactory ;
29
30
41
42
import org .apache .cassandra .exceptions .UnauthorizedException ;
42
43
import org .apache .cassandra .schema .SchemaKeyspace ;
43
44
import org .apache .cassandra .thrift .ThriftValidation ;
45
+ import org .apache .cassandra .tracing .TraceKeyspace ;
44
46
import org .apache .cassandra .utils .FBUtilities ;
45
47
import org .apache .cassandra .utils .JVMStabilityInspector ;
46
48
import org .apache .cassandra .utils .CassandraVersion ;
@@ -54,29 +56,40 @@ public class ClientState
54
56
private static final Logger logger = LoggerFactory .getLogger (ClientState .class );
55
57
public static final CassandraVersion DEFAULT_CQL_VERSION = org .apache .cassandra .cql3 .QueryProcessor .CQL_VERSION ;
56
58
57
- private static final Set <IResource > READABLE_SYSTEM_RESOURCES = new HashSet <>() ;
58
- private static final Set <IResource > PROTECTED_AUTH_RESOURCES = new HashSet <>() ;
59
- private static final Set <IResource > DROPPABLE_SYSTEM_AUTH_TABLES = new HashSet <>() ;
59
+ public static final ImmutableSet <IResource > READABLE_SYSTEM_RESOURCES ;
60
+ public static final ImmutableSet <IResource > PROTECTED_AUTH_RESOURCES ;
61
+ public static final ImmutableSet <IResource > DROPPABLE_SYSTEM_AUTH_TABLES ;
60
62
static
61
63
{
62
64
// We want these system cfs to be always readable to authenticated users since many tools rely on them
63
65
// (nodetool, cqlsh, bulkloader, etc.)
64
- for (String cf : Arrays .asList (SystemKeyspace .LOCAL , SystemKeyspace .PEERS ))
65
- READABLE_SYSTEM_RESOURCES .add (DataResource .table (SystemKeyspace .NAME , cf ));
66
+ ImmutableSet .Builder <IResource > readableBuilder = ImmutableSet .builder ();
67
+ for (String cf : Arrays .asList (SystemKeyspace .LOCAL , SystemKeyspace .PEERS , SystemKeyspace .SIZE_ESTIMATES ))
68
+ readableBuilder .add (DataResource .table (SystemKeyspace .NAME , cf ));
66
69
67
- SchemaKeyspace .ALL .forEach (table -> READABLE_SYSTEM_RESOURCES .add (DataResource .table (SchemaKeyspace .NAME , table )));
70
+ // make all schema tables readable by default (required by the drivers)
71
+ SchemaKeyspace .ALL .forEach (table -> readableBuilder .add (DataResource .table (SchemaKeyspace .NAME , table )));
68
72
73
+ // make system_traces readable by all or else tracing will require explicit grants
74
+ readableBuilder .add (DataResource .table (TraceKeyspace .NAME , TraceKeyspace .EVENTS ));
75
+ readableBuilder .add (DataResource .table (TraceKeyspace .NAME , TraceKeyspace .SESSIONS ));
76
+ READABLE_SYSTEM_RESOURCES = readableBuilder .build ();
77
+
78
+ ImmutableSet .Builder <IResource > protectedBuilder = ImmutableSet .builder ();
79
+ // neither clients nor tools need authentication/authorization
69
80
if (!Config .isClientMode ())
70
81
{
71
- PROTECTED_AUTH_RESOURCES .addAll (DatabaseDescriptor .getAuthenticator ().protectedResources ());
72
- PROTECTED_AUTH_RESOURCES .addAll (DatabaseDescriptor .getAuthorizer ().protectedResources ());
73
- PROTECTED_AUTH_RESOURCES .addAll (DatabaseDescriptor .getRoleManager ().protectedResources ());
82
+ protectedBuilder .addAll (DatabaseDescriptor .getAuthenticator ().protectedResources ());
83
+ protectedBuilder .addAll (DatabaseDescriptor .getAuthorizer ().protectedResources ());
84
+ protectedBuilder .addAll (DatabaseDescriptor .getRoleManager ().protectedResources ());
74
85
}
75
-
86
+ PROTECTED_AUTH_RESOURCES = protectedBuilder .build ();
87
+ ImmutableSet .Builder <IResource > droppableBuilder = ImmutableSet .builder ();
76
88
// allow users with sufficient privileges to drop legacy tables (users, credentials, permissions) from AUTH_KS
77
- DROPPABLE_SYSTEM_AUTH_TABLES .add (DataResource .table (AuthKeyspace .NAME , PasswordAuthenticator .LEGACY_CREDENTIALS_TABLE ));
78
- DROPPABLE_SYSTEM_AUTH_TABLES .add (DataResource .table (AuthKeyspace .NAME , CassandraRoleManager .LEGACY_USERS_TABLE ));
79
- DROPPABLE_SYSTEM_AUTH_TABLES .add (DataResource .table (AuthKeyspace .NAME , CassandraAuthorizer .USER_PERMISSIONS ));
89
+ droppableBuilder .add (DataResource .table (AuthKeyspace .NAME , PasswordAuthenticator .LEGACY_CREDENTIALS_TABLE ));
90
+ droppableBuilder .add (DataResource .table (AuthKeyspace .NAME , CassandraRoleManager .LEGACY_USERS_TABLE ));
91
+ droppableBuilder .add (DataResource .table (AuthKeyspace .NAME , CassandraAuthorizer .USER_PERMISSIONS ));
92
+ DROPPABLE_SYSTEM_AUTH_TABLES = droppableBuilder .build ();
80
93
}
81
94
82
95
// Current user for the session
@@ -328,9 +341,12 @@ private void hasAccess(String keyspace, Permission perm, DataResource resource)
328
341
329
342
preventSystemKSSchemaModification (keyspace , resource , perm );
330
343
344
+ // Some system data is always readable
331
345
if ((perm == Permission .SELECT ) && READABLE_SYSTEM_RESOURCES .contains (resource ))
332
346
return ;
333
347
348
+ // Modifications to any resource upon which the authenticator, authorizer or role manager depend should not be
349
+ // be performed by users
334
350
if (PROTECTED_AUTH_RESOURCES .contains (resource ))
335
351
if ((perm == Permission .CREATE ) || (perm == Permission .ALTER ) || (perm == Permission .DROP ))
336
352
throw new UnauthorizedException (String .format ("%s schema is protected" , resource ));
@@ -348,7 +364,25 @@ public void ensureHasPermission(Permission perm, IResource resource) throws Unau
348
364
if (((FunctionResource )resource ).getKeyspace ().equals (SystemKeyspace .NAME ))
349
365
return ;
350
366
351
- checkPermissionOnResourceChain (perm , resource );
367
+ if (resource instanceof DataResource && !(user .isSuper () || user .isSystem ()))
368
+ {
369
+ DataResource dataResource = (DataResource )resource ;
370
+ if (!dataResource .isRootLevel ())
371
+ {
372
+ String keyspace = dataResource .getKeyspace ();
373
+ // A user may have permissions granted on ALL KEYSPACES, but this should exclude system keyspaces. Any
374
+ // permission on those keyspaces or their tables must be granted to the user either explicitly or
375
+ // transitively. The set of grantable permissions for system keyspaces is further limited,
376
+ // see the Permission enum for details.
377
+ if (Schema .isSystemKeyspace (keyspace ))
378
+ {
379
+ ensurePermissionOnResourceChain (perm , Resources .chain (dataResource , IResource ::hasParent ));
380
+ return ;
381
+ }
382
+ }
383
+ }
384
+
385
+ ensurePermissionOnResourceChain (perm , resource );
352
386
}
353
387
354
388
// Convenience method called from checkAccess method of CQLStatement
@@ -363,14 +397,20 @@ public void ensureHasPermission(Permission permission, Function function)
363
397
if (function .isNative ())
364
398
return ;
365
399
366
- checkPermissionOnResourceChain (permission , FunctionResource .function (function .name ().keyspace ,
367
- function .name ().name ,
368
- function .argTypes ()));
400
+ ensurePermissionOnResourceChain (permission , FunctionResource .function (function .name ().keyspace ,
401
+ function .name ().name ,
402
+ function .argTypes ()));
403
+ }
404
+
405
+ private void ensurePermissionOnResourceChain (Permission perm , IResource resource )
406
+ {
407
+ ensurePermissionOnResourceChain (perm , Resources .chain (resource ));
369
408
}
370
409
371
- private void checkPermissionOnResourceChain (Permission perm , IResource resource )
410
+ private void ensurePermissionOnResourceChain (Permission perm , List <? extends IResource > resources )
372
411
{
373
- for (IResource r : Resources .chain (resource ))
412
+ IResource resource = resources .get (0 );
413
+ for (IResource r : resources )
374
414
if (authorize (r ).contains (perm ))
375
415
return ;
376
416
0 commit comments