cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gdusba...@apache.org
Subject svn commit: r980222 - in /cassandra/trunk: conf/ src/java/org/apache/cassandra/auth/ src/java/org/apache/cassandra/thrift/
Date Wed, 28 Jul 2010 21:01:57 GMT
Author: gdusbabek
Date: Wed Jul 28 21:01:57 2010
New Revision: 980222

URL: http://svn.apache.org/viewvc?rev=980222&view=rev
Log:
new IAuthenticator interface. patch by stuhood, reviewed by gdusbabek. CASSANDRA-1237

Added:
    cassandra/trunk/src/java/org/apache/cassandra/auth/AuthenticatedUser.java
Removed:
    cassandra/trunk/conf/access.properties
Modified:
    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/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=980222&r1=980221&r2=980222&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java Wed Jul
28 21:01:57 2010
@@ -20,25 +20,31 @@ package org.apache.cassandra.auth;
  * 
  */
 
+import java.util.Map;
 
 import org.apache.cassandra.config.ConfigurationException;
-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 class AllowAllAuthenticator implements IAuthenticator
 {
+    private final static AuthenticatedUser USER = new AuthenticatedUser("allow_all", true);
+
+    @Override
+    public AuthenticatedUser defaultUser()
+    {
+        return USER;
+    }
+
     @Override
-    public AccessLevel login(String keyspace, AuthenticationRequest authRequest) throws AuthenticationException,
AuthorizationException
+    public AuthenticatedUser login(Map<String,String> credentials) throws AuthenticationException,
AuthorizationException
     {
-        // do nothing, allow anything
-        return AccessLevel.FULL;
+        return USER;
     }
     
-   @Override    
+    @Override    
     public void validateConfiguration() throws ConfigurationException
-   {
+    {
         // do nothing, no configuration to validate
     }
 }

Added: cassandra/trunk/src/java/org/apache/cassandra/auth/AuthenticatedUser.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/auth/AuthenticatedUser.java?rev=980222&view=auto
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/auth/AuthenticatedUser.java (added)
+++ cassandra/trunk/src/java/org/apache/cassandra/auth/AuthenticatedUser.java Wed Jul 28 21:01:57
2010
@@ -0,0 +1,76 @@
+/*
+ * 
+ * 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.auth;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cassandra.avro.AccessLevel;
+
+/**
+ * An authenticated user and her groups.
+ */
+public class AuthenticatedUser
+{
+    public final String username;
+    public final Set<String> groups;
+    public final boolean isSuper;
+
+    public AuthenticatedUser(String username, boolean isSuper)
+    {
+        this.username = username;
+        this.groups = Collections.emptySet();
+        this.isSuper = isSuper;
+    }
+
+    public AuthenticatedUser(String username, Set<String> groups, boolean isSuper)
+    {
+        this.username = username;
+        this.groups = Collections.unmodifiableSet(groups);
+        this.isSuper = isSuper;
+    }
+
+    /**
+     * @return The access level granted to the user by the given access maps.
+     */
+    public AccessLevel levelFor(Map<String,AccessLevel> usersAccess, Map<String,AccessLevel>
groupsAccess)
+    {
+        // determine the maximum access level for this user and groups
+        AccessLevel level = usersAccess.get(username);
+        if (level == null)
+            level = AccessLevel.NONE;
+        for (String group : groups)
+        {
+            AccessLevel forGroup = groupsAccess.get(group);
+            if (forGroup != null && forGroup.ordinal() > level.ordinal())
+                level = forGroup;
+        }
+        return level;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "#<User %s groups=%s>".format(username, groups);
+    }
+}

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=980222&r1=980221&r2=980222&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/auth/IAuthenticator.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/auth/IAuthenticator.java Wed Jul 28 21:01:57
2010
@@ -20,16 +20,20 @@ package org.apache.cassandra.auth;
  * 
  */
 
+import java.util.Map;
 
 import org.apache.cassandra.config.ConfigurationException;
-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 AccessLevel login(String keyspace, AuthenticationRequest auth_request) throws
AuthenticationException, AuthorizationException;
+    /**
+     * @return The user that a connection is initialized with, or 'null' if a user must call
login().
+     */
+    public AuthenticatedUser defaultUser();
+
+    public AuthenticatedUser login(Map<String,String> credentials) throws AuthenticationException,
AuthorizationException;
 
     public void validateConfiguration() throws ConfigurationException;
 }

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=980222&r1=980221&r2=980222&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/auth/SimpleAuthenticator.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/auth/SimpleAuthenticator.java Wed Jul 28
21:01:57 2010
@@ -25,17 +25,15 @@ import java.io.*;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Properties;
+import java.util.Map;
 
 import org.apache.cassandra.config.ConfigurationException;
-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 class SimpleAuthenticator implements IAuthenticator
 {
     public final static String PASSWD_FILENAME_PROPERTY        = "passwd.properties";
-    public final static String ACCESS_FILENAME_PROPERTY        = "access.properties";
     public final static String PMODE_PROPERTY                  = "passwd.mode";
     public static final String USERNAME_KEY                    = "username";
     public static final String PASSWORD_KEY                    = "password";
@@ -46,7 +44,14 @@ public class SimpleAuthenticator impleme
     };
 
     @Override
-    public AccessLevel login(String keyspace, AuthenticationRequest authRequest) throws AuthenticationException,
AuthorizationException
+    public AuthenticatedUser defaultUser()
+    {
+        // users must log in
+        return null;
+    }
+
+    @Override
+    public AuthenticatedUser login(Map<String,String> credentials) throws AuthenticationException,
AuthorizationException
     {
         String pmode_plain = System.getProperty(PMODE_PROPERTY);
         PasswordMode mode = PasswordMode.PLAIN;
@@ -71,10 +76,10 @@ public class SimpleAuthenticator impleme
 
         String pfilename = System.getProperty(PASSWD_FILENAME_PROPERTY);
 
-        String username = authRequest.getCredentials().get(USERNAME_KEY);
+        String username = credentials.get(USERNAME_KEY);
         if (null == username) throw new AuthenticationException("Authentication request was
missing the required key '" + USERNAME_KEY + "'");
 
-        String password = authRequest.getCredentials().get(PASSWORD_KEY);
+        String password = credentials.get(PASSWORD_KEY);
         if (null == password) throw new AuthenticationException("Authentication request was
missing the required key '" + PASSWORD_KEY + "'");
 
         boolean authenticated = false;
@@ -96,15 +101,13 @@ public class SimpleAuthenticator impleme
                 case MD5:
                     authenticated = MessageDigest.isEqual(password.getBytes(), MessageDigest.getInstance("MD5").digest(props.getProperty(username).getBytes()));
                     break;
+                default:
+                    throw new RuntimeException("Unknown PasswordMode " + mode);
             }
         }
         catch (NoSuchAlgorithmException e)
         {
-            throw new AuthenticationException("You requested MD5 checking but the MD5 digest
algorithm is not available: " + e.getMessage());
-        }
-        catch (FileNotFoundException e)
-        {
-            throw new RuntimeException("Authentication table file given by property " + PASSWD_FILENAME_PROPERTY
+ " could not be found: " + e.getMessage());
+            throw new RuntimeException("You requested MD5 checking but the MD5 digest algorithm
is not available: " + e.getMessage());
         }
         catch (IOException e)
         {
@@ -117,63 +120,21 @@ public class SimpleAuthenticator impleme
 
         if (!authenticated) throw new AuthenticationException(authenticationErrorMessage(mode,
username));
 
-        // 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);
-        AccessLevel authorized = AccessLevel.NONE;
-        try
-        {
-            FileInputStream in = new FileInputStream(afilename);
-            Properties props = new Properties();
-            props.load(in);
-            in.close();
-
-            // structure:
-            // given keyspace X, users A B and C can be authorized like this (separate their
names with spaces):
-            // X = A B C
-            
-            // note we keep the message here and for other authorization problems exactly
the same to prevent attackers
-            // from guessing what keyspaces are valid
-            if (null == props.getProperty(keyspace))
-                throw new AuthorizationException(authorizationErrorMessage(keyspace, username));
-
-            for (String allow : props.getProperty(keyspace).split(","))
-            {
-                if (allow.equals(username)) authorized = AccessLevel.FULL;
-            }
-        }
-        catch (FileNotFoundException e)
-        {
-            throw new RuntimeException("Authorization table file given by property " + ACCESS_FILENAME_PROPERTY
+ " could not be found: " + e.getMessage());
-        }
-        catch (IOException e)
-        {
-            throw new RuntimeException("Authorization table file given by property " + ACCESS_FILENAME_PROPERTY
+ " could not be opened: " + e.getMessage());
-        }
-
-        if (authorized == AccessLevel.NONE) throw new AuthorizationException(authorizationErrorMessage(keyspace,
username));
-        
-        return authorized;
+        // TODO: Should allow/require a user to configure a 'super' username.
+        return new AuthenticatedUser(username, false);
     }
 
-   @Override
+    @Override
     public void validateConfiguration() throws ConfigurationException 
     {
-        String aFileName = System.getProperty(SimpleAuthenticator.ACCESS_FILENAME_PROPERTY);
         String pfilename = System.getProperty(SimpleAuthenticator.PASSWD_FILENAME_PROPERTY);
-        if (aFileName == null || pfilename == null)
+        if (pfilename == null)
         {
             throw new ConfigurationException("When using " + this.getClass().getCanonicalName()
+ " " + 
-                    SimpleAuthenticator.ACCESS_FILENAME_PROPERTY + " and " + 
                     SimpleAuthenticator.PASSWD_FILENAME_PROPERTY + " properties must be defined.");

         }
     }
 
-    static String authorizationErrorMessage(String keyspace, String username)
-    {
-        return String.format("User %s could not be authorized to use keyspace %s", username,
keyspace);
-    }
-
     static String authenticationErrorMessage(PasswordMode mode, String username)
     {
         return String.format("Given password in password mode %s could not be validated for
user %s", mode, 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=980222&r1=980221&r2=980222&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java Wed Jul 28 21:01:57
2010
@@ -30,6 +30,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.auth.AllowAllAuthenticator;
+import org.apache.cassandra.auth.AuthenticatedUser;
 import org.apache.cassandra.concurrent.StageManager;
 import org.apache.cassandra.config.ConfigurationException;
 import org.apache.cassandra.config.KSMetaData;
@@ -66,14 +67,14 @@ public class CassandraServer implements 
     private final static List<Column> EMPTY_SUBCOLUMNS = Collections.emptyList();
 
     // will be set only by login()
-    private ThreadLocal<AccessLevel> loginDone = new ThreadLocal<AccessLevel>()

-    {
+    private ThreadLocal<AuthenticatedUser> loginDone = new ThreadLocal<AuthenticatedUser>()
{
         @Override
-        protected AccessLevel initialValue()
+        public AuthenticatedUser initialValue()
         {
-            return AccessLevel.NONE;
+            return DatabaseDescriptor.getAuthenticator().defaultUser();
         }
     };
+
     /*
      * Keyspace associated with session
      */
@@ -706,22 +707,14 @@ public class CassandraServer implements 
         return splits;
     }
 
-    public AccessLevel login(AuthenticationRequest auth_request) throws AuthenticationException,
AuthorizationException, TException
+    public void login(AuthenticationRequest auth_request) throws AuthenticationException,
AuthorizationException, TException
     {
-        AccessLevel level;
-        
-        if (keySpace.get() == null)
-        {
-            throw new AuthenticationException("You have not set a specific keyspace; please
call set_keyspace first");
-        }
-        
-        level = DatabaseDescriptor.getAuthenticator().login(keySpace.get(), auth_request);
+        AuthenticatedUser user = DatabaseDescriptor.getAuthenticator().login(auth_request.getCredentials());
         
         if (logger.isDebugEnabled())
-            logger.debug("login confirmed; new access level is " + level);
+            logger.debug("login confirmed; user is " + user);
         
-        loginDone.set(level);
-        return level;
+        loginDone.set(user);
     }
 
     public void logout()
@@ -735,18 +728,11 @@ public class CassandraServer implements 
 
     protected void checkKeyspaceAndLoginAuthorized(AccessLevel level) throws InvalidRequestException
     {
-        if (keySpace.get() == null)
-        {
-            throw new InvalidRequestException("You have not assigned a keyspace; please use
set_keyspace (and login if necessary)");
-        }
-        
-        if (!(DatabaseDescriptor.getAuthenticator() instanceof AllowAllAuthenticator))
-        {
-            if (loginDone.get() == null)
-                throw new InvalidRequestException("You have not logged into keyspace " +
keySpace.get());
-            if (loginDone.get().getValue() < level.getValue())
-                throw new InvalidRequestException("Your credentials are not sufficient to
perform " + level + " operations");
-        }
+        if (loginDone.get() == null)
+            throw new InvalidRequestException("You have not logged in");
+
+        // FIXME: if no keyspace set, check against global authlist. otherwise, check
+        // against keyspace authlist
     }
 
     /**
@@ -877,6 +863,7 @@ public class CassandraServer implements 
         // IAuthenticator was devised prior to, and without thought for, dynamic keyspace
creation. As
         // a result, we must choose between letting anyone/everyone create keyspaces (which
they likely
         // won't even be able to use), or be honest and disallow it entirely if configured
for auth.
+        // See CASSANDRA-1271 for a proposed solution.
         if (!(DatabaseDescriptor.getAuthenticator() instanceof AllowAllAuthenticator))
             throw new InvalidRequestException("Unable to create new keyspace while authentication
is enabled.");
 
@@ -1034,10 +1021,6 @@ public class CassandraServer implements 
             throw new InvalidRequestException("Keyspace does not exist");
         }
         
-        // If switching, invalidate previous access level; force a new login.
-        if (keySpace.get() != null && !keySpace.get().equals(keyspace))
-            loginDone.set(AccessLevel.NONE);
-        
         keySpace.set(keyspace);
         requestSchedulerId.set(keyspace);
     }



Mime
View raw message