From ec7a5f1040545905016feb18ee5e31224eae624c Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 7 Dec 2012 17:23:40 -0600 Subject: [PATCH 1/2] Cleanup from 5025, allow recovering nodes to pull immediately --- .../apache/cassandra/service/MigrationManager.java | 13 ++++++++++--- .../apache/cassandra/service/StorageService.java | 4 +--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/java/org/apache/cassandra/service/MigrationManager.java b/src/java/org/apache/cassandra/service/MigrationManager.java index 72a9a845e9..9a82517e7c 100644 --- a/src/java/org/apache/cassandra/service/MigrationManager.java +++ b/src/java/org/apache/cassandra/service/MigrationManager.java @@ -33,6 +33,9 @@ import java.util.Collection; import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +68,10 @@ public class MigrationManager implements IEndpointStateChangeSubscriber private static final int MIGRATION_REQUEST_RETRIES = 3; private static final ByteBuffer LAST_MIGRATION_KEY = ByteBufferUtil.bytes("Last Migration"); + private static final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + + public static final int MIGRATION_DELAY_IN_MS = 60000; + public void onJoin(InetAddress endpoint, EndpointState epState) {} @@ -106,9 +113,9 @@ public class MigrationManager implements IEndpointStateChangeSubscriber if (Schema.instance.getVersion().equals(theirVersion)) return; - if (Schema.emptyVersion.equals(Schema.instance.getVersion())) + if (Schema.emptyVersion.equals(Schema.instance.getVersion()) || runtimeMXBean.getUptime() < MIGRATION_DELAY_IN_MS) { - // If we think we may be bootstrapping, submit MigrationTask immediately + // If we think we may be bootstrapping or have recently started, submit MigrationTask immediately submitMigrationTask(endpoint); } else @@ -128,7 +135,7 @@ public class MigrationManager implements IEndpointStateChangeSubscriber submitMigrationTask(endpoint); } }; - StorageService.optionalTasks.schedule(runnable, 1, TimeUnit.MINUTES); + StorageService.optionalTasks.schedule(runnable, MIGRATION_DELAY_IN_MS, TimeUnit.MILLISECONDS); } } diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index d0412795f5..a948786ee3 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -546,8 +546,7 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe Gossiper.instance.start(SystemTable.incrementAndGetGeneration()); // needed for node-ring gathering. // gossip Schema.emptyVersion forcing immediate check for schema updates (see MigrationManager#maybeScheduleSchemaPull) - Schema.instance.updateVersion(); // Ensure we know our own actual Schema UUID in preparation for updates - MigrationManager.passiveAnnounce(Schema.emptyVersion); + Schema.instance.updateVersionAndAnnounce(); // Ensure we know our own actual Schema UUID in preparation for updates // add rpc listening info Gossiper.instance.addLocalApplicationState(ApplicationState.RPC_ADDRESS, valueFactory.rpcaddress(DatabaseDescriptor.getRpcAddress())); @@ -556,7 +555,6 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe MessagingService.instance().listen(FBUtilities.getLocalAddress()); LoadBroadcaster.instance.startBroadcasting(); - MigrationManager.passiveAnnounce(Schema.instance.getVersion()); Gossiper.instance.addLocalApplicationState(ApplicationState.RELEASE_VERSION, valueFactory.releaseVersion()); HintedHandOffManager.instance.start(); From bddfa9e120bdafc204bde97bb51de1f86bf9695b Mon Sep 17 00:00:00 2001 From: Aleksey Yeschenko Date: Sat, 8 Dec 2012 18:18:22 +0300 Subject: [PATCH 2/2] Update IAuthenticator to match the new IAuthorizer; patch by Aleksey Yeschenko, reviewed by Jonathan Ellis for CASSANDRA-5003 --- CHANGES.txt | 1 + NEWS.txt | 14 ++ doc/native_protocol.spec | 2 + .../conf/passwd.properties | 5 +- .../cassandra/auth/SimpleAuthenticator.java | 24 ++-- pylib/cqlshlib/cql3handling.py | 42 ++++-- .../cassandra/auth/AllowAllAuthenticator.java | 52 +++++-- .../cassandra/auth/AllowAllAuthorizer.java | 18 +-- src/java/org/apache/cassandra/auth/Auth.java | 131 ++++++++++++++++++ .../cassandra/auth/AuthenticatedUser.java | 38 +++-- .../apache/cassandra/auth/IAuthenticator.java | 96 +++++++++++-- .../apache/cassandra/auth/IAuthorizer.java | 18 +-- .../org/apache/cassandra/auth/IResource.java | 8 +- .../cassandra/auth/LegacyAuthenticator.java | 92 ++++++++++++ .../cassandra/auth/LegacyAuthorizer.java | 15 +- .../apache/cassandra/config/CFMetaData.java | 6 + .../cassandra/config/DatabaseDescriptor.java | 4 +- .../apache/cassandra/config/KSMetaData.java | 7 + .../org/apache/cassandra/config/Schema.java | 5 +- src/java/org/apache/cassandra/cql3/Cql.g | 88 ++++++++++-- .../apache/cassandra/cql3/QueryProcessor.java | 21 +++ .../apache/cassandra/cql3/UserOptions.java | 62 +++++++++ .../cql3/statements/AlterUserStatement.java | 86 ++++++++++++ .../statements/AuthenticationStatement.java | 57 ++++++++ .../statements/AuthorizationStatement.java | 10 +- .../cql3/statements/CreateUserStatement.java | 64 +++++++++ .../cql3/statements/DropUserStatement.java | 62 +++++++++ .../cql3/statements/GrantStatement.java | 7 +- .../statements/ListPermissionsStatement.java | 25 +++- .../cql3/statements/ListUsersStatement.java | 48 +++++++ .../PermissionAlteringStatement.java | 7 +- .../cql3/statements/RevokeStatement.java | 7 +- .../exceptions/AuthenticationException.java | 26 ++++ .../cassandra/exceptions/ExceptionCode.java | 2 + .../cassandra/service/CassandraDaemon.java | 8 +- .../apache/cassandra/service/ClientState.java | 64 ++++----- .../cassandra/thrift/CassandraServer.java | 9 +- .../cassandra/thrift/ThriftConversion.java | 5 + .../messages/CredentialsMessage.java | 3 +- .../transport/messages/ErrorMessage.java | 3 + .../transport/messages/StartupMessage.java | 6 +- 41 files changed, 1082 insertions(+), 166 deletions(-) create mode 100644 src/java/org/apache/cassandra/auth/Auth.java create mode 100644 src/java/org/apache/cassandra/auth/LegacyAuthenticator.java create mode 100644 src/java/org/apache/cassandra/cql3/UserOptions.java create mode 100644 src/java/org/apache/cassandra/cql3/statements/AlterUserStatement.java create mode 100644 src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java create mode 100644 src/java/org/apache/cassandra/cql3/statements/CreateUserStatement.java create mode 100644 src/java/org/apache/cassandra/cql3/statements/DropUserStatement.java create mode 100644 src/java/org/apache/cassandra/cql3/statements/ListUsersStatement.java create mode 100644 src/java/org/apache/cassandra/exceptions/AuthenticationException.java diff --git a/CHANGES.txt b/CHANGES.txt index 77a488cebc..48ebb87f50 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,7 @@ * Fix preparing updates with collections (CASSANDRA-5017) * Don't generate UUID based on other node address (CASSANDRA-5002) * Fix message when trying to alter a clustering key type (CASSANDRA-5012) + * Update IAuthenticator to match the new IAuthorizer (CASSANDRA-5003) Merged from 1.1 * Improve schema propagation performance (CASSANDRA-5025) * Fix for IndexHelper.IndexFor throws OOB Exception (CASSANDRA-5030) diff --git a/NEWS.txt b/NEWS.txt index bc361c5d18..b834923c76 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -14,6 +14,15 @@ by version X, but the inverse is not necessarily the case.) Upgrading --------- + - IAuthenticator interface has been updated to support dynamic + user creation, modification and removal. Users, even when stored + externally, now have to be explicitly created using + CREATE USER query first. AllowAllAuthenticator and SimpleAuthenticator + have been updated for the new interface, but you'll have to update + your old IAuthenticator implementations for 1.2. To ease this process, + a new abstract LegacyAuthenticator class has been added - subclass it + in your old IAuthenticator implementaion and everything should just work + (this only affects users who implemented custom authenticators). - IAuthority interface has been deprecated in favor of IAuthorizer. AllowAllAuthority and SimpleAuthority have been renamed to AllowAllAuthorizer and SimpleAuthorizer, respectively. In order to @@ -107,6 +116,11 @@ Features GRANT, REVOKE, LIST PERMISSIONS. A native implementation storing the permissions in Cassandra is being worked on and we expect to include it in 1.2.1 or 1.2.2. + - IAuthenticator interface has been updated to support dynamic user + creation, modification and removal via new CQL3 statements: + CREATE USER, ALTER USER, DROP USER, LIST USERS. A native implementation + that stores users in Cassandra itself is being worked on and is expected to + become part of 1.2.1 or 1.2.2. 1.1.5 diff --git a/doc/native_protocol.spec b/doc/native_protocol.spec index ab44b21065..7d0d07b009 100644 --- a/doc/native_protocol.spec +++ b/doc/native_protocol.spec @@ -550,6 +550,8 @@ Table of Contents 0x000A Protocol error: some client message triggered a protocol violation (for instance a QUERY message is sent before a STARTUP one has been sent) + 0x0100 Bad credentials: CREDENTIALS request failed because Cassandra + did not accept the provided credentials. 0x1000 Unavailable exception. The rest of the ERROR message body will be diff --git a/examples/simple_authentication/conf/passwd.properties b/examples/simple_authentication/conf/passwd.properties index 96a8ec93ae..3099ba6b94 100644 --- a/examples/simple_authentication/conf/passwd.properties +++ b/examples/simple_authentication/conf/passwd.properties @@ -17,7 +17,8 @@ # This is a sample password file for SimpleAuthenticator. The format of # this file is username=password. If -Dpasswd.mode=MD5 then the password # is represented as an md5 digest, otherwise it is cleartext (keep this -# in mind when setting file mode and ownership). +# in mind when setting file mode and ownership). 'cassandra' is the default +# superuser and can be removed later. +cassandra=cassandra jsmith=havebadpass -Elvis\ Presley=graceland4evar dilbert=nomoovertime diff --git a/examples/simple_authentication/src/org/apache/cassandra/auth/SimpleAuthenticator.java b/examples/simple_authentication/src/org/apache/cassandra/auth/SimpleAuthenticator.java index 357a465bbe..0248244e47 100644 --- a/examples/simple_authentication/src/org/apache/cassandra/auth/SimpleAuthenticator.java +++ b/examples/simple_authentication/src/org/apache/cassandra/auth/SimpleAuthenticator.java @@ -29,23 +29,21 @@ import java.security.MessageDigest; import java.util.Map; import java.util.Properties; +import org.apache.cassandra.exceptions.AuthenticationException; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.io.util.FileUtils; -import org.apache.cassandra.thrift.AuthenticationException; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.Hex; -public class SimpleAuthenticator implements IAuthenticator +public class SimpleAuthenticator extends LegacyAuthenticator { public final static String PASSWD_FILENAME_PROPERTY = "passwd.properties"; public final static String PMODE_PROPERTY = "passwd.mode"; - public static final String USERNAME_KEY = "username"; - public static final String PASSWORD_KEY = "password"; public enum PasswordMode { PLAIN, MD5, - }; + } public AuthenticatedUser defaultUser() { @@ -53,7 +51,7 @@ public class SimpleAuthenticator implements IAuthenticator return null; } - public AuthenticatedUser authenticate(Map credentials) throws AuthenticationException + public AuthenticatedUser authenticate(Map credentials) throws AuthenticationException { String pmode_plain = System.getProperty(PMODE_PROPERTY); PasswordMode mode = PasswordMode.PLAIN; @@ -78,19 +76,13 @@ public class SimpleAuthenticator implements IAuthenticator String pfilename = System.getProperty(PASSWD_FILENAME_PROPERTY); - String username = null; - CharSequence user = credentials.get(USERNAME_KEY); - if (user == null) + String username = credentials.get(USERNAME_KEY); + if (username == null) throw new AuthenticationException("Authentication request was missing the required key '" + USERNAME_KEY + "'"); - else - username = user.toString(); - String password = null; - CharSequence pass = credentials.get(PASSWORD_KEY); - if (pass == null) + String password = credentials.get(PASSWORD_KEY); + if (password == null) throw new AuthenticationException("Authentication request was missing the required key '" + PASSWORD_KEY + "'"); - else - password = pass.toString(); boolean authenticated = false; diff --git a/pylib/cqlshlib/cql3handling.py b/pylib/cqlshlib/cql3handling.py index cbb2700d91..3c24114bea 100644 --- a/pylib/cqlshlib/cql3handling.py +++ b/pylib/cqlshlib/cql3handling.py @@ -257,6 +257,7 @@ JUNK ::= /([ \t\r\f\v]+|(--|[/][/])[^\n\r]*([\n\r]|$)|[/][*].*?[*][/])/ ; | | | + | | ; @@ -277,10 +278,16 @@ JUNK ::= /([ \t\r\f\v]+|(--|[/][/])[^\n\r]*([\n\r]|$)|[/][*].*?[*][/])/ ; | ; - ::= | - | - | - ; + ::= + | + | + | + ; + + ::= + | + | + ; # timestamp is included here, since it's also a keyword ::= typename=( | | ) ; @@ -1239,6 +1246,27 @@ syntax_rules += r''' ; ''' +syntax_rules += r''' + ::= user=( | ) + ; + + ::= "CREATE" "USER" + ( "WITH" "PASSWORD" )? + ( "SUPERUSER" | "NOSUPERUSER" )? + ; + + ::= "ALTER" "USER" + ( "WITH" "PASSWORD" )? + ( "SUPERUSER" | "NOSUPERUSER" )? + ; + + ::= "DROP" "USER" + ; + + ::= "LIST" "USERS" + ; +''' + syntax_rules += r''' ::= "GRANT" "ON" "TO" ; @@ -1269,14 +1297,12 @@ syntax_rules += r''' | ( "KEYSPACE" ) | ( "TABLE"? ) ; - - ::= user=( | ) - ; ''' + @completer_for('username', 'user') def username_user_completer(ctxt, cass): - # TODO: implement user autocompletion + # TODO: implement user autocompletion for grant/revoke/list/drop user/alter user # with I could see a way to do this usefully, but I don't. I don't know # how any Authorities other than AllowAllAuthorizer work :/ return [Hint('')] diff --git a/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java b/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java index cd93dd0dd3..def6045013 100644 --- a/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java +++ b/src/java/org/apache/cassandra/auth/AllowAllAuthenticator.java @@ -17,31 +17,61 @@ */ package org.apache.cassandra.auth; +import java.util.Collections; import java.util.Map; +import java.util.Set; +import org.apache.cassandra.exceptions.AuthenticationException; import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.cassandra.thrift.AuthenticationException; +import org.apache.cassandra.exceptions.InvalidRequestException; public class AllowAllAuthenticator implements IAuthenticator { - private final static AuthenticatedUser DEFAULT_USER = new AuthenticatedUser("nobody"); - - public AuthenticatedUser defaultUser() + public boolean requireAuthentication() { - return DEFAULT_USER; + return false; } - public AuthenticatedUser authenticate(Map credentials) throws AuthenticationException + public Set