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
= driver
->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
;
313 bufferlist openidc_resp
;
315 if (openidc_wellknown_url
.back() == '/') {
316 openidc_wellknown_url
.pop_back();
318 openidc_wellknown_url
.append("/.well-known/openid-configuration");
320 RGWHTTPTransceiver
openidc_req(cct
, "GET", openidc_wellknown_url
, &openidc_resp
);
323 openidc_req
.append_header("Content-Type", "application/x-www-form-urlencoded");
325 int res
= openidc_req
.process(y
);
327 ldpp_dout(dpp
, 10) << "HTTP request res: " << res
<< dendl
;
332 ldpp_dout(dpp
, 20) << "HTTP status: " << openidc_req
.get_http_status() << dendl
;
333 ldpp_dout(dpp
, 20) << "JSON Response is: " << openidc_resp
.c_str() << dendl
;
336 if (parser
.parse(openidc_resp
.c_str(), openidc_resp
.length())) {
337 JSONObj::data_val val
;
338 if (parser
.get_data("jwks_uri", &val
)) {
339 cert_url
= val
.str
.c_str();
340 ldpp_dout(dpp
, 20) << "Cert URL is: " << cert_url
.c_str() << dendl
;
342 ldpp_dout(dpp
, 0) << "Malformed json returned while fetching openidc url" << dendl
;
349 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
351 if (algorithm
!= "HS256" && algorithm
!= "HS384" && algorithm
!= "HS512") {
352 string cert_url
= get_cert_url(iss
, dpp
, y
);
353 if (cert_url
.empty()) {
358 bufferlist cert_resp
;
359 RGWHTTPTransceiver
cert_req(cct
, "GET", cert_url
, &cert_resp
);
361 cert_req
.append_header("Content-Type", "application/x-www-form-urlencoded");
363 int res
= cert_req
.process(y
);
365 ldpp_dout(dpp
, 10) << "HTTP request res: " << res
<< dendl
;
369 ldpp_dout(dpp
, 20) << "HTTP status: " << cert_req
.get_http_status() << dendl
;
370 ldpp_dout(dpp
, 20) << "JSON Response is: " << cert_resp
.c_str() << dendl
;
373 if (parser
.parse(cert_resp
.c_str(), cert_resp
.length())) {
374 JSONObj::data_val val
;
375 if (parser
.get_data("keys", &val
)) {
376 if (val
.str
[0] == '[') {
379 if (val
.str
[val
.str
.size() - 1] == ']') {
380 val
.str
= val
.str
.erase(val
.str
.size() - 1, 1);
382 if (parser
.parse(val
.str
.c_str(), val
.str
.size())) {
384 if (JSONDecoder::decode_json("x5c", x5c
, &parser
)) {
386 bool found_valid_cert
= false;
387 for (auto& it
: x5c
) {
388 cert
= "-----BEGIN CERTIFICATE-----\n" + it
+ "\n-----END CERTIFICATE-----";
389 ldpp_dout(dpp
, 20) << "Certificate is: " << cert
.c_str() << dendl
;
390 if (is_cert_valid(thumbprints
, cert
)) {
391 found_valid_cert
= true;
394 found_valid_cert
= true;
396 if (! found_valid_cert
) {
397 ldpp_dout(dpp
, 0) << "Cert doesn't match that with the thumbprints registered with oidc provider: " << cert
.c_str() << dendl
;
401 //verify method takes care of expired tokens also
402 if (algorithm
== "RS256") {
403 auto verifier
= jwt::verify()
404 .allow_algorithm(jwt::algorithm::rs256
{cert
});
406 verifier
.verify(decoded
);
407 } else if (algorithm
== "RS384") {
408 auto verifier
= jwt::verify()
409 .allow_algorithm(jwt::algorithm::rs384
{cert
});
411 verifier
.verify(decoded
);
412 } else if (algorithm
== "RS512") {
413 auto verifier
= jwt::verify()
414 .allow_algorithm(jwt::algorithm::rs512
{cert
});
416 verifier
.verify(decoded
);
417 } else if (algorithm
== "ES256") {
418 auto verifier
= jwt::verify()
419 .allow_algorithm(jwt::algorithm::es256
{cert
});
421 verifier
.verify(decoded
);
422 } else if (algorithm
== "ES384") {
423 auto verifier
= jwt::verify()
424 .allow_algorithm(jwt::algorithm::es384
{cert
});
426 verifier
.verify(decoded
);
427 } else if (algorithm
== "ES512") {
428 auto verifier
= jwt::verify()
429 .allow_algorithm(jwt::algorithm::es512
{cert
});
431 verifier
.verify(decoded
);
432 } else if (algorithm
== "PS256") {
433 auto verifier
= jwt::verify()
434 .allow_algorithm(jwt::algorithm::ps256
{cert
});
436 verifier
.verify(decoded
);
437 } else if (algorithm
== "PS384") {
438 auto verifier
= jwt::verify()
439 .allow_algorithm(jwt::algorithm::ps384
{cert
});
441 verifier
.verify(decoded
);
442 } else if (algorithm
== "PS512") {
443 auto verifier
= jwt::verify()
444 .allow_algorithm(jwt::algorithm::ps512
{cert
});
446 verifier
.verify(decoded
);
448 } catch (std::runtime_error
& e
) {
449 ldpp_dout(dpp
, 0) << "Signature validation failed: " << e
.what() << dendl
;
453 ldpp_dout(dpp
, 0) << "Signature validation failed" << dendl
;
457 ldpp_dout(dpp
, 0) << "x5c not present" << dendl
;
461 ldpp_dout(dpp
, 0) << "Malformed JSON object for keys" << dendl
;
465 ldpp_dout(dpp
, 0) << "keys not present in JSON" << dendl
;
469 ldpp_dout(dpp
, 0) << "Malformed json returned while fetching cert" << dendl
;
471 } //if-else parser cert_resp
473 ldpp_dout(dpp
, 0) << "JWT signed by HMAC algos are currently not supported" << dendl
;
478 WebTokenEngine::result_t
479 WebTokenEngine::authenticate( const DoutPrefixProvider
* dpp
,
480 const std::string
& token
,
481 const req_state
* const s
,
482 optional_yield y
) const
484 if (! is_applicable(token
)) {
485 return result_t::deny();
489 auto [t
, princ_tags
] = get_from_jwt(dpp
, token
, s
, y
);
491 string role_session
= s
->info
.args
.get("RoleSessionName");
492 if (role_session
.empty()) {
493 ldout(s
->cct
, 0) << "Role Session Name is empty " << dendl
;
494 return result_t::deny(-EACCES
);
496 string role_arn
= s
->info
.args
.get("RoleArn");
497 string role_tenant
= get_role_tenant(role_arn
);
498 string role_name
= get_role_name(role_arn
);
499 std::unique_ptr
<rgw::sal::RGWRole
> role
= driver
->get_role(role_name
, role_tenant
);
500 int ret
= role
->get(dpp
, y
);
502 ldpp_dout(dpp
, 0) << "Role not found: name:" << role_name
<< " tenant: " << role_tenant
<< dendl
;
503 return result_t::deny(-EACCES
);
505 boost::optional
<multimap
<string
,string
>> role_tags
= role
->get_tags();
506 auto apl
= apl_factory
->create_apl_web_identity(cct
, s
, role_session
, role_tenant
, *t
, role_tags
, princ_tags
);
507 return result_t::grant(std::move(apl
));
509 return result_t::deny(-EACCES
);
512 return result_t::deny(-EACCES
);
516 } // namespace rgw::auth::sts
518 int RGWREST_STS::verify_permission(optional_yield y
)
520 STS::STSService
_sts(s
->cct
, driver
, s
->user
->get_id(), s
->auth
.identity
.get());
521 sts
= std::move(_sts
);
523 string rArn
= s
->info
.args
.get("RoleArn");
524 const auto& [ret
, role
] = sts
.getRoleInfo(s
, rArn
, y
);
526 ldpp_dout(this, 0) << "failed to get role info using role arn: " << rArn
<< dendl
;
529 string policy
= role
->get_assume_role_policy();
530 buffer::list bl
= buffer::list::static_from_string(policy
);
533 //TODO - This step should be part of Role Creation
535 const rgw::IAM::Policy
p(s
->cct
, s
->user
->get_tenant(), bl
, false);
536 if (!s
->principal_tags
.empty()) {
537 auto res
= p
.eval(s
->env
, *s
->auth
.identity
, rgw::IAM::stsTagSession
, boost::none
);
538 if (res
!= rgw::IAM::Effect::Allow
) {
539 ldout(s
->cct
, 0) << "evaluating policy for stsTagSession returned deny/pass" << dendl
;
544 if (get_type() == RGW_STS_ASSUME_ROLE_WEB_IDENTITY
) {
545 op
= rgw::IAM::stsAssumeRoleWithWebIdentity
;
547 op
= rgw::IAM::stsAssumeRole
;
550 auto res
= p
.eval(s
->env
, *s
->auth
.identity
, op
, boost::none
);
551 if (res
!= rgw::IAM::Effect::Allow
) {
552 ldout(s
->cct
, 0) << "evaluating policy for op: " << op
<< " returned deny/pass" << dendl
;
555 } catch (rgw::IAM::PolicyParseException
& e
) {
556 ldpp_dout(this, 0) << "failed to parse policy: " << e
.what() << dendl
;
563 void RGWREST_STS::send_response()
566 set_req_state_err(s
, op_ret
);
572 int RGWSTSGetSessionToken::verify_permission(optional_yield y
)
574 rgw::Partition partition
= rgw::Partition::aws
;
575 rgw::Service service
= rgw::Service::s3
;
576 if (!verify_user_permission(this,
578 rgw::ARN(partition
, service
, "", s
->user
->get_tenant(), ""),
579 rgw::IAM::stsGetSessionToken
)) {
580 ldpp_dout(this, 0) << "User does not have permssion to perform GetSessionToken" << dendl
;
587 int RGWSTSGetSessionToken::get_params()
589 duration
= s
->info
.args
.get("DurationSeconds");
590 serialNumber
= s
->info
.args
.get("SerialNumber");
591 tokenCode
= s
->info
.args
.get("TokenCode");
593 if (! duration
.empty()) {
595 uint64_t duration_in_secs
= strict_strtoll(duration
.c_str(), 10, &err
);
597 ldpp_dout(this, 0) << "Invalid value of input duration: " << duration
<< dendl
;
601 if (duration_in_secs
< STS::GetSessionTokenRequest::getMinDuration() ||
602 duration_in_secs
> s
->cct
->_conf
->rgw_sts_max_session_duration
) {
603 ldpp_dout(this, 0) << "Invalid duration in secs: " << duration_in_secs
<< dendl
;
611 void RGWSTSGetSessionToken::execute(optional_yield y
)
613 if (op_ret
= get_params(); op_ret
< 0) {
617 STS::STSService
sts(s
->cct
, driver
, s
->user
->get_id(), s
->auth
.identity
.get());
619 STS::GetSessionTokenRequest
req(duration
, serialNumber
, tokenCode
);
620 const auto& [ret
, creds
] = sts
.getSessionToken(this, req
);
621 op_ret
= std::move(ret
);
624 s
->formatter
->open_object_section("GetSessionTokenResponse");
625 s
->formatter
->open_object_section("GetSessionTokenResult");
626 s
->formatter
->open_object_section("Credentials");
627 creds
.dump(s
->formatter
);
628 s
->formatter
->close_section();
629 s
->formatter
->close_section();
630 s
->formatter
->close_section();
634 int RGWSTSAssumeRoleWithWebIdentity::get_params()
636 duration
= s
->info
.args
.get("DurationSeconds");
637 providerId
= s
->info
.args
.get("ProviderId");
638 policy
= s
->info
.args
.get("Policy");
639 roleArn
= s
->info
.args
.get("RoleArn");
640 roleSessionName
= s
->info
.args
.get("RoleSessionName");
641 iss
= s
->info
.args
.get("provider_id");
642 sub
= s
->info
.args
.get("sub");
643 aud
= s
->info
.args
.get("aud");
645 if (roleArn
.empty() || roleSessionName
.empty() || sub
.empty() || aud
.empty()) {
646 ldpp_dout(this, 0) << "ERROR: one of role arn or role session name or token is empty" << dendl
;
650 if (! policy
.empty()) {
651 bufferlist bl
= bufferlist::static_from_string(policy
);
653 const rgw::IAM::Policy
p(
654 s
->cct
, s
->user
->get_tenant(), bl
,
655 s
->cct
->_conf
.get_val
<bool>("rgw_policy_reject_invalid_principals"));
657 catch (rgw::IAM::PolicyParseException
& e
) {
658 ldpp_dout(this, 5) << "failed to parse policy: " << e
.what() << "policy" << policy
<< dendl
;
659 s
->err
.message
= e
.what();
660 return -ERR_MALFORMED_DOC
;
667 void RGWSTSAssumeRoleWithWebIdentity::execute(optional_yield y
)
669 if (op_ret
= get_params(); op_ret
< 0) {
673 STS::AssumeRoleWithWebIdentityRequest
req(s
->cct
, duration
, providerId
, policy
, roleArn
,
674 roleSessionName
, iss
, sub
, aud
, s
->principal_tags
);
675 STS::AssumeRoleWithWebIdentityResponse response
= sts
.assumeRoleWithWebIdentity(this, req
);
676 op_ret
= std::move(response
.assumeRoleResp
.retCode
);
680 s
->formatter
->open_object_section("AssumeRoleWithWebIdentityResponse");
681 s
->formatter
->open_object_section("AssumeRoleWithWebIdentityResult");
682 encode_json("SubjectFromWebIdentityToken", response
.sub
, s
->formatter
);
683 encode_json("Audience", response
.aud
, s
->formatter
);
684 s
->formatter
->open_object_section("AssumedRoleUser");
685 response
.assumeRoleResp
.user
.dump(s
->formatter
);
686 s
->formatter
->close_section();
687 s
->formatter
->open_object_section("Credentials");
688 response
.assumeRoleResp
.creds
.dump(s
->formatter
);
689 s
->formatter
->close_section();
690 encode_json("Provider", response
.providerId
, s
->formatter
);
691 encode_json("PackedPolicySize", response
.assumeRoleResp
.packedPolicySize
, s
->formatter
);
692 s
->formatter
->close_section();
693 s
->formatter
->close_section();
697 int RGWSTSAssumeRole::get_params()
699 duration
= s
->info
.args
.get("DurationSeconds");
700 externalId
= s
->info
.args
.get("ExternalId");
701 policy
= s
->info
.args
.get("Policy");
702 roleArn
= s
->info
.args
.get("RoleArn");
703 roleSessionName
= s
->info
.args
.get("RoleSessionName");
704 serialNumber
= s
->info
.args
.get("SerialNumber");
705 tokenCode
= s
->info
.args
.get("TokenCode");
707 if (roleArn
.empty() || roleSessionName
.empty()) {
708 ldpp_dout(this, 0) << "ERROR: one of role arn or role session name is empty" << dendl
;
712 if (! policy
.empty()) {
713 bufferlist bl
= bufferlist::static_from_string(policy
);
715 const rgw::IAM::Policy
p(
716 s
->cct
, s
->user
->get_tenant(), bl
,
717 s
->cct
->_conf
.get_val
<bool>("rgw_policy_reject_invalid_principals"));
719 catch (rgw::IAM::PolicyParseException
& e
) {
720 ldpp_dout(this, 0) << "failed to parse policy: " << e
.what() << "policy" << policy
<< dendl
;
721 s
->err
.message
= e
.what();
722 return -ERR_MALFORMED_DOC
;
729 void RGWSTSAssumeRole::execute(optional_yield y
)
731 if (op_ret
= get_params(); op_ret
< 0) {
735 STS::AssumeRoleRequest
req(s
->cct
, duration
, externalId
, policy
, roleArn
,
736 roleSessionName
, serialNumber
, tokenCode
);
737 STS::AssumeRoleResponse response
= sts
.assumeRole(s
, req
, y
);
738 op_ret
= std::move(response
.retCode
);
741 s
->formatter
->open_object_section("AssumeRoleResponse");
742 s
->formatter
->open_object_section("AssumeRoleResult");
743 s
->formatter
->open_object_section("Credentials");
744 response
.creds
.dump(s
->formatter
);
745 s
->formatter
->close_section();
746 s
->formatter
->open_object_section("AssumedRoleUser");
747 response
.user
.dump(s
->formatter
);
748 s
->formatter
->close_section();
749 encode_json("PackedPolicySize", response
.packedPolicySize
, s
->formatter
);
750 s
->formatter
->close_section();
751 s
->formatter
->close_section();
755 int RGW_Auth_STS::authorize(const DoutPrefixProvider
*dpp
,
756 rgw::sal::Driver
* driver
,
757 const rgw::auth::StrategyRegistry
& auth_registry
,
758 req_state
*s
, optional_yield y
)
760 return rgw::auth::Strategy::apply(dpp
, auth_registry
.get_sts(), s
, y
);
763 using op_generator
= RGWOp
*(*)();
764 static const std::unordered_map
<std::string_view
, op_generator
> op_generators
= {
765 {"AssumeRole", []() -> RGWOp
* {return new RGWSTSAssumeRole
;}},
766 {"GetSessionToken", []() -> RGWOp
* {return new RGWSTSGetSessionToken
;}},
767 {"AssumeRoleWithWebIdentity", []() -> RGWOp
* {return new RGWSTSAssumeRoleWithWebIdentity
;}}
770 bool RGWHandler_REST_STS::action_exists(const req_state
* s
)
772 if (s
->info
.args
.exists("Action")) {
773 const std::string action_name
= s
->info
.args
.get("Action");
774 return op_generators
.contains(action_name
);
779 RGWOp
*RGWHandler_REST_STS::op_post()
781 if (s
->info
.args
.exists("Action")) {
782 const std::string action_name
= s
->info
.args
.get("Action");
783 const auto action_it
= op_generators
.find(action_name
);
784 if (action_it
!= op_generators
.end()) {
785 return action_it
->second();
787 ldpp_dout(s
, 10) << "unknown action '" << action_name
<< "' for STS handler" << dendl
;
789 ldpp_dout(s
, 10) << "missing action argument in STS handler" << dendl
;
794 int RGWHandler_REST_STS::init(rgw::sal::Driver
* driver
,
796 rgw::io::BasicClient
*cio
)
799 s
->prot_flags
= RGW_REST_STS
;
801 return RGWHandler_REST::init(driver
, 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
, driver
, auth_registry
, s
, y
);
809 return RGW_Auth_S3::authorize(dpp
, driver
, auth_registry
, s
, y
);
813 RGWRESTMgr_STS::get_handler(rgw::sal::Driver
* driver
,
815 const rgw::auth::StrategyRegistry
& auth_registry
,
816 const std::string
& frontend_prefix
)
818 return new RGWHandler_REST_STS(auth_registry
);