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
 }


Reply via email to