- RFC Name: [RBAC]
- RFC ID: [16]
- Start Date: [2017-02-10]
- Owner: [Mike Goldsmith]
- Current Status: [Accepted]
This RFC defines how the Couchbase client libraries are to authenticate and operate with a cluster that utilises the RBAC cluster authentication mechanism.
Couchbase Server has an advanced authentication mechanism where custom user profiles are created with a username and password and are assigned roles, such as Get, Insert and Delete, on one or more buckets. When a client makes a socket connection with the cluster it provides its assigned username and password which are verified by the cluster.
The RBAC authentication mechanism extends the Authenticator
API by adding a new PasswordAuthenticator
object type. Those credentials will be provided to the cluster in the same fashion as the current ClassicAuthenticator
but will be interpreted differently internally. The RBAC authenticator only contains a single username and password and will be used to authenticate all connections.
The following is an example implementation:
public class PasswordAuthenticator : IAuthenticator
{
public string Username { get; set; }
public string Password { get; set; }
}
The following is an example of creating and assign the new credentials:
var authenticator = new PasswordAuthenticator("mike", "secure123");
var cluster = new Cluster();
cluster.Authenticate(authenticator);
var bucket = cluster.OpenBucket("default");
Internally the process to authenticate a connection with RBAC credentials has changed where before previously a bucketname and optional password were used, RBAC requires a username and password. Also, before retrieving a bucket configuration an additional SelectBucket
operation must be executed which is used to verify the current user has access to that bucket. The SelectBucket
operation is not supported on pre-Spock clusters and will return an error. The client will need to do a feature check to see if the cluster expects a SelectBucket
operation to be executed.
A new cluster feature has been added that indicates if the cluster can support the enhanced authentication process. This should be checked for with the Hello operation and if the server responds with a positive result for that feature, you must then execute the SelectBucket
operation.
The SelectBucket
operation must be sent after authentication and before any bucket operation, such as GetClusterConfig
. The memcached documentation for using RBAC that describes the SelectBucket
operation usage (time of writing / latest).
The SelectBucket operation properties are below:
Property | Value |
---|---|
Operation Code | 0x89 |
Key | The bucket name to authenticate against. |
Extras | None |
Body | None |
The server responds with a basic result to indicate if the user has access or not, with a status of either Success (0x0000)
or AccessError (0x0024)
. On AccessError
, an Authentication
error should be returned as this indicates the RBAC credentials were not accepted by the cluster and should be treated a permanent Authorization error.
Note: The XERROR (0x07)
feature must be enabled in order to receive an EACCESS error. If the client does not send XERROR as part of the Hello operation when establishing a connection, the server will disconnect the connection. This behavior may change in the future, but is something client developers should be aware of.
KV operations utilise the TCP connection that was used to authenticate with so subsequent requests do not need to re-authenticate.
If a user performs an operation they is not authorized for, the server will respond with the error code EACCESS. See Client Error Messages for appropriate error message.
For each service that does not use an already authenticated TCP connection, the RBAC credentials will need to be passed using the Authorization header with the Basic scheme.
The value part of the header is to be a base64 encoded combination of the username and password, the format of the value is below:
{username}:{password}
The cluster and bucket managers provides credentials in the same manner as with the classic authenticator via form encoded values.
Currently, cluster level query retrieves the first bucket defined in the ClassicAuthenticator
bucket credentials array and submits the query to that bucket. The RBAC Authenticator does not define bucket credentials.
NOTE: Both .NET and Java require a bucket to be opened manually before a cluster level query can be submitted. This is because a bucket is used to construct and submit the query and this can be done using the cached bucket to send the query to the cluster.
RBAC credentials supersede the bucket name / password combinations used in the classic authenticator and because they are passed to the cluster in the same fashion if the cluster does not support RBAC, a normal authentication error will be returned.
Scenario | Error Message |
---|---|
Mixed Authentication After one type of authentication credentials has been provided, any other credentials (eg bucketname/password) types should return an error to indicate mixed authentication mechanisms are not support. The SDK maintains the credentials and will return an Authentication based error. For example, if cluster.OpenBucket("default", "password") is called after RBAC credentials have been provided. |
Unable to mix authentication types between RBAC and bucketname/password combinations. |
Each client is also expected to return consistent error messages for standard scenarios, such as invalid username and/or password. A list is managed on the following link Client Error Messages.
The username for a given user may be embedded as part of the connection string. This allows an authenticator to not provide the username and it will be used from the connection string instead. The username is inserted between the protocol and hostname/IP with the following format:
<protocol>://<username>@<hostname>
For example, if the following connection string was provided, the username "mike" would be used.
couchbase://[email protected]
With the introduction of username as a connection string parameter and other ways to provide the authentication credentials, it is important to record what the preference order should be. The following list is in ascending priority order with 1 having the highest priority:
- Programmatic, e.g. client receives directly from code
- Explicit configuration, e.g. if the client supports explicitly specifying username and/or password in configuration
- Connection string, as discussed above in Connection Strings
A new Authenticate
overload (where possible) should be added to the Cluster
interface that provides a easy means to store a username and password. This would internally create and store a PasswordAuthenticator
. An example is below:
cluster.Authenticate("username", "password");
Libcouchbase allows RBAC (and more generally cluster based auth) through a number of interfaces. The interface most closely mirrored in this RFC is the lcbauth
interface, which was initially implemented in 2.6.4, and will be updated in 2.7.4 (http://review.couchbase.org/75348).
More C-friendly ways exist to set these parameters, and do not involve creating new objects and having to call function accessors:
- For single bucket credentials, you may use the
username
field in the connection string, or theusername
field inlcb_create_st
. Password is as normal. - For multi-bucket credentials, you can use the
LCB_CNTL_BUCKET_CRED
setting to incrementally add morebucket:password
pairs (though this is not applicable to the RBAC model).
Using lcb_AUTHENTICATOR
(Authenticator cognate):
lcb_create_st params = { 0 };
params.version =3 ;
params.v.v3.connstr = "couchbase://localhost/bucketName";
lcb_create(instance, ¶ms);
lcbauth_new() // creates new authenticator
lcbauth_set_mode(auth, LCBAUTH_MODE_RBAC) // RBAC mode
lcbauth_add_pass(auth, "username", "password", LCBAUTH_F_CLUSTER);
lcb_set_auth(instance, auth);
lcbauth_unref(auth); // instance owns lone reference.
Without lcb_AUTHENTICATOR
:
lcb_create_st params = { 0 };
params.version = 3;
params.v.v3.connstr = "couchbase://localhost/bucketname";
params.v.v3.username = "username";
params.v.v3.passwd = "password";
lcb_create(instance, ¶ms);
- [2017-03-10] - Added Connection strings to support username
- [2017-03-14] - Support SelectBucket feature
- [2017-04-04] - Add info regarding disconnect for auth failure without XERROR enabled
- [2017-04-04] - Add link to expected client error messages
- [2017-04-27] - Add LibCouchbase implementation notes
- [2017-05-04] - Add Authenticate overload for username & password
- [2017-05-26] - Improved username priority wording
Language | Representative | Date |
---|---|---|
C | Mark Nunberg | 2017-05-17 |
Go | Brett Lawson | 2017-05-16 |
Java | Mark Nitschinger | 2017-05-16 |
.Net | Jeff Morris | 2017-05-16 |
NodeJS | Brett Lawson | 2017-05-16 |
PHP | Sergey Avseyev | 2017-05-10 |
Python | Mark Nunberg | 2017-05-16 |