From: Radoslaw Zarzynski Date: Mon, 15 May 2017 13:33:50 +0000 (+0200) Subject: rgw: switch from boost::string_ref to string_view in AWSv4-related code (part 2). X-Git-Tag: v12.1.0~155^2~15 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8dab93de67082933a30640f8fefb7e0cf736230f;p=ceph.git rgw: switch from boost::string_ref to string_view in AWSv4-related code (part 2). Signed-off-by: Radoslaw Zarzynski --- diff --git a/src/rgw/rgw_auth_keystone.cc b/src/rgw/rgw_auth_keystone.cc index 614f837cecb7..5ab70e945977 100644 --- a/src/rgw/rgw_auth_keystone.cc +++ b/src/rgw/rgw_auth_keystone.cc @@ -289,9 +289,9 @@ TokenEngine::authenticate(const std::string& token, * Try to validate S3 auth against keystone s3token interface */ std::pair, int> -EC2Engine::get_from_keystone(const std::string& access_key_id, +EC2Engine::get_from_keystone(const boost::string_view& access_key_id, const std::string& string_to_sign, - const std::string& signature) const + const boost::string_view& signature) const { /* prepare keystone url */ std::string keystone_url = config.get_endpoint_url(); @@ -335,9 +335,9 @@ EC2Engine::get_from_keystone(const std::string& access_key_id, JSONFormatter credentials(false); credentials.open_object_section(""); credentials.open_object_section("credentials"); - credentials.dump_string("access", access_key_id); + credentials.dump_string("access", sview2cstr(access_key_id).data()); credentials.dump_string("token", rgw::to_base64(string_to_sign)); - credentials.dump_string("signature", signature); + credentials.dump_string("signature", sview2cstr(signature).data()); credentials.close_section(); credentials.close_section(); @@ -414,8 +414,8 @@ EC2Engine::get_creds_info(const EC2Engine::token_envelope_t& token, } rgw::auth::Engine::result_t EC2Engine::authenticate( - const std::string& access_key_id, - const std::string& signature, + const boost::string_view& access_key_id, + const boost::string_view& signature, const std::string& string_to_sign, const signature_factory_t& signature_factory, const completer_factory_t& completer_factory, diff --git a/src/rgw/rgw_auth_keystone.h b/src/rgw/rgw_auth_keystone.h index 934fec1cf482..53884ebe37f9 100644 --- a/src/rgw/rgw_auth_keystone.h +++ b/src/rgw/rgw_auth_keystone.h @@ -7,6 +7,7 @@ #include #include +#include #include "rgw_auth.h" #include "rgw_rest_s3.h" @@ -87,11 +88,11 @@ class EC2Engine : public rgw::auth::s3::AWSEngine { const std::vector& admin_roles ) const noexcept; std::pair, int> - get_from_keystone(const std::string& access_key_id, + get_from_keystone(const boost::string_view& access_key_id, const std::string& string_to_sign, - const std::string& signature) const; - result_t authenticate(const std::string& access_key_id, - const std::string& signature, + const boost::string_view& signature) const; + result_t authenticate(const boost::string_view& access_key_id, + const boost::string_view& signature, const std::string& string_to_sign, const signature_factory_t& signature_factory, const completer_factory_t& completer_factory, diff --git a/src/rgw/rgw_auth_s3.cc b/src/rgw/rgw_auth_s3.cc index 3cfffdfb0094..97b963bc6e8c 100644 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@ -13,7 +13,6 @@ #include "rgw_rest.h" #include "rgw_crypt_sanitize.h" -#include "include/str_list.h" #include #define dout_context g_ceph_context @@ -250,11 +249,11 @@ namespace s3 { /* FIXME(rzarzynski): duplicated from rgw_rest_s3.h. */ #define RGW_AUTH_GRACE_MINS 15 -static inline int parse_v4_credentials_qs(const req_info& info, /* in */ - std::string& credential, /* out */ - std::string& signedheaders, /* out */ - std::string& signature, /* out */ - std::string& date) /* out */ +static inline int parse_v4_query_string(const req_info& info, /* in */ + boost::string_view& credential, /* out */ + boost::string_view& signedheaders, /* out */ + boost::string_view& signature, /* out */ + boost::string_view& date) /* out */ { /* auth ships with req params ... */ @@ -266,8 +265,9 @@ static inline int parse_v4_credentials_qs(const req_info& info, /* in date = info.args.get("X-Amz-Date"); struct tm date_t; - if (!parse_iso8601(date.c_str(), &date_t, NULL, false)) + if (!parse_iso8601(sview2cstr(date).data(), &date_t, nullptr, false)) { return -EPERM; + } /* Used for pre-signatured url, We shouldn't return -ERR_REQUEST_TIME_SKEWED * when current time <= X-Amz-Expires */ @@ -276,12 +276,12 @@ static inline int parse_v4_credentials_qs(const req_info& info, /* in uint64_t now_req = 0; uint64_t now = ceph_clock_now(); - std::string expires = info.args.get("X-Amz-Expires"); + boost::string_view expires = info.args.get("X-Amz-Expires"); if (!expires.empty()) { /* X-Amz-Expires provides the time period, in seconds, for which the generated presigned URL is valid. The minimum value you can set is 1, and the maximum is 604800 (seven days) */ - time_t exp = atoll(expires.c_str()); + time_t exp = atoll(expires.data()); if ((exp < 1) || (exp > 7*24*60*60)) { dout(10) << "NOTICE: exp out of range, exp = " << exp << dendl; return -EPERM; @@ -319,56 +319,99 @@ static inline int parse_v4_credentials_qs(const req_info& info, /* in return 0; } -static inline int parse_v4_credentials_hdrs(const req_info& info, /* in */ - std::string& credential, /* out */ - std::string& signedheaders, /* out */ - std::string& signature, /* out */ - std::string& date) /* out */ +namespace { +static bool get_next_token(const boost::string_view& s, + size_t& pos, + const char* const delims, + boost::string_view& token) { - /* auth ships in headers ... */ + const size_t start = s.find_first_not_of(delims, pos); + if (start == boost::string_view::npos) { + pos = s.size(); + return false; + } - /* ------------------------- handle Credential header */ + size_t end = s.find_first_of(delims, start); + if (end != boost::string_view::npos) + pos = end + 1; + else { + pos = end = s.size(); + } - const char* const http_auth = info.env->get("HTTP_AUTHORIZATION"); - string auth_str = http_auth; + token = s.substr(start, end - start); + return true; +} - constexpr size_t min_len = strlen(AWS4_HMAC_SHA256_STR) + 1; - if (auth_str.length() < min_len) { - dout(10) << "credentials string is too short" << dendl; - return -EINVAL; +std::vector get_str_vec(const boost::string_view& str, + const char* const delims) +{ + std::vector str_vec; + + size_t pos = 0; + boost::string_view token; + while (pos < str.size()) { + if (get_next_token(str, pos, delims, token)) { + if (token.size() > 0) { + str_vec.push_back(token); + } + } } - list auth_list; - get_str_list(auth_str.substr(min_len), ",", auth_list); + return str_vec; +} - map kv; +std::vector get_str_vec(const boost::string_view& str) +{ + const char delims[] = ";,= \t"; + return get_str_vec(str, delims); +} +}; - for (string& s : auth_list) { - string key, val; - int ret = parse_key_value(s, key, val); - if (ret < 0) { - dout(10) << "NOTICE: failed to parse auth header (s=" << s << ")" << dendl; +static inline int parse_v4_auth_header(const req_info& info, /* in */ + boost::string_view& credential, /* out */ + boost::string_view& signedheaders, /* out */ + boost::string_view& signature, /* out */ + boost::string_view& date) /* out */ +{ + boost::string_view input(info.env->get("HTTP_AUTHORIZATION", "")); + try { + input = input.substr(::strlen(AWS4_HMAC_SHA256_STR) + 1); + } catch (std::out_of_range&) { + /* We should never ever run into this situation as the presence of + * AWS4_HMAC_SHA256_STR had been verified earlier. */ + dout(10) << "credentials string is too short" << dendl; + return -EINVAL; + } + + std::map kv; + for (const auto& s : get_str_vec(input, ",")) { + const auto parsed_pair = parse_key_value(s); + if (parsed_pair) { + kv[parsed_pair->first] = parsed_pair->second; + } else { + dout(10) << "NOTICE: failed to parse auth header (s=" << s << ")" + << dendl; return -EINVAL; } - kv[key] = std::move(val); } - static std::array aws4_presigned_required_keys = { + static const std::array required_keys = { "Credential", "SignedHeaders", "Signature" }; - for (string& k : aws4_presigned_required_keys) { - if (kv.find(k) == kv.end()) { + /* Ensure that the presigned required keys are really there. */ + for (const auto& k : required_keys) { + if (kv.find(k) == std::end(kv)) { dout(10) << "NOTICE: auth header missing key: " << k << dendl; return -EINVAL; } } - credential = std::move(kv["Credential"]); - signedheaders = std::move(kv["SignedHeaders"]); - signature = std::move(kv["Signature"]); + credential = kv["Credential"]; + signedheaders = kv["SignedHeaders"]; + signature = kv["Signature"]; /* sig hex str */ dout(10) << "v4 signature format = " << signature << dendl; @@ -388,25 +431,25 @@ static inline int parse_v4_credentials_hdrs(const req_info& info, /* i return 0; } -int parse_credentials(const req_info& info, /* in */ - std::string& access_key_id, /* out */ - std::string& credential_scope, /* out */ - std::string& signedheaders, /* out */ - std::string& signature, /* out */ - std::string& date, /* out */ - bool& using_qs) /* out */ +int parse_credentials(const req_info& info, /* in */ + boost::string_view& access_key_id, /* out */ + boost::string_view& credential_scope, /* out */ + boost::string_view& signedheaders, /* out */ + boost::string_view& signature, /* out */ + boost::string_view& date, /* out */ + bool& using_qs) /* out */ { const char* const http_auth = info.env->get("HTTP_AUTHORIZATION"); using_qs = http_auth == nullptr || http_auth[0] == '\0'; int ret; - std::string credential; + boost::string_view credential; if (using_qs) { - ret = parse_v4_credentials_qs(info, credential, signedheaders, - signature, date); + ret = parse_v4_query_string(info, credential, signedheaders, + signature, date); } else { - ret = parse_v4_credentials_hdrs(info, credential, signedheaders, - signature, date); + ret = parse_v4_auth_header(info, credential, signedheaders, + signature, date); } if (ret < 0) { @@ -532,12 +575,12 @@ std::string get_v4_canonical_qs(const req_info& info, const bool using_qs) boost::optional get_v4_canonical_headers(const req_info& info, - const std::string& signedheaders, + const boost::string_view& signedheaders, const bool using_qs, const bool force_boto2_compat) { map canonical_hdrs_map; - istringstream sh(signedheaders); + istringstream sh(signedheaders.to_string()); string token; string port = info.env->get("SERVER_PORT", ""); string secure_port = info.env->get("SERVER_PORT_SECURE", ""); @@ -598,7 +641,7 @@ get_v4_canon_req_hash(CephContext* cct, const std::string& canonical_uri, const std::string& canonical_qs, const std::string& canonical_hdrs, - const std::string& signed_hdrs, + const boost::string_view& signed_hdrs, const boost::string_view& request_payload_hash) { ldout(cct, 10) << "payload request hash = " << request_payload_hash << dendl; @@ -612,7 +655,7 @@ get_v4_canon_req_hash(CephContext* cct, .append("\n") .append(canonical_hdrs) .append("\n") - .append(signed_hdrs) + .append(signed_hdrs.data(), signed_hdrs.length()) .append("\n") .append(request_payload_hash.data(), request_payload_hash.length()); @@ -830,10 +873,14 @@ AWSv4ComplMulti::calc_chunk_signature(const std::string& payload_hash) const { std::string string_to_sign = "AWS4-HMAC-SHA256-PAYLOAD\n"; - string_to_sign.append(date + "\n"); - string_to_sign.append(credential_scope + "\n"); - string_to_sign.append(prev_chunk_signature + "\n"); - string_to_sign.append(std::string(AWS4_EMPTY_PAYLOAD_HASH) + "\n"); + string_to_sign.append(date.data(), date.length()); + string_to_sign.append("\n"); + string_to_sign.append(credential_scope.data(), credential_scope.length()); + string_to_sign.append("\n"); + string_to_sign.append(prev_chunk_signature); + string_to_sign.append("\n"); + string_to_sign.append(AWS4_EMPTY_PAYLOAD_HASH, strlen(AWS4_EMPTY_PAYLOAD_HASH)); + string_to_sign.append("\n"); string_to_sign.append(payload_hash); ldout(cct, 20) << "AWSv4ComplMulti: string_to_sign=\n" << string_to_sign @@ -988,9 +1035,9 @@ bool AWSv4ComplMulti::complete() rgw::auth::Completer::cmplptr_t AWSv4ComplMulti::create(const req_state* const s, - std::string date, - std::string credential_scope, - std::string seed_signature, + boost::string_view date, + boost::string_view credential_scope, + boost::string_view seed_signature, const boost::optional& secret_key) { if (!secret_key) { diff --git a/src/rgw/rgw_auth_s3.h b/src/rgw/rgw_auth_s3.h index 69ea89f3d527..11abf9ccc0e7 100644 --- a/src/rgw/rgw_auth_s3.h +++ b/src/rgw/rgw_auth_s3.h @@ -141,10 +141,8 @@ class AWSv4ComplMulti : public rgw::auth::Completer, CephContext* const cct; - /* TODO(rzarzynski): move to boost::string_ref. This should be just fine - * as (all?) parameters here are actually views over req_info. */ - const std::string date; - const std::string credential_scope; + const boost::string_view date; + const boost::string_view credential_scope; const signing_key_t signing_key; class ChunkMeta { @@ -160,7 +158,7 @@ class AWSv4ComplMulti : public rgw::auth::Completer, signature(signature.to_string()) { } - ChunkMeta(const boost::string_ref signature) + ChunkMeta(const boost::string_view& signature) : signature(signature.to_string()) { } @@ -187,7 +185,7 @@ class AWSv4ComplMulti : public rgw::auth::Completer, /* Factory: create an object representing metadata of first, initial chunk * in a stream. */ - static ChunkMeta create_first(const boost::string_ref seed_signature) { + static ChunkMeta create_first(const boost::string_view& seed_signature) { return ChunkMeta(seed_signature); } @@ -212,9 +210,9 @@ public: /* We need the constructor to be public because of the std::make_shared that * is employed by the create() method. */ AWSv4ComplMulti(const req_state* const s, - std::string date, - std::string credential_scope, - std::string seed_signature, + boost::string_view date, + boost::string_view credential_scope, + boost::string_view seed_signature, const signing_key_t& signing_key) : io_base_t(nullptr), cct(s->cct), @@ -244,9 +242,9 @@ public: /* Factories. */ static cmplptr_t create(const req_state* s, - std::string date, - std::string credential_scope, - std::string seed_signature, + boost::string_view date, + boost::string_view credential_scope, + boost::string_view seed_signature, const boost::optional& secret_key); }; @@ -324,13 +322,13 @@ static constexpr char AWS4_HMAC_SHA256_STR[] = "AWS4-HMAC-SHA256"; static constexpr char AWS4_EMPTY_PAYLOAD_HASH[] = \ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; -int parse_credentials(const req_info& info, /* in */ - std::string& access_key_id, /* out */ - std::string& credential_scope, /* out */ - std::string& signedheaders, /* out */ - std::string& signature, /* out */ - std::string& date, /* out */ - bool& using_qs); /* out */ +int parse_credentials(const req_info& info, /* in */ + boost::string_view& access_key_id, /* out */ + boost::string_view& credential_scope, /* out */ + boost::string_view& signedheaders, /* out */ + boost::string_view& signature, /* out */ + boost::string_view& date, /* out */ + bool& using_qs); /* out */ static inline std::string get_v4_canonical_uri(const req_info& info) { /* The code should normalize according to RFC 3986 but S3 does NOT do path @@ -396,10 +394,11 @@ static inline bool is_v4_payload_streamed(const char* const exp_payload_hash) std::string get_v4_canonical_qs(const req_info& info, bool using_qs); -boost::optional get_v4_canonical_headers(const req_info& info, - const std::string& signedheaders, - bool using_qs, - bool force_boto2_compat); +boost::optional +get_v4_canonical_headers(const req_info& info, + const boost::string_view& signedheaders, + bool using_qs, + bool force_boto2_compat); extern sha256_digest_t get_v4_canon_req_hash(CephContext* cct, @@ -407,7 +406,7 @@ get_v4_canon_req_hash(CephContext* cct, const std::string& canonical_uri, const std::string& canonical_qs, const std::string& canonical_hdrs, - const std::string& signed_hdrs, + const boost::string_view& signed_hdrs, const boost::string_view& request_payload_hash); std::string get_v4_string_to_sign(CephContext* cct, diff --git a/src/rgw/rgw_b64.h b/src/rgw/rgw_b64.h index 3f79eccd0ee2..c4ad98806692 100644 --- a/src/rgw/rgw_b64.h +++ b/src/rgw/rgw_b64.h @@ -5,6 +5,7 @@ #define RGW_B64_H #include +#include #include #include #include @@ -18,19 +19,19 @@ namespace rgw { * A header-only Base64 encoder built on boost::archive. The * formula is based on a class poposed for inclusion in boost in * 2011 by Denis Shevchenko (abandoned), updated slightly - * (e.g., uses boost::string_ref). + * (e.g., uses boost::string_view). * * Also, wrap_width added as template argument, based on * feedback from Marcus. */ template::max()> - inline std::string to_base64(boost::string_ref sref) + inline std::string to_base64(boost::string_view sview) { using namespace boost::archive::iterators; // output must be =padded modulo 3 - auto psize = sref.size(); + auto psize = sview.size(); while ((psize % 3) != 0) { ++psize; } @@ -42,26 +43,26 @@ namespace rgw { insert_linebreaks< base64_from_binary< transform_width< - boost::string_ref::const_iterator + boost::string_view::const_iterator ,6,8> > ,wrap_width > b64_iter; - std::string outstr(b64_iter(sref.data()), - b64_iter(sref.data() + sref.size())); + std::string outstr(b64_iter(sview.data()), + b64_iter(sview.data() + sview.size())); // pad outstr with '=' to a length that is a multiple of 3 - for (size_t ix = 0; ix < (psize-sref.size()); ++ix) + for (size_t ix = 0; ix < (psize-sview.size()); ++ix) outstr.push_back('='); return outstr; } - inline std::string from_base64(boost::string_ref sref) + inline std::string from_base64(boost::string_view sview) { using namespace boost::archive::iterators; - if (sref.empty()) + if (sview.empty()) return std::string(); /* MIME-compliant input will have line-breaks, so we have to * filter WS */ @@ -69,19 +70,18 @@ namespace rgw { transform_width< binary_from_base64< remove_whitespace< - boost::string_ref::const_iterator>> + boost::string_view::const_iterator>> ,8,6 > b64_iter; - while (sref.back() == '=') - sref.remove_suffix(1); + while (sview.back() == '=') + sview.remove_suffix(1); - std::string outstr(b64_iter(sref.data()), - b64_iter(sref.data() + sref.size())); + std::string outstr(b64_iter(sview.data()), + b64_iter(sview.data() + sview.size())); return outstr; } - } /* namespace */ #endif /* RGW_B64_H */ diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc index f107ad33eb19..99993e1883f8 100644 --- a/src/rgw/rgw_common.cc +++ b/src/rgw/rgw_common.cc @@ -464,6 +464,17 @@ static void trim_whitespace(const string& src, string& dst) dst = src.substr(start, end - start + 1); } +static boost::string_view trim_whitespace(const boost::string_view& src) +{ + const char* spacestr = " \t\n\r\f\v"; + const size_t start = src.find_first_not_of(spacestr); + if (start == boost::string_view::npos) { + return boost::string_view(); + } + + const size_t end = src.find_last_not_of(spacestr); + return src.substr(start, end - start + 1); +} static bool check_str_end(const char *s) { if (!s) @@ -544,8 +555,7 @@ bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns, bool extended_for dout(0) << "parse_iso8601 failed" << dendl; return false; } - string str; - trim_whitespace(p, str); + const boost::string_view str = trim_whitespace(p); int len = str.size(); if (len == 0 || (len == 1 && str[0] == 'Z')) @@ -556,8 +566,8 @@ bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns, bool extended_for return false; uint32_t ms; - string nsstr = str.substr(1, len - 2); - int r = stringtoul(nsstr, &ms); + boost::string_view nsstr = str.substr(1, len - 2); + int r = stringtoul(nsstr.to_string(), &ms); if (r < 0) return false; @@ -608,6 +618,27 @@ int parse_key_value(string& in_str, string& key, string& val) return parse_key_value(in_str, "=", key,val); } +boost::optional> +parse_key_value(const boost::string_view& in_str, + const boost::string_view& delim) +{ + const size_t pos = in_str.find(delim); + if (pos == boost::string_view::npos) { + return boost::none; + } + + const auto key = trim_whitespace(in_str.substr(0, pos)); + const auto val = trim_whitespace(in_str.substr(pos + 1)); + + return std::make_pair(key, val); +} + +boost::optional> +parse_key_value(const boost::string_view& in_str) +{ + return parse_key_value(in_str, "="); +} + int parse_time(const char *time_str, real_time *time) { struct tm tm; @@ -1453,9 +1484,9 @@ string rgw_trim_whitespace(const string& src) return src.substr(start, end - start + 1); } -boost::string_ref rgw_trim_whitespace(const boost::string_ref& src) +boost::string_view rgw_trim_whitespace(const boost::string_view& src) { - boost::string_ref res = src; + boost::string_view res = src; while (res.size() > 0 && std::isspace(res.front())) { res.remove_prefix(1); @@ -1528,7 +1559,7 @@ int RGWUserCaps::get_cap(const string& cap, string& type, uint32_t *pperm) { int pos = cap.find('='); if (pos >= 0) { - trim_whitespace(cap.substr(0, pos), type); + type = trim_whitespace(cap.substr(0, pos)).to_string(); } if (!is_valid_cap_type(type)) diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 6e425016ecd9..a90a0daa9245 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -2153,12 +2153,20 @@ extern string rgw_string_unquote(const string& s); extern void parse_csv_string(const string& ival, vector& ovals); extern int parse_key_value(string& in_str, string& key, string& val); extern int parse_key_value(string& in_str, const char *delim, string& key, string& val); + +extern boost::optional> +parse_key_value(const boost::string_view& in_str, + const boost::string_view& delim); +extern boost::optional> +parse_key_value(const boost::string_view& in_str); + + /** time parsing */ extern int parse_time(const char *time_str, real_time *time); extern bool parse_rfc2616(const char *s, struct tm *t); extern bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns = NULL, bool extended_format = true); extern string rgw_trim_whitespace(const string& src); -extern boost::string_ref rgw_trim_whitespace(const boost::string_ref& src); +extern boost::string_view rgw_trim_whitespace(const boost::string_view& src); extern string rgw_trim_quotes(const string& val); extern void rgw_to_iso8601(const real_time& t, char *dest, int buf_size); diff --git a/src/rgw/rgw_crypt.cc b/src/rgw/rgw_crypt.cc index 0d57f4da270a..9fb474c46f0e 100644 --- a/src/rgw/rgw_crypt.cc +++ b/src/rgw/rgw_crypt.cc @@ -9,7 +9,7 @@ #include #include #include "include/assert.h" -#include +#include #include #include "include/str_map.h" #include "crypto/crypto_accel.h" @@ -923,8 +923,8 @@ static int get_barbican_url(CephContext * const cct, } static int request_key_from_barbican(CephContext *cct, - boost::string_ref key_id, - boost::string_ref key_selector, + boost::string_view key_id, + boost::string_view key_selector, const std::string& barbican_token, std::string& actual_key) { std::string secret_url; @@ -967,8 +967,8 @@ static map get_str_map(const string &str) { } static int get_actual_key_from_kms(CephContext *cct, - boost::string_ref key_id, - boost::string_ref key_selector, + boost::string_view key_id, + boost::string_view key_selector, std::string& actual_key) { int res = 0; @@ -1012,7 +1012,7 @@ static int get_actual_key_from_kms(CephContext *cct, static inline void set_attr(map& attrs, const char* key, - boost::string_ref value) + boost::string_view value) { bufferlist bl; bl.append(value.data(), value.size()); @@ -1051,7 +1051,7 @@ static const crypt_option_names crypt_options[] = { {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID", "x-amz-server-side-encryption-aws-kms-key-id"}, }; -static boost::string_ref get_crypt_attribute( +static boost::string_view get_crypt_attribute( RGWEnv* env, std::mapfind(crypt_options[option].post_part_name); if (iter == parts->end()) - return boost::string_ref(); + return boost::string_view(); bufferlist& data = iter->second.data; - boost::string_ref str = boost::string_ref(data.c_str(), data.length()); + boost::string_view str = boost::string_view(data.c_str(), data.length()); return rgw_trim_whitespace(str); } else { const char* hdr = env->get(crypt_options[option].http_header_name, nullptr); if (hdr != nullptr) { - return boost::string_ref(hdr); + return boost::string_view(hdr); } else { - return boost::string_ref(); + return boost::string_view(); } } } @@ -1091,7 +1091,7 @@ int rgw_s3_prepare_encrypt(struct req_state* s, int res = 0; crypt_http_responses.clear(); { - boost::string_ref req_sse_ca = + boost::string_view req_sse_ca = get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM); if (! req_sse_ca.empty()) { if (req_sse_ca != "AES256") { @@ -1106,7 +1106,7 @@ int rgw_s3_prepare_encrypt(struct req_state* s, if (key_bin.size() != AES_256_CBC::AES_256_KEYSIZE) { return -ERR_INVALID_REQUEST; } - boost::string_ref keymd5 = + boost::string_view keymd5 = get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5); std::string keymd5_bin = from_base64(keymd5); if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) { @@ -1135,7 +1135,7 @@ int rgw_s3_prepare_encrypt(struct req_state* s, return 0; } /* AMAZON server side encryption with KMS (key management service) */ - boost::string_ref req_sse = + boost::string_view req_sse = get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION); if (! req_sse.empty()) { if (req_sse != "aws:kms") { @@ -1145,7 +1145,7 @@ int rgw_s3_prepare_encrypt(struct req_state* s, !s->info.env->exists("SERVER_PORT_SECURE")) { return -ERR_INVALID_REQUEST; } - boost::string_ref key_id = + boost::string_view key_id = get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID); if (key_id.empty()) { return -ERR_INVALID_ACCESS_KEY; diff --git a/src/rgw/rgw_crypt.h b/src/rgw/rgw_crypt.h index 1774983758d0..77f07f8f2fe2 100644 --- a/src/rgw/rgw_crypt.h +++ b/src/rgw/rgw_crypt.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include /** * \brief Interface for block encryption methods diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 4f0ccc896f20..056956099cf2 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -3567,7 +3567,7 @@ AWSGeneralAbstractor::get_auth_data(const req_state* const s) const } static inline -std::string v4_signature(const std::string& credential_scope, +std::string v4_signature(const boost::string_view& credential_scope, CephContext* const cct, const boost::string_view& secret_key, @@ -3592,12 +3592,12 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s, /* FIXME: const. */ bool using_qs) const { - std::string access_key_id; - std::string signed_hdrs; + boost::string_view access_key_id; + boost::string_view signed_hdrs; - std::string date; - std::string credential_scope; - std::string client_signature; + boost::string_view date; + boost::string_view credential_scope; + boost::string_view client_signature; int ret = rgw::auth::s3::parse_credentials(s->info, access_key_id, @@ -3637,7 +3637,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s, std::move(canonical_uri), std::move(canonical_qs), std::move(*canonical_headers), - std::move(signed_hdrs), + signed_hdrs, exp_payload_hash); auto string_to_sign = \ @@ -3666,8 +3666,8 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s, * aws4_auth_needs_complete and aws4_auth_streaming_mode are set to false * by default. We don't need to change that. */ if (is_v4_payload_unsigned(exp_payload_hash) || is_v4_payload_empty(s)) { - return std::make_tuple(std::move(access_key_id), - std::move(client_signature), + return std::make_tuple(access_key_id, + client_signature, std::move(string_to_sign), sig_factory, null_completer_factory); @@ -3703,8 +3703,8 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s, const auto cmpl_factory = std::bind(AWSv4ComplSingle::create, s, std::placeholders::_1); - return std::make_tuple(std::move(access_key_id), - std::move(client_signature), + return std::make_tuple(access_key_id, + client_signature, std::move(string_to_sign), sig_factory, cmpl_factory); @@ -3739,12 +3739,12 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s, * for CanonReq. */ const auto cmpl_factory = std::bind(AWSv4ComplMulti::create, s, - std::move(date), - std::move(credential_scope), + date, + credential_scope, client_signature, std::placeholders::_1); - return std::make_tuple(std::move(access_key_id), - std::move(client_signature), + return std::make_tuple(access_key_id, + client_signature, std::move(string_to_sign), sig_factory, cmpl_factory); @@ -3760,8 +3760,8 @@ std::tuple AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const { - std::string access_key_id; - std::string signature; + boost::string_view access_key_id; + boost::string_view signature; bool qsr = false; const char* http_auth = s->info.env->get("HTTP_AUTHORIZATION"); @@ -3772,9 +3772,11 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const signature = s->info.args.get("Signature"); qsr = true; - std::string expires = s->info.args.get("Expires"); + boost::string_view expires = s->info.args.get("Expires"); if (! expires.empty()) { - const time_t exp = atoll(expires.c_str()); + /* It looks we have the guarantee that expires is a null-terminated, + * and thus string_view::data() can be safely used. */ + const time_t exp = atoll(expires.data()); time_t now; time(&now); @@ -3784,9 +3786,9 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const } } else { /* The "Authorization" HTTP header is being used. */ - const std::string auth_str(http_auth + strlen("AWS ")); + const boost::string_view auth_str(http_auth + strlen("AWS ")); const size_t pos = auth_str.rfind(':'); - if (pos != std::string::npos) { + if (pos != boost::string_view::npos) { access_key_id = auth_str.substr(0, pos); signature = auth_str.substr(pos + 1); } @@ -3838,15 +3840,15 @@ std::tuple AWSBrowserUploadAbstractor::get_auth_data_v4(const req_state* const s) const { - const std::string& credential = s->auth.s3_postobj_creds.x_amz_credential; + const boost::string_view credential = s->auth.s3_postobj_creds.x_amz_credential; /* grab access key id */ const size_t pos = credential.find("/"); - const std::string access_key_id = credential.substr(0, pos); + const boost::string_view access_key_id = credential.substr(0, pos); dout(10) << "access key id = " << access_key_id << dendl; /* grab credential scope */ - const std::string credential_scope = credential.substr(pos + 1); + const boost::string_view credential_scope = credential.substr(pos + 1); dout(10) << "credential scope = " << credential_scope << dendl; const auto sig_factory = std::bind(v4_signature, @@ -3934,8 +3936,8 @@ rgw::auth::s3::LDAPEngine::get_creds_info(const rgw::RGWToken& token) const noex rgw::auth::Engine::result_t rgw::auth::s3::LDAPEngine::authenticate( - const std::string& access_key_id, - const std::string& signature, + const boost::string_view& access_key_id, + const boost::string_view& signature, const std::string& string_to_sign, const signature_factory_t& signature_factory, const completer_factory_t& completer_factory, @@ -3978,8 +3980,8 @@ rgw::auth::s3::LDAPEngine::authenticate( /* LocalEndgine */ rgw::auth::Engine::result_t rgw::auth::s3::LocalEngine::authenticate( - const std::string& access_key_id, - const std::string& signature, + const boost::string_view& _access_key_id, + const boost::string_view& signature, const std::string& string_to_sign, const signature_factory_t& signature_factory, const completer_factory_t& completer_factory, @@ -3987,6 +3989,8 @@ rgw::auth::s3::LocalEngine::authenticate( { /* get the user info */ RGWUserInfo user_info; + /* TODO(rzarzynski): we need to have string-view taking variant. */ + const std::string access_key_id = _access_key_id.to_string(); if (rgw_get_user_info_by_access_key(store, access_key_id, user_info) < 0) { ldout(cct, 5) << "error reading user info, uid=" << access_key_id << " can't authenticate" << dendl; diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index 8bf803628caa..0c34d5b66a19 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -8,6 +8,8 @@ #include +#include + #include "rgw_op.h" #include "rgw_rest.h" #include "rgw_http_errors.h" @@ -664,8 +666,8 @@ public: public: virtual ~VersionAbstractor() {}; - using access_key_id_t = std::string; - using signature_t = std::string; + using access_key_id_t = boost::string_view; + using signature_t = boost::string_view; using string_to_sign_t = std::string; /* Transformation for crafting the AWS signature at server side which is @@ -707,8 +709,8 @@ protected: /* TODO(rzarzynski): clean up. We've too many input parameter hee. Also * the signature get_auth_data() of VersionAbstractor is too complicated. * Replace these thing with a simple, dedicated structure. */ - virtual result_t authenticate(const std::string& access_key_id, - const std::string& signature, + virtual result_t authenticate(const boost::string_view& access_key_id, + const boost::string_view& signature, const std::string& string_to_sign, const signature_factory_t& signature_factory, const completer_factory_t& completer_factory, @@ -716,8 +718,8 @@ protected: public: result_t authenticate(const req_state* const s) const final { - std::string access_key_id; - std::string signature; + boost::string_view access_key_id; + boost::string_view signature; std::string string_to_sign; VersionAbstractor::signature_factory_t signature_factory; @@ -818,8 +820,8 @@ protected: acl_strategy_t get_acl_strategy() const; auth_info_t get_creds_info(const rgw::RGWToken& token) const noexcept; - result_t authenticate(const std::string& access_key_id, - const std::string& signature, + result_t authenticate(const boost::string_view& access_key_id, + const boost::string_view& signature, const std::string& string_to_sign, const signature_factory_t& signature_factory, const completer_factory_t& completer_factory, @@ -847,8 +849,8 @@ class LocalEngine : public AWSEngine { RGWRados* const store; const rgw::auth::LocalApplier::Factory* const apl_factory; - result_t authenticate(const std::string& access_key_id, - const std::string& signature, + result_t authenticate(const boost::string_view& access_key_id, + const boost::string_view& signature, const std::string& string_to_sign, const signature_factory_t& signature_factory, const completer_factory_t& completer_factory, diff --git a/src/rgw/rgw_string.h b/src/rgw/rgw_string.h index 74e023b4cb19..6bc529cb8604 100644 --- a/src/rgw/rgw_string.h +++ b/src/rgw/rgw_string.h @@ -7,6 +7,8 @@ #include #include +#include +#include struct ltstr_nocase { bool operator()(const string& s1, const string& s2) const @@ -94,4 +96,20 @@ static inline int stringtoul(const string& s, uint32_t *val) return 0; } +/* A converter between boost::string_view and null-terminated C-strings. + * It copies memory while trying to utilize the local memory instead of + * issuing dynamic allocations. */ +template +static inline boost::container::small_vector +sview2cstr(const boost::string_view& sv) +{ + boost::container::small_vector cstr; + cstr.reserve(sv.size() + sizeof('\0')); + + cstr.assign(std::begin(sv), std::end(sv)); + cstr.push_back('\0'); + + return cstr; +} + #endif