Merge pull request #7597 from rzarzynski/wip-rgw-keystone-proper-fail

rgw: improve error handling in S3/Keystone integration

Reviewed-by: Yehuda Sadeh <yehuda@redhat.com>
This commit is contained in:
Yehuda Sadeh 2016-02-24 14:40:02 -08:00
commit 1c4ccfe3c4
3 changed files with 55 additions and 30 deletions

View File

@ -118,6 +118,7 @@ int RGWHTTPClient::process(const char *method, const char *url)
dout(0) << "curl_easy_perform returned error: " << error_buf << dendl;
ret = -EINVAL;
}
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_status);
curl_easy_cleanup(curl_handle);
curl_slist_free_all(h);

View File

@ -19,6 +19,7 @@ class RGWHTTPClient
bufferlist::iterator send_iter;
size_t send_len;
bool has_send_len;
long http_status;
rgw_http_req_data *req_data;
@ -33,8 +34,18 @@ protected:
list<pair<string, string> > headers;
int init_request(const char *method, const char *url, rgw_http_req_data *req_data);
public:
explicit RGWHTTPClient(CephContext *_cct): send_len (0), has_send_len(false), req_data(NULL), user_info(NULL), cct(_cct) {}
static const long HTTP_STATUS_NOSTATUS = 0;
static const long HTTP_STATUS_UNAUTHORIZED = 401;
virtual ~RGWHTTPClient();
explicit RGWHTTPClient(CephContext *_cct)
: send_len(0),
has_send_len(false),
http_status(HTTP_STATUS_NOSTATUS),
req_data(nullptr),
user_info(nullptr),
cct(_cct) {
}
void set_user_info(void *info) {
user_info = info;
@ -57,6 +68,10 @@ public:
has_send_len = true;
}
long get_http_status() const {
return http_status;
}
int process(const char *method, const char *url);
int process(const char *url) { return process("GET", url); }

View File

@ -2798,10 +2798,15 @@ int RGW_Auth_S3_Keystone_ValidateToken::validate_s3token(
int ret = process("POST", keystone_url.c_str());
if (ret < 0) {
dout(2) << "s3 keystone: token validation ERROR: " << rx_buffer.c_str()
<< dendl;
<< dendl;
return -EPERM;
}
/* if the supplied signature is wrong, we will get 401 from Keystone */
if (get_http_status() == HTTP_STATUS_UNAUTHORIZED) {
return -ERR_SIGNATURE_NO_MATCH;
}
/* now parse response */
if (response.parse(cct, rx_buffer) < 0) {
dout(2) << "s3 keystone: token parsing failed" << dendl;
@ -2817,9 +2822,10 @@ int RGW_Auth_S3_Keystone_ValidateToken::validate_s3token(
}
if (!found) {
ldout(cct, 5) << "s3 keystone: user does not hold a matching role; required roles: "
<< cct->_conf->rgw_keystone_accepted_roles << dendl;
return -EPERM;
ldout(cct, 5) << "s3 keystone: user does not hold a matching role;"
" required roles: "
<< cct->_conf->rgw_keystone_accepted_roles << dendl;
return -ERR_INVALID_ACCESS_KEY;
}
/* everything seems fine, continue with this user */
@ -3461,7 +3467,7 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
}
/* try keystone auth first */
int keystone_result = -EINVAL;
int keystone_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;
@ -3470,8 +3476,9 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
string token;
if (!rgw_create_s3_canonical_header(s->info,
&s->header_time, token, qsr)) {
&s->header_time, token, qsr)) {
dout(10) << "failed to create auth header\n" << token << dendl;
keystone_result = -EPERM;
} else {
keystone_result = keystone_validator.validate_s3token(auth_id, token,
auth_sign);
@ -3481,14 +3488,17 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
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;
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;
return -ERR_REQUEST_TIME_SKEWED;
}
@ -3510,18 +3520,17 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
}
}
/* keystone failed (or not enabled); check if we want to use rados backend */
if (!store->ctx()->_conf->rgw_s3_auth_use_rados
&& keystone_result < 0)
return keystone_result;
/* now try rados backend, but only if keystone did not succeed */
if (keystone_result < 0) {
if (!store->ctx()->_conf->rgw_s3_auth_use_rados) {
/* No other auth option possible. Terminate request. */
return keystone_result;
}
/* 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 -ERR_INVALID_ACCESS_KEY;
<< " can't authenticate" << dendl;
return keystone_result;
}
/* now verify signature */
@ -3535,14 +3544,14 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
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) {
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;
<< "; 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;
}