Prepare legacy auth statements if tables initialised after node startup

Patch by Alex Petrov; reviewed by Sam Tunnicliffe for CASSANDRA-12813


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

Branch: refs/heads/cassandra-3.X
Commit: 312e21bda7c50f05fc5f8868740b513022385951
Parents: eaf46a1
Author: Alex Petrov <oleksandr.pet...@gmail.com>
Authored: Fri Oct 21 16:58:33 2016 +0200
Committer: Sam Tunnicliffe <s...@beobal.com>
Committed: Fri Oct 28 16:04:36 2016 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../cassandra/auth/CassandraAuthorizer.java     | 14 +++++--
 .../cassandra/auth/PasswordAuthenticator.java   | 40 ++++++++++++++------
 3 files changed, 40 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/312e21bd/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index a22439b..b33ef8d 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 2.2.9
+ * Prepare legacy authenticate statement if credentials table initialised 
after node startup (CASSANDRA-12813)
  * Change cassandra.wait_for_tracing_events_timeout_secs default to 0 
(CASSANDRA-12754)
  * Clean up permissions when a UDA is dropped (CASSANDRA-12720)
  * Limit colUpdateTimeDelta histogram updates to reasonable deltas 
(CASSANDRA-11117)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/312e21bd/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java 
b/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
index 88069a2..360d59a 100644
--- a/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
+++ b/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
@@ -209,11 +209,19 @@ public class CassandraAuthorizer implements IAuthorizer
                                                              
Lists.newArrayList(ByteBufferUtil.bytes(role.getRoleName()),
                                                                                
 ByteBufferUtil.bytes(resource.getName())));
 
+        SelectStatement statement;
         // If it exists, read from the legacy user permissions table to handle 
the case where the cluster
         // is being upgraded and so is running with mixed versions of the 
authz schema
-        SelectStatement statement = 
Schema.instance.getCFMetaData(AuthKeyspace.NAME, USER_PERMISSIONS) == null
-                                    ? authorizeRoleStatement
-                                    : legacyAuthorizeRoleStatement;
+        if (Schema.instance.getCFMetaData(AuthKeyspace.NAME, USER_PERMISSIONS) 
== null)
+            statement = authorizeRoleStatement;
+        else
+        {
+            // If the permissions table was initialised only after the 
statement got prepared, re-prepare (CASSANDRA-12813)
+            if (legacyAuthorizeRoleStatement == null)
+                legacyAuthorizeRoleStatement = prepare(USERNAME, 
USER_PERMISSIONS);
+            statement = legacyAuthorizeRoleStatement;
+        }
+
         ResultMessage.Rows rows = 
statement.execute(QueryState.forInternalCalls(), options) ;
         UntypedResultSet result = UntypedResultSet.create(rows.result);
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/312e21bd/src/java/org/apache/cassandra/auth/PasswordAuthenticator.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/PasswordAuthenticator.java 
b/src/java/org/apache/cassandra/auth/PasswordAuthenticator.java
index c0d2283..20f8790 100644
--- a/src/java/org/apache/cassandra/auth/PasswordAuthenticator.java
+++ b/src/java/org/apache/cassandra/auth/PasswordAuthenticator.java
@@ -77,11 +77,7 @@ public class PasswordAuthenticator implements IAuthenticator
     {
         try
         {
-            // If the legacy users table exists try to verify credentials 
there. This is to handle the case
-            // where the cluster is being upgraded and so is running with 
mixed versions of the authn tables
-            SelectStatement authenticationStatement = 
Schema.instance.getCFMetaData(AuthKeyspace.NAME, LEGACY_CREDENTIALS_TABLE) == 
null
-                                                    ? authenticateStatement
-                                                    : 
legacyAuthenticateStatement;
+            SelectStatement authenticationStatement = 
authenticationStatement();
             return doAuthenticate(username, password, authenticationStatement);
         }
         catch (RequestExecutionException e)
@@ -91,6 +87,23 @@ public class PasswordAuthenticator implements IAuthenticator
         }
     }
 
+    /**
+     * If the legacy users table exists try to verify credentials there. This 
is to handle the case
+     * where the cluster is being upgraded and so is running with mixed 
versions of the authn tables
+     */
+    private SelectStatement authenticationStatement()
+    {
+        if (Schema.instance.getCFMetaData(AuthKeyspace.NAME, 
LEGACY_CREDENTIALS_TABLE) == null)
+            return authenticateStatement;
+        else
+        {
+            // If the credentials was initialised only after statement got 
prepared, re-prepare (CASSANDRA-12813).
+            if (legacyAuthenticateStatement == null)
+                prepareLegacyAuthenticateStatement();
+            return legacyAuthenticateStatement;
+        }
+    }
+
     public Set<DataResource> protectedResources()
     {
         // Also protected by CassandraRoleManager, but the duplication doesn't 
hurt and is more explicit
@@ -110,13 +123,16 @@ public class PasswordAuthenticator implements 
IAuthenticator
         authenticateStatement = prepare(query);
 
         if (Schema.instance.getCFMetaData(AuthKeyspace.NAME, 
LEGACY_CREDENTIALS_TABLE) != null)
-        {
-            query = String.format("SELECT %s from %s.%s WHERE username = ?",
-                                  SALTED_HASH,
-                                  AuthKeyspace.NAME,
-                                  LEGACY_CREDENTIALS_TABLE);
-            legacyAuthenticateStatement = prepare(query);
-        }
+            prepareLegacyAuthenticateStatement();
+    }
+
+    private void prepareLegacyAuthenticateStatement()
+    {
+        String query = String.format("SELECT %s from %s.%s WHERE username = ?",
+                                     SALTED_HASH,
+                                     AuthKeyspace.NAME,
+                                     LEGACY_CREDENTIALS_TABLE);
+        legacyAuthenticateStatement = prepare(query);
     }
 
     public AuthenticatedUser legacyAuthenticate(Map<String, String> 
credentials) throws AuthenticationException

Reply via email to