message(STATUS "${AIO_LIBS}")
endif(${WITH_AIO})
+option(WITH_OPENLDAP "OPENLDAP is here" ON)
+if(${WITH_OPENLDAP})
+find_package(OpenLdap REQUIRED)
+set(HAVE_OPENLDAP ${OPENLDAP_FOUND})
+message(STATUS "${OPENLDAP_LIBS}")
+endif(${WITH_OPENLDAP})
+
option(WITH_FUSE "Fuse is here" ON)
if(${WITH_FUSE})
find_package(fuse)
--- /dev/null
+# - Find OpenLDAP C Libraries
+#
+# OPENLDAP_PREFIX - where to find ldap.h and libraries
+# OPENLDAP_FOUND - True if found.
+
+set(OPENLDAP_INCLUDE_DIR "${OPENLDAP_PREFIX}/include")
+set(OPENLDAP_LIB_DIR "${OPENLDAP_PREFIX}/lib")
+
+find_path(OPENLDAP_INCLUDE_DIR ldap.h NO_DEFAULT_PATH PATHS
+ /usr/include
+ /opt/local/include
+ /usr/local/include
+ )
+
+find_library(LIBLDAP NAMES ldap)
+find_library(LIBLBER NAMES lber)
+
+if (OPENLDAP_INCLUDE_DIR AND LIBLDAP AND LIBLBER)
+ set(OPENLDAP_FOUND TRUE)
+else (OPENLDAP_INCLUDE_DIR AND LIBLDAP AND LIBLBER)
+ set(OPENLDAP_FOUND FALSE)
+endif (OPENLDAP_INCLUDE_DIR AND LIBLDAP AND LIBLBER)
+
+if (OPENLDAP_FOUND)
+ message(STATUS "Found ldap: ${OPENLDAP_INCLUDE_DIR}")
+else ()
+ message(STATUS "Failed to find ldap.h")
+ if (OPENLDAP_FIND_REQUIRED)
+ message(FATAL_ERROR "Missing required ldap.h")
+ endif ()
+endif ()
+
+set(OPENLDAP_LIBS ${LIBLDAP} ${LIBLBER})
+
+mark_as_advanced(
+ OPENLDAP_INCLUDE_DIR OPENLDAP_LIB_DIR OPENLDAP_LIBRARIES
+)
rgw/rgw_http_client.cc
rgw/rgw_json_enc.cc
rgw/rgw_keystone.cc
+ rgw/rgw_ldap.cc
rgw/rgw_loadgen.cc
rgw/rgw_log.cc
rgw/rgw_metadata.cc
cls_rgw_client cls_lock_client cls_refcount_client
cls_log_client cls_statelog_client cls_timeindex_client
cls_version_client cls_replica_log_client cls_user_client
- curl expat global fcgi resolv ssl crypto ${BLKID_LIBRARIES})
+ curl expat global fcgi resolv ssl crypto ${BLKID_LIBRARIES} ${OPENLDAP_LIBS}
+ ${ALLOC_LIBS})
install(TARGETS radosgw DESTINATION bin)
add_executable(radosgw-admin ${radosgw_admin_srcs})
OPTION(rgw_keystone_verify_ssl, OPT_BOOL, true) // should we try to verify keystone's ssl
OPTION(rgw_s3_auth_use_rados, OPT_BOOL, true) // should we try to use the internal credentials for s3?
OPTION(rgw_s3_auth_use_keystone, OPT_BOOL, false) // should we try to use keystone for s3?
+
+/* OpenLDAP-style LDAP parameter strings */
+/* rgw_ldap_uri space-separated list of LDAP servers in URI format */
+OPTION(rgw_ldap_uri, OPT_STR, "ldaps://<ldap.your.domain>")
+/* rgw_ldap_binddn LDAP entry RGW will bind with (user match) */
+OPTION(rgw_ldap_binddn, OPT_STR, "uid=admin,cn=users,dc=example,dc=com")
+/* rgw_ldap_searchdn LDAP search base (basedn) */
+OPTION(rgw_ldap_searchdn, OPT_STR, "cn=users,cn=accounts,dc=example,dc=com")
+/* rgw_ldap_memberattr LDAP attribute containing RGW user names */
+OPTION(rgw_ldap_memberattr, OPT_STR, "uid")
+/* rgw_ldap_secret file containing credentials for rgw_ldap_binddn */
+OPTION(rgw_ldap_secret, OPT_STR, "/etc/openldap/secret")
+/* rgw_s3_auth_use_ldap use LDAP for RGW auth? */
+OPTION(rgw_s3_auth_use_ldap, OPT_BOOL, false)
+
OPTION(rgw_admin_entry, OPT_STR, "admin") // entry point for which a url is considered an admin request
OPTION(rgw_enforce_swift_acls, OPT_BOOL, true)
OPTION(rgw_swift_token_expiration, OPT_INT, 24 * 3600) // time in seconds for swift token expiration
rgw/rgw_http_client.cc \
rgw/rgw_json_enc.cc \
rgw/rgw_keystone.cc \
+ rgw/rgw_ldap.cc \
rgw/rgw_loadgen.cc \
rgw/rgw_log.cc \
rgw/rgw_metadata.cc \
if (r)
return -EIO;
+ const string& ldap_uri = store->ctx()->_conf->rgw_ldap_uri;
+ const string& ldap_binddn = store->ctx()->_conf->rgw_ldap_binddn;
+ const string& ldap_searchdn = store->ctx()->_conf->rgw_ldap_searchdn;
+ const string& ldap_memberattr =
+ store->ctx()->_conf->rgw_ldap_memberattr;
+
+ ldh = new rgw::LDAPHelper(ldap_uri, ldap_binddn, ldap_searchdn,
+ ldap_memberattr);
+ ldh->init();
+ ldh->bind();
+
rgw_user_init(store);
rgw_bucket_init(store->meta_mgr);
rgw_log_usage_init(g_ceph_context, store);
#include "rgw_common.h"
#include "rgw_user.h"
#include "rgw_lib.h"
+#include "rgw_ldap.h"
+#include "rgw_token.h"
+
/* XXX
* ASSERT_H somehow not defined after all the above (which bring
return -EINVAL;
if (user.suspended)
return -ERR_USER_SUSPENDED;
+ } else {
+ /* try external authenticators (ldap for now) */
+ rgw::LDAPHelper* ldh = rgwlib.get_ldh();
+ RGWToken token{from_base64(key.id)};
+ if (ldh->auth(token.id, token.key) == 0) {
+ /* try to store user if it doesn't already exist */
+ if (rgw_get_user_info_by_uid(store, token.id, user) < 0) {
+ int ret = rgw_store_user_info(store, user, NULL, NULL, 0,
+ true);
+ if (ret < 0) {
+ dout(10) << "NOTICE: failed to store new user's info: ret=" << ret
+ << dendl;
+ }
+ }
+ } /* auth success */
}
return ret;
- }
+ } /* authorize */
/* find or create an RGWFileHandle */
LookupFHResult lookup_fh(RGWFileHandle* parent, const char *name,
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "rgw_ldap.h"
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef RGW_LDAP_H
+#define RGW_LDAP_H
+
+#define LDAP_DEPRECATED 1
+#include "ldap.h"
+
+#include <stdint.h>
+#include <tuple>
+#include <vector>
+#include <string>
+#include <iostream>
+
+namespace rgw {
+
+ class LDAPHelper
+ {
+ std::string uri;
+ std::string binddn;
+ std::string searchdn;
+ std::string memberattr;
+ LDAP *ldap, *tldap;
+
+ public:
+ LDAPHelper(std::string _uri, std::string _binddn, std::string _searchdn,
+ std::string _memberattr)
+ : uri(std::move(_uri)), binddn(std::move(_binddn)), searchdn(_searchdn),
+ memberattr(_memberattr), ldap(nullptr) {
+ // nothing
+ }
+
+ int init() {
+ int ret;
+ ret = ldap_initialize(&ldap, uri.c_str());
+ return ret;
+ }
+
+ int bind() {
+ return ldap_simple_bind_s(ldap, nullptr, nullptr);
+ }
+
+ int simple_bind(const char *dn, const std::string& pwd) {
+ int ret = ldap_initialize(&tldap, uri.c_str());
+ ret = ldap_simple_bind_s(tldap, dn, pwd.c_str());
+ if (ret == LDAP_SUCCESS) {
+ ldap_unbind(tldap);
+ return 0;
+ }
+ return -1;
+ }
+
+ int auth(const std::string uid, const std::string pwd) {
+ int ret;
+ std::string filter;
+ filter = "(";
+ filter += memberattr;
+ filter += "=";
+ filter += uid;
+ filter += ")";
+ char *attrs[] = { const_cast<char*>(memberattr.c_str()), nullptr };
+ LDAPMessage *answer, *entry;
+ ret = ldap_search_s(ldap, searchdn.c_str(), LDAP_SCOPE_SUBTREE,
+ filter.c_str(), attrs, 0, &answer);
+ if (ret == LDAP_SUCCESS) {
+ entry = ldap_first_entry(ldap, answer);
+ char *dn = ldap_get_dn(ldap, entry);
+ //std::cout << dn << std::endl;
+ ret = simple_bind(dn, pwd);
+ ldap_memfree(dn);
+ ldap_msgfree(answer);
+ }
+ return ret;
+ }
+
+ ~LDAPHelper() {
+ if (ldap)
+ ldap_unbind(ldap);
+ }
+
+ };
+
+} /* namespace rgw */
+
+#endif /* RGW_LDAP_H */
#include "rgw_frontend.h"
#include "rgw_process.h"
#include "rgw_rest_s3.h" // RGW_Auth_S3
+#include "rgw_ldap.h"
+#include "include/assert.h"
class OpsLogSocket;
RGWFrontendConfig* fec;
RGWLibFrontend* fe;
OpsLogSocket* olog;
+ rgw::LDAPHelper* ldh;
RGWREST rest; // XXX needed for RGWProcessEnv
RGWProcessEnv env;
RGWRados* store;
RGWLibFrontend* get_fe() { return fe; }
+ rgw::LDAPHelper* get_ldh() { return ldh; }
+
int init();
int init(vector<const char *>& args);
int stop();
#include "rgw_cors_s3.h"
#include "rgw_rest_conn.h"
#include "rgw_rest_s3.h"
-
#include "rgw_client_io.h"
+#include "include/assert.h"
+
#define dout_subsys ceph_subsys_rgw
using namespace std;
#include "rgw_op.h"
#include "rgw_rest.h"
+#include "include/assert.h"
+
#include "common/WorkQueue.h"
#include "common/Throttle.h"
#include "rgw_rest_config.h"
#include "rgw_client_io.h"
#include "common/errno.h"
+#include "include/assert.h"
#define dout_subsys ceph_subsys_rgw
#include "rgw_rest_log.h"
#include "rgw_client_io.h"
#include "common/errno.h"
+#include "include/assert.h"
#define LOG_CLASS_LIST_MAX_ENTRIES (1000)
#define dout_subsys ceph_subsys_rgw
#include "rgw_client_io.h"
#include "common/errno.h"
#include "common/strtol.h"
+#include "include/assert.h"
#define dout_subsys ceph_subsys_rgw
#include "rgw_rest_opstate.h"
#include "rgw_client_io.h"
#include "common/errno.h"
+#include "include/assert.h"
#define OPSTATE_LIST_MAX_ENTRIES 1000
#define dout_subsys ceph_subsys_rgw
#include "rgw_rest_s3.h"
#include "rgw_rest_config.h"
+#include "include/assert.h"
+
#define dout_subsys ceph_subsys_rgw
// reject 'period push' if we would have to fetch too many intermediate periods
#include "rgw_rest_replica_log.h"
#include "rgw_client_io.h"
#include "common/errno.h"
+#include "include/assert.h"
#define dout_subsys ceph_subsys_rgw
#define REPLICA_INPUT_MAX_LEN (512*1024)
#include <typeinfo> // for 'typeid'
+#include "rgw_ldap.h"
+#include "rgw_token.h"
+#include "include/assert.h"
+
#define dout_subsys ceph_subsys_rgw
+using namespace rgw;
using namespace ceph::crypto;
+using std::get;
+
void list_all_buckets_start(struct req_state *s)
{
s->formatter->open_array_section_in_ns("ListAllMyBucketsResult",
op_ret = rgw_get_user_info_by_access_key(store, s3_access_key, user_info);
if (op_ret < 0) {
- // Try keystone authentication as well
- int keystone_result = -EINVAL;
- if (!store->ctx()->_conf->rgw_s3_auth_use_keystone ||
- store->ctx()->_conf->rgw_keystone_url.empty()) {
- return -EACCES;
- }
- dout(20) << "s3 keystone: trying keystone auth" << dendl;
-
- RGW_Auth_S3_Keystone_ValidateToken keystone_validator(store->ctx());
- keystone_result =
- keystone_validator.validate_s3token(s3_access_key,
- string(encoded_policy.c_str(),
- encoded_policy.length()),
- received_signature_str);
+ // try external authenticators
+ if (store->ctx()->_conf->rgw_s3_auth_use_keystone &&
+ store->ctx()->_conf->rgw_keystone_url.empty())
+ {
+ // keystone
+ int external_auth_result = -EINVAL;
+ dout(20) << "s3 keystone: trying keystone auth" << dendl;
+
+ RGW_Auth_S3_Keystone_ValidateToken keystone_validator(store->ctx());
+ external_auth_result =
+ keystone_validator.validate_s3token(s3_access_key,
+ string(encoded_policy.c_str(),
+ encoded_policy.length()),
+ received_signature_str);
+
+ if (external_auth_result < 0) {
+ ldout(s->cct, 0) << "User lookup failed!" << dendl;
+ err_msg = "Bad access key / signature";
+ return -EACCES;
+ }
- if (keystone_result < 0) {
- ldout(s->cct, 0) << "User lookup failed!" << dendl;
- err_msg = "Bad access key / signature";
- return -EACCES;
- }
+ string project_id = keystone_validator.response.get_project_id();
+ rgw_user uid(project_id);
- string project_id = keystone_validator.response.get_project_id();
- user_info.user_id = project_id;
- user_info.display_name = keystone_validator.response.get_project_name();
+ user_info.user_id = project_id;
+ user_info.display_name = keystone_validator.response.get_project_name();
- rgw_user uid(project_id);
- /* try to store user if it not already exists */
- if (rgw_get_user_info_by_uid(store, uid, user_info) < 0) {
- int ret = rgw_store_user_info(store, user_info, NULL, NULL, 0, true);
- if (ret < 0) {
- dout(10) << "NOTICE: failed to store new user's info: ret="
- << ret << dendl;
- }
- s->perm_mask = RGW_PERM_FULL_CONTROL;
+ /* try to store user if it not already exists */
+ if (rgw_get_user_info_by_uid(store, uid, user_info) < 0) {
+ int ret = rgw_store_user_info(store, user_info, NULL, NULL, 0, true);
+ if (ret < 0) {
+ dout(10) << "NOTICE: failed to store new user's info: ret="
+ << ret << dendl;
+ }
+ s->perm_mask = RGW_PERM_FULL_CONTROL;
+ }
+ } else if (store->ctx()->_conf->rgw_s3_auth_use_ldap &&
+ store->ctx()->_conf->rgw_ldap_uri.empty()) {
+ RGWToken token{from_base64(s3_access_key)};
+ rgw::LDAPHelper *ldh = RGW_Auth_S3::get_ldap_ctx(store);
+ if (ldh->auth(token.id, token.key) != 0)
+ return -EACCES;
+
+ /* ok, succeeded, try to create shadow */
+ user_info.user_id = token.id;
+ user_info.display_name = token.id; // cn?
+
+ /* try to store user if it not already exists */
+ if (rgw_get_user_info_by_uid(store, user_info.user_id,
+ user_info) < 0) {
+ int ret = rgw_store_user_info(store, user_info, NULL, NULL, 0, true);
+ if (ret < 0) {
+ dout(10) << "NOTICE: failed to store new user's info: ret=" << ret
+ << dendl;
+ }
+ s->perm_mask = RGW_PERM_FULL_CONTROL;
+ }
+ } else {
+ return -EACCES;
}
} else {
map<string, RGWAccessKey> access_keys = user_info.access_keys;
return RGWHandler_REST::init(store, s, cio);
}
+/* RGW_Auth_S3 static members */
+std::mutex RGW_Auth_S3::mtx;
+rgw::LDAPHelper* RGW_Auth_S3::ldh;
+
+/* static */
+void RGW_Auth_S3::init_impl(RGWRados* store)
+{
+ const string& ldap_uri = store->ctx()->_conf->rgw_ldap_uri;
+ const string& ldap_binddn = store->ctx()->_conf->rgw_ldap_binddn;
+ const string& ldap_searchdn = store->ctx()->_conf->rgw_ldap_searchdn;
+ const string& ldap_memberattr =
+ store->ctx()->_conf->rgw_ldap_memberattr;
+
+ ldh = new rgw::LDAPHelper(ldap_uri, ldap_binddn, ldap_searchdn,
+ ldap_memberattr);
+
+ ldh->init();
+ ldh->bind();
+}
+
/*
* Try to validate S3 auth against keystone s3token interface
*/
{
/* neither keystone and rados enabled; warn and exit! */
- if (!store->ctx()->_conf->rgw_s3_auth_use_rados
- && !store->ctx()->_conf->rgw_s3_auth_use_keystone) {
+ if (!store->ctx()->_conf->rgw_s3_auth_use_rados &&
+ !store->ctx()->_conf->rgw_s3_auth_use_keystone &&
+ !store->ctx()->_conf->rgw_s3_auth_use_ldap) {
dout(0) << "WARNING: no authorization backend enabled! Users will never authenticate." << dendl;
return -EPERM;
}
}
/* try keystone auth first */
- int keystone_result = -ERR_INVALID_ACCESS_KEY;;
+ int external_auth_result = -ERR_INVALID_ACCESS_KEY;;
if (store->ctx()->_conf->rgw_s3_auth_use_keystone
&& !store->ctx()->_conf->rgw_keystone_url.empty()) {
dout(20) << "s3 keystone: trying keystone auth" << dendl;
if (!rgw_create_s3_canonical_header(s->info,
&s->header_time, token, qsr)) {
dout(10) << "failed to create auth header\n" << token << dendl;
- keystone_result = -EPERM;
+ external_auth_result = -EPERM;
} else {
- keystone_result = keystone_validator.validate_s3token(auth_id, token,
+ external_auth_result = keystone_validator.validate_s3token(auth_id, token,
auth_sign);
- if (keystone_result == 0) {
+ if (external_auth_result == 0) {
// Check for time skew first
time_t req_sec = s->header_time.sec();
}
}
- if (keystone_result < 0) {
- if (!store->ctx()->_conf->rgw_s3_auth_use_rados) {
- /* No other auth option possible. Terminate request. */
- return keystone_result;
- }
+ if ((external_auth_result < 0) &&
+ (store->ctx()->_conf->rgw_s3_auth_use_ldap) &&
+ (! store->ctx()->_conf->rgw_ldap_uri.empty())) {
+
+ RGW_Auth_S3::init(store);
+
+ RGWToken token{from_base64(auth_id)};
+ if (ldh->auth(token.id, token.key) != 0)
+ external_auth_result = -EACCES;
+ else {
+ /* ok, succeeded */
+ external_auth_result = 0;
+ /* create local account, if none exists */
+ s->user->user_id = token.id;
+ s->user->display_name = token.id; // cn?
+ if (rgw_get_user_info_by_uid(store, s->user->user_id,
+ *(s->user)) < 0) {
+ int ret = rgw_store_user_info(store, *(s->user), NULL, NULL, 0, true);
+ if (ret < 0) {
+ dout(10) << "NOTICE: failed to store new user's info: ret=" << ret
+ << dendl;
+ }
+ s->perm_mask = RGW_PERM_FULL_CONTROL;
+ }
+ } /* success */
+ } /* ldap */
+
+ /* keystone failed (or not enabled); check if we want to use rados backend */
+ if (!store->ctx()->_conf->rgw_s3_auth_use_rados
+ && external_auth_result < 0)
+ return external_auth_result;
+ /* now try rados backend, but only if keystone did not succeed */
+ if (external_auth_result < 0) {
/* get the user info */
if (rgw_get_user_info_by_access_key(store, auth_id, *(s->user)) < 0) {
dout(5) << "error reading user info, uid=" << auth_id
<< " can't authenticate" << dendl;
- return keystone_result;
+ return external_auth_result;
}
/* now verify signature */
}
}
- } /* if keystone_result < 0 */
+ } /* if external_auth_result < 0 */
// populate the owner info
s->owner.set_id(s->user->user_id);
#define CEPH_RGW_REST_S3_H
#define TIME_BUF_SIZE 128
+#include <mutex>
+
#include "rgw_op.h"
#include "rgw_http_errors.h"
#include "rgw_acl_s3.h"
#include "rgw_policy_s3.h"
#include "rgw_keystone.h"
#include "rgw_rest_conn.h"
+#include "rgw_ldap.h"
#define RGW_AUTH_GRACE_MINS 15
};
class RGW_Auth_S3 {
-public:
- static int authorize(RGWRados *store, struct req_state *s);
- static int authorize_aws4_auth_complete(RGWRados *store, struct req_state *s);
private:
+ static std::mutex mtx;
+ static rgw::LDAPHelper* ldh;
+
static int authorize_v2(RGWRados *store, struct req_state *s);
static int authorize_v4(RGWRados *store, struct req_state *s);
static int authorize_v4_complete(RGWRados *store, struct req_state *s,
- const string& request_payload, bool unsigned_payload);
+ const string& request_payload,
+ bool unsigned_payload);
+public:
+ static int authorize(RGWRados *store, struct req_state *s);
+ static int authorize_aws4_auth_complete(RGWRados *store, struct req_state *s);
+
+ static inline void init(RGWRados* store) {
+ if (! ldh) {
+ std::lock_guard<std::mutex> lck(mtx);
+ if (! ldh) {
+ init_impl(store);
+ }
+ }
+ }
+
+ static inline rgw::LDAPHelper* get_ldap_ctx(RGWRados* store) {
+ init(store);
+ return ldh;
+ }
+ static void init_impl(RGWRados* store);
};
class RGWHandler_Auth_S3 : public RGWHandler_REST {
#include "rgw_rest_user.h"
#include "include/str_list.h"
+#include "include/assert.h"
#define dout_subsys ceph_subsys_rgw
)
endif(${HAVE_LIBFUSE})
+# librgw_file_gp (just the rgw_file get-put bucket ops)
+add_executable(test_rgw_ldap
+ ../rgw/rgw_ldap.cc
+ test_rgw_ldap.cc
+ $<TARGET_OBJECTS:heap_profiler_objs>
+ )
+set_target_properties(test_rgw_ldap PROPERTIES COMPILE_FLAGS
+ ${UNITTEST_CXX_FLAGS})
+target_link_libraries(test_rgw_ldap
+ librados
+ ${OPENLDAP_LIBS}
+ ${Boost_LIBRARIES}
+ ${ALLOC_LIBS}
+ ${UNITTEST_LIBS}
+ )
+
if(${WITH_CEPHFS})
add_executable(test_c_headers
test_c_headers.c
librgw.la $(PTHREAD_LIBS) $(LIBOS) $(CEPH_GLOBAL) $(EXTRALIBS)
bin_DEBUGPROGRAMS += test_rgw_token
+test_rgw_ldap_SOURCES = ../rgw/rgw_ldap.cc test/test_rgw_ldap.cc
+test_rgw_ldap_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+test_rgw_ldap_LDADD = $(UNITTEST_LDADD) \
+ librados.la $(PTHREAD_LIBS) $(LIBOS) $(CEPH_GLOBAL) ${OPENLDAP_LIBS}
+ $(EXTRALIBS)
+bin_DEBUGPROGRAMS += test_rgw_token
+
endif # WITH_RADOSGW
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2015 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include <stdint.h>
+#include <tuple>
+#include <iostream>
+#include <vector>
+#include <map>
+#include <random>
+
+#include "rgw/rgw_ldap.h"
+#include "rgw/rgw_token.h"
+
+#include "gtest/gtest.h"
+#include "common/ceph_argparse.h"
+#include "common/debug.h"
+#include "global/global_init.h"
+
+#define dout_subsys ceph_subsys_rgw
+
+namespace {
+
+ struct {
+ int argc;
+ char **argv;
+ } saved_args;
+
+ bool do_hexdump = false;
+
+ string access_key("ewogICAgIlJHV19UT0tFTiI6IHsKICAgICAgICAidmVyc2lvbiI6IDEsCiAgICAgICAgInR5cGUiOiAibGRhcCIsCiAgICAgICAgImlkIjogImFkbWluIiwKICAgICAgICAia2V5IjogImxpbnV4Ym94IgogICAgfQp9Cg=="); // {admin,linuxbox}
+ string other_key("ewogICAgIlJHV19UT0tFTiI6IHsKICAgICAgICAidmVyc2lvbiI6IDEsCiAgICAgICAgInR5cGUiOiAibGRhcCIsCiAgICAgICAgImlkIjogImFkbWluIiwKICAgICAgICAia2V5IjogImJhZHBhc3MiCiAgICB9Cn0K"); // {admin,badpass}
+
+ string ldap_uri = "ldaps://f23-kdc.rgw.com";
+ string ldap_binddn = "uid=admin,cn=users,cn=accounts,dc=rgw,dc=com";
+ string ldap_searchdn = "cn=users,cn=accounts,dc=rgw,dc=com";
+ string ldap_memberattr = "uid";
+
+ rgw::LDAPHelper ldh(ldap_uri, ldap_binddn, ldap_searchdn, ldap_memberattr);
+
+} /* namespace */
+
+TEST(RGW_LDAP, INIT) {
+ int ret = ldh.init();
+ ASSERT_EQ(ret, 0);
+}
+
+TEST(RGW_LDAP, BIND) {
+ int ret = ldh.bind();
+ ASSERT_EQ(ret, 0);
+}
+
+TEST(RGW_LDAP, AUTH) {
+ using std::get;
+ using namespace rgw;
+ int ret = 0;
+ {
+ RGWToken token{from_base64(access_key)};
+ ret = ldh.auth(token.id, token.key);
+ ASSERT_EQ(ret, 0);
+ }
+ {
+ RGWToken token{from_base64(other_key)};
+ ret = ldh.auth(token.id, token.key);
+ ASSERT_NE(ret, 0);
+ }
+}
+
+TEST(RGW_LDAP, SHUTDOWN) {
+ // nothing
+}
+
+int main(int argc, char *argv[])
+{
+ string val;
+ vector<const char*> args;
+
+ argv_to_vec(argc, const_cast<const char**>(argv), args);
+ env_to_vec(args);
+
+ for (auto arg_iter = args.begin(); arg_iter != args.end();) {
+ if (ceph_argparse_witharg(args, arg_iter, &val, "--access",
+ (char*) nullptr)) {
+ access_key = val;
+ } else if (ceph_argparse_flag(args, arg_iter, "--hexdump",
+ (char*) nullptr)) {
+ do_hexdump = true;
+ } else {
+ ++arg_iter;
+ }
+ }
+
+ /* dont accidentally run as anonymous */
+ if (access_key == "") {
+ std::cout << argv[0] << " no AWS credentials, exiting" << std::endl;
+ return EPERM;
+ }
+
+ saved_args.argc = argc;
+ saved_args.argv = argv;
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}