X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ceph%2Fsrc%2Frgw%2Frgw_rest_sts.cc;h=093c92d3633ea5e2c5d16eb4a67e9dc6ffc6d0eb;hb=20effc670b57271cb089376d6d0800990e5218d5;hp=3791ef0f1adebe20ac5504ec609865564ef7894e;hpb=494da23a05e25ed98f5539f3b89e6af3cafe3fec;p=ceph.git diff --git a/ceph/src/rgw/rgw_rest_sts.cc b/ceph/src/rgw/rgw_rest_sts.cc index 3791ef0f1..093c92d36 100644 --- a/ceph/src/rgw/rgw_rest_sts.cc +++ b/ceph/src/rgw/rgw_rest_sts.cc @@ -1,5 +1,11 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab +// vim: ts=8 sw=2 smarttab ft=cpp +#include +#include +#include +#include +#include +#include #include #include @@ -7,8 +13,9 @@ #include #include -#include "ceph_ver.h" + +#include "ceph_ver.h" #include "common/Formatter.h" #include "common/utf8.h" #include "common/ceph_json.h" @@ -16,8 +23,8 @@ #include "rgw_rest.h" #include "rgw_auth.h" #include "rgw_auth_registry.h" +#include "jwt-cpp/jwt.h" #include "rgw_rest_sts.h" -#include "rgw_auth_s3.h" #include "rgw_formats.h" #include "rgw_client_io.h" @@ -28,19 +35,15 @@ #include "rgw_iam_policy_keywords.h" #include "rgw_sts.h" +#include "rgw_rest_oidc_provider.h" -#include -#include -#include - -#include #define dout_context g_ceph_context #define dout_subsys ceph_subsys_rgw -namespace rgw { -namespace auth { -namespace sts { +using namespace std; + +namespace rgw::auth::sts { bool WebTokenEngine::is_applicable(const std::string& token) const noexcept @@ -48,110 +51,503 @@ WebTokenEngine::is_applicable(const std::string& token) const noexcept return ! token.empty(); } -boost::optional -WebTokenEngine::get_from_idp(const DoutPrefixProvider* dpp, const std::string& token) const +std::string +WebTokenEngine::get_role_tenant(const string& role_arn) const +{ + string tenant; + auto r_arn = rgw::ARN::parse(role_arn); + if (r_arn) { + tenant = r_arn->account; + } + return tenant; +} + +std::string +WebTokenEngine::get_role_name(const string& role_arn) const +{ + string role_name; + auto r_arn = rgw::ARN::parse(role_arn); + if (r_arn) { + role_name = r_arn->resource; + } + if (!role_name.empty()) { + auto pos = role_name.find_last_of('/'); + if(pos != string::npos) { + role_name = role_name.substr(pos + 1); + } + } + return role_name; +} + +std::unique_ptr +WebTokenEngine::get_provider(const DoutPrefixProvider *dpp, const string& role_arn, const string& iss) const +{ + string tenant = get_role_tenant(role_arn); + + string idp_url = iss; + auto pos = idp_url.find("http://"); + if (pos == std::string::npos) { + pos = idp_url.find("https://"); + if (pos != std::string::npos) { + idp_url.erase(pos, 8); + } else { + pos = idp_url.find("www."); + if (pos != std::string::npos) { + idp_url.erase(pos, 4); + } + } + } else { + idp_url.erase(pos, 7); + } + auto provider_arn = rgw::ARN(idp_url, "oidc-provider", tenant); + string p_arn = provider_arn.to_string(); + std::unique_ptr provider = store->get_oidc_provider(); + provider->set_arn(p_arn); + provider->set_tenant(tenant); + auto ret = provider->get(dpp); + if (ret < 0) { + return nullptr; + } + return provider; +} + +bool +WebTokenEngine::is_client_id_valid(vector& client_ids, const string& client_id) const +{ + for (auto it : client_ids) { + if (it == client_id) { + return true; + } + } + return false; +} + +bool +WebTokenEngine::is_cert_valid(const vector& thumbprints, const string& cert) const +{ + //calculate thumbprint of cert + std::unique_ptr certbio(BIO_new_mem_buf(cert.data(), cert.size()), BIO_free_all); + std::unique_ptr keybio(BIO_new(BIO_s_mem()), BIO_free_all); + string pw=""; + std::unique_ptr x_509cert(PEM_read_bio_X509(certbio.get(), nullptr, nullptr, const_cast(pw.c_str())), X509_free); + const EVP_MD* fprint_type = EVP_sha1(); + unsigned int fprint_size; + unsigned char fprint[EVP_MAX_MD_SIZE]; + + if (!X509_digest(x_509cert.get(), fprint_type, fprint, &fprint_size)) { + return false; + } + stringstream ss; + for (unsigned int i = 0; i < fprint_size; i++) { + ss << std::setfill('0') << std::setw(2) << std::hex << (0xFF & (unsigned int)fprint[i]); + } + std::string digest = ss.str(); + + for (auto& it : thumbprints) { + if (boost::iequals(it,digest)) { + return true; + } + } + return false; +} + +template +void +WebTokenEngine::recurse_and_insert(const string& key, const jwt::claim& c, T& t) const +{ + string s_val; + jwt::claim::type c_type = c.get_type(); + switch(c_type) { + case jwt::claim::type::null: + break; + case jwt::claim::type::boolean: + case jwt::claim::type::number: + case jwt::claim::type::int64: + { + s_val = c.to_json().serialize(); + t.emplace(std::make_pair(key, s_val)); + break; + } + case jwt::claim::type::string: + { + s_val = c.to_json().to_str(); + t.emplace(std::make_pair(key, s_val)); + break; + } + case jwt::claim::type::array: + { + const picojson::array& arr = c.as_array(); + for (auto& a : arr) { + recurse_and_insert(key, jwt::claim(a), t); + } + break; + } + case jwt::claim::type::object: + { + const picojson::object& obj = c.as_object(); + for (auto& m : obj) { + recurse_and_insert(m.first, jwt::claim(m.second), t); + } + break; + } + } + return; +} + +//Extract all token claims so that they can be later used in the Condition element of Role's trust policy +WebTokenEngine::token_t +WebTokenEngine::get_token_claims(const jwt::decoded_jwt& decoded) const +{ + WebTokenEngine::token_t token; + const auto& claims = decoded.get_payload_claims(); + + for (auto& c : claims) { + if (c.first == string(princTagsNamespace)) { + continue; + } + recurse_and_insert(c.first, c.second, token); + } + return token; +} + +//Offline validation of incoming Web Token which is a signed JWT (JSON Web Token) +std::tuple, boost::optional> +WebTokenEngine::get_from_jwt(const DoutPrefixProvider* dpp, const std::string& token, const req_state* const s, + optional_yield y) const { - //Access token conforming to OAuth2.0 - if (! cct->_conf->rgw_sts_token_introspection_url.empty()) { - bufferlist introspect_resp; - RGWHTTPTransceiver introspect_req(cct, "POST", cct->_conf->rgw_sts_token_introspection_url, &introspect_resp); + WebTokenEngine::token_t t; + WebTokenEngine::principal_tags_t principal_tags; + try { + const auto& decoded = jwt::decode(token); + + auto& payload = decoded.get_payload(); + ldpp_dout(dpp, 20) << " payload = " << payload << dendl; + + t = get_token_claims(decoded); + + string iss; + if (decoded.has_issuer()) { + iss = decoded.get_issuer(); + } + + set aud; + if (decoded.has_audience()) { + aud = decoded.get_audience(); + } + + string client_id; + if (decoded.has_payload_claim("client_id")) { + client_id = decoded.get_payload_claim("client_id").as_string(); + } + if (client_id.empty() && decoded.has_payload_claim("clientId")) { + client_id = decoded.get_payload_claim("clientId").as_string(); + } + string azp; + if (decoded.has_payload_claim("azp")) { + azp = decoded.get_payload_claim("azp").as_string(); + } + + string role_arn = s->info.args.get("RoleArn"); + auto provider = get_provider(dpp, role_arn, iss); + if (! provider) { + ldpp_dout(dpp, 0) << "Couldn't get oidc provider info using input iss" << iss << dendl; + throw -EACCES; + } + if (decoded.has_payload_claim(string(princTagsNamespace))) { + auto& cl = decoded.get_payload_claim(string(princTagsNamespace)); + if (cl.get_type() == jwt::claim::type::object || cl.get_type() == jwt::claim::type::array) { + recurse_and_insert("dummy", cl, principal_tags); + for (auto it : principal_tags) { + ldpp_dout(dpp, 5) << "Key: " << it.first << " Value: " << it.second << dendl; + } + } else { + ldpp_dout(dpp, 0) << "Malformed principal tags" << cl.as_string() << dendl; + throw -EINVAL; + } + } + vector client_ids = provider->get_client_ids(); + vector thumbprints = provider->get_thumbprints(); + if (! client_ids.empty()) { + bool found = false; + for (auto& it : aud) { + if (is_client_id_valid(client_ids, it)) { + found = true; + break; + } + } + if (! found && ! is_client_id_valid(client_ids, client_id) && ! is_client_id_valid(client_ids, azp)) { + ldpp_dout(dpp, 0) << "Client id in token doesn't match with that registered with oidc provider" << dendl; + throw -EACCES; + } + } + //Validate signature + if (decoded.has_algorithm()) { + auto& algorithm = decoded.get_algorithm(); + try { + validate_signature(dpp, decoded, algorithm, iss, thumbprints, y); + } catch (...) { + throw -EACCES; + } + } else { + return {boost::none, boost::none}; + } + } catch (int error) { + if (error == -EACCES) { + throw -EACCES; + } + ldpp_dout(dpp, 5) << "Invalid JWT token" << dendl; + return {boost::none, boost::none}; + } + catch (...) { + ldpp_dout(dpp, 5) << "Invalid JWT token" << dendl; + return {boost::none, boost::none}; + } + return {t, principal_tags}; +} + +std::string +WebTokenEngine::get_cert_url(const string& iss, const DoutPrefixProvider *dpp, optional_yield y) const +{ + string cert_url; + string openidc_wellknown_url = iss + "/.well-known/openid-configuration"; + bufferlist openidc_resp; + RGWHTTPTransceiver openidc_req(cct, "GET", openidc_wellknown_url, &openidc_resp); + + //Headers + openidc_req.append_header("Content-Type", "application/x-www-form-urlencoded"); + + int res = openidc_req.process(y); + if (res < 0) { + ldpp_dout(dpp, 10) << "HTTP request res: " << res << dendl; + throw -EINVAL; + } + + //Debug only + ldpp_dout(dpp, 20) << "HTTP status: " << openidc_req.get_http_status() << dendl; + ldpp_dout(dpp, 20) << "JSON Response is: " << openidc_resp.c_str() << dendl; + + JSONParser parser; + if (parser.parse(openidc_resp.c_str(), openidc_resp.length())) { + JSONObj::data_val val; + if (parser.get_data("jwks_uri", &val)) { + cert_url = val.str.c_str(); + ldpp_dout(dpp, 20) << "Cert URL is: " << cert_url.c_str() << dendl; + } else { + ldpp_dout(dpp, 0) << "Malformed json returned while fetching openidc url" << dendl; + } + } + return cert_url; +} + +void +WebTokenEngine::validate_signature(const DoutPrefixProvider* dpp, const jwt::decoded_jwt& decoded, const string& algorithm, const string& iss, const vector& thumbprints, optional_yield y) const +{ + if (algorithm != "HS256" && algorithm != "HS384" && algorithm != "HS512") { + string cert_url = get_cert_url(iss, dpp, y); + if (cert_url.empty()) { + throw -EINVAL; + } + + // Get certificate + bufferlist cert_resp; + RGWHTTPTransceiver cert_req(cct, "GET", cert_url, &cert_resp); //Headers - introspect_req.append_header("Content-Type", "application/x-www-form-urlencoded"); - string base64_creds = "Basic " + rgw::to_base64(cct->_conf->rgw_sts_client_id + ":" + cct->_conf->rgw_sts_client_secret); - introspect_req.append_header("Authorization", base64_creds); - // POST data - string post_data = "token=" + token; - introspect_req.set_post_data(post_data); - introspect_req.set_send_length(post_data.length()); - - int res = introspect_req.process(); + cert_req.append_header("Content-Type", "application/x-www-form-urlencoded"); + + int res = cert_req.process(y); if (res < 0) { ldpp_dout(dpp, 10) << "HTTP request res: " << res << dendl; throw -EINVAL; } //Debug only - ldpp_dout(dpp, 20) << "HTTP status: " << introspect_req.get_http_status() << dendl; - ldpp_dout(dpp, 20) << "JSON Response is: " << introspect_resp.c_str() << dendl; + ldpp_dout(dpp, 20) << "HTTP status: " << cert_req.get_http_status() << dendl; + ldpp_dout(dpp, 20) << "JSON Response is: " << cert_resp.c_str() << dendl; JSONParser parser; - WebTokenEngine::token_t token; - if (!parser.parse(introspect_resp.c_str(), introspect_resp.length())) { - ldpp_dout(dpp, 2) << "Malformed json" << dendl; - throw -EINVAL; + if (parser.parse(cert_resp.c_str(), cert_resp.length())) { + JSONObj::data_val val; + if (parser.get_data("keys", &val)) { + if (val.str[0] == '[') { + val.str.erase(0, 1); + } + if (val.str[val.str.size() - 1] == ']') { + val.str = val.str.erase(val.str.size() - 1, 1); + } + if (parser.parse(val.str.c_str(), val.str.size())) { + vector x5c; + if (JSONDecoder::decode_json("x5c", x5c, &parser)) { + string cert; + bool found_valid_cert = false; + for (auto& it : x5c) { + cert = "-----BEGIN CERTIFICATE-----\n" + it + "\n-----END CERTIFICATE-----"; + ldpp_dout(dpp, 20) << "Certificate is: " << cert.c_str() << dendl; + if (is_cert_valid(thumbprints, cert)) { + found_valid_cert = true; + break; + } + found_valid_cert = true; + } + if (! found_valid_cert) { + ldpp_dout(dpp, 0) << "Cert doesn't match that with the thumbprints registered with oidc provider: " << cert.c_str() << dendl; + throw -EINVAL; + } + try { + //verify method takes care of expired tokens also + if (algorithm == "RS256") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::rs256{cert}); + + verifier.verify(decoded); + } else if (algorithm == "RS384") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::rs384{cert}); + + verifier.verify(decoded); + } else if (algorithm == "RS512") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::rs512{cert}); + + verifier.verify(decoded); + } else if (algorithm == "ES256") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::es256{cert}); + + verifier.verify(decoded); + } else if (algorithm == "ES384") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::es384{cert}); + + verifier.verify(decoded); + } else if (algorithm == "ES512") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::es512{cert}); + + verifier.verify(decoded); + } else if (algorithm == "PS256") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::ps256{cert}); + + verifier.verify(decoded); + } else if (algorithm == "PS384") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::ps384{cert}); + + verifier.verify(decoded); + } else if (algorithm == "PS512") { + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::ps512{cert}); + + verifier.verify(decoded); + } + } catch (std::runtime_error& e) { + ldpp_dout(dpp, 0) << "Signature validation failed: " << e.what() << dendl; + throw; + } + catch (...) { + ldpp_dout(dpp, 0) << "Signature validation failed" << dendl; + throw; + } + } else { + ldpp_dout(dpp, 0) << "x5c not present" << dendl; + throw -EINVAL; + } + } else { + ldpp_dout(dpp, 0) << "Malformed JSON object for keys" << dendl; + throw -EINVAL; + } + } else { + ldpp_dout(dpp, 0) << "keys not present in JSON" << dendl; + throw -EINVAL; + } //if-else get-data } else { - bool is_active; - JSONDecoder::decode_json("active", is_active, &parser); - if (! is_active) { - ldpp_dout(dpp, 0) << "Active state is false" << dendl; - throw -ERR_INVALID_IDENTITY_TOKEN; - } - JSONDecoder::decode_json("iss", token.iss, &parser); - JSONDecoder::decode_json("aud", token.aud, &parser); - JSONDecoder::decode_json("sub", token.sub, &parser); - JSONDecoder::decode_json("user_name", token.user_name, &parser); - } - return token; + ldpp_dout(dpp, 0) << "Malformed json returned while fetching cert" << dendl; + throw -EINVAL; + } //if-else parser cert_resp + } else { + ldpp_dout(dpp, 0) << "JWT signed by HMAC algos are currently not supported" << dendl; + throw -EINVAL; } - return boost::none; } WebTokenEngine::result_t WebTokenEngine::authenticate( const DoutPrefixProvider* dpp, const std::string& token, - const req_state* const s) const + const req_state* const s, + optional_yield y) const { - boost::optional t; - if (! is_applicable(token)) { return result_t::deny(); } try { - t = get_from_idp(dpp, token); - } catch(...) { + auto [t, princ_tags] = get_from_jwt(dpp, token, s, y); + if (t) { + string role_session = s->info.args.get("RoleSessionName"); + if (role_session.empty()) { + ldout(s->cct, 0) << "Role Session Name is empty " << dendl; + return result_t::deny(-EACCES); + } + string role_arn = s->info.args.get("RoleArn"); + string role_tenant = get_role_tenant(role_arn); + string role_name = get_role_name(role_arn); + std::unique_ptr role = store->get_role(role_name, role_tenant); + int ret = role->get(dpp, y); + if (ret < 0) { + ldpp_dout(dpp, 0) << "Role not found: name:" << role_name << " tenant: " << role_tenant << dendl; + return result_t::deny(-EACCES); + } + boost::optional> role_tags = role->get_tags(); + auto apl = apl_factory->create_apl_web_identity(cct, s, role_session, role_tenant, *t, role_tags, princ_tags); + return result_t::grant(std::move(apl)); + } return result_t::deny(-EACCES); } - - if (t) { - auto apl = apl_factory->create_apl_web_identity(cct, s, *t); - return result_t::grant(std::move(apl)); + catch (...) { + return result_t::deny(-EACCES); } - return result_t::deny(-EACCES); } -}; /* namespace sts */ -}; /* namespace auth */ -}; /* namespace rgw */ +} // namespace rgw::auth::sts -int RGWREST_STS::verify_permission() +int RGWREST_STS::verify_permission(optional_yield y) { - STS::STSService _sts(s->cct, store, s->user->user_id, s->auth.identity.get()); + STS::STSService _sts(s->cct, store, s->user->get_id(), s->auth.identity.get()); sts = std::move(_sts); string rArn = s->info.args.get("RoleArn"); - const auto& [ret, role] = sts.getRoleInfo(rArn); + const auto& [ret, role] = sts.getRoleInfo(s, rArn, y); if (ret < 0) { + ldpp_dout(this, 0) << "failed to get role info using role arn: " << rArn << dendl; return ret; } - string policy = role.get_assume_role_policy(); + string policy = role->get_assume_role_policy(); buffer::list bl = buffer::list::static_from_string(policy); //Parse the policy //TODO - This step should be part of Role Creation try { - const rgw::IAM::Policy p(s->cct, s->user->user_id.tenant, bl); - //Check if the input role arn is there as one of the Principals in the policy, - // If yes, then return 0, else -EPERM - auto p_res = p.eval_principal(s->env, *s->auth.identity); - if (p_res == rgw::IAM::Effect::Deny) { - return -EPERM; + const rgw::IAM::Policy p(s->cct, s->user->get_tenant(), bl); + if (!s->principal_tags.empty()) { + auto res = p.eval(s->env, *s->auth.identity, rgw::IAM::stsTagSession, boost::none); + if (res != rgw::IAM::Effect::Allow) { + ldout(s->cct, 0) << "evaluating policy for stsTagSession returned deny/pass" << dendl; + return -EPERM; + } + } + uint64_t op; + if (get_type() == RGW_STS_ASSUME_ROLE_WEB_IDENTITY) { + op = rgw::IAM::stsAssumeRoleWithWebIdentity; + } else { + op = rgw::IAM::stsAssumeRole; } - auto c_res = p.eval_conditions(s->env); - if (c_res == rgw::IAM::Effect::Deny) { + + auto res = p.eval(s->env, *s->auth.identity, op, boost::none); + if (res != rgw::IAM::Effect::Allow) { + ldout(s->cct, 0) << "evaluating policy for op: " << op << " returned deny/pass" << dendl; return -EPERM; } } catch (rgw::IAM::PolicyParseException& e) { - ldout(s->cct, 20) << "failed to parse policy: " << e.what() << dendl; + ldpp_dout(this, 0) << "failed to parse policy: " << e.what() << dendl; return -EPERM; } @@ -167,14 +563,15 @@ void RGWREST_STS::send_response() end_header(s); } -int RGWSTSGetSessionToken::verify_permission() +int RGWSTSGetSessionToken::verify_permission(optional_yield y) { - rgw::IAM::Partition partition = rgw::IAM::Partition::aws; - rgw::IAM::Service service = rgw::IAM::Service::s3; + rgw::Partition partition = rgw::Partition::aws; + rgw::Service service = rgw::Service::s3; if (!verify_user_permission(this, s, - rgw::IAM::ARN(partition, service, "", s->user->user_id.tenant, ""), + rgw::ARN(partition, service, "", s->user->get_tenant(), ""), rgw::IAM::stsGetSessionToken)) { + ldpp_dout(this, 0) << "User does not have permssion to perform GetSessionToken" << dendl; return -EACCES; } @@ -188,25 +585,33 @@ int RGWSTSGetSessionToken::get_params() tokenCode = s->info.args.get("TokenCode"); if (! duration.empty()) { - uint64_t duration_in_secs = stoull(duration); + string err; + uint64_t duration_in_secs = strict_strtoll(duration.c_str(), 10, &err); + if (!err.empty()) { + ldpp_dout(this, 0) << "Invalid value of input duration: " << duration << dendl; + return -EINVAL; + } + if (duration_in_secs < STS::GetSessionTokenRequest::getMinDuration() || - duration_in_secs > s->cct->_conf->rgw_sts_max_session_duration) + duration_in_secs > s->cct->_conf->rgw_sts_max_session_duration) { + ldpp_dout(this, 0) << "Invalid duration in secs: " << duration_in_secs << dendl; return -EINVAL; + } } return 0; } -void RGWSTSGetSessionToken::execute() +void RGWSTSGetSessionToken::execute(optional_yield y) { if (op_ret = get_params(); op_ret < 0) { return; } - STS::STSService sts(s->cct, store, s->user->user_id, s->auth.identity.get()); + STS::STSService sts(s->cct, store, s->user->get_id(), s->auth.identity.get()); STS::GetSessionTokenRequest req(duration, serialNumber, tokenCode); - const auto& [ret, creds] = sts.getSessionToken(req); + const auto& [ret, creds] = sts.getSessionToken(this, req); op_ret = std::move(ret); //Dump the output if (op_ret == 0) { @@ -232,17 +637,17 @@ int RGWSTSAssumeRoleWithWebIdentity::get_params() aud = s->info.args.get("aud"); if (roleArn.empty() || roleSessionName.empty() || sub.empty() || aud.empty()) { - ldout(s->cct, 20) << "ERROR: one of role arn or role session name or token is empty" << dendl; + ldpp_dout(this, 0) << "ERROR: one of role arn or role session name or token is empty" << dendl; return -EINVAL; } if (! policy.empty()) { bufferlist bl = bufferlist::static_from_string(policy); try { - const rgw::IAM::Policy p(s->cct, s->user->user_id.tenant, bl); + const rgw::IAM::Policy p(s->cct, s->user->get_tenant(), bl); } catch (rgw::IAM::PolicyParseException& e) { - ldout(s->cct, 20) << "failed to parse policy: " << e.what() << "policy" << policy << dendl; + ldpp_dout(this, 20) << "failed to parse policy: " << e.what() << "policy" << policy << dendl; return -ERR_MALFORMED_DOC; } } @@ -250,15 +655,15 @@ int RGWSTSAssumeRoleWithWebIdentity::get_params() return 0; } -void RGWSTSAssumeRoleWithWebIdentity::execute() +void RGWSTSAssumeRoleWithWebIdentity::execute(optional_yield y) { if (op_ret = get_params(); op_ret < 0) { return; } - STS::AssumeRoleWithWebIdentityRequest req(duration, providerId, policy, roleArn, - roleSessionName, iss, sub, aud); - STS::AssumeRoleWithWebIdentityResponse response = sts.assumeRoleWithWebIdentity(req); + STS::AssumeRoleWithWebIdentityRequest req(s->cct, duration, providerId, policy, roleArn, + roleSessionName, iss, sub, aud, s->principal_tags); + STS::AssumeRoleWithWebIdentityResponse response = sts.assumeRoleWithWebIdentity(this, req); op_ret = std::move(response.assumeRoleResp.retCode); //Dump the output @@ -291,17 +696,17 @@ int RGWSTSAssumeRole::get_params() tokenCode = s->info.args.get("TokenCode"); if (roleArn.empty() || roleSessionName.empty()) { - ldout(s->cct, 20) << "ERROR: one of role arn or role session name is empty" << dendl; + ldpp_dout(this, 0) << "ERROR: one of role arn or role session name is empty" << dendl; return -EINVAL; } if (! policy.empty()) { bufferlist bl = bufferlist::static_from_string(policy); try { - const rgw::IAM::Policy p(s->cct, s->user->user_id.tenant, bl); + const rgw::IAM::Policy p(s->cct, s->user->get_tenant(), bl); } catch (rgw::IAM::PolicyParseException& e) { - ldout(s->cct, 20) << "failed to parse policy: " << e.what() << "policy" << policy << dendl; + ldpp_dout(this, 0) << "failed to parse policy: " << e.what() << "policy" << policy << dendl; return -ERR_MALFORMED_DOC; } } @@ -309,15 +714,15 @@ int RGWSTSAssumeRole::get_params() return 0; } -void RGWSTSAssumeRole::execute() +void RGWSTSAssumeRole::execute(optional_yield y) { if (op_ret = get_params(); op_ret < 0) { return; } - STS::AssumeRoleRequest req(duration, externalId, policy, roleArn, + STS::AssumeRoleRequest req(s->cct, duration, externalId, policy, roleArn, roleSessionName, serialNumber, tokenCode); - STS::AssumeRoleResponse response = sts.assumeRole(req); + STS::AssumeRoleResponse response = sts.assumeRole(s, req, y); op_ret = std::move(response.retCode); //Dump the output if (op_ret == 0) { @@ -336,23 +741,17 @@ void RGWSTSAssumeRole::execute() } int RGW_Auth_STS::authorize(const DoutPrefixProvider *dpp, - RGWRados *store, + rgw::sal::Store* store, const rgw::auth::StrategyRegistry& auth_registry, - struct req_state *s) + struct req_state *s, optional_yield y) { - return rgw::auth::Strategy::apply(dpp, auth_registry.get_sts(), s); + return rgw::auth::Strategy::apply(dpp, auth_registry.get_sts(), s, y); } void RGWHandler_REST_STS::rgw_sts_parse_input() { - const auto max_size = s->cct->_conf->rgw_max_put_param_size; - - int ret = 0; - bufferlist data; - std::tie(ret, data) = rgw_rest_read_all_input(s, max_size, false); - string post_body = data.to_str(); - if (data.length() > 0) { - ldout(s->cct, 10) << "Content of POST: " << post_body << dendl; + if (post_body.size() > 0) { + ldpp_dout(s, 10) << "Content of POST: " << post_body << dendl; if (post_body.find("Action") != string::npos) { boost::char_separator sep("&"); @@ -360,15 +759,10 @@ void RGWHandler_REST_STS::rgw_sts_parse_input() for (const auto& t : tokens) { auto pos = t.find("="); if (pos != string::npos) { - std::string key = t.substr(0, pos); - std::string value = t.substr(pos + 1, t.size() - 1); - if (key == "RoleArn" || key == "Policy") { - value = url_decode(value); - } - ldout(s->cct, 10) << "Key: " << key << "Value: " << value << dendl; - s->info.args.append(key, value); - } - } + s->info.args.append(t.substr(0,pos), + url_decode(t.substr(pos+1, t.size() -1))); + } + } } } auto payload_hash = rgw::auth::s3::calc_v4_payload_hash(post_body); @@ -393,26 +787,26 @@ RGWOp *RGWHandler_REST_STS::op_post() return nullptr; } -int RGWHandler_REST_STS::init(RGWRados *store, +int RGWHandler_REST_STS::init(rgw::sal::Store* store, struct req_state *s, rgw::io::BasicClient *cio) { s->dialect = "sts"; if (int ret = RGWHandler_REST_STS::init_from_header(s, RGW_FORMAT_XML, true); ret < 0) { - ldout(s->cct, 10) << "init_from_header returned err=" << ret << dendl; + ldpp_dout(s, 10) << "init_from_header returned err=" << ret << dendl; return ret; } return RGWHandler_REST::init(store, s, cio); } -int RGWHandler_REST_STS::authorize(const DoutPrefixProvider* dpp) +int RGWHandler_REST_STS::authorize(const DoutPrefixProvider* dpp, optional_yield y) { if (s->info.args.exists("Action") && s->info.args.get("Action") == "AssumeRoleWithWebIdentity") { - return RGW_Auth_STS::authorize(dpp, store, auth_registry, s); + return RGW_Auth_STS::authorize(dpp, store, auth_registry, s, y); } - return RGW_Auth_S3::authorize(dpp, store, auth_registry, s); + return RGW_Auth_S3::authorize(dpp, store, auth_registry, s, y); } int RGWHandler_REST_STS::init_from_header(struct req_state* s, @@ -422,7 +816,7 @@ int RGWHandler_REST_STS::init_from_header(struct req_state* s, string req; string first; - s->prot_flags |= RGW_REST_STS; + s->prot_flags = RGW_REST_STS; const char *p, *req_name; if (req_name = s->relative_uri.c_str(); *req_name == '?') { @@ -432,7 +826,7 @@ int RGWHandler_REST_STS::init_from_header(struct req_state* s, } s->info.args.set(p); - s->info.args.parse(); + s->info.args.parse(s); /* must be called after the args parsing */ if (int ret = allocate_formatter(s, default_formatter, configurable_format); ret < 0) @@ -458,9 +852,10 @@ int RGWHandler_REST_STS::init_from_header(struct req_state* s, } RGWHandler_REST* -RGWRESTMgr_STS::get_handler(struct req_state* const s, - const rgw::auth::StrategyRegistry& auth_registry, - const std::string& frontend_prefix) +RGWRESTMgr_STS::get_handler(rgw::sal::Store* store, + struct req_state* const s, + const rgw::auth::StrategyRegistry& auth_registry, + const std::string& frontend_prefix) { return new RGWHandler_REST_STS(auth_registry); }