diff options
author | Yehuda Sadeh <yehuda@inktank.com> | 2013-05-23 13:09:08 -0700 |
---|---|---|
committer | Yehuda Sadeh <yehuda@inktank.com> | 2013-05-23 13:09:08 -0700 |
commit | 0c805b6c771bff259239458ccd5431543005c842 (patch) | |
tree | c82f4db08997bd9f0e1595cf3dc22e53b4b9a69d | |
parent | f2f73538d9017af3fec61201e894f69b7cbc3d9e (diff) | |
download | ceph-0c805b6c771bff259239458ccd5431543005c842.tar.gz |
rgw: rest_client, forward requests
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r-- | src/rgw/rgw_auth_s3.cc | 58 | ||||
-rw-r--r-- | src/rgw/rgw_auth_s3.h | 1 | ||||
-rw-r--r-- | src/rgw/rgw_common.h | 4 | ||||
-rw-r--r-- | src/rgw/rgw_env.cc | 12 | ||||
-rw-r--r-- | src/rgw/rgw_rest_client.cc | 56 | ||||
-rw-r--r-- | src/rgw/rgw_rest_client.h | 1 | ||||
-rw-r--r-- | src/rgw/rgw_rest_s3.cc | 61 |
7 files changed, 129 insertions, 64 deletions
diff --git a/src/rgw/rgw_auth_s3.cc b/src/rgw/rgw_auth_s3.cc index e3c08e75526..89cc80d3421 100644 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@ -134,4 +134,62 @@ int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, string& return 0; } +static inline bool is_base64_for_content_md5(unsigned char c) { + return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '=')); +} + +/* + * get the header authentication information required to + * compute a request's signature + */ +bool rgw_create_s3_canonical_header(req_info& info, utime_t& header_time, string& dest, bool qsr) +{ + const char *content_md5 = info.env->get("HTTP_CONTENT_MD5"); + if (content_md5) { + for (const char *p = content_md5; *p; p++) { + if (!is_base64_for_content_md5(*p)) { + dout(0) << "NOTICE: bad content-md5 provided (not base64), aborting request p=" << *p << " " << (int)*p << dendl; + return false; + } + } + } + const char *content_type = info.env->get("CONTENT_TYPE"); + + string date; + if (qsr) { + date = info.args.get("Expires"); + } else { + const char *str = info.env->get("HTTP_DATE"); + const char *req_date = str; + if (str) { + date = str; + } else { + req_date = info.env->get("HTTP_X_AMZ_DATE"); + if (!req_date) { + dout(0) << "NOTICE: missing date for auth header" << dendl; + return false; + } + } + + struct tm t; + if (!parse_rfc2616(req_date, &t)) { + dout(0) << "NOTICE: failed to parse date for auth header" << dendl; + return false; + } + if (t.tm_year < 70) { + dout(0) << "NOTICE: bad date (predates epoch): " << req_date << dendl; + return false; + } + header_time = utime_t(timegm(&t), 0); + } + + map<string, string>& meta_map = info.x_meta_map; + map<string, string>& sub_resources = info.args.get_sub_resources(); + + rgw_create_s3_canonical_header(info.method, content_md5, content_type, date.c_str(), + meta_map, info.request_uri.c_str(), sub_resources, + dest); + + return true; +} diff --git a/src/rgw/rgw_auth_s3.h b/src/rgw/rgw_auth_s3.h index 63813b91717..c8bfbc92c06 100644 --- a/src/rgw/rgw_auth_s3.h +++ b/src/rgw/rgw_auth_s3.h @@ -7,6 +7,7 @@ void rgw_create_s3_canonical_header(const char *method, const char *content_md5, const char *content_type, const char *date, map<string, string>& meta_map, const char *request_uri, map<string, string>& sub_resources, string& dest_str); +bool rgw_create_s3_canonical_header(req_info& info, utime_t& header_time, string& dest, bool qsr); int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, string& dest); diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index dc1b0a13bb4..162e4932ff2 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -259,6 +259,10 @@ public: size_t get_size(const char *name, size_t def_val = 0); bool exists(const char *name); bool exists_prefix(const char *prefix); + + void remove(const char *name); + void set(const char *name, const char *val); + std::map<string, string>& get_map() { return env_map; } }; class RGWConf { diff --git a/src/rgw/rgw_env.cc b/src/rgw/rgw_env.cc index e23fa257d1b..78ac0d41d7a 100644 --- a/src/rgw/rgw_env.cc +++ b/src/rgw/rgw_env.cc @@ -92,6 +92,18 @@ bool RGWEnv::exists_prefix(const char *prefix) return (strncmp(iter->first.c_str(), prefix, strlen(prefix)) == 0); } +void RGWEnv::set(const char *name, const char *val) +{ + env_map[name] = val; +} + +void RGWEnv::remove(const char *name) +{ + map<string, string>::iterator iter = env_map.find(name); + if (iter != env_map.end()) + env_map.erase(iter); +} + void RGWConf::init(CephContext *cct, RGWEnv *env) { enable_ops_log = cct->_conf->rgw_enable_ops_log; diff --git a/src/rgw/rgw_rest_client.cc b/src/rgw/rgw_rest_client.cc index 80d58388a89..c19a71be617 100644 --- a/src/rgw/rgw_rest_client.cc +++ b/src/rgw/rgw_rest_client.cc @@ -52,6 +52,14 @@ int RGWRESTClient::read_header(void *ptr, size_t len) return 0; } +static void get_new_date_str(CephContext *cct, string& date_str) +{ + utime_t tm = ceph_clock_now(cct); + stringstream s; + tm.gmtime(s); + date_str = s.str(); +} + int RGWRESTClient::execute(RGWAccessKey& key, const char *method, const char *resource) { string new_url = url; @@ -65,10 +73,8 @@ int RGWRESTClient::execute(RGWAccessKey& key, const char *method, const char *re } new_url.append(new_resource); - utime_t tm = ceph_clock_now(cct); - stringstream s; - tm.gmtime(s); - string date_str = s.str(); + string date_str; + get_new_date_str(cct, date_str); headers.push_back(make_pair<string, string>("HTTP_DATE", date_str)); string canonical_header; @@ -96,3 +102,45 @@ int RGWRESTClient::execute(RGWAccessKey& key, const char *method, const char *re return rgw_http_error_to_errno(status); } +int RGWRESTClient::forward_request(RGWAccessKey& key, req_info& info) +{ + + RGWEnv new_env = *info.env; /* copy environment */ + + string date_str; + get_new_date_str(cct, date_str); + new_env.set("HTTP_DATE", date_str.c_str()); + + req_info new_info(info); + new_info.env = &new_env; + + map<string, string>& m = new_env.get_map(); + + string canonical_header; + utime_t header_time; + if (!rgw_create_s3_canonical_header(new_info, header_time, canonical_header, false)) { + ldout(cct, 0) << "failed to create canonical s3 header" << dendl; + return -EINVAL; + } + + string digest; + int ret = rgw_get_s3_header_digest(canonical_header, key.key, digest); + if (ret < 0) { + return ret; + } + + string auth_hdr = "AWS " + key.id + ":" + digest; + ldout(cct, 15) << "generated auth header: " << auth_hdr << dendl; + + m["AUTHORIZATION"] = auth_hdr; + + map<string, string>::iterator iter; + for (iter = m.begin(); iter != m.end(); ++iter) { + headers.push_back(make_pair<string, string>(iter->first, iter->second)); + } + + int r = process(new_info.method, new_info.request_uri.c_str()); + if (r < 0) + return r; + + return rgw_http_error_to_errno(status);} diff --git a/src/rgw/rgw_rest_client.h b/src/rgw/rgw_rest_client.h index 95e1f28697d..a117bb12a77 100644 --- a/src/rgw/rgw_rest_client.h +++ b/src/rgw/rgw_rest_client.h @@ -28,6 +28,7 @@ public: int read_header(void *ptr, size_t len); int execute(RGWAccessKey& key, const char *method, const char *resource); + int forward_request(RGWAccessKey& key, req_info& info); }; diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 082b310f351..00305b54d2b 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -1900,65 +1900,6 @@ int RGWHandler_ObjStore_S3::init(RGWRados *store, struct req_state *s, RGWClient return RGWHandler_ObjStore::init(store, s, cio); } -static inline bool is_base64_for_content_md5(unsigned char c) { - return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '=')); -} - -/* - * get the header authentication information required to - * compute a request's signature - */ -static bool get_auth_header(req_info& info, utime_t& header_time, string& dest, bool qsr) -{ - const char *content_md5 = info.env->get("HTTP_CONTENT_MD5"); - if (content_md5) { - for (const char *p = content_md5; *p; p++) { - if (!is_base64_for_content_md5(*p)) { - dout(0) << "NOTICE: bad content-md5 provided (not base64), aborting request p=" << *p << " " << (int)*p << dendl; - return false; - } - } - } - - const char *content_type = info.env->get("CONTENT_TYPE"); - - string date; - if (qsr) { - date = info.args.get("Expires"); - } else { - const char *str = info.env->get("HTTP_DATE"); - const char *req_date = str; - if (str) { - date = str; - } else { - req_date = info.env->get("HTTP_X_AMZ_DATE"); - if (!req_date) { - dout(0) << "NOTICE: missing date for auth header" << dendl; - return false; - } - } - - struct tm t; - if (!parse_rfc2616(req_date, &t)) { - dout(0) << "NOTICE: failed to parse date for auth header" << dendl; - return false; - } - if (t.tm_year < 70) { - dout(0) << "NOTICE: bad date (predates epoch): " << req_date << dendl; - return false; - } - header_time = utime_t(timegm(&t), 0); - } - - map<string, string>& meta_map = info.x_meta_map; - map<string, string>& sub_resources = info.args.get_sub_resources(); - - rgw_create_s3_canonical_header(info.method, content_md5, content_type, date.c_str(), - meta_map, info.request_uri.c_str(), sub_resources, - dest); - - return true; -} /* * verify that a signed request comes from the keyholder @@ -2015,7 +1956,7 @@ int RGW_Auth_S3::authorize(RGWRados *store, struct req_state *s) /* now verify signature */ string auth_hdr; - if (!get_auth_header(s->info, s->header_time, auth_hdr, qsr)) { + 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; } |