Skip to content

Commit

Permalink
Add lcb_AUTHENTICATOR interface
Browse files Browse the repository at this point in the history
This provides a shared authentication object allowing modification of
authentication information on the fly.

In the future we might want to include locking here for thread safety.
This isn't necessary yet.

Change-Id: I77f9b901ef466fe7227ceeb9b7326bec7b8a0c1f
Reviewed-on: http://review.couchbase.org/66467
Tested-by: buildbot <build@couchbase.com>
Reviewed-by: Sergey Avseyev <sergey.avseyev@gmail.com>
  • Loading branch information
mnunberg authored and Mark Nunberg committed Oct 24, 2016
1 parent 822615c commit cf5fb1d
Show file tree
Hide file tree
Showing 13 changed files with 254 additions and 97 deletions.
101 changes: 101 additions & 0 deletions include/libcouchbase/auth.h
@@ -0,0 +1,101 @@
#ifndef LCB_AUTH_H
#define LCB_AUTH_H

#ifdef __cplusplus
namespace lcb { class Authenticator; }
typedef lcb::Authenticator lcb_AUTHENTICATOR;
extern "C" {
#else /* C only! */
typedef struct lcb_AUTHENTICATOR_Cdummy lcb_AUTHENTICATOR;
#endif

/**
* @class lcb_AUTHENTICATOR
*
* The lcb_AUTHENTICATOR object allows greater flexibility with regard to
* adding more than a single bucket/password credential pair. It also restores
* the ability to use "true" usernames (though these are not used at present
* yet).
*/

/**
* @volatile
* Creates a new authenticator object. You may destroy it using lcbauth_unref().
* The returned object initially has a refcount of 1.
*
* @return A new authenticator object.
*/
LIBCOUCHBASE_API
lcb_AUTHENTICATOR *
lcbauth_new(void);

/**
* Flags to use when adding a new set of credentials to lcbauth_add_pass
*/
typedef enum {
/** User/Password is administrative; for cluster */
LCBAUTH_F_CLUSTER = 1<<1,

/** User is bucket name. Password is bucket password */
LCBAUTH_F_BUCKET = 1<<2
} lcbauth_ADDPASSFLAGS;

/**
* @volatile
*
* Add a set of credentials
* @param auth
* @param user the username (or bucketname, if LCBAUTH_F_BUCKET is passed)
* @param pass the password. If the password is NULL, the credential is removed
* @param flags one of @ref LCBAUTH_F_CLUSTER or @ref LCBAUTH_F_BUCKET.
*/
LIBCOUCHBASE_API
lcb_error_t
lcbauth_add_pass(lcb_AUTHENTICATOR *auth, const char *user, const char *pass, int flags);

/**
* @volatile
*
* Gets the global username and password. This is either the lone bucket
* password, or an explicit cluster password.
* @param auth
* @param[out] u Global username
* @param[out] p Global password
*/
void
lcbauth_get_upass(const lcb_AUTHENTICATOR *auth, const char **u, const char **p);


/**
* @private
*
* Get a user/bucket password
* @param auth the authenticator
* @param name the name of the bucket
* @return the password for the bucket, or NULL if the bucket has no password
* (or is unknown to the authenticator)
*/
const char *
lcbauth_get_bpass(const lcb_AUTHENTICATOR *auth, const char *name);

/**
* @uncomitted
* Increments the refcount on the authenticator object
* @param auth
*/
LIBCOUCHBASE_API
void
lcbauth_ref(lcb_AUTHENTICATOR *auth);

/**
* Decrements the refcount on the authenticator object
* @param auth
*/
LIBCOUCHBASE_API
void
lcbauth_unref(lcb_AUTHENTICATOR *auth);

#ifdef __cplusplus
}
#endif
#endif /* LCB_AUTH_H */
13 changes: 13 additions & 0 deletions include/libcouchbase/couchbase.h
Expand Up @@ -54,6 +54,7 @@ typedef struct lcb_http_request_st *lcb_http_request_t;
#include <libcouchbase/http.h>
#include <libcouchbase/configuration.h>
#include <libcouchbase/kvbuf.h>
#include <libcouchbase/auth.h>
#include <libcouchbase/_cxxwrap.h>

#ifdef __cplusplus
Expand Down Expand Up @@ -387,6 +388,18 @@ lcb_set_bootstrap_callback(lcb_t instance, lcb_bootstrap_callback callback);
LIBCOUCHBASE_API
lcb_error_t
lcb_get_bootstrap_status(lcb_t instance);

/**
* Sets the authenticator object for the instance. This may be done anytime, but
* should probably be done before calling `lcb_connect()` for best effect.
*
* @param instance the handle
* @param auth the authenticator object used. The library will increase the
* refcount on the authenticator object.
*/
LIBCOUCHBASE_API
void
lcb_set_auth(lcb_t instance, lcb_AUTHENTICATOR *auth);
/**@}*/


Expand Down
34 changes: 34 additions & 0 deletions src/auth-priv.h
@@ -0,0 +1,34 @@
#ifndef LCB_AUTH_PRIV_H
#define LCB_AUTH_PRIV_H
#include <libcouchbase/auth.h>

#ifdef __cplusplus
#include <string>
#include <map>

namespace lcb {
class Authenticator {
public:
typedef std::map<std::string,std::string> Map;
const std::string& username() const { return m_username; }
const std::string& password() const { return m_password; }
const Map& buckets() const { return m_buckets; }
Authenticator() : m_refcount(1) {}

size_t refcount() const { return m_refcount; }
void incref() { ++m_refcount; }
void decref() { if (!--m_refcount) { delete this; } }
lcb_error_t add(const char *user, const char *pass, int flags);
lcb_error_t init(const std::string& username_, const std::string& bucket,
const std::string& password, lcb_type_t conntype);

private:
// todo: refactor these out
Map m_buckets;
std::string m_username;
std::string m_password;
size_t m_refcount;
};
}
#endif
#endif /* LCB_AUTH_H */
81 changes: 53 additions & 28 deletions src/auth.cc
@@ -1,5 +1,5 @@
#include <libcouchbase/couchbase.h>
#include "auth.h"
#include "auth-priv.h"

using namespace lcb;

Expand All @@ -9,53 +9,78 @@ lcbauth_new()
return new Authenticator();
}

void
lcbauth_free(lcb_AUTHENTICATOR *auth)
{
delete auth;
}

const char *
lcbauth_get_bpass(const lcb_AUTHENTICATOR *auth, const char *u)
{
Authenticator::Map::const_iterator ii = auth->m_buckets.find(u);
if (ii == auth->m_buckets.end()) {
Authenticator::Map::const_iterator ii = auth->buckets().find(u);
if (ii == auth->buckets().end()) {
return NULL;
}
return ii->second.c_str();
}

lcb_error_t
lcbauth_add_pass(lcb_AUTHENTICATOR *auth, const char *u, const char *p, int flags)
{
return auth->add(u, p, flags);
}

lcb_error_t
Authenticator::add(const char *u, const char *p, int flags)
{
if (!flags) {
return LCB_EINVAL;
}

if (flags & LCBAUTH_F_CLUSTER) {
if (!p) {
m_username.clear();
m_password.clear();
} else {
m_username = u;
m_password = p;
}
}
if (flags & LCBAUTH_F_BUCKET) {
if (!p) {
m_buckets.erase(u);
} else {
m_buckets[u] = p;
}
}
return LCB_SUCCESS;
}

void
lcbauth_set(lcb_AUTHENTICATOR *auth, const char *u, const char *p,
int is_global)
lcbauth_get_upass(const lcb_AUTHENTICATOR *auth, const char **u, const char **p)
{
if (is_global) {
auth->m_username = u;
auth->m_password = p;
if (!auth->username().empty()) {
*u = auth->username().c_str();
*p = auth->password().empty() ? NULL : auth->password().c_str();

} else if (!auth->buckets().empty()) {
Authenticator::Map::const_iterator it = auth->buckets().begin();
*u = it->first.c_str();
if (!it->second.empty()) {
*p = it->second.c_str();
} else {
*p = NULL;
}
} else {
auth->m_buckets[u] = p;
*u = *p = NULL;
}
}

void
lcb_authenticator_clear(lcb_AUTHENTICATOR *auth)
lcbauth_ref(lcb_AUTHENTICATOR *auth)
{
auth->m_buckets.clear();
auth->incref();
}

void
lcbauth_get_upass(const lcb_AUTHENTICATOR *auth, const char **u, const char **p)
lcbauth_unref(lcb_AUTHENTICATOR *auth)
{
if (!auth->m_username.empty()) {
*u = auth->m_username.c_str();
} else {
*u = NULL;
}
if (!auth->m_password.empty()) {
*p = auth->m_password.c_str();
} else {
*p = NULL;
}
auth->decref();
}

lcb_error_t
Expand Down
54 changes: 0 additions & 54 deletions src/auth.h

This file was deleted.

6 changes: 3 additions & 3 deletions src/cntl.cc
Expand Up @@ -497,7 +497,7 @@ HANDLER(bucket_auth_handler) {
if (mode == LCB_CNTL_SET) {
/* Parse the bucket string... */
cred = (const lcb_BUCKETCRED *)arg;
lcbauth_set(instance->settings->auth, (*cred)[0], (*cred)[1], 0);
lcbauth_add_pass(instance->settings->auth, (*cred)[0], (*cred)[1], LCBAUTH_F_BUCKET);
(void)cmd; (void)arg;
} else if (mode == CNTL__MODE_SETSTRING) {
const char *ss = reinterpret_cast<const char *>(arg);
Expand All @@ -509,9 +509,9 @@ HANDLER(bucket_auth_handler) {
if (!root.isArray() || root.size() != 2) {
return LCB_ECTL_BADARG;
}
lcbauth_set(instance->settings->auth,
lcbauth_add_pass(instance->settings->auth,
root[0].asString().c_str(),
root[1].asString().c_str(), 0);
root[1].asString().c_str(), LCBAUTH_F_BUCKET);
} else {
return LCB_ECTL_UNSUPPMODE;
}
Expand Down
7 changes: 6 additions & 1 deletion src/http/http.cc
Expand Up @@ -433,7 +433,12 @@ Request::setup_inputs(const lcb_CMDHTTP *cmd)
if (cmd->cmdflags & LCB_CMDHTTP_F_NOUPASS) {
username = password = NULL;
} else if (username == NULL && password == NULL) {
lcbauth_get_upass(LCBT_SETTING(instance, auth), &username, &password);
if (reqtype == LCB_HTTP_TYPE_MANAGEMENT) {
lcbauth_get_upass(LCBT_SETTING(instance, auth), &username, &password);
} else {
username = LCBT_SETTING(instance, bucket);
password = lcbauth_get_bpass(LCBT_SETTING(instance, auth), username);
}
}

base = get_api_node(rc);
Expand Down
11 changes: 11 additions & 0 deletions src/instance.cc
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/
#include "internal.h"
#include "auth-priv.h"
#include "connspec.h"
#include "logging.h"
#include "hostlist.h"
Expand Down Expand Up @@ -51,6 +52,16 @@ const void *lcb_get_cookie(lcb_t instance)
return instance->cookie;
}

LIBCOUCHBASE_API
void
lcb_set_auth(lcb_t instance, lcb_AUTHENTICATOR *auth)
{
/* First increase refcount in case they are the same object(!) */
lcbauth_ref(auth);
lcbauth_unref(instance->settings->auth);
instance->settings->auth = auth;
}

void
lcb_st::add_bs_host(const char *host, int port, unsigned bstype)
{
Expand Down

0 comments on commit cf5fb1d

Please sign in to comment.