Skip to content

Commit

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

Signed-off-by: Pritha Srivastava <prsrivas@redhat.com>
  • Loading branch information
pritha-srivastava committed Jul 27, 2016
1 parent 88c604d commit cf81f4d
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 67 deletions.
196 changes: 129 additions & 67 deletions src/rgw/rgw_rest_s3.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4050,77 +4050,24 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
} /* success */
} /* token */
} /* 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;

S3AuthFactory aplfact(store, s->account_name);
/* 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 external_auth_result;
}
RGWS3V2TokenExtractor token_extr(s);
RGWS3V2LocalAuthEngine localauth(s, store, token_extr, &aplfact);

/* now verify signature */
string auth_hdr;
if (!rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr,
qsr)) {
dout(10) << "failed to create auth header\n" << auth_hdr << dendl;
return -EPERM;
}
dout(10) << "auth_hdr:\n" << auth_hdr << dendl;

time_t req_sec = s->header_time.sec();
if ((req_sec < now - RGW_AUTH_GRACE_MINS * 60 ||
req_sec > now + RGW_AUTH_GRACE_MINS * 60) && !qsr) {
dout(10) << "req_sec=" << req_sec << " now=" << now
<< "; now - RGW_AUTH_GRACE_MINS=" << now - RGW_AUTH_GRACE_MINS * 60
<< "; now + RGW_AUTH_GRACE_MINS=" << now + RGW_AUTH_GRACE_MINS * 60
<< dendl;
dout(0) << "NOTICE: request time skew too big now=" << utime_t(now, 0)
<< " req_time=" << s->header_time
<< dendl;
return -ERR_REQUEST_TIME_SKEWED;
}

map<string, RGWAccessKey>::iterator iter =
s->user->access_keys.find(auth_id);
if (iter == s->user->access_keys.end()) {
dout(0) << "ERROR: access key not encoded in user info" << dendl;
return -EPERM;
}
RGWAccessKey& k = iter->second;

if (!k.subuser.empty()) {
map<string, RGWSubUser>::iterator uiter =
s->user->subusers.find(k.subuser);
if (uiter == s->user->subusers.end()) {
dout(0) << "NOTICE: could not find subuser: " << k.subuser << dendl;
return -EPERM;
if (! localauth.is_applicable()) {
return external_auth_result;
} else {
auto applier = localauth.authenticate();
if (! applier) {
return external_auth_result;
} else {
applier->load_acct_info(*s->user);
s->perm_mask = applier->get_perm_mask();
s->auth_identity = std::move(applier);
}
RGWSubUser& subuser = uiter->second;
s->perm_mask = subuser.perm_mask;
} else
s->perm_mask = RGW_PERM_FULL_CONTROL;

string digest;
int ret = rgw_get_s3_header_digest(auth_hdr, k.key, digest);
if (ret < 0) {
return -EPERM;
}

dout(15) << "calculated digest=" << digest << dendl;
dout(15) << "auth_sign=" << auth_sign << dendl;
dout(15) << "compare=" << auth_sign.compare(digest) << dendl;

if (auth_sign != digest) {
return -ERR_SIGNATURE_NO_MATCH;
}

if (s->user->system) {
s->system_request = true;
dout(20) << "system request" << dendl;
Expand All @@ -4129,7 +4076,7 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
RGWUserInfo effective_user;
if (!effective_uid.empty()) {
rgw_user euid(effective_uid);
ret = rgw_get_user_info_by_uid(store, euid, effective_user);
int ret = rgw_get_user_info_by_uid(store, euid, effective_user);
if (ret < 0) {
ldout(s->cct, 0) << "User lookup failed!" << dendl;
return -EACCES;
Expand Down Expand Up @@ -4410,3 +4357,118 @@ RGWOp* RGWHandler_REST_Service_S3Website::get_obj_op(bool get_data)
op->set_get_data(get_data);
return op;
}

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

if (!date.empty()) {
time_t exp = atoll(date.c_str());
if (now >= exp) {
return false;
}
}

return true;
}

void RGWS3V2TokenBasedAuthEngine::get_other_tokens()
{
if (!s->http_auth || !(*s->http_auth)) {
auth_sign = s->info.args.get("Signature");
date = s->info.args.get("Expires");
qsr = true;
} else {
string auth_str(s->http_auth + 4);
int pos = auth_str.rfind(':');
if (pos >= 0) {
auth_sign = auth_str.substr(pos + 1);
}
}
}

std::string RGWS3V2TokenExtractor::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;
}

bool RGWS3V2LocalAuthEngine::is_applicable() const noexcept
{
if (!RGWS3V2TokenBasedAuthEngine::is_applicable()) {
return false;
}

if (!cct->_conf->rgw_s3_auth_use_rados) {
return false;
}

return true;
}

RGWAuthApplier::aplptr_t RGWS3V2LocalAuthEngine::authenticate() const
{
/* get the user info */
string access_key = token;
if (rgw_get_user_info_by_access_key(store, access_key, *(s->user)) < 0) {
dout(5) << "error reading user info, uid=" << token
<< " can't authenticate" << dendl;
return nullptr;
}

/* now verify signature */
string auth_hdr;
if (!rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr,
qsr)) {
dout(10) << "failed to create auth header\n" << auth_hdr << dendl;
return nullptr;
}
dout(10) << "auth_hdr:\n" << auth_hdr << dendl;

time_t req_sec = s->header_time.sec();
if ((req_sec < now - RGW_AUTH_GRACE_MINS * 60 ||
req_sec > now + RGW_AUTH_GRACE_MINS * 60) && !qsr) {
dout(10) << "req_sec=" << req_sec << " now=" << now
<< "; now - RGW_AUTH_GRACE_MINS=" << now - RGW_AUTH_GRACE_MINS * 60
<< "; now + RGW_AUTH_GRACE_MINS=" << now + RGW_AUTH_GRACE_MINS * 60
<< dendl;
dout(0) << "NOTICE: request time skew too big now=" << utime_t(now, 0)
<< " req_time=" << s->header_time
<< dendl;
return nullptr;
}

map<string, RGWAccessKey>::iterator iter = s->user->access_keys.find(token);
if (iter == s->user->access_keys.end()) {
dout(0) << "ERROR: access key not encoded in user info" << dendl;
return nullptr;
}
RGWAccessKey& k = iter->second;

string digest;
int ret = rgw_get_s3_header_digest(auth_hdr, k.key, digest);
if (ret < 0) {
return nullptr;
}

dout(15) << "calculated digest=" << digest << dendl;
dout(15) << "auth_sign=" << auth_sign << dendl;
dout(15) << "compare=" << auth_sign.compare(digest) << dendl;

if (auth_sign != digest) {
return nullptr;
}

return apl_factory->create_apl_local(cct, *(s->user), k.subuser);
}
84 changes: 84 additions & 0 deletions src/rgw/rgw_rest_s3.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
#include "rgw_rest_conn.h"
#include "rgw_ldap.h"

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

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

#define RGW_AUTH_GRACE_MINS 15

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

class RGWS3V2TokenBasedAuthEngine : public RGWTokenBasedAuthEngine {
void get_other_tokens();

protected:
req_state * const s;
std::string auth_sign;
std::string date;
bool qsr;
time_t now;

RGWS3V2TokenBasedAuthEngine(req_state * const s,
CephContext * const cct,
const Extractor& extr)
: RGWTokenBasedAuthEngine(cct, extr),
s(s),
qsr(false) {
get_other_tokens();
time(&now);
}

bool is_applicable() const noexcept override;
};

class RGWS3V2TokenExtractor : public RGWS3V2TokenBasedAuthEngine::Extractor {
protected:
const req_state * const s;

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

class RGWS3V2LocalAuthEngine: RGWS3V2TokenBasedAuthEngine
{
protected:
RGWRados* const store;
const RGWLocalAuthApplier::Factory * const apl_factory;

public:
RGWS3V2LocalAuthEngine(req_state * const s,
RGWRados* const store,
Extractor &ex,
const RGWLocalAuthApplier::Factory * const apl_factory)
: RGWS3V2TokenBasedAuthEngine(s, s->cct, ex),
store(store),
apl_factory(apl_factory) {
}

const char* get_name() const noexcept override {
return "RGWS3V2LocalAuthEngine";
}
bool is_applicable() const noexcept override;
RGWAuthApplier::aplptr_t authenticate() const override;
};

class S3AuthFactory : public RGWLocalAuthApplier::Factory {
typedef RGWAuthApplier::aplptr_t aplptr_t;
RGWRados * const store;
const std::string acct_override;

public:
S3AuthFactory(RGWRados * const store,
const std::string& acct_override)
: store(store),
acct_override(acct_override) {
}

aplptr_t create_apl_local(CephContext * const cct,
const RGWUserInfo& user_info,
const std::string& subuser) const override {
return aplptr_t(
new RGWThirdPartyAccountAuthApplier<RGWLocalAuthApplier>(
RGWLocalAuthApplier(cct, user_info, subuser),
store, acct_override));
}
};
#endif /* CEPH_RGW_REST_S3_H */

0 comments on commit cf81f4d

Please sign in to comment.