Skip to content

Commit

Permalink
Merge pull request #10448 from pritha-srivastava/wip_s3_v2_localauth_…
Browse files Browse the repository at this point in the history
…rework

rgw: Rework of s3 v2 local authentication code.

verfied:  f23, subset of s3tests
  • Loading branch information
mattbenjamin committed Aug 12, 2016
2 parents f8263dc + b5b3e5c commit 41aa39f
Show file tree
Hide file tree
Showing 3 changed files with 261 additions and 119 deletions.
273 changes: 171 additions & 102 deletions src/rgw/rgw_rest_s3.cc
Expand Up @@ -1714,8 +1714,8 @@ int RGWPostObj_ObjStore_S3::get_policy()
op_ret = rgw_get_user_info_by_access_key(store, s3_access_key, user_info);
if (op_ret < 0) {
S3AuthFactory aplfact(store, s->account_name);
RGWGetPolicyLDAPTokenExtractor token_extr(s3_access_key);
RGWLDAPAuthEngine ldap(s->cct, store, token_extr, &aplfact);
RGWGetPolicyV2Extractor extr(s3_access_key, received_signature_str);
RGWLDAPAuthEngine ldap(s->cct, store, extr, &aplfact);
// try external authenticators
if (store->ctx()->_conf->rgw_s3_auth_use_keystone &&
store->ctx()->_conf->rgw_keystone_url.empty())
Expand Down Expand Up @@ -1754,13 +1754,22 @@ int RGWPostObj_ObjStore_S3::get_policy()
s->perm_mask = RGW_PERM_FULL_CONTROL;
}
} else if (ldap.is_applicable()) {
auto applier = ldap.authenticate();
if (! applier) {
try {
auto applier = ldap.authenticate();
if (! applier) {
return -EACCES;
}

try {
applier->load_acct_info(*s->user);
s->perm_mask = applier->get_perm_mask();
applier->modify_request_state(s);
s->auth_identity = std::move(applier);
} catch (int err) {
return -EACCES;
}
} catch (int err) {
return -EACCES;
} else {
applier->load_acct_info(*s->user);
s->perm_mask = applier->get_perm_mask();
s->auth_identity = std::move(applier);
}
} else {
return -EACCES;
Expand Down Expand Up @@ -3949,91 +3958,57 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
}

S3AuthFactory aplfact(store, s->account_name);
RGWLDAPTokenExtractor token_extr(s);
RGWLDAPAuthEngine ldap(s->cct, store, token_extr, &aplfact);
RGWS3V2Extractor extr(s);
RGWLDAPAuthEngine ldap(s->cct, store, extr, &aplfact);

if (ldap.is_applicable()) {
auto applier = ldap.authenticate();
if (!applier) {
external_auth_result = -EACCES;
} else {
applier->load_acct_info(*s->user);
s->perm_mask = applier->get_perm_mask();
s->auth_identity = std::move(applier);
external_auth_result = 0;
try {
auto applier = ldap.authenticate();
if (! applier) {
external_auth_result = -EACCES;
} else {
try {
applier->load_acct_info(*s->user);
s->perm_mask = applier->get_perm_mask();
applier->modify_request_state(s);
s->auth_identity = std::move(applier);
external_auth_result = 0;
} catch (int err) {
ldout(s->cct, 5) << "applier threw err=" << err << dendl;
external_auth_result = err;
}
}
} catch (int err) {
ldout(s->cct, 5) << "ldap auth engine threw err=" << err << dendl;
external_auth_result = err;
}
}

/* 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 external_auth_result;
}
RGWS3V2LocalAuthEngine localauth(s, store, 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;
}
try {
auto applier = localauth.authenticate();
if (! applier) {
return external_auth_result;
}
try {
applier->load_acct_info(*s->user);
s->perm_mask = applier->get_perm_mask();
applier->modify_request_state(s);
s->auth_identity = std::move(applier);
} catch (int err) {
ldout(s->cct, 5) << "applier threw err=" << err << dendl;
return err;
}
} catch (int err) {
ldout(s->cct, 5) << "local auth engine threw err=" << err << dendl;
return err;
}
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 @@ -4042,7 +4017,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 @@ -4329,9 +4304,9 @@ std::mutex RGWLDAPAuthEngine::mtx;

void RGWLDAPAuthEngine::init(CephContext* const cct)
{
if (!ldh) {
if (! ldh) {
std::lock_guard<std::mutex> lck(mtx);
if (!ldh) {
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;
Expand Down Expand Up @@ -4368,34 +4343,34 @@ RGWLDAPAuthEngine::get_creds_info(const rgw::RGWToken& token) const noexcept

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

if (!cct->_conf->rgw_s3_auth_use_ldap ||
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
{
if(! base64_token.valid()) {
return nullptr;
}
//TODO: Uncomment, when we have a migration plan in place.
//Check if a user of type other than 'ldap' is already present, if yes, then
//return error.
RGWUserInfo user_info;
/*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 != TYPE_LDAP) {
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;
Expand All @@ -4404,17 +4379,111 @@ RGWAuthApplier::aplptr_t RGWLDAPAuthEngine::authenticate() const
return apl_factory->create_apl_remote(cct, get_acl_strategy(), get_creds_info(base64_token));
}

std::string RGWLDAPTokenExtractor::get_token() const
void RGWS3V2Extractor::get_auth_keys(std::string& access_key_id,
std::string& signature,
std::string& expires,
bool& qsr) const
{
string token = "";
if (!s->http_auth || !(*s->http_auth)) {
token = s->info.args.get("AWSAccessKeyId");
qsr = false;
if (! s->http_auth || !(*s->http_auth)) {
access_key_id = s->info.args.get("AWSAccessKeyId");
signature = s->info.args.get("Signature");
expires = s->info.args.get("Expires");
qsr = true;
} else {
string auth_str(s->http_auth + 4);
int pos = auth_str.rfind(':');
if (pos >=0 ) {
token = auth_str.substr(0, pos);
if (pos >= 0) {
access_key_id = auth_str.substr(0, pos);
signature = auth_str.substr(pos + 1);
}
}
}

bool RGWS3V2LocalAuthEngine::is_applicable() const noexcept
{
if (! RGWS3V2AuthEngine::is_applicable()) {
return false;
}
if (! s->cct->_conf->rgw_s3_auth_use_rados) {
return false;
}

return true;
}

RGWAuthApplier::aplptr_t RGWS3V2LocalAuthEngine::authenticate() const
{
if (access_key_id.empty() || signature.empty()) {
ldout(s->cct, 5) << "access_key_id or signature is empty" << dendl;
throw -EINVAL;
}

time_t now;
time(&now);
if (! expires.empty()) {
time_t exp = atoll(expires.c_str());
if (now >= exp) {
throw -EPERM;
}
}
/* get the user info */
string access_key = access_key_id;
if (rgw_get_user_info_by_access_key(store, access_key, *(s->user)) < 0) {
ldout(s->cct, 5) << "error reading user info, uid=" << access_key_id
<< " can't authenticate" << dendl;
return nullptr;
}
//TODO: Uncomment, when we have a migration plan in place.
/*else {
if (s->user->type != TYPE_RGW) {
ldout(cct, 10) << "ERROR: User id of type: " << s->user->type << " is present" << dendl;
throw -EPERM;
}
}*/

/* now verify signature */
string auth_hdr;
if (! rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr,
qsr)) {
ldout(s->cct, 10) << "failed to create auth header\n" << auth_hdr << dendl;
throw -EPERM;
}
ldout(s->cct, 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) {
ldout(s->cct, 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;
ldout(s->cct, 0) << "NOTICE: request time skew too big now=" << utime_t(now, 0)
<< " req_time=" << s->header_time
<< dendl;
throw -ERR_REQUEST_TIME_SKEWED;
}

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

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

ldout(s->cct, 15) << "calculated digest=" << digest << dendl;
ldout(s->cct, 15) << "auth_sign=" << signature << dendl;
ldout(s->cct, 15) << "compare=" << signature.compare(digest) << dendl;

if (signature != digest) {
throw -ERR_SIGNATURE_NO_MATCH;
}

return apl_factory->create_apl_local(cct, *(s->user), k.subuser);
}

0 comments on commit 41aa39f

Please sign in to comment.