Author: eevans
Date: Mon Mar 22 23:11:16 2010
New Revision: 926388
URL: http://svn.apache.org/viewvc?rev=926388&view=rev
Log:
access levels for Thrift authorization
Patch by Ted Zlatanov and eevans for CASSANDRA-900
Modified:
cassandra/trunk/interface/cassandra.thrift
cassandra/trunk/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java
cassandra/trunk/src/java/org/apache/cassandra/auth/IAuthenticator.java
cassandra/trunk/src/java/org/apache/cassandra/auth/SimpleAuthenticator.java
cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java
Modified: cassandra/trunk/interface/cassandra.thrift
URL:
http://svn.apache.org/viewvc/cassandra/trunk/interface/cassandra.thrift?rev=926388&r1=926387&r2=926388&view=diff
==============================================================================
--- cassandra/trunk/interface/cassandra.thrift (original)
+++ cassandra/trunk/interface/cassandra.thrift Mon Mar 22 23:11:16 2010
@@ -305,7 +305,7 @@ struct AuthenticationRequest {
service Cassandra {
# auth methods
- void login(1: required string keyspace, 2:required AuthenticationRequest
auth_request) throws (1:AuthenticationException authnx,
2:AuthorizationException authzx),
+ AccessLevel login(1: required string keyspace, 2:required
AuthenticationRequest auth_request) throws (1:AuthenticationException authnx,
2:AuthorizationException authzx),
# retrieval methods
Modified:
cassandra/trunk/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java?rev=926388&r1=926387&r2=926388&view=diff
==============================================================================
---
cassandra/trunk/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java
(original)
+++
cassandra/trunk/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java
Mon Mar 22 23:11:16 2010
@@ -21,6 +21,7 @@ package org.apache.cassandra.auth;
*/
+import org.apache.cassandra.thrift.AccessLevel;
import org.apache.cassandra.thrift.AuthenticationException;
import org.apache.cassandra.thrift.AuthenticationRequest;
import org.apache.cassandra.thrift.AuthorizationException;
@@ -28,8 +29,9 @@ import org.apache.cassandra.thrift.Autho
public class AllowAllAuthenticator implements IAuthenticator
{
@Override
- public void login(String keyspace, AuthenticationRequest authRequest)
throws AuthenticationException, AuthorizationException
+ public AccessLevel login(String keyspace, AuthenticationRequest
authRequest) throws AuthenticationException, AuthorizationException
{
// do nothing, allow anything
+ return AccessLevel.FULL;
}
}
Modified: cassandra/trunk/src/java/org/apache/cassandra/auth/IAuthenticator.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/auth/IAuthenticator.java?rev=926388&r1=926387&r2=926388&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/auth/IAuthenticator.java
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/auth/IAuthenticator.java Mon
Mar 22 23:11:16 2010
@@ -21,11 +21,12 @@ package org.apache.cassandra.auth;
*/
+import org.apache.cassandra.thrift.AccessLevel;
import org.apache.cassandra.thrift.AuthenticationException;
import org.apache.cassandra.thrift.AuthenticationRequest;
import org.apache.cassandra.thrift.AuthorizationException;
public interface IAuthenticator
{
- public void login(String keyspace, AuthenticationRequest auth_request)
throws AuthenticationException, AuthorizationException;
+ public AccessLevel login(String keyspace, AuthenticationRequest
auth_request) throws AuthenticationException, AuthorizationException;
}
Modified:
cassandra/trunk/src/java/org/apache/cassandra/auth/SimpleAuthenticator.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/auth/SimpleAuthenticator.java?rev=926388&r1=926387&r2=926388&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/auth/SimpleAuthenticator.java
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/auth/SimpleAuthenticator.java
Mon Mar 22 23:11:16 2010
@@ -26,6 +26,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
+import org.apache.cassandra.thrift.AccessLevel;
import org.apache.cassandra.thrift.AuthenticationException;
import org.apache.cassandra.thrift.AuthenticationRequest;
import org.apache.cassandra.thrift.AuthorizationException;
@@ -44,7 +45,7 @@ public class SimpleAuthenticator impleme
};
@Override
- public void login(String keyspace, AuthenticationRequest authRequest)
throws AuthenticationException, AuthorizationException
+ public AccessLevel login(String keyspace, AuthenticationRequest
authRequest) throws AuthenticationException, AuthorizationException
{
String pmode_plain = System.getProperty(PMODE_PROPERTY);
PasswordMode mode = PasswordMode.PLAIN;
@@ -118,7 +119,7 @@ public class SimpleAuthenticator impleme
// if we're here, the authentication succeeded. Now let's see if the
user is authorized for this keyspace.
String afilename = System.getProperty(ACCESS_FILENAME_PROPERTY);
- boolean authorized = false;
+ AccessLevel authorized = AccessLevel.NONE;
try
{
FileInputStream in = new FileInputStream(afilename);
@@ -134,7 +135,7 @@ public class SimpleAuthenticator impleme
if (null == props.getProperty(keyspace)) throw new
AuthorizationException(authorizationErrorMessage(keyspace, username));
for (String allow : props.getProperty(keyspace).split(","))
{
- if (allow.equals(username)) authorized = true;
+ if (allow.equals(username)) authorized = AccessLevel.FULL;
}
}
catch (FileNotFoundException e)
@@ -150,7 +151,9 @@ public class SimpleAuthenticator impleme
throw new RuntimeException("Unexpected authorization problem", e);
}
- if (!authorized) throw new
AuthorizationException(authorizationErrorMessage(keyspace, username));
+ if (authorized == AccessLevel.NONE) throw new
AuthorizationException(authorizationErrorMessage(keyspace, username));
+
+ return authorized;
}
static String authorizationErrorMessage(String keyspace, String username)
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=926388&r1=926387&r2=926388&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java
Mon Mar 22 23:11:16 2010
@@ -53,12 +53,12 @@ public class CassandraServer implements
private final static List<Column> EMPTY_SUBCOLUMNS =
Collections.emptyList();
// will be set only by login()
- private ThreadLocal<Boolean> loginDone = new ThreadLocal<Boolean>()
+ private ThreadLocal<AccessLevel> loginDone = new
ThreadLocal<AccessLevel>()
{
@Override
- protected Boolean initialValue()
+ protected AccessLevel initialValue()
{
- return false;
+ return AccessLevel.NONE;
}
};
@@ -215,9 +215,8 @@ public class CassandraServer implements
{
if (logger.isDebugEnabled())
logger.debug("get_slice");
-
- checkLoginDone();
-
+
+ checkLoginAuthorized(AccessLevel.READONLY);
return multigetSliceInternal(keyspace, Arrays.asList(key),
column_parent, predicate, consistency_level).get(key);
}
@@ -227,7 +226,7 @@ public class CassandraServer implements
if (logger.isDebugEnabled())
logger.debug("multiget_slice");
- checkLoginDone();
+ checkLoginAuthorized(AccessLevel.READONLY);
return multigetSliceInternal(keyspace, keys, column_parent, predicate,
consistency_level);
}
@@ -266,7 +265,7 @@ public class CassandraServer implements
if (logger.isDebugEnabled())
logger.debug("get");
- checkLoginDone();
+ checkLoginAuthorized(AccessLevel.READONLY);
ColumnOrSuperColumn column = multigetInternal(table,
Arrays.asList(key), column_path, consistency_level).get(key);
if (!column.isSetColumn() && !column.isSetSuper_column())
@@ -283,7 +282,7 @@ public class CassandraServer implements
if (logger.isDebugEnabled())
logger.debug("multiget");
- checkLoginDone();
+ checkLoginAuthorized(AccessLevel.READONLY);
return multigetInternal(table, keys, column_path, consistency_level);
}
@@ -328,7 +327,7 @@ public class CassandraServer implements
if (logger.isDebugEnabled())
logger.debug("get_count");
- checkLoginDone();
+ checkLoginAuthorized(AccessLevel.READONLY);
SliceRange range = new SliceRange(ArrayUtils.EMPTY_BYTE_ARRAY,
ArrayUtils.EMPTY_BYTE_ARRAY, false, Integer.MAX_VALUE);
SlicePredicate predicate = new SlicePredicate().setSlice_range(range);
@@ -341,7 +340,7 @@ public class CassandraServer implements
if (logger.isDebugEnabled())
logger.debug("insert");
- checkLoginDone();
+ checkLoginAuthorized(AccessLevel.READWRITE);
ThriftValidation.validateKey(key);
ThriftValidation.validateColumnPath(table, column_path);
@@ -364,7 +363,7 @@ public class CassandraServer implements
if (logger.isDebugEnabled())
logger.debug("batch_insert");
- checkLoginDone();
+ checkLoginAuthorized(AccessLevel.READWRITE);
ThriftValidation.validateKey(key);
@@ -385,7 +384,25 @@ public class CassandraServer implements
if (logger.isDebugEnabled())
logger.debug("batch_mutate");
- checkLoginDone();
+ AccessLevel needed = AccessLevel.READWRITE;
+
+ TOP:
+ for (Map<String, List<Mutation>> submap : mutation_map.values())
+ {
+ for (List<Mutation> mutations: submap.values())
+ {
+ for (Mutation m : mutations)
+ {
+ if (m.isSetDeletion())
+ {
+ needed = AccessLevel.FULL;
+ break TOP;
+ }
+ }
+ }
+ }
+
+ checkLoginAuthorized(needed);
List<RowMutation> rowMutations = new ArrayList<RowMutation>();
for (Map.Entry<String, Map<String, List<Mutation>>> mutationEntry:
mutation_map.entrySet())
@@ -428,7 +445,7 @@ public class CassandraServer implements
if (logger.isDebugEnabled())
logger.debug("remove");
- checkLoginDone();
+ checkLoginAuthorized(AccessLevel.FULL);
ThriftValidation.validateKey(key);
ThriftValidation.validateColumnPathOrParent(table, column_path);
@@ -559,7 +576,7 @@ public class CassandraServer implements
private List<KeySlice> getRangeSlicesInternal(String keyspace,
ColumnParent column_parent, SlicePredicate predicate, KeyRange range,
ConsistencyLevel consistency_level)
throws InvalidRequestException, UnavailableException,
TimedOutException
{
- checkLoginDone();
+ checkLoginAuthorized(AccessLevel.READONLY);
ThriftValidation.validateColumnParent(keyspace, column_parent);
ThriftValidation.validatePredicate(keyspace, column_parent, predicate);
@@ -643,21 +660,22 @@ public class CassandraServer implements
return splits;
}
- public void login(String keyspace, AuthenticationRequest auth_request)
throws AuthenticationException, AuthorizationException, TException
+ public AccessLevel login(String keyspace, AuthenticationRequest
auth_request) throws AuthenticationException, AuthorizationException, TException
{
- DatabaseDescriptor.getAuthenticator().login(keyspace, auth_request);
- loginDone.set(true);
+ AccessLevel level =
DatabaseDescriptor.getAuthenticator().login(keyspace, auth_request);
+ loginDone.set(level);
+ return level;
}
- protected void checkLoginDone() throws InvalidRequestException
+ protected void checkLoginAuthorized(AccessLevel level) throws
InvalidRequestException
{
- // FIXME: This disables the "you must call login()" requirement when
the configured
+ // FIXME: This disables access level checks when the configured
// authenticator is AllowAllAuthenticator. This is a temporary measure
until CASSANDRA-714 is complete.
if (DatabaseDescriptor.getAuthenticator() instanceof
AllowAllAuthenticator)
return;
- if (!loginDone.get()) throw new InvalidRequestException("Login is
required before any other API calls");
+ if (loginDone.get() == AccessLevel.NONE) throw new
InvalidRequestException("Your login access level was not sufficient to do " +
level + " operations");
+ if (loginDone.get().getValue() >= level.getValue()) throw new
InvalidRequestException("Your login access level was not sufficient to do " +
level + " operations");
}
-
// main method moved to CassandraDaemon
}