Implement Virtual Tables for Auth Caches

Patch by Aleksei Zotov; reviewed by Sam Tunnicliffe, and Benjamin Lerer for CASSANDRA-16914
This commit is contained in:
Aleksei Zotov 2021-09-17 17:52:07 +04:00
parent eae7b9c3ad
commit 63292292b8
37 changed files with 1522 additions and 158 deletions

View File

@ -1,4 +1,5 @@
4.1
* Implement Virtual Tables for Auth Caches (CASSANDRA-16914)
* Actively update auth cache in the background (CASSANDRA-16957)
* Add unix time conversion functions (CASSANDRA-17029)
* JVMStabilityInspector.forceHeapSpaceOomMaybe should handle all non-heap OOMs rather than only supporting direct only (CASSANDRA-17128)

View File

@ -69,6 +69,9 @@ New features
- Added a new feature to allow denylisting (i.e. blocking read, write, or range read configurable) access to partition
keys in configured keyspaces and tables. See doc/operating/denylisting_partitions.rst for details on using this new
feature. Also see CASSANDRA-12106.
- Information about pending hints is now available through `nodetool listpendinghints` and `pending_hints` virtual
table.
- Added ability to invalidate auth caches through corresponding `nodetool` commands and virtual tables.
Upgrading
---------
@ -76,8 +79,6 @@ Upgrading
confirm it is set to value lower than 31 otherwise Cassandra will fail to start. See CASSANDRA-9384
for further details. You also need to regenerate passwords for users for who the password
was created while the above property was set to be more than 30 otherwise they will not be able to log in.
- Information about pending hints is now available through `nodetool listpendinghints` and `pending_hints` virtual
table.
Deprecation
-----------

View File

@ -17,8 +17,7 @@
Virtual Tables
--------------
Apache Cassandra 4.0 implements virtual tables (`CASSANDRA-7622
<https://issues.apache.org/jira/browse/CASSANDRA-7622>`_).
Virtual tables are supported starting from version 4.0.
Definition
^^^^^^^^^^
@ -92,52 +91,69 @@ Virtual tables in a virtual keyspace may be listed with ``DESC TABLES``. The ``
cqlsh> USE system_views;
cqlsh:system_views> DESC TABLES;
coordinator_scans clients tombstones_scanned internode_inbound
disk_usage sstable_tasks live_scanned caches
local_writes max_partition_size local_reads
coordinator_writes internode_outbound thread_pools
local_scans coordinator_reads settings
caches internode_outbound roles_cache_keys
clients jmx_permissions_cache_keys rows_per_read
coordinator_read_latency local_read_latency settings
coordinator_scan_latency local_scan_latency sstable_tasks
coordinator_write_latency local_write_latency system_properties
credentials_cache_keys max_partition_size thread_pools
disk_usage network_permissions_cache_keys tombstones_per_read
internode_inbound permissions_cache_keys
Some of the salient virtual tables in ``system_views`` virtual keyspace are described in Table 1.
Table 1 : Virtual Tables in system_views
+------------------+---------------------------------------------------+
|Virtual Table | Description |
+------------------+---------------------------------------------------+
| clients |Lists information about all connected clients. |
+------------------+---------------------------------------------------+
| disk_usage |Disk usage including disk_space, keyspace_name, |
| |and table_name by system keyspaces. |
+------------------+---------------------------------------------------+
| local_writes |A table metric for local writes |
| |including count, keyspace_name, |
| |max, median, per_second, and |
| |table_name. |
+------------------+---------------------------------------------------+
| caches |Displays the general cache information including |
| |cache name, capacity_bytes, entry_count, hit_count,|
| |hit_ratio double, recent_hit_rate_per_second, |
| |recent_request_rate_per_second, request_count, and |
| |size_bytes. |
+------------------+---------------------------------------------------+
| local_reads |A table metric for local reads information. |
+------------------+---------------------------------------------------+
| sstable_tasks |Lists currently running tasks such as compactions |
| |and upgrades on SSTables. |
+------------------+---------------------------------------------------+
|internode_inbound |Lists information about the inbound |
| |internode messaging. |
+------------------+---------------------------------------------------+
| thread_pools |Lists metrics for each thread pool. |
+------------------+---------------------------------------------------+
| settings |Displays configuration settings in cassandra.yaml. |
+------------------+---------------------------------------------------+
|max_partition_size|A table metric for maximum partition size. |
+------------------+---------------------------------------------------+
|internode_outbound|Information about the outbound internode messaging.|
| | |
+------------------+---------------------------------------------------+
+------------------------------+---------------------------------------------------+
|Virtual Table | Description |
+------------------------------+---------------------------------------------------+
| clients |Lists information about all connected clients. |
+------------------------------+---------------------------------------------------+
| disk_usage |Disk usage including disk_space, keyspace_name, |
| |and table_name by system keyspaces. |
+------------------------------+---------------------------------------------------+
| local_writes |A table metric for local writes |
| |including count, keyspace_name, |
| |max, median, per_second, and |
| |table_name. |
+------------------------------+---------------------------------------------------+
| caches |Displays the general cache information including |
| |cache name, capacity_bytes, entry_count, hit_count,|
| |hit_ratio double, recent_hit_rate_per_second, |
| |recent_request_rate_per_second, request_count, and |
| |size_bytes. |
+------------------------------+---------------------------------------------------+
| local_reads |A table metric for local reads information. |
+------------------------------+---------------------------------------------------+
| sstable_tasks |Lists currently running tasks such as compactions |
| |and upgrades on SSTables. |
+------------------------------+---------------------------------------------------+
| internode_inbound |Lists information about the inbound internode |
| |messaging. |
+------------------------------+---------------------------------------------------+
| thread_pools |Lists metrics for each thread pool. |
+------------------------------+---------------------------------------------------+
| settings |Displays configuration settings in cassandra.yaml. |
+------------------------------+---------------------------------------------------+
| max_partition_size |A table metric for maximum partition size. |
+------------------------------+---------------------------------------------------+
| internode_outbound |Information about the outbound internode messaging.|
+------------------------------+---------------------------------------------------+
| credentials_cache_keys |Displays credentials cache keys. Supports DELETE |
| |and TRUNCATE operations. |
+------------------------------+---------------------------------------------------+
| jmx_permissions_cache_keys |Displays JMX permissions cache keys. Supports |
| |DELETE and TRUNCATE operations. |
+------------------------------+---------------------------------------------------+
|network_permissions_cache_keys|Displays netwrok permissions cache keys. Supports |
| |DELETE and TRUNCATE operations. |
+------------------------------+---------------------------------------------------+
| permissions_cache_keys |Displays permissions cache keys. Supports DELETE |
| |and TRUNCATE operations. |
+------------------------------+---------------------------------------------------+
| roles_cache_keys |Displays roles cache keys. Supports DELETE and |
| |TRUNCATE operations. |
+------------------------------+---------------------------------------------------+
We shall discuss some of the virtual tables in more detail next.
@ -187,7 +203,7 @@ The virtual tables may be described with ``DESCRIBE`` statement. The DDL listed
Caches Virtual Table
********************
The ``caches`` virtual table lists information about the caches. The four caches presently created are chunks, counters, keys and rows. A query on the ``caches`` virtual table returns the following details:
The ``caches`` virtual table lists information about the caches. The four caches presently created are chunks, counters, keys and rows. A query on the ``caches`` virtual table returns the following details:
::
@ -307,6 +323,57 @@ As another example, to find how much time is remaining for SSTable tasks, use th
SELECT total - progress AS remaining
FROM system_views.sstable_tasks;
Auth Caches Keys Virtual Tables
****************************
Every authentication cache has a separate virtual table associated. The virtual tables show the keys stored in caches
and additionally support DELETE and TRUNCATE operations. In fact these operations just invalidate data in caches, no
data is actually deleted from real tables.
The tables show the following information:
::
cqlsh:system_views> select * from credentials_cache_keys;
role
------
bob
(1 rows)
::
cqlsh:system_views> select * from jmx_permissions_cache_keys;
role
------
bob
(1 rows)
::
cqlsh:system_views> select * from network_permissions_cache_keys;
role
------
bob
(1 rows)
::
cqlsh:system_views> select * from permissions_cache_keys;
role | resource
------+-------------
bob | roles/alice
bob | data/ks1
(2 rows)
::
cqlsh:system_views> select * from roles_cache_keys;
role
------
bob
(1 rows)
Other Virtual Tables
********************

View File

@ -18,7 +18,9 @@
package org.apache.cassandra.auth;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@ -188,6 +190,17 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
return MBEAN_NAME_BASE + name;
}
/**
* Retrive all cached entries. Will call {@link LoadingCache#asMap()} which does not trigger "load".
* @return a map of cached key-value pairs
*/
public Map<K, V> getAll()
{
if (cache == null)
return Collections.emptyMap();
return Collections.unmodifiableMap(cache.asMap());
}
/**
* Retrieve a value from the cache. Will call {@link LoadingCache#get(Object)} which will
* "load" the value if it's not present, thus populating the key.
@ -213,7 +226,7 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
}
/**
* Invalidate a key
* Invalidate a key.
* @param k key to invalidate
*/
public void invalidate(K k)

View File

@ -38,8 +38,8 @@ public class AuthenticatedUser
public static final AuthenticatedUser ANONYMOUS_USER = new AuthenticatedUser(ANONYMOUS_USERNAME);
// User-level permissions cache.
private static final PermissionsCache permissionsCache = new PermissionsCache(DatabaseDescriptor.getAuthorizer());
private static final NetworkPermissionsCache networkPermissionsCache = new NetworkPermissionsCache(DatabaseDescriptor.getNetworkAuthorizer());
public static final PermissionsCache permissionsCache = new PermissionsCache(DatabaseDescriptor.getAuthorizer());
public static final NetworkPermissionsCache networkPermissionsCache = new NetworkPermissionsCache(DatabaseDescriptor.getNetworkAuthorizer());
private final String name;
// primary Role of the logged in user

View File

@ -81,6 +81,11 @@ public class PasswordAuthenticator implements IAuthenticator
return true;
}
public CredentialsCache getCredentialsCache()
{
return cache;
}
protected static boolean checkpw(String password, String hash)
{
try
@ -271,7 +276,7 @@ public class PasswordAuthenticator implements IAuthenticator
}
}
private static class CredentialsCache extends AuthCache<String, String> implements CredentialsCacheMBean
public static class CredentialsCache extends AuthCache<String, String> implements CredentialsCacheMBean
{
private CredentialsCache(PasswordAuthenticator authenticator)
{

View File

@ -45,8 +45,8 @@ public class PermissionsCache extends AuthCache<Pair<AuthenticatedUser, IResourc
return get(Pair.create(user, resource));
}
public void invalidatePermissions(String userName, String resourceName)
public void invalidatePermissions(String roleName, String resourceName)
{
invalidate(Pair.create(new AuthenticatedUser(userName), Resources.fromName(resourceName)));
invalidate(Pair.create(new AuthenticatedUser(roleName), Resources.fromName(resourceName)));
}
}

View File

@ -22,5 +22,5 @@ public interface PermissionsCacheMBean extends AuthCacheMBean
{
public static final String CACHE_NAME = "PermissionsCache";
public void invalidatePermissions(String userName, String resourceName);
public void invalidatePermissions(String roleName, String resourceName);
}

View File

@ -34,7 +34,7 @@ public class Role
* for IRoleManager implementations (in particular, CassandraRoleManager)
*/
public final RoleResource resource ;
public final RoleResource resource;
public final boolean isSuper;
public final boolean canLogin;
public final Set<String> memberOf;

View File

@ -20,11 +20,8 @@ package org.apache.cassandra.auth;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -38,26 +35,8 @@ public class Roles
private static final Role NO_ROLE = new Role("", false, false, Collections.emptyMap(), Collections.emptySet());
private static RolesCache cache;
static
{
initRolesCache(DatabaseDescriptor.getRoleManager(),
() -> DatabaseDescriptor.getAuthenticator().requireAuthentication());
}
@VisibleForTesting
public static void initRolesCache(IRoleManager roleManager, BooleanSupplier enableCache)
{
if (cache != null)
cache.unregisterMBean();
cache = new RolesCache(roleManager, enableCache);
}
@VisibleForTesting
public static void clearCache()
{
cache.invalidate();
}
public static final RolesCache cache = new RolesCache(DatabaseDescriptor.getRoleManager(),
() -> DatabaseDescriptor.getAuthenticator().requireAuthentication());
/**
* Identify all roles granted to the supplied Role, including both directly granted

View File

@ -104,7 +104,7 @@ public class AuthorizationProxy implements InvocationHandler
"registerMBean",
"unregisterMBean");
private static final JmxPermissionsCache permissionsCache = new JmxPermissionsCache();
public static final JmxPermissionsCache jmxPermissionsCache = new JmxPermissionsCache();
private MBeanServer mbs;
/*
@ -118,7 +118,7 @@ public class AuthorizationProxy implements InvocationHandler
the permissions from the local cache, which in turn loads them from the configured IAuthorizer
but can be overridden for testing.
*/
protected Function<RoleResource, Set<PermissionDetails>> getPermissions = permissionsCache::get;
protected Function<RoleResource, Set<PermissionDetails>> getPermissions = jmxPermissionsCache::get;
/*
Used to decide whether authorization is enabled or not, usually this depends on the configured
@ -477,7 +477,7 @@ public class AuthorizationProxy implements InvocationHandler
.collect(Collectors.toSet());
}
private static final class JmxPermissionsCache extends AuthCache<RoleResource, Set<PermissionDetails>>
public static final class JmxPermissionsCache extends AuthCache<RoleResource, Set<PermissionDetails>>
implements JmxPermissionsCacheMBean
{
protected JmxPermissionsCache()

View File

@ -26,7 +26,7 @@ import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Range;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.ClusteringBound;
@ -145,7 +145,7 @@ public abstract class AbstractMutableVirtualTable extends AbstractVirtualTable
throw invalidRequest("Range deletion is not supported by table %s", metadata);
}
protected void applyRowDeletion(ColumnValues partitionKey, ColumnValues clusteringColumnValues)
protected void applyRowDeletion(ColumnValues partitionKey, ColumnValues clusteringColumns)
{
throw invalidRequest("Row deletion is not supported by table %s", metadata);
}

View File

@ -0,0 +1,78 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import java.util.Optional;
import org.apache.cassandra.auth.IAuthenticator;
import org.apache.cassandra.auth.PasswordAuthenticator;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.dht.LocalPartitioner;
import org.apache.cassandra.schema.TableMetadata;
final class CredentialsCacheKeysTable extends AbstractMutableVirtualTable
{
private static final String ROLE = "role";
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private final Optional<PasswordAuthenticator> passwordAuthenticatorOptional;
CredentialsCacheKeysTable(String keyspace)
{
super(TableMetadata.builder(keyspace, "credentials_cache_keys")
.comment("keys in the credentials cache")
.kind(TableMetadata.Kind.VIRTUAL)
.partitioner(new LocalPartitioner(UTF8Type.instance))
.addPartitionKeyColumn(ROLE, UTF8Type.instance)
.build());
IAuthenticator authenticator = DatabaseDescriptor.getAuthenticator();
if (authenticator instanceof PasswordAuthenticator)
this.passwordAuthenticatorOptional = Optional.of((PasswordAuthenticator) authenticator);
else
this.passwordAuthenticatorOptional = Optional.empty();
}
public DataSet data()
{
SimpleDataSet result = new SimpleDataSet(metadata());
passwordAuthenticatorOptional
.ifPresent(passwordAuthenticator -> passwordAuthenticator.getCredentialsCache().getAll()
.forEach((roleName, ignored) -> result.row(roleName)));
return result;
}
@Override
protected void applyPartitionDeletion(ColumnValues partitionKey)
{
String roleName = partitionKey.value(0);
passwordAuthenticatorOptional
.ifPresent(passwordAuthenticator -> passwordAuthenticator.getCredentialsCache().invalidate(roleName));
}
@Override
public void truncate()
{
passwordAuthenticatorOptional
.ifPresent(passwordAuthenticator -> passwordAuthenticator.getCredentialsCache().invalidate());
}
}

View File

@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import org.apache.cassandra.auth.RoleResource;
import org.apache.cassandra.auth.jmx.AuthorizationProxy;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.dht.LocalPartitioner;
import org.apache.cassandra.schema.TableMetadata;
final class JmxPermissionsCacheKeysTable extends AbstractMutableVirtualTable
{
private static final String ROLE = "role";
JmxPermissionsCacheKeysTable(String keyspace)
{
super(TableMetadata.builder(keyspace, "jmx_permissions_cache_keys")
.comment("keys in the JMX permissions cache")
.kind(TableMetadata.Kind.VIRTUAL)
.partitioner(new LocalPartitioner(UTF8Type.instance))
.addPartitionKeyColumn(ROLE, UTF8Type.instance)
.build());
}
public DataSet data()
{
SimpleDataSet result = new SimpleDataSet(metadata());
AuthorizationProxy.jmxPermissionsCache.getAll()
.forEach((roleResource, ignored) -> result.row(roleResource.getRoleName()));
return result;
}
@Override
protected void applyPartitionDeletion(ColumnValues partitionKey)
{
RoleResource roleResource = RoleResource.role(partitionKey.value(0));
AuthorizationProxy.jmxPermissionsCache.invalidate(roleResource);
}
@Override
public void truncate()
{
AuthorizationProxy.jmxPermissionsCache.invalidate();
}
}

View File

@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import org.apache.cassandra.auth.AuthenticatedUser;
import org.apache.cassandra.auth.RoleResource;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.dht.LocalPartitioner;
import org.apache.cassandra.schema.TableMetadata;
final class NetworkPermissionsCacheKeysTable extends AbstractMutableVirtualTable
{
private static final String ROLE = "role";
NetworkPermissionsCacheKeysTable(String keyspace)
{
super(TableMetadata.builder(keyspace, "network_permissions_cache_keys")
.comment("keys in the network permissions cache")
.kind(TableMetadata.Kind.VIRTUAL)
.partitioner(new LocalPartitioner(UTF8Type.instance))
.addPartitionKeyColumn(ROLE, UTF8Type.instance)
.build());
}
public DataSet data()
{
SimpleDataSet result = new SimpleDataSet(metadata());
AuthenticatedUser.networkPermissionsCache.getAll()
.forEach((roleResource, ignored) -> result.row(roleResource.getRoleName()));
return result;
}
@Override
protected void applyPartitionDeletion(ColumnValues partitionKey)
{
RoleResource roleResource = RoleResource.role(partitionKey.value(0));
AuthenticatedUser.networkPermissionsCache.invalidate(roleResource);
}
@Override
public void truncate()
{
AuthenticatedUser.networkPermissionsCache.invalidate();
}
}

View File

@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import org.apache.cassandra.auth.AuthenticatedUser;
import org.apache.cassandra.auth.IResource;
import org.apache.cassandra.auth.Resources;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.dht.LocalPartitioner;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.utils.Pair;
final class PermissionsCacheKeysTable extends AbstractMutableVirtualTable
{
private static final String ROLE = "role";
private static final String RESOURCE = "resource";
PermissionsCacheKeysTable(String keyspace)
{
super(TableMetadata.builder(keyspace, "permissions_cache_keys")
.comment("keys in the permissions cache")
.kind(TableMetadata.Kind.VIRTUAL)
.partitioner(new LocalPartitioner(UTF8Type.instance))
.addPartitionKeyColumn(ROLE, UTF8Type.instance)
.addPartitionKeyColumn(RESOURCE, UTF8Type.instance)
.build());
}
public DataSet data()
{
SimpleDataSet result = new SimpleDataSet(metadata());
AuthenticatedUser.permissionsCache.getAll()
.forEach((userResoursePair, ignored) ->
result.row(userResoursePair.left.getName(), userResoursePair.right.getName()));
return result;
}
@Override
protected void applyPartitionDeletion(ColumnValues partitionKey)
{
AuthenticatedUser user = new AuthenticatedUser(partitionKey.value(0));
IResource resource = resourceFromNameIfExists(partitionKey.value(1));
// no need to delete invalid resource
if (resource == null)
return;
AuthenticatedUser.permissionsCache.invalidate(Pair.create(user, resource));
}
@Override
public void truncate()
{
AuthenticatedUser.permissionsCache.invalidate();
}
private IResource resourceFromNameIfExists(String name)
{
try
{
return Resources.fromName(name);
}
catch (IllegalArgumentException e)
{
return null;
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import org.apache.cassandra.auth.RoleResource;
import org.apache.cassandra.auth.Roles;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.dht.LocalPartitioner;
import org.apache.cassandra.schema.TableMetadata;
final class RolesCacheKeysTable extends AbstractMutableVirtualTable
{
private static final String ROLE = "role";
RolesCacheKeysTable(String keyspace)
{
super(TableMetadata.builder(keyspace, "roles_cache_keys")
.comment("keys in the roles cache")
.kind(TableMetadata.Kind.VIRTUAL)
.partitioner(new LocalPartitioner(UTF8Type.instance))
.addPartitionKeyColumn(ROLE, UTF8Type.instance)
.build());
}
public DataSet data()
{
SimpleDataSet result = new SimpleDataSet(metadata());
Roles.cache.getAll()
.forEach((roleResource, ignored) -> result.row(roleResource.getRoleName()));
return result;
}
@Override
protected void applyPartitionDeletion(ColumnValues partitionKey)
{
RoleResource roleResource = RoleResource.role(partitionKey.value(0));
Roles.cache.invalidate(roleResource);
}
@Override
public void truncate()
{
Roles.cache.invalidate();
}
}

View File

@ -38,6 +38,11 @@ public final class SystemViewsKeyspace extends VirtualKeyspace
.add(new InternodeInboundTable(VIRTUAL_VIEWS))
.add(new PendingHintsTable(VIRTUAL_VIEWS))
.addAll(TableMetricTables.getAll(VIRTUAL_VIEWS))
.add(new CredentialsCacheKeysTable(VIRTUAL_VIEWS))
.add(new JmxPermissionsCacheKeysTable(VIRTUAL_VIEWS))
.add(new NetworkPermissionsCacheKeysTable(VIRTUAL_VIEWS))
.add(new PermissionsCacheKeysTable(VIRTUAL_VIEWS))
.add(new RolesCacheKeysTable(VIRTUAL_VIEWS))
.build());
}
}

View File

@ -544,9 +544,9 @@ public class NodeProbe implements AutoCloseable
pcProxy.invalidate();
}
public void invalidatePermissionsCache(String userName, String resourceName)
public void invalidatePermissionsCache(String roleName, String resourceName)
{
pcProxy.invalidatePermissions(userName, resourceName);
pcProxy.invalidatePermissions(roleName, resourceName);
}
public void invalidateRolesCache()

View File

@ -38,7 +38,7 @@ import static com.google.common.base.Preconditions.checkArgument;
@Command(name = "invalidatepermissionscache", description = "Invalidate the permissions cache")
public class InvalidatePermissionsCache extends NodeToolCmd
{
@Arguments(usage = "[<user>]", description = "A specific user for whom permissions need to be invalidated")
@Arguments(usage = "[<role>]", description = "A role for which permissions to specified resources need to be invalidated")
private List<String> args = new ArrayList<>();
// Data Resources
@ -52,6 +52,11 @@ public class InvalidatePermissionsCache extends NodeToolCmd
description = "Keyspace to invalidate permissions for")
private String keyspace;
@Option(title = "all-tables",
name = {"--all-tables"},
description = "Invalidate permissions for 'ALL TABLES'")
private boolean allTables;
@Option(title = "table",
name = {"--table"},
description = "Table to invalidate permissions for (you must specify --keyspace for using this option)")
@ -105,28 +110,34 @@ public class InvalidatePermissionsCache extends NodeToolCmd
&& !allRoles && StringUtils.isEmpty(role)
&& !allFunctions && StringUtils.isEmpty(functionsInKeyspace) && StringUtils.isEmpty(function)
&& !allMBeans && StringUtils.isEmpty(mBean),
"No options allowed without a <user> being specified");
"No resource options allowed without a <role> being specified");
probe.invalidatePermissionsCache();
}
else
{
checkArgument(args.size() == 1,
"A single <user> is only supported / you have a typo in the options spelling");
"A single <role> is only supported / you have a typo in the resource options spelling");
List<String> resourceNames = new ArrayList<>();
// Data Resources
if (allKeyspaces)
resourceNames.add(DataResource.root().getName());
if (allTables)
if (StringUtils.isNotEmpty(keyspace))
resourceNames.add(DataResource.allTables(keyspace).getName());
else
throw new IllegalArgumentException("--all-tables option should be passed along with --keyspace option");
if (StringUtils.isNotEmpty(table))
if (StringUtils.isNotEmpty(keyspace))
resourceNames.add(DataResource.table(keyspace, table).getName());
else
throw new IllegalArgumentException("--table option should be passed along with --keyspace option");
else
if (StringUtils.isNotEmpty(keyspace))
resourceNames.add(DataResource.keyspace(keyspace).getName());
if (StringUtils.isNotEmpty(keyspace) && !allTables && StringUtils.isEmpty(table))
resourceNames.add(DataResource.keyspace(keyspace).getName());
// Roles Resources
if (allRoles)
@ -155,10 +166,13 @@ public class InvalidatePermissionsCache extends NodeToolCmd
if (StringUtils.isNotEmpty(mBean))
resourceNames.add(JMXResource.mbean(mBean).getName());
String userName = args.get(0);
String roleName = args.get(0);
if (resourceNames.isEmpty())
throw new IllegalArgumentException("No resource options specified");
for (String resourceName : resourceNames)
probe.invalidatePermissionsCache(userName, resourceName);
probe.invalidatePermissionsCache(roleName, resourceName);
}
}

View File

@ -17,6 +17,7 @@
*/
package org.apache.cassandra.auth;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.IntConsumer;
@ -27,6 +28,7 @@ import org.junit.Test;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.exceptions.UnavailableException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@ -224,6 +226,43 @@ public class AuthCacheTest
}
}
@Test
public void testCacheLoaderIsNotCalledOnGetAllWhenCacheIsDisabled()
{
isCacheEnabled = false;
TestCache<String, Integer> authCache = new TestCache<>(this::countingLoader, this::setValidity, () -> validity, () -> isCacheEnabled);
authCache.get("10");
Map<String, Integer> result = authCache.getAll();
// even though the cache is disabled and nothing is cache we still use loadFunction on get operation, so
// its counter has been incremented
assertThat(result).isEmpty();
assertEquals(1, loadCounter);
}
@Test
public void testCacheLoaderIsNotCalledOnGetAllWhenCacheIsEmpty()
{
TestCache<String, Integer> authCache = new TestCache<>(this::countingLoader, this::setValidity, () -> validity, () -> isCacheEnabled);
Map<String, Integer> result = authCache.getAll();
assertThat(result).isEmpty();
assertEquals(0, loadCounter);
}
@Test
public void testCacheLoaderIsNotCalledOnGetAllWhenCacheIsNotEmpty()
{
TestCache<String, Integer> authCache = new TestCache<>(this::countingLoader, this::setValidity, () -> validity, () -> isCacheEnabled);
authCache.get("10");
Map<String, Integer> result = authCache.getAll();
assertThat(result).hasSize(1);
assertThat(result).containsEntry("10", 10);
assertEquals(1, loadCounter);
}
private void setValidity(int validity)
{
this.validity = validity;

View File

@ -20,6 +20,7 @@ package org.apache.cassandra.auth;
import java.util.concurrent.Callable;
import org.apache.cassandra.auth.jmx.AuthorizationProxy;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.QueryProcessor;
import org.apache.cassandra.cql3.UntypedResultSet;
@ -121,6 +122,15 @@ public class AuthTestUtils
}
}
public static class NoAuthSetupAuthorizationProxy extends AuthorizationProxy
{
public NoAuthSetupAuthorizationProxy()
{
super();
this.isAuthSetupComplete = () -> true;
}
}
public static void grantRolesTo(IRoleManager roleManager, RoleResource grantee, RoleResource...granted)
{
for(RoleResource toGrant : granted)

View File

@ -43,13 +43,12 @@ import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.service.ClientState;
import static org.apache.cassandra.auth.AuthKeyspace.NETWORK_PERMISSIONS;
import static org.apache.cassandra.auth.AuthTestUtils.LocalCassandraRoleManager;
import static org.apache.cassandra.auth.AuthTestUtils.getRolesReadCount;
import static org.apache.cassandra.schema.SchemaConstants.AUTH_KEYSPACE_NAME;
public class CassandraNetworkAuthorizerTest
{
public static void setupSuperUser()
private static void setupSuperUser()
{
QueryProcessor.executeInternal(String.format("INSERT INTO %s.%s (role, is_superuser, can_login, salted_hash) "
+ "VALUES ('%s', true, true, '%s')",
@ -63,13 +62,12 @@ public class CassandraNetworkAuthorizerTest
public static void defineSchema() throws ConfigurationException
{
SchemaLoader.prepareServer();
SchemaLoader.setupAuth(new LocalCassandraRoleManager(),
new PasswordAuthenticator(),
SchemaLoader.setupAuth(new AuthTestUtils.LocalCassandraRoleManager(),
new AuthTestUtils.LocalPasswordAuthenticator(),
new AuthTestUtils.LocalCassandraAuthorizer(),
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
setupSuperUser();
// not strictly necessary to init the cache here, but better to be explicit
Roles.initRolesCache(DatabaseDescriptor.getRoleManager(), () -> true);
}
@Before
@ -122,7 +120,7 @@ public class CassandraNetworkAuthorizerTest
AuthenticationStatement authStmt = (AuthenticationStatement) statement;
// invalidate roles cache so that any changes to the underlying roles are picked up
Roles.clearCache();
Roles.cache.invalidate();
authStmt.execute(getClientState());
}
@ -193,7 +191,7 @@ public class CassandraNetworkAuthorizerTest
assertDcPermRow(username, "dc1");
// clear the roles cache to lose the (non-)superuser status for the user
Roles.clearCache();
Roles.cache.invalidate();
auth("ALTER ROLE %s WITH superuser = true", username);
Assert.assertEquals(DCPermissions.all(), dcPerms(username));
}
@ -207,7 +205,7 @@ public class CassandraNetworkAuthorizerTest
}
@Test
public void getLoginPrivilegeFromRolesCache() throws Exception
public void getLoginPrivilegeFromRolesCache()
{
String username = createName();
auth("CREATE ROLE %s", username);

View File

@ -55,7 +55,7 @@ public class CassandraRoleManagerTest
// collects all of the necessary info with a single query for each granted role.
// This just tests that that is the case, i.e. we perform 1 read per role in the
// transitive set of granted roles
IRoleManager roleManager = new LocalCassandraRoleManager();
IRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
roleManager.setup();
for (RoleResource r : ALL_ROLES)
roleManager.createRole(AuthenticatedUser.ANONYMOUS_USER, r, new RoleOptions());

View File

@ -50,6 +50,9 @@ public class ResourcesTest
assertEquals(DataResource.keyspace("ks1"), Resources.fromName("data/ks1"));
assertEquals("data/ks1", DataResource.keyspace("ks1").getName());
assertEquals(DataResource.allTables("ks1"), Resources.fromName("data/ks1/*"));
assertEquals("data/ks1/*", DataResource.allTables("ks1").getName());
assertEquals(DataResource.table("ks1", "t1"), Resources.fromName("data/ks1/t1"));
assertEquals("data/ks1/t1", DataResource.table("ks1", "t1").getName());
}

View File

@ -28,11 +28,13 @@ import org.junit.Test;
import org.apache.cassandra.SchemaLoader;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.schema.KeyspaceParams;
import org.apache.cassandra.schema.SchemaConstants;
import org.apache.cassandra.schema.TableMetadata;
import static org.apache.cassandra.auth.AuthTestUtils.*;
import static org.apache.cassandra.auth.AuthTestUtils.ALL_ROLES;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_C;
import static org.apache.cassandra.auth.AuthTestUtils.getRolesReadCount;
import static org.apache.cassandra.auth.AuthTestUtils.grantRolesTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@ -43,14 +45,12 @@ public class RolesTest
public static void setupClass()
{
SchemaLoader.prepareServer();
// create the system_auth keyspace so the IRoleManager can function as normal
SchemaLoader.createKeyspace(SchemaConstants.AUTH_KEYSPACE_NAME,
KeyspaceParams.simple(1),
Iterables.toArray(AuthKeyspace.metadata().tables, TableMetadata.class));
IRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
SchemaLoader.setupAuth(roleManager,
new AuthTestUtils.LocalPasswordAuthenticator(),
new AuthTestUtils.LocalCassandraAuthorizer(),
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
IRoleManager roleManager = new LocalCassandraRoleManager();
roleManager.setup();
Roles.initRolesCache(roleManager, () -> true);
for (RoleResource role : ALL_ROLES)
roleManager.createRole(AuthenticatedUser.ANONYMOUS_USER, role, new RoleOptions());
grantRolesTo(roleManager, ROLE_A, ROLE_B, ROLE_C);

View File

@ -0,0 +1,168 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import com.google.common.collect.ImmutableList;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.datastax.driver.core.EndPoint;
import com.datastax.driver.core.PlainTextAuthProvider;
import org.apache.cassandra.auth.AuthTestUtils;
import org.apache.cassandra.auth.AuthenticatedUser;
import org.apache.cassandra.auth.IAuthenticator;
import org.apache.cassandra.auth.IRoleManager;
import org.apache.cassandra.auth.RoleResource;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B;
public class CredentialsCacheKeysTableTest extends CQLTester
{
private static final String KS_NAME = "vts";
private static AuthTestUtils.LocalPasswordAuthenticator passwordAuthenticator;
@SuppressWarnings("FieldCanBeLocal")
private CredentialsCacheKeysTable table;
@BeforeClass
public static void setUpClass()
{
// high value is used for convenient debugging
DatabaseDescriptor.setCredentialsValidity(20_000);
CQLTester.setUpClass();
CQLTester.requireAuthentication();
passwordAuthenticator = (AuthTestUtils.LocalPasswordAuthenticator) DatabaseDescriptor.getAuthenticator();
IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
}
@Before
public void config()
{
table = new CredentialsCacheKeysTable(KS_NAME);
VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, ImmutableList.of(table)));
// ensure nothing keeps cached between tests
passwordAuthenticator.getCredentialsCache().invalidate();
}
@AfterClass
public static void tearDownClass()
{
DatabaseDescriptor.setCredentialsValidity(DatabaseDescriptor.getRawConfig().credentials_validity_in_ms);
}
@Test
public void testSelectAllWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.credentials_cache_keys"));
}
@Test
public void testSelectAllWhenPermissionsAreCached() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
assertRows(execute("SELECT * FROM vts.credentials_cache_keys"),
row("role_a"),
row("role_b"));
}
@Test
public void testSelectPartitionWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.credentials_cache_keys WHERE role='role_a'"));
}
@Test
public void testSelectPartitionWhenPermissionsAreCached() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
assertRows(execute("SELECT * FROM vts.credentials_cache_keys WHERE role='role_a'"),
row("role_a"));
}
@Test
public void testDeletePartition() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
execute("DELETE FROM vts.credentials_cache_keys WHERE role='role_a'");
assertRows(execute("SELECT * FROM vts.credentials_cache_keys"),
row("role_b"));
}
@Test
public void testDeletePartitionWithInvalidValues() throws Throwable
{
cachePermissions(ROLE_A);
execute("DELETE FROM vts.credentials_cache_keys WHERE role='invalid_role'");
assertRows(execute("SELECT * FROM vts.credentials_cache_keys WHERE role='role_a'"),
row("role_a"));
}
@Test
public void testTruncateTable() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
execute("TRUNCATE vts.credentials_cache_keys");
assertEmpty(execute("SELECT * FROM vts.credentials_cache_keys"));
}
@Test
public void testUnsupportedOperations() throws Throwable
{
// range tombstone is not supported, however, this table has no clustering columns, so it is not covered by tests
// column deletion is not supported, however, this table has no regular columns, so it is not covered by tests
// insert is not supported
assertInvalidMessage("Column modification is not supported by table vts.credentials_cache_keys",
"INSERT INTO vts.credentials_cache_keys (role) VALUES ('role_e')");
// update is not supported, however, this table has no regular columns, so it is not covered by tests
}
private void cachePermissions(RoleResource roleResource)
{
IAuthenticator.SaslNegotiator saslNegotiator = passwordAuthenticator.newSaslNegotiator(null);
saslNegotiator.evaluateResponse(new PlainTextAuthProvider(roleResource.getRoleName(), "ignored")
.newAuthenticator((EndPoint) null, null)
.initialResponse());
saslNegotiator.getAuthenticatedUser();
}
}

View File

@ -0,0 +1,188 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.security.auth.Subject;
import com.google.common.collect.ImmutableList;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.auth.AuthTestUtils;
import org.apache.cassandra.auth.AuthenticatedUser;
import org.apache.cassandra.auth.CassandraPrincipal;
import org.apache.cassandra.auth.IAuthorizer;
import org.apache.cassandra.auth.IResource;
import org.apache.cassandra.auth.IRoleManager;
import org.apache.cassandra.auth.JMXResource;
import org.apache.cassandra.auth.Permission;
import org.apache.cassandra.auth.RoleResource;
import org.apache.cassandra.auth.jmx.AuthorizationProxy;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B;
public class JmxPermissionsCacheKeysTableTest extends CQLTester
{
private static final String KS_NAME = "vts";
private static final AuthorizationProxy authorizationProxy = new AuthTestUtils.NoAuthSetupAuthorizationProxy();
@SuppressWarnings("FieldCanBeLocal")
private JmxPermissionsCacheKeysTable table;
// this method is intentionally not called "setUpClass" to let it throw exception brought by startJMXServer method
@BeforeClass
public static void setup() throws Exception {
// high value is used for convenient debugging
DatabaseDescriptor.setPermissionsValidity(20_000);
CQLTester.setUpClass();
CQLTester.requireAuthentication();
IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
List<IResource> resources = Arrays.asList(
JMXResource.root(),
JMXResource.mbean("org.apache.cassandra.db:type=Tables,*"));
IAuthorizer authorizer = DatabaseDescriptor.getAuthorizer();
for (IResource resource : resources)
{
Set<Permission> permissions = resource.applicablePermissions();
authorizer.grant(AuthenticatedUser.SYSTEM_USER, permissions, resource, ROLE_A);
authorizer.grant(AuthenticatedUser.SYSTEM_USER, permissions, resource, ROLE_B);
}
startJMXServer();
}
@Before
public void config()
{
table = new JmxPermissionsCacheKeysTable(KS_NAME);
VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, ImmutableList.of(table)));
// ensure nothing keeps cached between tests
AuthorizationProxy.jmxPermissionsCache.invalidate();
}
@AfterClass
public static void tearDownClass()
{
DatabaseDescriptor.setPermissionsValidity(DatabaseDescriptor.getRawConfig().permissions_validity_in_ms);
}
@Test
public void testSelectAllWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.jmx_permissions_cache_keys"));
}
@Test
public void testSelectAllWhenPermissionsAreCached() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
assertRows(execute("SELECT * FROM vts.jmx_permissions_cache_keys"),
row("role_a"),
row("role_b"));
}
@Test
public void testSelectPartitionWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.jmx_permissions_cache_keys WHERE role='role_a'"));
}
@Test
public void testSelectPartitionWhenPermissionsAreCached() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
assertRows(execute("SELECT * FROM vts.jmx_permissions_cache_keys WHERE role='role_a'"),
row("role_a"));
}
@Test
public void testDeletePartition() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
execute("DELETE FROM vts.jmx_permissions_cache_keys WHERE role='role_a'");
assertRows(execute("SELECT * FROM vts.jmx_permissions_cache_keys"),
row("role_b"));
}
@Test
public void testDeletePartitionWithInvalidValues() throws Throwable
{
cachePermissions(ROLE_A);
execute("DELETE FROM vts.jmx_permissions_cache_keys WHERE role='invalid_role'");
assertRows(execute("SELECT * FROM vts.jmx_permissions_cache_keys WHERE role='role_a'"),
row("role_a"));
}
@Test
public void testTruncateTable() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
execute("TRUNCATE vts.jmx_permissions_cache_keys");
assertEmpty(execute("SELECT * FROM vts.jmx_permissions_cache_keys"));
}
@Test
public void testUnsupportedOperations() throws Throwable
{
// range tombstone is not supported, however, this table has no clustering columns, so it is not covered by tests
// column deletion is not supported, however, this table has no regular columns, so it is not covered by tests
// insert is not supported
assertInvalidMessage("Column modification is not supported by table vts.jmx_permissions_cache_keys",
"INSERT INTO vts.jmx_permissions_cache_keys (role) VALUES ('role_e')");
// update is not supported, however, this table has no regular columns, so it is not covered by tests
}
private void cachePermissions(RoleResource roleResource)
{
Subject userSubject = new Subject();
userSubject.getPrincipals().add(new CassandraPrincipal(roleResource.getRoleName()));
authorizationProxy.authorize(userSubject, "queryNames", null);
}
}

View File

@ -0,0 +1,165 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import com.google.common.collect.ImmutableList;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.auth.AuthTestUtils;
import org.apache.cassandra.auth.AuthenticatedUser;
import org.apache.cassandra.auth.DCPermissions;
import org.apache.cassandra.auth.INetworkAuthorizer;
import org.apache.cassandra.auth.IRoleManager;
import org.apache.cassandra.auth.RoleResource;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B;
public class NetworkPermissionsCacheKeysTableTest extends CQLTester
{
private static final String KS_NAME = "vts";
@SuppressWarnings("FieldCanBeLocal")
private NetworkPermissionsCacheKeysTable table;
@BeforeClass
public static void setUpClass()
{
// high value is used for convenient debugging
DatabaseDescriptor.setPermissionsValidity(20_000);
CQLTester.setUpClass();
CQLTester.requireAuthentication();
IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
INetworkAuthorizer networkAuthorizer = DatabaseDescriptor.getNetworkAuthorizer();
networkAuthorizer.setRoleDatacenters(ROLE_A, DCPermissions.all());
networkAuthorizer.setRoleDatacenters(ROLE_B, DCPermissions.subset(DATA_CENTER, DATA_CENTER_REMOTE));
}
@Before
public void config()
{
table = new NetworkPermissionsCacheKeysTable(KS_NAME);
VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, ImmutableList.of(table)));
// ensure nothing keeps cached between tests
AuthenticatedUser.networkPermissionsCache.invalidate();
}
@AfterClass
public static void tearDownClass()
{
DatabaseDescriptor.setPermissionsValidity(DatabaseDescriptor.getRawConfig().permissions_validity_in_ms);
}
@Test
public void testSelectAllWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.network_permissions_cache_keys"));
}
@Test
public void testSelectAllWhenPermissionsAreCached() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
assertRows(execute("SELECT * FROM vts.network_permissions_cache_keys"),
row("role_a"),
row("role_b"));
}
@Test
public void testSelectPartitionWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.network_permissions_cache_keys WHERE role='role_a'"));
}
@Test
public void testSelectPartitionWhenPermissionsAreCached() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
assertRows(execute("SELECT * FROM vts.network_permissions_cache_keys WHERE role='role_a'"),
row("role_a"));
}
@Test
public void testDeletePartition() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
execute("DELETE FROM vts.network_permissions_cache_keys WHERE role='role_a'");
assertRows(execute("SELECT * FROM vts.network_permissions_cache_keys"),
row("role_b"));
}
@Test
public void testDeletePartitionWithInvalidValues() throws Throwable
{
cachePermissions(ROLE_A);
execute("DELETE FROM vts.network_permissions_cache_keys WHERE role='invalid_role'");
assertRows(execute("SELECT * FROM vts.network_permissions_cache_keys WHERE role='role_a'"),
row("role_a"));
}
@Test
public void testTruncateTable() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
execute("TRUNCATE vts.network_permissions_cache_keys");
assertEmpty(execute("SELECT * FROM vts.network_permissions_cache_keys"));
}
@Test
public void testUnsupportedOperations() throws Throwable
{
// range tombstone is not supported, however, this table has no clustering columns, so it is not covered by tests
// column deletion is not supported, however, this table has no regular columns, so it is not covered by tests
// insert is not supported
assertInvalidMessage("Column modification is not supported by table vts.network_permissions_cache_keys",
"INSERT INTO vts.network_permissions_cache_keys (role) VALUES ('role_e')");
// update is not supported, however, this table has no regular columns, so it is not covered by tests
}
private void cachePermissions(RoleResource roleResource)
{
AuthenticatedUser.networkPermissionsCache.get(roleResource);
}
}

View File

@ -0,0 +1,185 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.auth.AuthTestUtils;
import org.apache.cassandra.auth.AuthenticatedUser;
import org.apache.cassandra.auth.DataResource;
import org.apache.cassandra.auth.IAuthorizer;
import org.apache.cassandra.auth.IResource;
import org.apache.cassandra.auth.IRoleManager;
import org.apache.cassandra.auth.Permission;
import org.apache.cassandra.auth.RoleResource;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B;
public class PermissionsCacheKeysTableTest extends CQLTester
{
private static final String KS_NAME = "vts";
@SuppressWarnings("FieldCanBeLocal")
private PermissionsCacheKeysTable table;
@BeforeClass
public static void setUpClass()
{
// high value is used for convenient debugging
DatabaseDescriptor.setPermissionsValidity(20_000);
CQLTester.setUpClass();
CQLTester.requireAuthentication();
IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
List<IResource> resources = Arrays.asList(
DataResource.root(),
DataResource.keyspace(KEYSPACE),
DataResource.table(KEYSPACE, "t1"));
IAuthorizer authorizer = DatabaseDescriptor.getAuthorizer();
for (IResource resource : resources)
{
Set<Permission> permissions = resource.applicablePermissions();
authorizer.grant(AuthenticatedUser.SYSTEM_USER, permissions, resource, ROLE_A);
authorizer.grant(AuthenticatedUser.SYSTEM_USER, permissions, resource, ROLE_B);
}
}
@Before
public void config()
{
table = new PermissionsCacheKeysTable(KS_NAME);
VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, ImmutableList.of(table)));
// ensure nothing keeps cached between tests
AuthenticatedUser.permissionsCache.invalidate();
}
@AfterClass
public static void tearDownClass()
{
DatabaseDescriptor.setPermissionsValidity(DatabaseDescriptor.getRawConfig().permissions_validity_in_ms);
}
@Test
public void testSelectAllWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.permissions_cache_keys"));
}
@Test
public void testSelectAllWhenPermissionsAreCached() throws Throwable
{
cachePermissionsForResource(ROLE_A, DataResource.root());
cachePermissionsForResource(ROLE_A, DataResource.keyspace(KEYSPACE));
cachePermissionsForResource(ROLE_B, DataResource.table(KEYSPACE, "t1"));
assertRows(execute("SELECT * FROM vts.permissions_cache_keys"),
row("role_a", "data"),
row("role_a", "data/cql_test_keyspace"),
row("role_b", "data/cql_test_keyspace/t1"));
}
@Test
public void testSelectPartitionWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.permissions_cache_keys WHERE role='role_a' AND resource='data'"));
}
@Test
public void testSelectPartitionWhenPermissionsAreCached() throws Throwable
{
cachePermissionsForResource(ROLE_A, DataResource.root());
cachePermissionsForResource(ROLE_A, DataResource.keyspace(KEYSPACE));
cachePermissionsForResource(ROLE_B, DataResource.table(KEYSPACE, "t1"));
assertRows(execute("SELECT * FROM vts.permissions_cache_keys WHERE role='role_a' AND resource='data'"),
row("role_a", "data"));
}
@Test
public void testDeletePartition() throws Throwable
{
cachePermissionsForResource(ROLE_A, DataResource.root());
cachePermissionsForResource(ROLE_A, DataResource.keyspace(KEYSPACE));
execute("DELETE FROM vts.permissions_cache_keys WHERE role='role_a' AND resource='data'");
assertRows(execute("SELECT * FROM vts.permissions_cache_keys"),
row("role_a", "data/cql_test_keyspace"));
}
@Test
public void testDeletePartitionWithInvalidValues() throws Throwable
{
cachePermissionsForResource(ROLE_A, DataResource.root());
execute("DELETE FROM vts.permissions_cache_keys WHERE role='invalid_role' AND resource='data'");
execute("DELETE FROM vts.permissions_cache_keys WHERE role='role_a' AND resource='invalid_resource'");
assertRows(execute("SELECT * FROM vts.permissions_cache_keys WHERE role='role_a' AND resource='data'"),
row("role_a", "data"));
}
@Test
public void testTruncateTable() throws Throwable
{
cachePermissionsForResource(ROLE_A, DataResource.root());
cachePermissionsForResource(ROLE_B, DataResource.table(KEYSPACE, "t1"));
execute("TRUNCATE vts.permissions_cache_keys");
assertEmpty(execute("SELECT * FROM vts.permissions_cache_keys"));
}
@Test
public void testUnsupportedOperations() throws Throwable
{
// range tombstone is not supported, however, this table has no clustering columns, so it is not covered by tests
// column deletion is not supported, however, this table has no regular columns, so it is not covered by tests
// insert is not supported
assertInvalidMessage("Column modification is not supported by table vts.permissions_cache_keys",
"INSERT INTO vts.permissions_cache_keys (role, resource) VALUES ('role_e', 'data')");
// update is not supported, however, this table has no regular columns, so it is not covered by tests
}
private void cachePermissionsForResource(RoleResource roleResource, IResource resource)
{
AuthenticatedUser role = new AuthenticatedUser(roleResource.getRoleName());
role.getPermissions(resource);
}
}

View File

@ -0,0 +1,165 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.virtual;
import com.google.common.collect.ImmutableList;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.auth.AuthTestUtils;
import org.apache.cassandra.auth.AuthenticatedUser;
import org.apache.cassandra.auth.IRoleManager;
import org.apache.cassandra.auth.RoleResource;
import org.apache.cassandra.auth.Roles;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B;
import static org.apache.cassandra.auth.AuthTestUtils.ROLE_C;
public class RolesCacheKeysTableTest extends CQLTester
{
private static final String KS_NAME = "vts";
@SuppressWarnings("FieldCanBeLocal")
private RolesCacheKeysTable table;
@BeforeClass
public static void setUpClass()
{
// high value is used for convenient debugging
DatabaseDescriptor.setRolesValidity(20_000);
CQLTester.setUpClass();
CQLTester.requireAuthentication();
IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_C, AuthTestUtils.getLoginRoleOptions());
AuthTestUtils.grantRolesTo(roleManager, ROLE_A, ROLE_C);
AuthTestUtils.grantRolesTo(roleManager, ROLE_B, ROLE_C);
}
@Before
public void config()
{
table = new RolesCacheKeysTable(KS_NAME);
VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, ImmutableList.of(table)));
// ensure nothing keeps cached between tests
Roles.cache.invalidate();
}
@AfterClass
public static void tearDownClass()
{
DatabaseDescriptor.setRolesValidity(DatabaseDescriptor.getRawConfig().roles_validity_in_ms);
}
@Test
public void testSelectAllWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.roles_cache_keys"));
}
@Test
public void testSelectAllWhenPermissionsAreCached() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
assertRows(execute("SELECT * FROM vts.roles_cache_keys"),
row("role_a"),
row("role_b"));
}
@Test
public void testSelectPartitionWhenPermissionsAreNotCached() throws Throwable
{
assertEmpty(execute("SELECT * FROM vts.roles_cache_keys WHERE role='role_a'"));
}
@Test
public void testSelectPartitionWhenPermissionsAreCached() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
assertRows(execute("SELECT * FROM vts.roles_cache_keys WHERE role='role_a'"),
row("role_a"));
}
@Test
public void testDeletePartition() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
execute("DELETE FROM vts.roles_cache_keys WHERE role='role_a'");
assertRows(execute("SELECT * FROM vts.roles_cache_keys"),
row("role_b"));
}
@Test
public void testDeletePartitionWithInvalidValues() throws Throwable
{
cachePermissions(ROLE_A);
execute("DELETE FROM vts.roles_cache_keys WHERE role='invalid_role'");
assertRows(execute("SELECT * FROM vts.roles_cache_keys WHERE role='role_a'"),
row("role_a"));
}
@Test
public void testTruncateTable() throws Throwable
{
cachePermissions(ROLE_A);
cachePermissions(ROLE_B);
execute("TRUNCATE vts.roles_cache_keys");
assertEmpty(execute("SELECT * FROM vts.roles_cache_keys"));
}
@Test
public void testUnsupportedOperations() throws Throwable
{
// range tombstone is not supported, however, this table has no clustering columns, so it is not covered by tests
// column deletion is not supported, however, this table has no regular columns, so it is not covered by tests
// insert is not supported
assertInvalidMessage("Column modification is not supported by table vts.roles_cache_keys",
"INSERT INTO vts.roles_cache_keys (role) VALUES ('role_e')");
// update is not supported, however, this table has no regular columns, so it is not covered by tests
}
private void cachePermissions(RoleResource roleResource)
{
Roles.getRoleDetails(roleResource);
}
}

View File

@ -30,10 +30,8 @@ import org.apache.cassandra.SchemaLoader;
import org.apache.cassandra.auth.AuthKeyspace;
import org.apache.cassandra.auth.AuthTestUtils;
import org.apache.cassandra.auth.AuthenticatedUser;
import org.apache.cassandra.auth.CassandraAuthorizer;
import org.apache.cassandra.auth.DataResource;
import org.apache.cassandra.auth.IResource;
import org.apache.cassandra.auth.IRoleManager;
import org.apache.cassandra.auth.Permission;
import org.apache.cassandra.auth.Roles;
import org.apache.cassandra.config.DatabaseDescriptor;
@ -64,7 +62,8 @@ public class ClientStateTest
}
@Test
public void permissionsCheckStartsAtHeadOfResourceChain() throws Exception {
public void permissionsCheckStartsAtHeadOfResourceChain()
{
// verify that when performing a permissions check, we start from the
// root IResource in the applicable hierarchy and proceed to the more
// granular resources until we find the required permission (or until
@ -94,12 +93,10 @@ public class ClientStateTest
public boolean canLogin() { return true; }
};
IRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
roleManager.setup();
Roles.initRolesCache(roleManager, () -> true);
Roles.cache.invalidate();
// finally, need to configure CassandraAuthorizer so we don't shortcircuit out of the authz process
DatabaseDescriptor.setAuthorizer(new CassandraAuthorizer());
DatabaseDescriptor.setAuthorizer(new AuthTestUtils.LocalCassandraAuthorizer());
// check permissions on the table, which should check for the root resource first
// & return successfully without needing to proceed further

View File

@ -46,20 +46,20 @@ public class InvalidateCredentialsCacheTest extends CQLTester
{
SchemaLoader.prepareServer();
AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
PasswordAuthenticator authenticator = new AuthTestUtils.LocalPasswordAuthenticator();
PasswordAuthenticator passwordAuthenticator = new AuthTestUtils.LocalPasswordAuthenticator();
SchemaLoader.setupAuth(roleManager,
authenticator,
new AuthTestUtils.LocalCassandraAuthorizer(),
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
passwordAuthenticator,
new AuthTestUtils.LocalCassandraAuthorizer(),
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
roleANegotiator = authenticator.newSaslNegotiator(null);
roleANegotiator = passwordAuthenticator.newSaslNegotiator(null);
roleANegotiator.evaluateResponse(new PlainTextAuthProvider(ROLE_A.getRoleName(), "ignored")
.newAuthenticator((EndPoint) null, null)
.initialResponse());
roleBNegotiator = authenticator.newSaslNegotiator(null);
roleBNegotiator = passwordAuthenticator.newSaslNegotiator(null);
roleBNegotiator.evaluateResponse(new PlainTextAuthProvider(ROLE_B.getRoleName(), "ignored")
.newAuthenticator((EndPoint) null, null)
.initialResponse());

View File

@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class InvalidateJmxPermissionsCacheTest extends CQLTester
{
private static final AuthorizationProxy authorizationProxy = new NoAuthSetupAuthorizationProxy();
private static final AuthorizationProxy authorizationProxy = new AuthTestUtils.NoAuthSetupAuthorizationProxy();
@BeforeClass
public static void setup() throws Exception
@ -50,9 +50,9 @@ public class InvalidateJmxPermissionsCacheTest extends CQLTester
AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
AuthTestUtils.LocalCassandraAuthorizer authorizer = new AuthTestUtils.LocalCassandraAuthorizer();
SchemaLoader.setupAuth(roleManager,
new AuthTestUtils.LocalPasswordAuthenticator(),
authorizer,
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
new AuthTestUtils.LocalPasswordAuthenticator(),
authorizer,
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
JMXResource rootJmxResource = JMXResource.root();
Set<Permission> jmxPermissions = rootJmxResource.applicablePermissions();
@ -178,12 +178,4 @@ public class InvalidateJmxPermissionsCacheTest extends CQLTester
return subject;
}
private static class NoAuthSetupAuthorizationProxy extends AuthorizationProxy
{
public NoAuthSetupAuthorizationProxy()
{
super();
this.isAuthSetupComplete = () -> true;
}
}
}

View File

@ -40,9 +40,9 @@ public class InvalidateNetworkPermissionsCacheTest extends CQLTester
SchemaLoader.prepareServer();
AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
SchemaLoader.setupAuth(roleManager,
new AuthTestUtils.LocalPasswordAuthenticator(),
new AuthTestUtils.LocalCassandraAuthorizer(),
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
new AuthTestUtils.LocalPasswordAuthenticator(),
new AuthTestUtils.LocalCassandraAuthorizer(),
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());

View File

@ -56,9 +56,9 @@ public class InvalidatePermissionsCacheTest extends CQLTester
AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
AuthTestUtils.LocalCassandraAuthorizer authorizer = new AuthTestUtils.LocalCassandraAuthorizer();
SchemaLoader.setupAuth(roleManager,
new AuthTestUtils.LocalPasswordAuthenticator(),
authorizer,
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
new AuthTestUtils.LocalPasswordAuthenticator(),
authorizer,
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
@ -66,6 +66,7 @@ public class InvalidatePermissionsCacheTest extends CQLTester
List<IResource> resources = Arrays.asList(
DataResource.root(),
DataResource.keyspace(KEYSPACE),
DataResource.allTables(KEYSPACE),
DataResource.table(KEYSPACE, "t1"),
RoleResource.root(),
RoleResource.role("role_x"),
@ -104,10 +105,10 @@ public class InvalidatePermissionsCacheTest extends CQLTester
" [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" +
" [(-u <username> | --username <username>)] invalidatepermissionscache\n" +
" [--all-functions] [--all-keyspaces] [--all-mbeans] [--all-roles]\n" +
" [--function <function>]\n" +
" [--all-tables] [--function <function>]\n" +
" [--functions-in-keyspace <functions-in-keyspace>]\n" +
" [--keyspace <keyspace>] [--mbean <mbean>] [--role <role>]\n" +
" [--table <table>] [--] [<user>]\n" +
" [--table <table>] [--] [<role>]\n" +
"\n" +
"OPTIONS\n" +
" --all-functions\n" +
@ -122,6 +123,9 @@ public class InvalidatePermissionsCacheTest extends CQLTester
" --all-roles\n" +
" Invalidate permissions for 'ALL ROLES'\n" +
"\n" +
" --all-tables\n" +
" Invalidate permissions for 'ALL TABLES'\n" +
"\n" +
" --function <function>\n" +
" Function to invalidate permissions for (you must specify\n" +
" --functions-in-keyspace for using this option; function format:\n" +
@ -166,8 +170,9 @@ public class InvalidatePermissionsCacheTest extends CQLTester
" list of argument, (useful when arguments might be mistaken for\n" +
" command-line options\n" +
"\n" +
" [<user>]\n" +
" A specific user for whom permissions need to be invalidated\n" +
" [<role>]\n" +
" A role for which permissions to specified resources need to be\n" +
" invalidated\n" +
"\n" +
"\n";
assertThat(tool.getStdout()).isEqualTo(help);
@ -179,28 +184,40 @@ public class InvalidatePermissionsCacheTest extends CQLTester
ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "--all-keyspaces");
assertThat(tool.getExitCode()).isEqualTo(1);
assertThat(tool.getStdout())
.isEqualTo(wrapByDefaultNodetoolMessage("No options allowed without a <user> being specified"));
.isEqualTo(wrapByDefaultNodetoolMessage("No resource options allowed without a <role> being specified"));
assertThat(tool.getStderr()).isEmpty();
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "user1", "--invalid-option");
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "role1");
assertThat(tool.getExitCode()).isEqualTo(1);
assertThat(tool.getStdout())
.isEqualTo(wrapByDefaultNodetoolMessage("A single <user> is only supported / you have a typo in the options spelling"));
.isEqualTo(wrapByDefaultNodetoolMessage("No resource options specified"));
assertThat(tool.getStderr()).isEmpty();
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "user1", "--table", "t1");
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "role1", "--invalid-option");
assertThat(tool.getExitCode()).isEqualTo(1);
assertThat(tool.getStdout())
.isEqualTo(wrapByDefaultNodetoolMessage("A single <role> is only supported / you have a typo in the resource options spelling"));
assertThat(tool.getStderr()).isEmpty();
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "role1", "--all-tables");
assertThat(tool.getExitCode()).isEqualTo(1);
assertThat(tool.getStdout())
.isEqualTo(wrapByDefaultNodetoolMessage("--all-tables option should be passed along with --keyspace option"));
assertThat(tool.getStderr()).isEmpty();
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "role1", "--table", "t1");
assertThat(tool.getExitCode()).isEqualTo(1);
assertThat(tool.getStdout())
.isEqualTo(wrapByDefaultNodetoolMessage("--table option should be passed along with --keyspace option"));
assertThat(tool.getStderr()).isEmpty();
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "user1", "--function", "f[Int32Type]");
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "role1", "--function", "f[Int32Type]");
assertThat(tool.getExitCode()).isEqualTo(1);
assertThat(tool.getStdout())
.isEqualTo(wrapByDefaultNodetoolMessage("--function option should be passed along with --functions-in-keyspace option"));
assertThat(tool.getStderr()).isEmpty();
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "user1", "--functions-in-keyspace",
tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "role1", "--functions-in-keyspace",
KEYSPACE, "--function", "f[x]");
assertThat(tool.getExitCode()).isEqualTo(1);
assertThat(tool.getStdout())
@ -213,6 +230,7 @@ public class InvalidatePermissionsCacheTest extends CQLTester
{
assertInvalidation(DataResource.root(), Collections.singletonList("--all-keyspaces"));
assertInvalidation(DataResource.keyspace(KEYSPACE), Arrays.asList("--keyspace", KEYSPACE));
assertInvalidation(DataResource.allTables(KEYSPACE), Arrays.asList("--keyspace", KEYSPACE, "--all-tables"));
assertInvalidation(DataResource.table(KEYSPACE, "t1"),
Arrays.asList("--keyspace", KEYSPACE, "--table", "t1"));
assertInvalidation(RoleResource.root(), Collections.singletonList("--all-roles"));
@ -273,7 +291,7 @@ public class InvalidatePermissionsCacheTest extends CQLTester
}
@Test
public void testInvalidatePermissionsForAllUsers()
public void testInvalidatePermissionsForAllRoles()
{
DataResource rootDataResource = DataResource.root();
Set<Permission> dataPermissions = rootDataResource.applicablePermissions();

View File

@ -40,9 +40,9 @@ public class InvalidateRolesCacheTest extends CQLTester
SchemaLoader.prepareServer();
AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
SchemaLoader.setupAuth(roleManager,
new AuthTestUtils.LocalPasswordAuthenticator(),
new AuthTestUtils.LocalCassandraAuthorizer(),
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
new AuthTestUtils.LocalPasswordAuthenticator(),
new AuthTestUtils.LocalCassandraAuthorizer(),
new AuthTestUtils.LocalCassandraNetworkAuthorizer());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());