mirror of
https://github.com/ceph/ceph
synced 2025-03-11 02:39:05 +00:00
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:
commit
1c4ccfe3c4
@ -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);
|
||||
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user