Skip to content

Commit

Permalink
rgw: Rework of s3 LDAP Authentication code.
Browse files Browse the repository at this point in the history
The LDAP authentication code has been reworked based
on the new authentication infrastructure.

Signed-off-by: Pritha Srivastava <prsrivas@redhat.com>
  • Loading branch information
pritha-srivastava committed Jul 19, 2016
1 parent f8ecf53 commit 1d18215
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 46 deletions.
5 changes: 5 additions & 0 deletions src/rgw/rgw_auth.cc
Expand Up @@ -149,6 +149,11 @@ void RGWRemoteAuthApplier::create_account(const rgw_user& acct_user,
{
rgw_user new_acct_user = acct_user;

if (!info.acct_type.empty()) {
//ldap/keystone for s3 users
user_info.type = info.acct_type;
}

/* Administrator may enforce creating new accounts within their own tenants.
* The config parameter name is kept due to legacy. */
if (new_acct_user.tenant.empty() && g_conf->rgw_keystone_implicit_tenants) {
Expand Down
7 changes: 5 additions & 2 deletions src/rgw/rgw_auth.h
Expand Up @@ -117,16 +117,19 @@ class RGWRemoteAuthApplier : public RGWAuthApplier {
const std::string acct_name;
const uint32_t perm_mask;
const bool is_admin;
const std::string acct_type;

public:
AuthInfo(const rgw_user& acct_user,
const std::string& acct_name,
const uint32_t perm_mask,
const bool is_admin)
const bool is_admin,
const std::string acct_type="")
: acct_user(acct_user),
acct_name(acct_name),
perm_mask(perm_mask),
is_admin(is_admin) {
is_admin(is_admin),
acct_type(acct_type) {
}
};

Expand Down
6 changes: 5 additions & 1 deletion src/rgw/rgw_common.h
Expand Up @@ -547,14 +547,16 @@ struct RGWUserInfo
RGWQuotaInfo bucket_quota;
map<int, string> temp_url_keys;
RGWQuotaInfo user_quota;
std::string type;

RGWUserInfo()
: auid(0),
suspended(0),
max_buckets(RGW_DEFAULT_MAX_BUCKETS),
op_mask(RGW_OP_TYPE_ALL),
admin(0),
system(0) {
system(0),
type("") {
}

RGWAccessKey* get_key0() {
Expand Down Expand Up @@ -605,6 +607,7 @@ struct RGWUserInfo
::encode(user_quota, bl);
::encode(user_id.tenant, bl);
::encode(admin, bl);
::encode(type, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
Expand Down Expand Up @@ -677,6 +680,7 @@ struct RGWUserInfo
}
if (struct_v >= 18) {
::decode(admin, bl);
::decode(type, bl);
}
DECODE_FINISH(bl);
}
Expand Down
178 changes: 136 additions & 42 deletions src/rgw/rgw_rest_s3.cc
Expand Up @@ -31,6 +31,9 @@
#include "rgw_token.h"
#include "include/assert.h"

#include "rgw_auth.h"
#include "rgw_auth_decoimpl.h"

#define dout_subsys ceph_subsys_rgw

using namespace rgw;
Expand Down Expand Up @@ -3936,52 +3939,48 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
}
}

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);
class S3AuthFactory : public RGWRemoteAuthApplier::Factory {
typedef RGWAuthApplier::aplptr_t aplptr_t;
RGWRados * const store;
const std::string acct_override;

ldout(store->ctx(), 15)
<< __func__ << " LDAP auth uri="
<< store->ctx()->_conf->rgw_ldap_uri
<< dendl;
public:
S3AuthFactory(RGWRados * const store,
const std::string& acct_override)
: store(store),
acct_override(acct_override) {
}

RGWToken token{from_base64(auth_id)};
aplptr_t create_apl_remote(CephContext * const cct,
RGWRemoteAuthApplier::acl_strategy_t&& acl_alg,
const RGWRemoteAuthApplier::AuthInfo info
) const override {
return aplptr_t(
new RGWThirdPartyAccountAuthApplier<RGWRemoteAuthApplier>(
RGWRemoteAuthApplier(cct, store, std::move(acl_alg), info),
store, acct_override));
}
} aplfact(store, s->account_name);

if (! token.valid())
external_auth_result = -EACCES;
else {
ldout(store->ctx(), 10)
<< __func__ << " try LDAP auth uri="
<< store->ctx()->_conf->rgw_ldap_uri
<< " token.id=" << token.id
<< dendl;

if (ldh->auth(token.id, token.key) != 0)
external_auth_result = -EACCES;
else {
/* ok, succeeded */
external_auth_result = 0;
/* Extractor */
RGWLDAPTokenExtractor token_extr(s);

/* create local account, if none exists */
s->user->user_id = token.id;
s->user->display_name = token.id; // cn?
int ret = rgw_get_user_info_by_uid(store, s->user->user_id, *(s->user));
if (ret < 0) {
ret = rgw_store_user_info(store, *(s->user), nullptr, nullptr,
real_time(), true);
if (ret < 0) {
dout(10) << "NOTICE: failed to store new user's info: ret=" << ret
<< dendl;
}
}
RGWLDAPAuthEngine ldap(s->cct, store, token_extr, &aplfact);

/* set request perms */
s->perm_mask = RGW_PERM_FULL_CONTROL;
} /* success */
} /* token */
} /* ldap */
if (!ldap.is_applicable()) {
return -EPERM;
} else {
auto applier = ldap.authenticate();
if (!applier) {
return -EPERM;
}
else {
applier->load_acct_info(*s->user);
s->perm_mask = applier->get_perm_mask();
s->auth_identity = std::move(applier);
return 0;
}
}

/* keystone failed (or not enabled); check if we want to use rados backend */
if (!store->ctx()->_conf->rgw_s3_auth_use_rados
Expand All @@ -3997,7 +3996,7 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
return external_auth_result;
}

/* now verify signature */
/* now verify signature */
string auth_hdr;
if (!rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr,
qsr)) {
Expand Down Expand Up @@ -4342,3 +4341,98 @@ RGWOp* RGWHandler_REST_Service_S3Website::get_obj_op(bool get_data)
op->set_get_data(get_data);
return op;
}

rgw::LDAPHelper* RGWLDAPAuthEngine::ldh = nullptr;
std::mutex RGWLDAPAuthEngine::mtx;

void RGWLDAPAuthEngine::init(CephContext* const cct)
{
if (!ldh) {
std::lock_guard<std::mutex> lck(mtx);
if (!ldh) {
const string& ldap_uri = cct->_conf->rgw_ldap_uri;
const string& ldap_binddn = cct->_conf->rgw_ldap_binddn;
const string& ldap_searchdn = cct->_conf->rgw_ldap_searchdn;
const string& ldap_dnattr = cct->_conf->rgw_ldap_dnattr;
std::string ldap_bindpw = parse_rgw_ldap_bindpw(cct);

ldh = new rgw::LDAPHelper(ldap_uri, ldap_binddn, ldap_bindpw,
ldap_searchdn, ldap_dnattr);

ldh->init();
ldh->bind();
}
}
}

RGWRemoteAuthApplier::acl_strategy_t RGWLDAPAuthEngine::get_acl_strategy() const
{
//This is based on the assumption that the default acl strategy in
// get_perms_from_aclspec, will take care. Extra acl spec is not required.
return nullptr;
}

RGWRemoteAuthApplier::AuthInfo
RGWLDAPAuthEngine::get_creds_info(const rgw::RGWToken& token) const noexcept
{
return RGWRemoteAuthApplier::AuthInfo {
rgw_user(token.id),
token.id,
RGW_PERM_FULL_CONTROL,
true,
"ldap"
};
}

bool RGWLDAPAuthEngine::is_applicable() const noexcept
{
if (!RGWTokenBasedAuthEngine::is_applicable()) {
return false;
}

if (!cct->_conf->rgw_s3_auth_use_ldap ||
cct->_conf->rgw_ldap_uri.empty()) {
return false;
}

if(!base64_token.valid()) {
return false;
}

return true;
}

RGWAuthApplier::aplptr_t RGWLDAPAuthEngine::authenticate() const
{
//Check if a user of type other than 'ldap' is already present, if yes, then
//return error.
RGWUserInfo user_info;
user_info.user_id = base64_token.id;
if (rgw_get_user_info_by_uid(store, user_info.user_id, user_info) >= 0) {
if (user_info.type.compare("ldap") != 0) {
ldout(cct, 10) << "ERROR: User id of type: " << user_info.type << "is already present" << dendl;
return nullptr;
}
}

if (ldh->auth(base64_token.id, base64_token.key) != 0) {
return nullptr;
}

return apl_factory->create_apl_remote(cct, get_acl_strategy(), get_creds_info(base64_token));
}

std::string RGWLDAPTokenExtractor::get_token() const
{
string token = "";
if (!s->http_auth || !(*s->http_auth)) {
token = s->info.args.get("AWSAccessKeyId");
} else {
string auth_str(s->http_auth + 4);
int pos = auth_str.rfind(':');
if (pos >=0 ) {
token = auth_str.substr(0, pos);
}
}
return token;
}
47 changes: 47 additions & 0 deletions src/rgw/rgw_rest_s3.h
Expand Up @@ -16,6 +16,9 @@
#include "rgw_rest_conn.h"
#include "rgw_ldap.h"

#include "rgw_token.h"
#include "include/assert.h"

#define RGW_AUTH_GRACE_MINS 15

void rgw_get_errno_s3(struct rgw_http_errors *e, int err_no);
Expand Down Expand Up @@ -627,4 +630,48 @@ static inline int valid_s3_bucket_name(const string& name, bool relaxed=false)
return 0;
}

class RGWLDAPAuthEngine: RGWTokenBasedAuthEngine
{
static rgw::LDAPHelper* ldh;
static std::mutex mtx;
rgw::RGWToken base64_token;

static void init(CephContext* const cct);

protected:
RGWRados* const store;
const RGWRemoteAuthApplier::Factory * const apl_factory;

RGWRemoteAuthApplier::acl_strategy_t get_acl_strategy() const;
RGWRemoteAuthApplier::AuthInfo get_creds_info(const rgw::RGWToken& token) const noexcept;

public:
RGWLDAPAuthEngine(CephContext* const cct,
RGWRados* const store,
Extractor &ex,
const RGWRemoteAuthApplier::Factory * const apl_factory)
: RGWTokenBasedAuthEngine(cct, ex),
store(store),
apl_factory(apl_factory) {
init(cct);
base64_token = rgw::from_base64(token);
}
const char* get_name() const noexcept override {
return "RGWLDAPAuthEngine";
}
bool is_applicable() const noexcept override;
RGWAuthApplier::aplptr_t authenticate() const override;
};

class RGWLDAPTokenExtractor : public RGWTokenBasedAuthEngine::Extractor {
protected:
const req_state * const s;

public:
RGWLDAPTokenExtractor(const req_state * const s)
: s(s) {
}
std::string get_token() const override;
};

#endif /* CEPH_RGW_REST_S3_H */
2 changes: 1 addition & 1 deletion src/rgw/rgw_token.h
Expand Up @@ -71,7 +71,7 @@ namespace rgw {

virtual uint32_t version() const { return 1; };

bool valid() {
bool valid() const{
return ((type != TOKEN_NONE) &&
(! id.empty()) &&
(! key.empty()));
Expand Down

0 comments on commit 1d18215

Please sign in to comment.