You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by al...@apache.org on 2013/05/26 04:40:54 UTC
git commit: Reuse prepared statements in hot auth queries
Updated Branches:
refs/heads/cassandra-1.2 234d4cfeb -> 1b5edee00
Reuse prepared statements in hot auth queries
patch by Aleksey Yeschenko; reviewed by Jonathan Ellis for
CASSANDRA-5594
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1b5edee0
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1b5edee0
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1b5edee0
Branch: refs/heads/cassandra-1.2
Commit: 1b5edee00faeb03ec4fc5dff779a031f7093241b
Parents: 234d4cf
Author: Aleksey Yeschenko <al...@apache.org>
Authored: Sun May 26 05:40:11 2013 +0300
Committer: Aleksey Yeschenko <al...@apache.org>
Committed: Sun May 26 05:40:11 2013 +0300
----------------------------------------------------------------------
CHANGES.txt | 1 +
src/java/org/apache/cassandra/auth/Auth.java | 62 +++++++++-----
.../apache/cassandra/auth/CassandraAuthorizer.java | 37 +++++++--
.../cassandra/auth/PasswordAuthenticator.java | 40 +++++++---
4 files changed, 100 insertions(+), 40 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5edee0/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index d3973b6..7b1970c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -7,6 +7,7 @@
* Improve batchlog replay behavior and hint ttl handling (CASSANDRA-5314)
* Exclude localTimestamp from validation for tombstones (CASSANDRA-5398)
* cqlsh: add custom prompt support (CASSANDRA-5539)
+ * Reuse prepared statements in hot auth queries (CASSANDRA-5594)
Merged from 1.1:
* Remove buggy thrift max message length option (CASSANDRA-5529)
* Fix NPE in Pig's widerow mode (CASSANDRA-5488)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5edee0/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 7ec5a33..c561aab 100644
--- a/src/java/org/apache/cassandra/auth/Auth.java
+++ b/src/java/org/apache/cassandra/auth/Auth.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.auth;
import java.util.concurrent.TimeUnit;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,12 +30,14 @@ 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.cql3.statements.SelectStatement;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.exceptions.RequestExecutionException;
+import org.apache.cassandra.exceptions.RequestValidationException;
import org.apache.cassandra.locator.SimpleStrategy;
-import org.apache.cassandra.service.IMigrationListener;
-import org.apache.cassandra.service.MigrationManager;
-import org.apache.cassandra.service.StorageService;
+import org.apache.cassandra.service.*;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FBUtilities;
public class Auth
@@ -57,6 +60,8 @@ public class Auth
USERS_CF,
90 * 24 * 60 * 60); // 3 months.
+ private static SelectStatement selectUserStatement;
+
/**
* Checks if the username is stored in AUTH_KS.USERS_CF.
*
@@ -65,15 +70,7 @@ public class Auth
*/
public static boolean isExistingUser(String username)
{
- String query = String.format("SELECT * FROM %s.%s WHERE name = '%s'", AUTH_KS, USERS_CF, escape(username));
- try
- {
- return !QueryProcessor.process(query, consistencyForUser(username)).isEmpty();
- }
- catch (RequestExecutionException e)
- {
- throw new RuntimeException(e);
- }
+ return !selectUser(username).isEmpty();
}
/**
@@ -84,16 +81,8 @@ public class Auth
*/
public static boolean isSuperuser(String username)
{
- String query = String.format("SELECT super FROM %s.%s WHERE name = '%s'", AUTH_KS, USERS_CF, escape(username));
- try
- {
- UntypedResultSet result = QueryProcessor.process(query, consistencyForUser(username));
- return !result.isEmpty() && result.one().getBoolean("super");
- }
- catch (RequestExecutionException e)
- {
- throw new RuntimeException(e);
- }
+ UntypedResultSet result = selectUser(username);
+ return !result.isEmpty() && result.one().getBoolean("super");
}
/**
@@ -157,6 +146,16 @@ public class Auth
SUPERUSER_SETUP_DELAY,
TimeUnit.MILLISECONDS);
}
+
+ try
+ {
+ String query = String.format("SELECT * FROM %s.%s WHERE name = ?", AUTH_KS, USERS_CF);
+ selectUserStatement = (SelectStatement) QueryProcessor.parseStatement(query).prepare().statement;
+ }
+ catch (RequestValidationException e)
+ {
+ throw new AssertionError(e); // not supposed to happen
+ }
}
// Only use QUORUM cl for the default superuser.
@@ -227,6 +226,25 @@ public class Auth
return StringUtils.replace(name, "'", "''");
}
+ private static UntypedResultSet selectUser(String username)
+ {
+ try
+ {
+ ResultMessage.Rows rows = selectUserStatement.execute(consistencyForUser(username),
+ new QueryState(new ClientState(true)),
+ Lists.newArrayList(ByteBufferUtil.bytes(username)));
+ return new UntypedResultSet(rows.result);
+ }
+ catch (RequestValidationException e)
+ {
+ throw new AssertionError(e); // not supposed to happen
+ }
+ catch (RequestExecutionException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* IMigrationListener implementation that cleans up permissions on dropped resources.
*/
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5edee0/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 0518734..396be71 100644
--- a/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
+++ b/src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
@@ -28,9 +28,14 @@ import org.slf4j.LoggerFactory;
import org.apache.cassandra.config.Schema;
import org.apache.cassandra.cql3.UntypedResultSet;
import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.cql3.statements.SelectStatement;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.exceptions.*;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.QueryState;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.utils.ByteBufferUtil;
/**
* CassandraAuthorizer is an IAuthorizer implementation that keeps
@@ -55,20 +60,26 @@ public class CassandraAuthorizer implements IAuthorizer
PERMISSIONS_CF,
90 * 24 * 60 * 60); // 3 months.
+ private SelectStatement authorizeStatement;
+
// Returns every permission on the resource granted to the user.
public Set<Permission> authorize(AuthenticatedUser user, IResource resource)
{
if (user.isSuper())
return Permission.ALL;
- UntypedResultSet rows;
+ UntypedResultSet result;
try
{
- rows = process(String.format("SELECT permissions FROM %s.%s WHERE username = '%s' AND resource = '%s'",
- Auth.AUTH_KS,
- PERMISSIONS_CF,
- escape(user.getName()),
- escape(resource.getName())));
+ ResultMessage.Rows rows = authorizeStatement.execute(ConsistencyLevel.ONE,
+ new QueryState(new ClientState(true)),
+ Lists.newArrayList(ByteBufferUtil.bytes(user.getName()),
+ ByteBufferUtil.bytes(resource.getName())));
+ result = new UntypedResultSet(rows.result);
+ }
+ catch (RequestValidationException e)
+ {
+ throw new AssertionError(e); // not supposed to happen
}
catch (RequestExecutionException e)
{
@@ -76,11 +87,11 @@ public class CassandraAuthorizer implements IAuthorizer
return Permission.NONE;
}
- if (rows.isEmpty() || !rows.one().has(PERMISSIONS))
+ if (result.isEmpty() || !result.one().has(PERMISSIONS))
return Permission.NONE;
Set<Permission> permissions = EnumSet.noneOf(Permission.class);
- for (String perm : rows.one().getSet(PERMISSIONS, UTF8Type.instance))
+ for (String perm : result.one().getSet(PERMISSIONS, UTF8Type.instance))
permissions.add(Permission.valueOf(perm));
return permissions;
}
@@ -239,6 +250,16 @@ public class CassandraAuthorizer implements IAuthorizer
throw new AssertionError(e);
}
}
+
+ try
+ {
+ String query = String.format("SELECT permissions FROM %s.%s WHERE username = ? AND resource = ?", Auth.AUTH_KS, PERMISSIONS_CF);
+ authorizeStatement = (SelectStatement) QueryProcessor.parseStatement(query).prepare().statement;
+ }
+ catch (RequestValidationException e)
+ {
+ throw new AssertionError(e); // not supposed to happen
+ }
}
// We only worry about one character ('). Make sure it's properly escaped.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5edee0/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 01adb1b..bcbdd29 100644
--- a/src/java/org/apache/cassandra/auth/PasswordAuthenticator.java
+++ b/src/java/org/apache/cassandra/auth/PasswordAuthenticator.java
@@ -22,6 +22,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,12 +31,14 @@ import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.Schema;
import org.apache.cassandra.cql3.UntypedResultSet;
import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.cql3.statements.SelectStatement;
import org.apache.cassandra.db.ConsistencyLevel;
-import org.apache.cassandra.exceptions.AuthenticationException;
-import org.apache.cassandra.exceptions.ConfigurationException;
-import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.exceptions.RequestExecutionException;
+import org.apache.cassandra.exceptions.*;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.QueryState;
import org.apache.cassandra.service.StorageService;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FBUtilities;
import org.mindrot.jbcrypt.BCrypt;
@@ -68,6 +71,8 @@ public class PasswordAuthenticator implements IAuthenticator
CREDENTIALS_CF,
90 * 24 * 60 * 60); // 3 months.
+ private SelectStatement authenticateStatement;
+
// No anonymous access.
public boolean requireAuthentication()
{
@@ -98,12 +103,14 @@ public class PasswordAuthenticator implements IAuthenticator
UntypedResultSet result;
try
{
- result = process(String.format("SELECT %s FROM %s.%s WHERE username = '%s'",
- SALTED_HASH,
- Auth.AUTH_KS,
- CREDENTIALS_CF,
- escape(username)),
- consistencyForUser(username));
+ ResultMessage.Rows rows = authenticateStatement.execute(consistencyForUser(username),
+ new QueryState(new ClientState(true)),
+ Lists.newArrayList(ByteBufferUtil.bytes(username)));
+ result = new UntypedResultSet(rows.result);
+ }
+ catch (RequestValidationException e)
+ {
+ throw new AssertionError(e); // not supposed to happen
}
catch (RequestExecutionException e)
{
@@ -174,6 +181,19 @@ public class PasswordAuthenticator implements IAuthenticator
Auth.SUPERUSER_SETUP_DELAY,
TimeUnit.MILLISECONDS);
}
+
+ try
+ {
+ String query = String.format("SELECT %s FROM %s.%s WHERE username = ?",
+ SALTED_HASH,
+ Auth.AUTH_KS,
+ CREDENTIALS_CF);
+ authenticateStatement = (SelectStatement) QueryProcessor.parseStatement(query).prepare().statement;
+ }
+ catch (RequestValidationException e)
+ {
+ throw new AssertionError(e); // not supposed to happen
+ }
}
private void setupCredentialsTable()