From: Radoslaw Zarzynski Date: Thu, 13 Apr 2017 16:49:38 +0000 (+0200) Subject: rgw: dissect AWSv4's Canonical QS crafting into a separated function. X-Git-Tag: v12.1.0~155^2~64 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b000b3528278e19b4c5f2f74b8711f10ca5633f8;p=ceph.git rgw: dissect AWSv4's Canonical QS crafting into a separated function. Signed-off-by: Radoslaw Zarzynski --- diff --git a/src/rgw/rgw_auth_s3.cc b/src/rgw/rgw_auth_s3.cc index 2b5c32741cdd..c988555cf301 100644 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@ -239,6 +239,97 @@ namespace rgw { namespace auth { namespace s3 { +static inline bool char_needs_aws4_escaping(const char c) +{ + if ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')) { + return false; + } + + switch (c) { + case '-': + case '_': + case '.': + case '~': + return false; + } + return true; +} + +static inline void aws4_uri_encode(const string& src, string& dst) +{ + const char *p = src.c_str(); + for (unsigned i = 0; i < src.size(); i++, p++) { + if (char_needs_aws4_escaping(*p)) { + rgw_uri_escape_char(*p, dst); + continue; + } + + dst.append(p, 1); + } +} + +std::string get_v4_canonical_qs(const req_info& info, const bool using_qs) +{ + std::string canonical_qs = info.request_params; + + if (!canonical_qs.empty()) { + + /* Handle case when query string exists. Step 3 in + * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html */ + map canonical_qs_map; + istringstream cqs(canonical_qs); + string keyval; + + while (getline(cqs, keyval, '&')) { + string key, val; + istringstream kv(keyval); + getline(kv, key, '='); + getline(kv, val, '='); + if (!using_qs || key != "X-Amz-Signature") { + string encoded_key; + string encoded_val; + if (key != "X-Amz-Credential") { + string key_decoded; + url_decode(key, key_decoded); + if (key.length() != key_decoded.length()) { + encoded_key = key; + } else { + aws4_uri_encode(key, encoded_key); + } + string val_decoded; + url_decode(val, val_decoded); + if (val.length() != val_decoded.length()) { + encoded_val = val; + } else { + aws4_uri_encode(val, encoded_val); + } + } else { + encoded_key = key; + encoded_val = val; + } + canonical_qs_map[encoded_key] = encoded_val; + } + } + + canonical_qs = ""; + + map::iterator last = canonical_qs_map.end(); + --last; + + for (map::iterator it = canonical_qs_map.begin(); + it != canonical_qs_map.end(); ++it) { + canonical_qs.append(it->first + "=" + it->second); + if (it != last) { + canonical_qs.append("&"); + } + } + } + + return canonical_qs; +} + std::string hash_string_sha256(const char* const data, const int len) { std::string dest; diff --git a/src/rgw/rgw_auth_s3.h b/src/rgw/rgw_auth_s3.h index f81559097497..f6b455a5eee3 100644 --- a/src/rgw/rgw_auth_s3.h +++ b/src/rgw/rgw_auth_s3.h @@ -176,6 +176,8 @@ static inline std::string get_v4_canonical_uri(const req_info& info) { return canonical_uri; } +std::string get_v4_canonical_qs(const req_info& info, bool using_qs); + std::string hash_string_sha256(const char* data, int len); std::string get_v4_canonical_request_hash(CephContext* cct, diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 4541b9f9c231..4bf44051eb0e 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -3531,37 +3531,6 @@ static inline bool is_base64_for_content_md5(unsigned char c) { return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '=')); } -static bool char_needs_aws4_escaping(char c) -{ - if ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9')) { - return false; - } - - switch (c) { - case '-': - case '_': - case '.': - case '~': - return false; - } - return true; -} - -static void aws4_uri_encode(const string& src, string& dst) -{ - const char *p = src.c_str(); - for (unsigned i = 0; i < src.size(); i++, p++) { - if (char_needs_aws4_escaping(*p)) { - rgw_uri_escape_char(*p, dst); - continue; - } - - dst.append(p, 1); - } -} - static std::array aws4_presigned_required_keys = { "Credential", "SignedHeaders", "Signature" }; /* @@ -3749,62 +3718,8 @@ int RGW_Auth_S3::authorize_v4(RGWRados *store, struct req_state *s, bool force_b s->aws4_auth->canonical_uri = rgw::auth::s3::get_v4_canonical_uri(s->info); /* craft canonical query string */ - s->aws4_auth->canonical_qs = s->info.request_params; - - if (!s->aws4_auth->canonical_qs.empty()) { - - /* handle case when query string exists. Step 3 in - * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html */ - - map canonical_qs_map; - istringstream cqs(s->aws4_auth->canonical_qs); - string keyval; - - while (getline(cqs, keyval, '&')) { - string key, val; - istringstream kv(keyval); - getline(kv, key, '='); - getline(kv, val, '='); - if (!using_qs || key != "X-Amz-Signature") { - string encoded_key; - string encoded_val; - if (key != "X-Amz-Credential") { - string key_decoded; - url_decode(key, key_decoded); - if (key.length() != key_decoded.length()) { - encoded_key = key; - } else { - aws4_uri_encode(key, encoded_key); - } - string val_decoded; - url_decode(val, val_decoded); - if (val.length() != val_decoded.length()) { - encoded_val = val; - } else { - aws4_uri_encode(val, encoded_val); - } - } else { - encoded_key = key; - encoded_val = val; - } - canonical_qs_map[encoded_key] = encoded_val; - } - } - - s->aws4_auth->canonical_qs = ""; - - map::iterator last = canonical_qs_map.end(); - --last; - - for (map::iterator it = canonical_qs_map.begin(); - it != canonical_qs_map.end(); ++it) { - s->aws4_auth->canonical_qs.append(it->first + "=" + it->second); - if (it != last) { - s->aws4_auth->canonical_qs.append("&"); - } - } - - } + s->aws4_auth->canonical_qs = \ + rgw::auth::s3::get_v4_canonical_qs(s->info, using_qs); /* craft canonical headers */