1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
10 #include <boost/algorithm/string/predicate.hpp>
11 #include <boost/format.hpp>
12 #include <boost/optional.hpp>
13 #include <boost/utility/in_place_factory.hpp>
14 #include <boost/tokenizer.hpp>
19 #include "common/Formatter.h"
20 #include "common/utf8.h"
21 #include "common/ceph_json.h"
25 #include "rgw_auth_registry.h"
26 #include "jwt-cpp/jwt.h"
27 #include "rgw_rest_sts.h"
29 #include "rgw_formats.h"
30 #include "rgw_client_io.h"
32 #include "rgw_request.h"
33 #include "rgw_process.h"
34 #include "rgw_iam_policy.h"
35 #include "rgw_iam_policy_keywords.h"
38 #include "rgw_rest_oidc_provider.h"
41 #define dout_context g_ceph_context
42 #define dout_subsys ceph_subsys_rgw
46 namespace rgw::auth::sts
{
49 WebTokenEngine::is_applicable(const std::string
& token
) const noexcept
51 return ! token
.empty();
55 WebTokenEngine::get_role_tenant(const string
& role_arn
) const
58 auto r_arn
= rgw::ARN::parse(role_arn
);
60 tenant
= r_arn
->account
;
66 WebTokenEngine::get_role_name(const string
& role_arn
) const
69 auto r_arn
= rgw::ARN::parse(role_arn
);
71 role_name
= r_arn
->resource
;
73 if (!role_name
.empty()) {
74 auto pos
= role_name
.find_last_of('/');
75 if(pos
!= string::npos
) {
76 role_name
= role_name
.substr(pos
+ 1);
82 std::unique_ptr
<rgw::sal::RGWOIDCProvider
>
83 WebTokenEngine::get_provider(const DoutPrefixProvider
*dpp
, const string
& role_arn
, const string
& iss
) const
85 string tenant
= get_role_tenant(role_arn
);
88 auto pos
= idp_url
.find("http://");
89 if (pos
== std::string::npos
) {
90 pos
= idp_url
.find("https://");
91 if (pos
!= std::string::npos
) {
92 idp_url
.erase(pos
, 8);
94 pos
= idp_url
.find("www.");
95 if (pos
!= std::string::npos
) {
96 idp_url
.erase(pos
, 4);
100 idp_url
.erase(pos
, 7);
102 auto provider_arn
= rgw::ARN(idp_url
, "oidc-provider", tenant
);
103 string p_arn
= provider_arn
.to_string();
104 std::unique_ptr
<rgw::sal::RGWOIDCProvider
> provider
= store
->get_oidc_provider();
105 provider
->set_arn(p_arn
);
106 provider
->set_tenant(tenant
);
107 auto ret
= provider
->get(dpp
);
115 WebTokenEngine::is_client_id_valid(vector
<string
>& client_ids
, const string
& client_id
) const
117 for (auto it
: client_ids
) {
118 if (it
== client_id
) {
126 WebTokenEngine::is_cert_valid(const vector
<string
>& thumbprints
, const string
& cert
) const
128 //calculate thumbprint of cert
129 std::unique_ptr
<BIO
, decltype(&BIO_free_all
)> certbio(BIO_new_mem_buf(cert
.data(), cert
.size()), BIO_free_all
);
130 std::unique_ptr
<BIO
, decltype(&BIO_free_all
)> keybio(BIO_new(BIO_s_mem()), BIO_free_all
);
132 std::unique_ptr
<X509
, decltype(&X509_free
)> x_509cert(PEM_read_bio_X509(certbio
.get(), nullptr, nullptr, const_cast<char*>(pw
.c_str())), X509_free
);
133 const EVP_MD
* fprint_type
= EVP_sha1();
134 unsigned int fprint_size
;
135 unsigned char fprint
[EVP_MAX_MD_SIZE
];
137 if (!X509_digest(x_509cert
.get(), fprint_type
, fprint
, &fprint_size
)) {
141 for (unsigned int i
= 0; i
< fprint_size
; i
++) {
142 ss
<< std::setfill('0') << std::setw(2) << std::hex
<< (0xFF & (unsigned int)fprint
[i
]);
144 std::string digest
= ss
.str();
146 for (auto& it
: thumbprints
) {
147 if (boost::iequals(it
,digest
)) {
154 template <typename T
>
156 WebTokenEngine::recurse_and_insert(const string
& key
, const jwt::claim
& c
, T
& t
) const
159 jwt::claim::type c_type
= c
.get_type();
161 case jwt::claim::type::null
:
163 case jwt::claim::type::boolean
:
164 case jwt::claim::type::number
:
165 case jwt::claim::type::int64
:
167 s_val
= c
.to_json().serialize();
168 t
.emplace(std::make_pair(key
, s_val
));
171 case jwt::claim::type::string
:
173 s_val
= c
.to_json().to_str();
174 t
.emplace(std::make_pair(key
, s_val
));
177 case jwt::claim::type::array
:
179 const picojson::array
& arr
= c
.as_array();
180 for (auto& a
: arr
) {
181 recurse_and_insert(key
, jwt::claim(a
), t
);
185 case jwt::claim::type::object
:
187 const picojson::object
& obj
= c
.as_object();
188 for (auto& m
: obj
) {
189 recurse_and_insert(m
.first
, jwt::claim(m
.second
), t
);
197 //Extract all token claims so that they can be later used in the Condition element of Role's trust policy
198 WebTokenEngine::token_t
199 WebTokenEngine::get_token_claims(const jwt::decoded_jwt
& decoded
) const
201 WebTokenEngine::token_t token
;
202 const auto& claims
= decoded
.get_payload_claims();
204 for (auto& c
: claims
) {
205 if (c
.first
== string(princTagsNamespace
)) {
208 recurse_and_insert(c
.first
, c
.second
, token
);
213 //Offline validation of incoming Web Token which is a signed JWT (JSON Web Token)
214 std::tuple
<boost::optional
<WebTokenEngine::token_t
>, boost::optional
<WebTokenEngine::principal_tags_t
>>
215 WebTokenEngine::get_from_jwt(const DoutPrefixProvider
* dpp
, const std::string
& token
, const req_state
* const s
,
216 optional_yield y
) const
218 WebTokenEngine::token_t t
;
219 WebTokenEngine::principal_tags_t principal_tags
;
221 const auto& decoded
= jwt::decode(token
);
223 auto& payload
= decoded
.get_payload();
224 ldpp_dout(dpp
, 20) << " payload = " << payload
<< dendl
;
226 t
= get_token_claims(decoded
);
229 if (decoded
.has_issuer()) {
230 iss
= decoded
.get_issuer();
234 if (decoded
.has_audience()) {
235 aud
= decoded
.get_audience();
239 if (decoded
.has_payload_claim("client_id")) {
240 client_id
= decoded
.get_payload_claim("client_id").as_string();
242 if (client_id
.empty() && decoded
.has_payload_claim("clientId")) {
243 client_id
= decoded
.get_payload_claim("clientId").as_string();
246 if (decoded
.has_payload_claim("azp")) {
247 azp
= decoded
.get_payload_claim("azp").as_string();
250 string role_arn
= s
->info
.args
.get("RoleArn");
251 auto provider
= get_provider(dpp
, role_arn
, iss
);
253 ldpp_dout(dpp
, 0) << "Couldn't get oidc provider info using input iss" << iss
<< dendl
;
256 if (decoded
.has_payload_claim(string(princTagsNamespace
))) {
257 auto& cl
= decoded
.get_payload_claim(string(princTagsNamespace
));
258 if (cl
.get_type() == jwt::claim::type::object
|| cl
.get_type() == jwt::claim::type::array
) {
259 recurse_and_insert("dummy", cl
, principal_tags
);
260 for (auto it
: principal_tags
) {
261 ldpp_dout(dpp
, 5) << "Key: " << it
.first
<< " Value: " << it
.second
<< dendl
;
264 ldpp_dout(dpp
, 0) << "Malformed principal tags" << cl
.as_string() << dendl
;
268 vector
<string
> client_ids
= provider
->get_client_ids();
269 vector
<string
> thumbprints
= provider
->get_thumbprints();
270 if (! client_ids
.empty()) {
272 for (auto& it
: aud
) {
273 if (is_client_id_valid(client_ids
, it
)) {
278 if (! found
&& ! is_client_id_valid(client_ids
, client_id
) && ! is_client_id_valid(client_ids
, azp
)) {
279 ldpp_dout(dpp
, 0) << "Client id in token doesn't match with that registered with oidc provider" << dendl
;
284 if (decoded
.has_algorithm()) {
285 auto& algorithm
= decoded
.get_algorithm();
287 validate_signature(dpp
, decoded
, algorithm
, iss
, thumbprints
, y
);
292 return {boost::none
, boost::none
};
294 } catch (int error
) {
295 if (error
== -EACCES
) {
298 ldpp_dout(dpp
, 5) << "Invalid JWT token" << dendl
;
299 return {boost::none
, boost::none
};
302 ldpp_dout(dpp
, 5) << "Invalid JWT token" << dendl
;
303 return {boost::none
, boost::none
};
305 return {t
, principal_tags
};
309 WebTokenEngine::get_cert_url(const string
& iss
, const DoutPrefixProvider
*dpp
, optional_yield y
) const
312 string openidc_wellknown_url
= iss
+ "/.well-known/openid-configuration";
313 bufferlist openidc_resp
;
314 RGWHTTPTransceiver
openidc_req(cct
, "GET", openidc_wellknown_url
, &openidc_resp
);
317 openidc_req
.append_header("Content-Type", "application/x-www-form-urlencoded");
319 int res
= openidc_req
.process(y
);
321 ldpp_dout(dpp
, 10) << "HTTP request res: " << res
<< dendl
;
326 ldpp_dout(dpp
, 20) << "HTTP status: " << openidc_req
.get_http_status() << dendl
;
327 ldpp_dout(dpp
, 20) << "JSON Response is: " << openidc_resp
.c_str() << dendl
;
330 if (parser
.parse(openidc_resp
.c_str(), openidc_resp
.length())) {
331 JSONObj::data_val val
;
332 if (parser
.get_data("jwks_uri", &val
)) {
333 cert_url
= val
.str
.c_str();
334 ldpp_dout(dpp
, 20) << "Cert URL is: " << cert_url
.c_str() << dendl
;
336 ldpp_dout(dpp
, 0) << "Malformed json returned while fetching openidc url" << dendl
;
343 WebTokenEngine::validate_signature(const DoutPrefixProvider
* dpp
, const jwt::decoded_jwt
& decoded
, const string
& algorithm
, const string
& iss
, const vector
<string
>& thumbprints
, optional_yield y
) const
345 if (algorithm
!= "HS256" && algorithm
!= "HS384" && algorithm
!= "HS512") {
346 string cert_url
= get_cert_url(iss
, dpp
, y
);
347 if (cert_url
.empty()) {
352 bufferlist cert_resp
;
353 RGWHTTPTransceiver
cert_req(cct
, "GET", cert_url
, &cert_resp
);
355 cert_req
.append_header("Content-Type", "application/x-www-form-urlencoded");
357 int res
= cert_req
.process(y
);
359 ldpp_dout(dpp
, 10) << "HTTP request res: " << res
<< dendl
;
363 ldpp_dout(dpp
, 20) << "HTTP status: " << cert_req
.get_http_status() << dendl
;
364 ldpp_dout(dpp
, 20) << "JSON Response is: " << cert_resp
.c_str() << dendl
;
367 if (parser
.parse(cert_resp
.c_str(), cert_resp
.length())) {
368 JSONObj::data_val val
;
369 if (parser
.get_data("keys", &val
)) {
370 if (val
.str
[0] == '[') {
373 if (val
.str
[val
.str
.size() - 1] == ']') {
374 val
.str
= val
.str
.erase(val
.str
.size() - 1, 1);
376 if (parser
.parse(val
.str
.c_str(), val
.str
.size())) {
378 if (JSONDecoder::decode_json("x5c", x5c
, &parser
)) {
380 bool found_valid_cert
= false;
381 for (auto& it
: x5c
) {
382 cert
= "-----BEGIN CERTIFICATE-----\n" + it
+ "\n-----END CERTIFICATE-----";
383 ldpp_dout(dpp
, 20) << "Certificate is: " << cert
.c_str() << dendl
;
384 if (is_cert_valid(thumbprints
, cert
)) {
385 found_valid_cert
= true;
388 found_valid_cert
= true;
390 if (! found_valid_cert
) {
391 ldpp_dout(dpp
, 0) << "Cert doesn't match that with the thumbprints registered with oidc provider: " << cert
.c_str() << dendl
;
395 //verify method takes care of expired tokens also
396 if (algorithm
== "RS256") {
397 auto verifier
= jwt::verify()
398 .allow_algorithm(jwt::algorithm::rs256
{cert
});
400 verifier
.verify(decoded
);
401 } else if (algorithm
== "RS384") {
402 auto verifier
= jwt::verify()
403 .allow_algorithm(jwt::algorithm::rs384
{cert
});
405 verifier
.verify(decoded
);
406 } else if (algorithm
== "RS512") {
407 auto verifier
= jwt::verify()
408 .allow_algorithm(jwt::algorithm::rs512
{cert
});
410 verifier
.verify(decoded
);
411 } else if (algorithm
== "ES256") {
412 auto verifier
= jwt::verify()
413 .allow_algorithm(jwt::algorithm::es256
{cert
});
415 verifier
.verify(decoded
);
416 } else if (algorithm
== "ES384") {
417 auto verifier
= jwt::verify()
418 .allow_algorithm(jwt::algorithm::es384
{cert
});
420 verifier
.verify(decoded
);
421 } else if (algorithm
== "ES512") {
422 auto verifier
= jwt::verify()
423 .allow_algorithm(jwt::algorithm::es512
{cert
});
425 verifier
.verify(decoded
);
426 } else if (algorithm
== "PS256") {
427 auto verifier
= jwt::verify()
428 .allow_algorithm(jwt::algorithm::ps256
{cert
});
430 verifier
.verify(decoded
);
431 } else if (algorithm
== "PS384") {
432 auto verifier
= jwt::verify()
433 .allow_algorithm(jwt::algorithm::ps384
{cert
});
435 verifier
.verify(decoded
);
436 } else if (algorithm
== "PS512") {
437 auto verifier
= jwt::verify()
438 .allow_algorithm(jwt::algorithm::ps512
{cert
});
440 verifier
.verify(decoded
);
442 } catch (std::runtime_error
& e
) {
443 ldpp_dout(dpp
, 0) << "Signature validation failed: " << e
.what() << dendl
;
447 ldpp_dout(dpp
, 0) << "Signature validation failed" << dendl
;
451 ldpp_dout(dpp
, 0) << "x5c not present" << dendl
;
455 ldpp_dout(dpp
, 0) << "Malformed JSON object for keys" << dendl
;
459 ldpp_dout(dpp
, 0) << "keys not present in JSON" << dendl
;
463 ldpp_dout(dpp
, 0) << "Malformed json returned while fetching cert" << dendl
;
465 } //if-else parser cert_resp
467 ldpp_dout(dpp
, 0) << "JWT signed by HMAC algos are currently not supported" << dendl
;
472 WebTokenEngine::result_t
473 WebTokenEngine::authenticate( const DoutPrefixProvider
* dpp
,
474 const std::string
& token
,
475 const req_state
* const s
,
476 optional_yield y
) const
478 if (! is_applicable(token
)) {
479 return result_t::deny();
483 auto [t
, princ_tags
] = get_from_jwt(dpp
, token
, s
, y
);
485 string role_session
= s
->info
.args
.get("RoleSessionName");
486 if (role_session
.empty()) {
487 ldout(s
->cct
, 0) << "Role Session Name is empty " << dendl
;
488 return result_t::deny(-EACCES
);
490 string role_arn
= s
->info
.args
.get("RoleArn");
491 string role_tenant
= get_role_tenant(role_arn
);
492 string role_name
= get_role_name(role_arn
);
493 std::unique_ptr
<rgw::sal::RGWRole
> role
= store
->get_role(role_name
, role_tenant
);
494 int ret
= role
->get(dpp
, y
);
496 ldpp_dout(dpp
, 0) << "Role not found: name:" << role_name
<< " tenant: " << role_tenant
<< dendl
;
497 return result_t::deny(-EACCES
);
499 boost::optional
<multimap
<string
,string
>> role_tags
= role
->get_tags();
500 auto apl
= apl_factory
->create_apl_web_identity(cct
, s
, role_session
, role_tenant
, *t
, role_tags
, princ_tags
);
501 return result_t::grant(std::move(apl
));
503 return result_t::deny(-EACCES
);
506 return result_t::deny(-EACCES
);
510 } // namespace rgw::auth::sts
512 int RGWREST_STS::verify_permission(optional_yield y
)
514 STS::STSService
_sts(s
->cct
, store
, s
->user
->get_id(), s
->auth
.identity
.get());
515 sts
= std::move(_sts
);
517 string rArn
= s
->info
.args
.get("RoleArn");
518 const auto& [ret
, role
] = sts
.getRoleInfo(s
, rArn
, y
);
520 ldpp_dout(this, 0) << "failed to get role info using role arn: " << rArn
<< dendl
;
523 string policy
= role
->get_assume_role_policy();
524 buffer::list bl
= buffer::list::static_from_string(policy
);
527 //TODO - This step should be part of Role Creation
529 const rgw::IAM::Policy
p(s
->cct
, s
->user
->get_tenant(), bl
);
530 if (!s
->principal_tags
.empty()) {
531 auto res
= p
.eval(s
->env
, *s
->auth
.identity
, rgw::IAM::stsTagSession
, boost::none
);
532 if (res
!= rgw::IAM::Effect::Allow
) {
533 ldout(s
->cct
, 0) << "evaluating policy for stsTagSession returned deny/pass" << dendl
;
538 if (get_type() == RGW_STS_ASSUME_ROLE_WEB_IDENTITY
) {
539 op
= rgw::IAM::stsAssumeRoleWithWebIdentity
;
541 op
= rgw::IAM::stsAssumeRole
;
544 auto res
= p
.eval(s
->env
, *s
->auth
.identity
, op
, boost::none
);
545 if (res
!= rgw::IAM::Effect::Allow
) {
546 ldout(s
->cct
, 0) << "evaluating policy for op: " << op
<< " returned deny/pass" << dendl
;
549 } catch (rgw::IAM::PolicyParseException
& e
) {
550 ldpp_dout(this, 0) << "failed to parse policy: " << e
.what() << dendl
;
557 void RGWREST_STS::send_response()
560 set_req_state_err(s
, op_ret
);
566 int RGWSTSGetSessionToken::verify_permission(optional_yield y
)
568 rgw::Partition partition
= rgw::Partition::aws
;
569 rgw::Service service
= rgw::Service::s3
;
570 if (!verify_user_permission(this,
572 rgw::ARN(partition
, service
, "", s
->user
->get_tenant(), ""),
573 rgw::IAM::stsGetSessionToken
)) {
574 ldpp_dout(this, 0) << "User does not have permssion to perform GetSessionToken" << dendl
;
581 int RGWSTSGetSessionToken::get_params()
583 duration
= s
->info
.args
.get("DurationSeconds");
584 serialNumber
= s
->info
.args
.get("SerialNumber");
585 tokenCode
= s
->info
.args
.get("TokenCode");
587 if (! duration
.empty()) {
589 uint64_t duration_in_secs
= strict_strtoll(duration
.c_str(), 10, &err
);
591 ldpp_dout(this, 0) << "Invalid value of input duration: " << duration
<< dendl
;
595 if (duration_in_secs
< STS::GetSessionTokenRequest::getMinDuration() ||
596 duration_in_secs
> s
->cct
->_conf
->rgw_sts_max_session_duration
) {
597 ldpp_dout(this, 0) << "Invalid duration in secs: " << duration_in_secs
<< dendl
;
605 void RGWSTSGetSessionToken::execute(optional_yield y
)
607 if (op_ret
= get_params(); op_ret
< 0) {
611 STS::STSService
sts(s
->cct
, store
, s
->user
->get_id(), s
->auth
.identity
.get());
613 STS::GetSessionTokenRequest
req(duration
, serialNumber
, tokenCode
);
614 const auto& [ret
, creds
] = sts
.getSessionToken(this, req
);
615 op_ret
= std::move(ret
);
618 s
->formatter
->open_object_section("GetSessionTokenResponse");
619 s
->formatter
->open_object_section("GetSessionTokenResult");
620 s
->formatter
->open_object_section("Credentials");
621 creds
.dump(s
->formatter
);
622 s
->formatter
->close_section();
623 s
->formatter
->close_section();
624 s
->formatter
->close_section();
628 int RGWSTSAssumeRoleWithWebIdentity::get_params()
630 duration
= s
->info
.args
.get("DurationSeconds");
631 providerId
= s
->info
.args
.get("ProviderId");
632 policy
= s
->info
.args
.get("Policy");
633 roleArn
= s
->info
.args
.get("RoleArn");
634 roleSessionName
= s
->info
.args
.get("RoleSessionName");
635 iss
= s
->info
.args
.get("provider_id");
636 sub
= s
->info
.args
.get("sub");
637 aud
= s
->info
.args
.get("aud");
639 if (roleArn
.empty() || roleSessionName
.empty() || sub
.empty() || aud
.empty()) {
640 ldpp_dout(this, 0) << "ERROR: one of role arn or role session name or token is empty" << dendl
;
644 if (! policy
.empty()) {
645 bufferlist bl
= bufferlist::static_from_string(policy
);
647 const rgw::IAM::Policy
p(s
->cct
, s
->user
->get_tenant(), bl
);
649 catch (rgw::IAM::PolicyParseException
& e
) {
650 ldpp_dout(this, 20) << "failed to parse policy: " << e
.what() << "policy" << policy
<< dendl
;
651 return -ERR_MALFORMED_DOC
;
658 void RGWSTSAssumeRoleWithWebIdentity::execute(optional_yield y
)
660 if (op_ret
= get_params(); op_ret
< 0) {
664 STS::AssumeRoleWithWebIdentityRequest
req(s
->cct
, duration
, providerId
, policy
, roleArn
,
665 roleSessionName
, iss
, sub
, aud
, s
->principal_tags
);
666 STS::AssumeRoleWithWebIdentityResponse response
= sts
.assumeRoleWithWebIdentity(this, req
);
667 op_ret
= std::move(response
.assumeRoleResp
.retCode
);
671 s
->formatter
->open_object_section("AssumeRoleWithWebIdentityResponse");
672 s
->formatter
->open_object_section("AssumeRoleWithWebIdentityResult");
673 encode_json("SubjectFromWebIdentityToken", response
.sub
, s
->formatter
);
674 encode_json("Audience", response
.aud
, s
->formatter
);
675 s
->formatter
->open_object_section("AssumedRoleUser");
676 response
.assumeRoleResp
.user
.dump(s
->formatter
);
677 s
->formatter
->close_section();
678 s
->formatter
->open_object_section("Credentials");
679 response
.assumeRoleResp
.creds
.dump(s
->formatter
);
680 s
->formatter
->close_section();
681 encode_json("Provider", response
.providerId
, s
->formatter
);
682 encode_json("PackedPolicySize", response
.assumeRoleResp
.packedPolicySize
, s
->formatter
);
683 s
->formatter
->close_section();
684 s
->formatter
->close_section();
688 int RGWSTSAssumeRole::get_params()
690 duration
= s
->info
.args
.get("DurationSeconds");
691 externalId
= s
->info
.args
.get("ExternalId");
692 policy
= s
->info
.args
.get("Policy");
693 roleArn
= s
->info
.args
.get("RoleArn");
694 roleSessionName
= s
->info
.args
.get("RoleSessionName");
695 serialNumber
= s
->info
.args
.get("SerialNumber");
696 tokenCode
= s
->info
.args
.get("TokenCode");
698 if (roleArn
.empty() || roleSessionName
.empty()) {
699 ldpp_dout(this, 0) << "ERROR: one of role arn or role session name is empty" << dendl
;
703 if (! policy
.empty()) {
704 bufferlist bl
= bufferlist::static_from_string(policy
);
706 const rgw::IAM::Policy
p(s
->cct
, s
->user
->get_tenant(), bl
);
708 catch (rgw::IAM::PolicyParseException
& e
) {
709 ldpp_dout(this, 0) << "failed to parse policy: " << e
.what() << "policy" << policy
<< dendl
;
710 return -ERR_MALFORMED_DOC
;
717 void RGWSTSAssumeRole::execute(optional_yield y
)
719 if (op_ret
= get_params(); op_ret
< 0) {
723 STS::AssumeRoleRequest
req(s
->cct
, duration
, externalId
, policy
, roleArn
,
724 roleSessionName
, serialNumber
, tokenCode
);
725 STS::AssumeRoleResponse response
= sts
.assumeRole(s
, req
, y
);
726 op_ret
= std::move(response
.retCode
);
729 s
->formatter
->open_object_section("AssumeRoleResponse");
730 s
->formatter
->open_object_section("AssumeRoleResult");
731 s
->formatter
->open_object_section("Credentials");
732 response
.creds
.dump(s
->formatter
);
733 s
->formatter
->close_section();
734 s
->formatter
->open_object_section("AssumedRoleUser");
735 response
.user
.dump(s
->formatter
);
736 s
->formatter
->close_section();
737 encode_json("PackedPolicySize", response
.packedPolicySize
, s
->formatter
);
738 s
->formatter
->close_section();
739 s
->formatter
->close_section();
743 int RGW_Auth_STS::authorize(const DoutPrefixProvider
*dpp
,
744 rgw::sal::Store
* store
,
745 const rgw::auth::StrategyRegistry
& auth_registry
,
746 struct req_state
*s
, optional_yield y
)
748 return rgw::auth::Strategy::apply(dpp
, auth_registry
.get_sts(), s
, y
);
751 void RGWHandler_REST_STS::rgw_sts_parse_input()
753 if (post_body
.size() > 0) {
754 ldpp_dout(s
, 10) << "Content of POST: " << post_body
<< dendl
;
756 if (post_body
.find("Action") != string::npos
) {
757 boost::char_separator
<char> sep("&");
758 boost::tokenizer
<boost::char_separator
<char>> tokens(post_body
, sep
);
759 for (const auto& t
: tokens
) {
760 auto pos
= t
.find("=");
761 if (pos
!= string::npos
) {
762 s
->info
.args
.append(t
.substr(0,pos
),
763 url_decode(t
.substr(pos
+1, t
.size() -1)));
768 auto payload_hash
= rgw::auth::s3::calc_v4_payload_hash(post_body
);
769 s
->info
.args
.append("PayloadHash", payload_hash
);
772 RGWOp
*RGWHandler_REST_STS::op_post()
774 rgw_sts_parse_input();
776 if (s
->info
.args
.exists("Action")) {
777 string action
= s
->info
.args
.get("Action");
778 if (action
== "AssumeRole") {
779 return new RGWSTSAssumeRole
;
780 } else if (action
== "GetSessionToken") {
781 return new RGWSTSGetSessionToken
;
782 } else if (action
== "AssumeRoleWithWebIdentity") {
783 return new RGWSTSAssumeRoleWithWebIdentity
;
790 int RGWHandler_REST_STS::init(rgw::sal::Store
* store
,
792 rgw::io::BasicClient
*cio
)
796 if (int ret
= RGWHandler_REST_STS::init_from_header(s
, RGW_FORMAT_XML
, true); ret
< 0) {
797 ldpp_dout(s
, 10) << "init_from_header returned err=" << ret
<< dendl
;
801 return RGWHandler_REST::init(store
, s
, cio
);
804 int RGWHandler_REST_STS::authorize(const DoutPrefixProvider
* dpp
, optional_yield y
)
806 if (s
->info
.args
.exists("Action") && s
->info
.args
.get("Action") == "AssumeRoleWithWebIdentity") {
807 return RGW_Auth_STS::authorize(dpp
, store
, auth_registry
, s
, y
);
809 return RGW_Auth_S3::authorize(dpp
, store
, auth_registry
, s
, y
);
812 int RGWHandler_REST_STS::init_from_header(struct req_state
* s
,
813 int default_formatter
,
814 bool configurable_format
)
819 s
->prot_flags
= RGW_REST_STS
;
821 const char *p
, *req_name
;
822 if (req_name
= s
->relative_uri
.c_str(); *req_name
== '?') {
825 p
= s
->info
.request_params
.c_str();
829 s
->info
.args
.parse(s
);
831 /* must be called after the args parsing */
832 if (int ret
= allocate_formatter(s
, default_formatter
, configurable_format
); ret
< 0)
835 if (*req_name
!= '/')
844 int pos
= req
.find('/');
846 first
= req
.substr(0, pos
);
855 RGWRESTMgr_STS::get_handler(rgw::sal::Store
* store
,
856 struct req_state
* const s
,
857 const rgw::auth::StrategyRegistry
& auth_registry
,
858 const std::string
& frontend_prefix
)
860 return new RGWHandler_REST_STS(auth_registry
);