Author: eevans Date: Wed Oct 6 15:19:13 2010 New Revision: 1005080 URL: http://svn.apache.org/viewvc?rev=1005080&view=rev Log: refactor ClientState and RPC for CF authorizations
Patch by eevans; reviewed by Stu Hood for CASSANDRA-1554 Modified: cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java cassandra/trunk/src/java/org/apache/cassandra/service/ClientState.java cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java Modified: cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java?rev=1005080&r1=1005079&r2=1005080&view=diff ============================================================================== --- cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java (original) +++ cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java Wed Oct 6 15:19:13 2010 @@ -823,7 +823,7 @@ public class CassandraServer implements { try { - state().hasKeyspaceAccess(perm); + state().hasColumnFamilyListAccess(perm); } catch (org.apache.cassandra.thrift.InvalidRequestException e) { @@ -1040,7 +1040,7 @@ public class CassandraServer implements try { - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyAccess((String)columnFamily, Permission.WRITE); schedule(); StorageProxy.truncateBlocking(state().getKeyspace(), columnFamily.toString()); } @@ -1073,7 +1073,7 @@ public class CassandraServer implements String keyspace = state().getKeyspace(); try { - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_parent.column_family.toString(), Permission.READ); } catch (org.apache.cassandra.thrift.InvalidRequestException thriftE) { @@ -1139,7 +1139,7 @@ public class CassandraServer implements try { - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_parent.column_family.toString(), Permission.READ); } catch (org.apache.cassandra.thrift.InvalidRequestException thriftE) { Modified: cassandra/trunk/src/java/org/apache/cassandra/service/ClientState.java URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/service/ClientState.java?rev=1005080&r1=1005079&r2=1005080&view=diff ============================================================================== --- cassandra/trunk/src/java/org/apache/cassandra/service/ClientState.java (original) +++ cassandra/trunk/src/java/org/apache/cassandra/service/ClientState.java Wed Oct 6 15:19:13 2010 @@ -26,7 +26,6 @@ import org.slf4j.LoggerFactory; import org.apache.cassandra.auth.AuthenticatedUser; import org.apache.cassandra.auth.Permission; import org.apache.cassandra.auth.Resources; -import org.apache.cassandra.config.Config.RequestSchedulerId; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.thrift.AuthenticationException; import org.apache.cassandra.thrift.InvalidRequestException; @@ -42,8 +41,6 @@ public class ClientState // Current user for the session private AuthenticatedUser user; private String keyspace; - private Set<Permission> keyspaceAccess; - private List<Object> resource = new ArrayList<Object>(); /** * Construct a new, empty ClientState: can be reused after logout() or reset(). @@ -52,26 +49,7 @@ public class ClientState { reset(); } - - /** - * Called when the keyspace or user have changed. - */ - private void updateKeyspaceAccess() - { - if (user == null || keyspace == null) - // user is not logged in or keyspace is not set - keyspaceAccess = null; - else - { - // authorize the user for the current keyspace - resource.clear(); - resource.add(Resources.ROOT); - resource.add(Resources.KEYSPACES); - resource.add(keyspace); - keyspaceAccess = DatabaseDescriptor.getAuthority().authorize(user, resource); - } - } - + public String getKeyspace() { return keyspace; @@ -80,7 +58,6 @@ public class ClientState public void setKeyspace(String ks) { keyspace = ks; - updateKeyspaceAccess(); } public String getSchedulingValue() @@ -101,7 +78,6 @@ public class ClientState if (logger.isDebugEnabled()) logger.debug("logged in: {}", user); this.user = user; - updateKeyspaceAccess(); } public void logout() @@ -115,8 +91,6 @@ public class ClientState { user = DatabaseDescriptor.getAuthenticator().defaultUser(); keyspace = null; - keyspaceAccess = null; - resource.clear(); } /** @@ -124,25 +98,54 @@ public class ClientState */ public void hasKeyspaceListAccess(Permission perm) throws InvalidRequestException { - if (user == null) - throw new InvalidRequestException("You have not logged in"); + validateLogin(); + List<Object> resource = Arrays.<Object>asList(Resources.ROOT, Resources.KEYSPACES); Set<Permission> perms = DatabaseDescriptor.getAuthority().authorize(user, resource); hasAccess(user, perms, perm, resource); } - + /** - * Confirms that the client thread has the given Permission in the context of the current Keyspace. + * Confirms that the client thread has the given Permission for the ColumnFamily list of + * the current keyspace. */ - public void hasKeyspaceAccess(Permission perm) throws InvalidRequestException + public void hasColumnFamilyListAccess(Permission perm) throws InvalidRequestException + { + validateLogin(); + validateKeyspace(); + + List<Object> resource = Arrays.<Object>asList(Resources.ROOT, Resources.KEYSPACES, keyspace); + Set<Permission> perms = DatabaseDescriptor.getAuthority().authorize(user, resource); + + hasAccess(user, perms, perm, resource); + } + + /** + * Confirms that the client thread has the given Permission in the context of the given + * ColumnFamily and the current keyspace. + */ + public void hasColumnFamilyAccess(String columnFamily, Permission perm) throws InvalidRequestException + { + validateLogin(); + validateKeyspace(); + + List<Object> resource = Arrays.<Object>asList(Resources.ROOT, Resources.KEYSPACES, keyspace, columnFamily); + Set<Permission> perms = DatabaseDescriptor.getAuthority().authorize(user, resource); + + hasAccess(user, perms, perm, resource); + } + + private void validateLogin() throws InvalidRequestException { if (user == null) throw new InvalidRequestException("You have not logged in"); - if (keyspaceAccess == null) + } + + private void validateKeyspace() throws InvalidRequestException + { + if (keyspace == null) throw new InvalidRequestException("You have not set a keyspace for this session"); - - hasAccess(user, keyspaceAccess, perm, resource); } private static void hasAccess(AuthenticatedUser user, Set<Permission> perms, Permission perm, List<Object> resource) throws InvalidRequestException Modified: cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java?rev=1005080&r1=1005079&r2=1005080&view=diff ============================================================================== --- cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java (original) +++ cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java Wed Oct 6 15:19:13 2010 @@ -257,7 +257,7 @@ public class CassandraServer implements if (logger.isDebugEnabled()) logger.debug("get_slice"); - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ); return multigetSliceInternal(state().getKeyspace(), Collections.singletonList(key), column_parent, predicate, consistency_level).get(key); } @@ -267,7 +267,7 @@ public class CassandraServer implements if (logger.isDebugEnabled()) logger.debug("multiget_slice"); - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ); return multigetSliceInternal(state().getKeyspace(), keys, column_parent, predicate, consistency_level); } @@ -306,7 +306,7 @@ public class CassandraServer implements if (logger.isDebugEnabled()) logger.debug("get"); - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_path.column_family, Permission.READ); String keyspace = state().getKeyspace(); ThriftValidation.validateColumnPath(keyspace, column_path); @@ -334,7 +334,7 @@ public class CassandraServer implements if (logger.isDebugEnabled()) logger.debug("get_count"); - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ); return get_slice(key, column_parent, predicate, consistency_level).size(); } @@ -345,7 +345,7 @@ public class CassandraServer implements if (logger.isDebugEnabled()) logger.debug("multiget_count"); - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ); String keyspace = state().getKeyspace(); Map<byte[], Integer> counts = new HashMap<byte[], Integer>(); @@ -363,7 +363,7 @@ public class CassandraServer implements if (logger.isDebugEnabled()) logger.debug("insert"); - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyAccess(column_parent.column_family, Permission.WRITE); ThriftValidation.validateKey(key); ThriftValidation.validateColumnParent(state().getKeyspace(), column_parent); @@ -386,8 +386,8 @@ public class CassandraServer implements { if (logger.isDebugEnabled()) logger.debug("batch_mutate"); - - state().hasKeyspaceAccess(Permission.WRITE); + + List<String> cfamsSeen = new ArrayList<String>(); List<RowMutation> rowMutations = new ArrayList<RowMutation>(); for (Map.Entry<byte[], Map<String, List<Mutation>>> mutationEntry: mutation_map.entrySet()) @@ -399,6 +399,13 @@ public class CassandraServer implements for (Map.Entry<String, List<Mutation>> columnFamilyMutations : columnFamilyToMutations.entrySet()) { String cfName = columnFamilyMutations.getKey(); + + // Avoid unneeded authorizations + if (!(cfamsSeen.contains(cfName))) + { + state().hasColumnFamilyAccess(cfName, Permission.WRITE); + cfamsSeen.add(cfName); + } for (Mutation mutation : columnFamilyMutations.getValue()) { @@ -417,7 +424,7 @@ public class CassandraServer implements if (logger.isDebugEnabled()) logger.debug("remove"); - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyAccess(column_path.column_family, Permission.WRITE); ThriftValidation.validateKey(key); ThriftValidation.validateColumnPathOrParent(state().getKeyspace(), column_path); @@ -472,7 +479,7 @@ public class CassandraServer implements logger.debug("range_slice"); String keyspace = state().getKeyspace(); - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ); ThriftValidation.validateColumnParent(keyspace, column_parent); ThriftValidation.validatePredicate(keyspace, column_parent, predicate); @@ -535,7 +542,7 @@ public class CassandraServer implements if (logger.isDebugEnabled()) logger.debug("scan"); - state().hasKeyspaceAccess(Permission.READ); + state().hasColumnFamilyAccess(column_parent.column_family, Permission.READ); String keyspace = state().getKeyspace(); ThriftValidation.validateColumnParent(keyspace, column_parent); ThriftValidation.validatePredicate(keyspace, column_parent, column_predicate); @@ -689,7 +696,7 @@ public class CassandraServer implements public String system_add_column_family(CfDef cf_def) throws InvalidRequestException, TException { - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyListAccess(Permission.WRITE); try { applyMigrationOnStage(new AddColumnFamily(convertToCFMetaData(cf_def))); @@ -711,7 +718,7 @@ public class CassandraServer implements public String system_drop_column_family(String column_family) throws InvalidRequestException, TException { - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyListAccess(Permission.WRITE); try { @@ -734,7 +741,7 @@ public class CassandraServer implements public String system_rename_column_family(String old_name, String new_name) throws InvalidRequestException, TException { - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyListAccess(Permission.WRITE); try { @@ -834,7 +841,7 @@ public class CassandraServer implements public String system_rename_keyspace(String old_name, String new_name) throws InvalidRequestException, TException { - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyListAccess(Permission.WRITE); try { @@ -858,7 +865,7 @@ public class CassandraServer implements /** update an existing keyspace, but do not allow column family modifications. */ public String system_update_keyspace(KsDef ks_def) throws InvalidRequestException, TException { - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyListAccess(Permission.WRITE); if (ks_def.getCf_defs() != null && ks_def.getCf_defs().size() > 0) throw new InvalidRequestException("Keyspace update must not contain any column family definitions."); @@ -896,7 +903,7 @@ public class CassandraServer implements public String system_update_column_family(CfDef cf_def) throws InvalidRequestException, TException { - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyListAccess(Permission.WRITE); if (cf_def.keyspace == null || cf_def.name == null) throw new InvalidRequestException("Keyspace and CF name must be set."); @@ -956,7 +963,7 @@ public class CassandraServer implements public void truncate(String cfname) throws InvalidRequestException, UnavailableException, TException { logger.debug("truncating {} in {}", cfname, state().getKeyspace()); - state().hasKeyspaceAccess(Permission.WRITE); + state().hasColumnFamilyAccess(cfname, Permission.WRITE); try { schedule();