Simplify auth setup and make system_auth ks alterable

Patch by Aleksey Yeschenko; reviewed by Jonathan Ellis for
CASSANDRA-5112


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/26596406
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/26596406
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/26596406

Branch: refs/heads/trunk
Commit: 265964064bd5012b871101e884d7e2032a44e32a
Parents: e531be7
Author: Aleksey Yeschenko <alek...@apache.org>
Authored: Thu Feb 14 01:19:04 2013 +0300
Committer: Aleksey Yeschenko <alek...@apache.org>
Committed: Thu Feb 14 01:19:04 2013 +0300

----------------------------------------------------------------------
 CHANGES.txt                                        |    1 +
 bin/cqlsh                                          |    2 +-
 pylib/cqlshlib/cql3handling.py                     |   12 +-
 src/java/org/apache/cassandra/auth/Auth.java       |  132 +++++++++++++--
 .../org/apache/cassandra/config/CFMetaData.java    |    8 +-
 .../cassandra/config/DatabaseDescriptor.java       |    4 +-
 .../org/apache/cassandra/config/KSMetaData.java    |    7 -
 src/java/org/apache/cassandra/config/Schema.java   |    3 +-
 .../org/apache/cassandra/cql3/QueryProcessor.java  |    4 +-
 .../cql3/statements/ListUsersStatement.java        |    2 +-
 .../apache/cassandra/service/CassandraDaemon.java  |    4 -
 .../org/apache/cassandra/service/ClientState.java  |   14 ++-
 .../apache/cassandra/service/MigrationManager.java |    7 +-
 .../apache/cassandra/service/StorageService.java   |   10 +-
 14 files changed, 153 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 5dd2499..3d0f633 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -18,6 +18,7 @@
  * Implement caching of authorization results (CASSANDRA-4295)
  * Add support for LZ4 compression (CASSANDRA-5038)
  * Fix missing columns in wide rows queries (CASSANDRA-5225)
+ * Simplify auth setup and make system_auth ks alterable (CASSANDRA-5112)
 
 
 1.2.1

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/bin/cqlsh
----------------------------------------------------------------------
diff --git a/bin/cqlsh b/bin/cqlsh
index 4f58bdc..6db59a3 100755
--- a/bin/cqlsh
+++ b/bin/cqlsh
@@ -173,7 +173,7 @@ else:
 
 debug_completion = bool(os.environ.get('CQLSH_DEBUG_COMPLETION', '') == 'YES')
 
-SYSTEM_KEYSPACES = ('system', 'system_traces', 'system_auth')
+SYSTEM_KEYSPACES = ('system', 'system_traces')
 
 # we want the cql parser to understand our cqlsh-specific commands too
 my_commands_ending_with_newline = (

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/pylib/cqlshlib/cql3handling.py
----------------------------------------------------------------------
diff --git a/pylib/cqlshlib/cql3handling.py b/pylib/cqlshlib/cql3handling.py
index 27bd67b..def573e 100644
--- a/pylib/cqlshlib/cql3handling.py
+++ b/pylib/cqlshlib/cql3handling.py
@@ -39,6 +39,7 @@ class UnexpectedTableStructure(UserWarning):
         return 'Unexpected table structure; may not translate correctly to 
CQL. ' + self.msg
 
 SYSTEM_KEYSPACES = ('system', 'system_traces', 'system_auth')
+NONALTERBALE_KEYSPACES = ('system', 'system_traces')
 
 class Cql3ParsingRuleSet(CqlParsingRuleSet):
     keywords = set((
@@ -306,6 +307,8 @@ JUNK ::= /([ 
\t\r\f\v]+|(--|[/][/])[^\n\r]*([\n\r]|$)|[/][*].*?[*][/])/ ;
 
 <nonSystemKeyspaceName> ::= ksname=<cfOrKsName> ;
 
+<alterableKeyspaceName> ::= ksname=<cfOrKsName> ;
+
 <cfOrKsName> ::= <identifier>
                | <quotedName>
                | <unreservedKeyword>;
@@ -686,6 +689,11 @@ def ks_name_completer(ctxt, cass):
     ksnames = [n for n in cass.get_keyspace_names() if n not in 
SYSTEM_KEYSPACES]
     return map(maybe_escape_name, ksnames)
 
+@completer_for('alterableKeyspaceName', 'ksname')
+def ks_name_completer(ctxt, cass):
+    ksnames = [n for n in cass.get_keyspace_names() if n not in 
NONALTERBALE_KEYSPACES]
+    return map(maybe_escape_name, ksnames)
+
 @completer_for('columnFamilyName', 'ksname')
 def cf_ks_name_completer(ctxt, cass):
     return [maybe_escape_name(ks) + '.' for ks in cass.get_keyspace_names()]
@@ -1242,7 +1250,7 @@ def alter_table_col_completer(ctxt, cass):
 explain_completion('alterInstructions', 'newcol', '<new_column_name>')
 
 syntax_rules += r'''
-<alterKeyspaceStatement> ::= "ALTER" ( "KEYSPACE" | "SCHEMA" ) 
ks=<nonSystemKeyspaceName>
+<alterKeyspaceStatement> ::= "ALTER" ( "KEYSPACE" | "SCHEMA" ) 
ks=<alterableKeyspaceName>
                                  "WITH" <newPropSpec> ( "AND" <newPropSpec> )*
                            ;
 '''
@@ -1295,7 +1303,7 @@ syntax_rules += r'''
              ;
 
 <dataResource> ::= ( "ALL" "KEYSPACES" )
-                 | ( "KEYSPACE" <nonSystemKeyspaceName> )
+                 | ( "KEYSPACE" <keyspaceName> )
                  | ( "TABLE"? <columnFamilyName> )
                  ;
 '''

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/auth/Auth.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/Auth.java 
b/src/java/org/apache/cassandra/auth/Auth.java
index a1ba3df..399dc26 100644
--- a/src/java/org/apache/cassandra/auth/Auth.java
+++ b/src/java/org/apache/cassandra/auth/Auth.java
@@ -17,15 +17,24 @@
  */
 package org.apache.cassandra.auth;
 
+import java.util.concurrent.TimeUnit;
+
+import com.google.common.collect.ImmutableMap;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.KSMetaData;
+import org.apache.cassandra.config.Schema;
 import org.apache.cassandra.cql3.UntypedResultSet;
 import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.db.ConsistencyLevel;
 import org.apache.cassandra.exceptions.RequestExecutionException;
+import org.apache.cassandra.locator.SimpleStrategy;
+import org.apache.cassandra.service.IMigrationListener;
 import org.apache.cassandra.service.MigrationManager;
+import org.apache.cassandra.service.StorageService;
 
 public class Auth
 {
@@ -33,9 +42,20 @@ public class Auth
 
     public static final String DEFAULT_SUPERUSER_NAME = "cassandra";
 
+    private static final long SUPERUSER_SETUP_DELAY = 10; // seconds.
+
     public static final String AUTH_KS = "system_auth";
     public static final String USERS_CF = "users";
 
+    private static final String USERS_CF_SCHEMA = String.format("CREATE TABLE 
%s.%s ("
+                                                                + "name text,"
+                                                                + "super 
boolean,"
+                                                                + "PRIMARY 
KEY(name)"
+                                                                + ") WITH 
gc_grace_seconds=%d",
+                                                                AUTH_KS,
+                                                                USERS_CF,
+                                                                90 * 24 * 60 * 
60); // 3 months.
+
     /**
      * Checks if the username is stored in AUTH_KS.USERS_CF.
      *
@@ -47,7 +67,7 @@ public class Auth
         String query = String.format("SELECT * FROM %s.%s WHERE name = '%s'", 
AUTH_KS, USERS_CF, escape(username));
         try
         {
-            return !QueryProcessor.process(query).isEmpty();
+            return !QueryProcessor.process(query, 
ConsistencyLevel.QUORUM).isEmpty();
         }
         catch (RequestExecutionException e)
         {
@@ -66,7 +86,7 @@ public class Auth
         String query = String.format("SELECT super FROM %s.%s WHERE name = 
'%s'", AUTH_KS, USERS_CF, escape(username));
         try
         {
-            UntypedResultSet result = QueryProcessor.process(query);
+            UntypedResultSet result = QueryProcessor.process(query, 
ConsistencyLevel.QUORUM);
             return !result.isEmpty() && result.one().getBoolean("super");
         }
         catch (RequestExecutionException e)
@@ -87,7 +107,8 @@ public class Auth
                                              AUTH_KS,
                                              USERS_CF,
                                              escape(username),
-                                             isSuper));
+                                             isSuper),
+                               ConsistencyLevel.QUORUM);
     }
 
     /**
@@ -100,7 +121,8 @@ public class Auth
         QueryProcessor.process(String.format("DELETE FROM %s.%s WHERE name = 
'%s'",
                                              AUTH_KS,
                                              USERS_CF,
-                                             escape(username)));
+                                             escape(username)),
+                               ConsistencyLevel.QUORUM);
     }
 
     /**
@@ -108,23 +130,75 @@ public class Auth
      */
     public static void setup()
     {
-        authenticator().setup();
-        authorizer().setup();
+        setupAuthKeyspace();
+        setupUsersTable();
+
+        DatabaseDescriptor.getAuthenticator().setup();
+        DatabaseDescriptor.getAuthorizer().setup();
 
         // register a custom MigrationListener for permissions cleanup after 
dropped keyspaces/cfs.
         MigrationManager.instance.register(new MigrationListener());
+
+        // the delay is here to give the node some time to see its peers - to 
reduce
+        // "Skipping default superuser setup: some nodes are not ready" log 
spam.
+        // It's the only reason for the delay.
+        StorageService.tasks.schedule(new Runnable()
+                                      {
+                                          public void run()
+                                          {
+                                              setupDefaultSuperuser();
+                                          }
+                                      },
+                                      SUPERUSER_SETUP_DELAY,
+                                      TimeUnit.SECONDS);
     }
 
-    /**
-     * Sets up default superuser.
-     */
-    public static void setupSuperuser()
+    private static void setupAuthKeyspace()
+    {
+        if (Schema.instance.getKSMetaData(AUTH_KS) == null)
+        {
+            try
+            {
+                KSMetaData ksm = KSMetaData.newKeyspace(AUTH_KS, 
SimpleStrategy.class.getName(), ImmutableMap.of("replication_factor", "1"), 
true);
+                MigrationManager.announceNewKeyspace(ksm, 0);
+            }
+            catch (Exception e)
+            {
+                throw new AssertionError(e); // shouldn't ever happen.
+            }
+        }
+    }
+
+    private static void setupUsersTable()
+    {
+        if (Schema.instance.getCFMetaData(AUTH_KS, USERS_CF) == null)
+        {
+            try
+            {
+                QueryProcessor.process(USERS_CF_SCHEMA, ConsistencyLevel.ONE);
+            }
+            catch (RequestExecutionException e)
+            {
+                throw new AssertionError(e);
+            }
+        }
+    }
+
+    private static void setupDefaultSuperuser()
     {
         try
         {
             // insert a default superuser if AUTH_KS.USERS_CF is empty.
-            if (QueryProcessor.process(String.format("SELECT * FROM %s.%s", 
AUTH_KS, USERS_CF)).isEmpty())
-                insertUser(DEFAULT_SUPERUSER_NAME, true);
+            if (QueryProcessor.process(String.format("SELECT * FROM %s.%s", 
AUTH_KS, USERS_CF), ConsistencyLevel.QUORUM).isEmpty())
+            {
+                logger.info("Creating default superuser '{}'", 
DEFAULT_SUPERUSER_NAME);
+                QueryProcessor.process(String.format("INSERT INTO %s.%s (name, 
super) VALUES ('%s', %s) USING TIMESTAMP 0",
+                                                     AUTH_KS,
+                                                     USERS_CF,
+                                                     DEFAULT_SUPERUSER_NAME,
+                                                     true),
+                                       ConsistencyLevel.QUORUM);
+            }
         }
         catch (RequestExecutionException e)
         {
@@ -138,13 +212,35 @@ public class Auth
         return StringUtils.replace(name, "'", "''");
     }
 
-    private static IAuthenticator authenticator()
+    /**
+     * IMigrationListener implementation that cleans up permissions on dropped 
resources.
+     */
+    public static class MigrationListener implements IMigrationListener
     {
-        return DatabaseDescriptor.getAuthenticator();
-    }
+        public void onDropKeyspace(String ksName)
+        {
+            
DatabaseDescriptor.getAuthorizer().revokeAll(DataResource.keyspace(ksName));
+        }
 
-    private static IAuthorizer authorizer()
-    {
-        return DatabaseDescriptor.getAuthorizer();
+        public void onDropColumnFamily(String ksName, String cfName)
+        {
+            
DatabaseDescriptor.getAuthorizer().revokeAll(DataResource.columnFamily(ksName, 
cfName));
+        }
+
+        public void onCreateKeyspace(String ksName)
+        {
+        }
+
+        public void onCreateColumnFamily(String ksName, String cfName)
+        {
+        }
+
+        public void onUpdateKeyspace(String ksName)
+        {
+        }
+
+        public void onUpdateColumnFamily(String ksName, String cfName)
+        {
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/config/CFMetaData.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java 
b/src/java/org/apache/cassandra/config/CFMetaData.java
index 1738d2d..9c76c9b 100644
--- a/src/java/org/apache/cassandra/config/CFMetaData.java
+++ b/src/java/org/apache/cassandra/config/CFMetaData.java
@@ -33,7 +33,6 @@ import org.apache.commons.lang.builder.ToStringBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.cassandra.auth.Auth;
 import org.apache.cassandra.cql3.CFDefinition;
 import org.apache.cassandra.cql3.QueryProcessor;
 import org.apache.cassandra.cql3.UntypedResultSet;
@@ -227,12 +226,7 @@ public final class CFMetaData
                                                               + "requested_at 
timestamp"
                                                               + ") WITH 
COMMENT='ranges requested for transfer here'");
 
-    public static final CFMetaData AuthUsersCf = compile(18, "CREATE TABLE " + 
Auth.USERS_CF + " ("
-                                                             + "name text 
PRIMARY KEY,"
-                                                             + "super boolean"
-                                                             + ") WITH 
gc_grace_seconds=864000;", Auth.AUTH_KS);
-
-    public static final CFMetaData CompactionLogCF = compile(19, "CREATE TABLE 
" + SystemTable.COMPACTION_LOG + " ("
+    public static final CFMetaData CompactionLogCF = compile(18, "CREATE TABLE 
" + SystemTable.COMPACTION_LOG + " ("
                                                                  + "id uuid 
PRIMARY KEY,"
                                                                  + 
"keyspace_name text,"
                                                                  + 
"columnfamily_name text,"

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java 
b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index e0fb9b5..e5afe56 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -470,9 +470,7 @@ public class DatabaseDescriptor
             }
 
             // Hardcoded system tables
-            List<KSMetaData> systemKeyspaces = 
Arrays.asList(KSMetaData.systemKeyspace(),
-                                                             
KSMetaData.traceKeyspace(),
-                                                             
KSMetaData.authKeyspace());
+            List<KSMetaData> systemKeyspaces = 
Arrays.asList(KSMetaData.systemKeyspace(), KSMetaData.traceKeyspace());
             assert systemKeyspaces.size() == Schema.systemKeyspaceNames.size();
             for (KSMetaData ksmd : systemKeyspaces)
             {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/config/KSMetaData.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/KSMetaData.java 
b/src/java/org/apache/cassandra/config/KSMetaData.java
index de41f57..b0764cc 100644
--- a/src/java/org/apache/cassandra/config/KSMetaData.java
+++ b/src/java/org/apache/cassandra/config/KSMetaData.java
@@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableMap;
 import org.apache.commons.lang.ObjectUtils;
 import org.apache.commons.lang.StringUtils;
 
-import org.apache.cassandra.auth.Auth;
 import org.apache.cassandra.cql3.QueryProcessor;
 import org.apache.cassandra.cql3.UntypedResultSet;
 import org.apache.cassandra.db.*;
@@ -104,12 +103,6 @@ public final class KSMetaData
         return new KSMetaData(Tracing.TRACE_KS, SimpleStrategy.class, 
ImmutableMap.of("replication_factor", "1"), true, cfDefs);
     }
 
-    public static KSMetaData authKeyspace()
-    {
-        List<CFMetaData> cfDefs = Arrays.asList(CFMetaData.AuthUsersCf);
-        return new KSMetaData(Auth.AUTH_KS, SimpleStrategy.class, 
ImmutableMap.of("replication_factor", "1"), true, cfDefs);
-    }
-
     public static KSMetaData testMetadata(String name, Class<? extends 
AbstractReplicationStrategy> strategyClass, Map<String, String> 
strategyOptions, CFMetaData... cfDefs)
     {
         return new KSMetaData(name, strategyClass, strategyOptions, true, 
Arrays.asList(cfDefs));

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/config/Schema.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/Schema.java 
b/src/java/org/apache/cassandra/config/Schema.java
index 5076f47..b2d557e 100644
--- a/src/java/org/apache/cassandra/config/Schema.java
+++ b/src/java/org/apache/cassandra/config/Schema.java
@@ -27,7 +27,6 @@ import com.google.common.collect.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.cassandra.auth.Auth;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.Table;
 import org.apache.cassandra.db.marshal.AbstractType;
@@ -67,7 +66,7 @@ public class Schema
 
     // 59adb24e-f3cd-3e02-97f0-5b395827453f
     public static final UUID emptyVersion;
-    public static final ImmutableSet<String> systemKeyspaceNames = 
ImmutableSet.of(Table.SYSTEM_KS, Tracing.TRACE_KS, Auth.AUTH_KS);
+    public static final ImmutableSet<String> systemKeyspaceNames = 
ImmutableSet.of(Table.SYSTEM_KS, Tracing.TRACE_KS);
 
     static
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/cql3/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java 
b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
index cbaf5d3..b612ceb 100644
--- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -143,12 +143,12 @@ public class QueryProcessor
         return processStatement(prepared, cl, queryState, 
Collections.<ByteBuffer>emptyList());
     }
 
-    public static UntypedResultSet process(String query) throws 
RequestExecutionException
+    public static UntypedResultSet process(String query, ConsistencyLevel cl) 
throws RequestExecutionException
     {
         try
         {
             QueryState state = new QueryState(new ClientState(true));
-            ResultMessage result = process(query, ConsistencyLevel.ONE, state);
+            ResultMessage result = process(query, cl, state);
             if (result instanceof ResultMessage.Rows)
                 return new 
UntypedResultSet(((ResultMessage.Rows)result).result);
             else

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/cql3/statements/ListUsersStatement.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/ListUsersStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/ListUsersStatement.java
index da6cb54..ebabf20 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ListUsersStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ListUsersStatement.java
@@ -42,7 +42,7 @@ public class ListUsersStatement extends 
AuthenticationStatement
     public ResultMessage execute(ClientState state) throws 
RequestValidationException, RequestExecutionException
     {
         return QueryProcessor.process(String.format("SELECT * FROM %s.%s", 
Auth.AUTH_KS, Auth.USERS_CF),
-                                      ConsistencyLevel.ONE,
+                                      ConsistencyLevel.QUORUM,
                                       new QueryState(new ClientState(true)));
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/service/CassandraDaemon.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/CassandraDaemon.java 
b/src/java/org/apache/cassandra/service/CassandraDaemon.java
index 605f94d..0a7b957 100644
--- a/src/java/org/apache/cassandra/service/CassandraDaemon.java
+++ b/src/java/org/apache/cassandra/service/CassandraDaemon.java
@@ -32,7 +32,6 @@ import org.apache.log4j.PropertyConfigurator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.cassandra.auth.Auth;
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.exceptions.ConfigurationException;
 import org.apache.cassandra.config.DatabaseDescriptor;
@@ -195,9 +194,6 @@ public class CassandraDaemon
             System.exit(100);
         }
 
-        // setup Authenticator and Authorizer.
-        Auth.setup();
-
         // clean up debris in the rest of the tables
         for (String table : Schema.instance.getTables())
         {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/service/ClientState.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/ClientState.java 
b/src/java/org/apache/cassandra/service/ClientState.java
index 110e134..48129e1 100644
--- a/src/java/org/apache/cassandra/service/ClientState.java
+++ b/src/java/org/apache/cassandra/service/ClientState.java
@@ -152,7 +152,7 @@ public class ClientState
         if (internalCall)
             return;
         validateLogin();
-        preventSystemKSSchemaModification(keyspace, perm);
+        preventSystemKSSchemaModification(keyspace, resource, perm);
         if (perm.equals(Permission.SELECT) && 
READABLE_SYSTEM_RESOURCES.contains(resource))
             return;
         if (PROTECTED_AUTH_RESOURCES.contains(resource))
@@ -173,10 +173,18 @@ public class ClientState
                                                       resource));
     }
 
-    private void preventSystemKSSchemaModification(String keyspace, Permission 
perm) throws UnauthorizedException
+    private void preventSystemKSSchemaModification(String keyspace, 
DataResource resource, Permission perm) throws UnauthorizedException
     {
-        if (Schema.systemKeyspaceNames.contains(keyspace.toLowerCase()) && 
!(perm.equals(Permission.SELECT) || perm.equals(Permission.MODIFY)))
+        // we only care about schema modification.
+        if (!(perm.equals(Permission.ALTER) || perm.equals(Permission.DROP) || 
perm.equals(Permission.CREATE)))
+            return;
+
+        if (Schema.systemKeyspaceNames.contains(keyspace.toLowerCase()))
             throw new UnauthorizedException(keyspace + " keyspace is not 
user-modifiable.");
+
+        // we want to allow altering AUTH_KS itself.
+        if (keyspace.equals(Auth.AUTH_KS) && !(resource.isKeyspaceLevel() && 
perm.equals(Permission.ALTER)))
+            throw new UnauthorizedException(String.format("Cannot %s %s", 
perm, resource));
     }
 
     public void validateLogin() throws UnauthorizedException

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/service/MigrationManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/MigrationManager.java 
b/src/java/org/apache/cassandra/service/MigrationManager.java
index d5d4c97..82d56e3 100644
--- a/src/java/org/apache/cassandra/service/MigrationManager.java
+++ b/src/java/org/apache/cassandra/service/MigrationManager.java
@@ -198,13 +198,18 @@ public class MigrationManager implements 
IEndpointStateChangeSubscriber
 
     public static void announceNewKeyspace(KSMetaData ksm) throws 
ConfigurationException
     {
+        announceNewKeyspace(ksm, FBUtilities.timestampMicros());
+    }
+
+    public static void announceNewKeyspace(KSMetaData ksm, long timestamp) 
throws ConfigurationException
+    {
         ksm.validate();
 
         if (Schema.instance.getTableDefinition(ksm.name) != null)
             throw new AlreadyExistsException(ksm.name);
 
         logger.info(String.format("Create new Keyspace: %s", ksm));
-        announce(ksm.toSchema(FBUtilities.timestampMicros()));
+        announce(ksm.toSchema(timestamp));
     }
 
     public static void announceNewColumnFamily(CFMetaData cfm) throws 
ConfigurationException

http://git-wip-us.apache.org/repos/asf/cassandra/blob/26596406/src/java/org/apache/cassandra/service/StorageService.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/StorageService.java 
b/src/java/org/apache/cassandra/service/StorageService.java
index 5f00c88..0f3a331 100644
--- a/src/java/org/apache/cassandra/service/StorageService.java
+++ b/src/java/org/apache/cassandra/service/StorageService.java
@@ -746,8 +746,7 @@ public class StorageService extends 
NotificationBroadcasterSupport implements IE
             logger.info("Startup completed! Now serving reads.");
             assert tokenMetadata.sortedTokens().size() > 0;
 
-            // setup default superuser (if needed).
-            Auth.setupSuperuser();
+            Auth.setup();
         }
         else
         {
@@ -786,8 +785,7 @@ public class StorageService extends 
NotificationBroadcasterSupport implements IE
             logger.info("Leaving write survey mode and joining ring at 
operator request");
             assert tokenMetadata.sortedTokens().size() > 0;
 
-            // setup default superuser (if needed).
-            Auth.setupSuperuser();
+            Auth.setup();
         }
     }
 
@@ -2308,7 +2306,7 @@ public class StorageService extends 
NotificationBroadcasterSupport implements IE
 
     public int forceRepairAsync(final String keyspace, final boolean 
isSequential, final boolean isLocal, final boolean primaryRange, final 
String... columnFamilies)
     {
-        if (Table.SYSTEM_KS.equals(keyspace) || 
Tracing.TRACE_KS.equals(keyspace) || Auth.AUTH_KS.equals(keyspace))
+        if (Table.SYSTEM_KS.equals(keyspace) || 
Tracing.TRACE_KS.equals(keyspace))
             return 0;
 
         final int cmd = nextRepairCommand.incrementAndGet();
@@ -2348,7 +2346,7 @@ public class StorageService extends 
NotificationBroadcasterSupport implements IE
 
     public void forceTableRepairRange(final String tableName, final 
Collection<Range<Token>> ranges, boolean isSequential, boolean  isLocal, final 
String... columnFamilies) throws IOException
     {
-        if (Table.SYSTEM_KS.equals(tableName) || 
Tracing.TRACE_KS.equals(tableName) || Auth.AUTH_KS.equals(tableName))
+        if (Table.SYSTEM_KS.equals(tableName) || 
Tracing.TRACE_KS.equals(tableName))
             return;
         createRepairTask(nextRepairCommand.incrementAndGet(), tableName, 
ranges, isSequential, isLocal, columnFamilies).run();
     }

Reply via email to