#include "common/sstring.hh"
#include "rgw_common.h"
#include "rgw_rest_s3.h"
-
#include "rgw_auth.h"
#include "rgw_auth_filters.h"
#include "rgw_auth_keystone.h"
// returns true if the request time is within RGW_AUTH_GRACE of the current time
bool is_time_skew_ok(time_t t);
+class STSAuthStrategy : public rgw::auth::Strategy,
+ public rgw::auth::RemoteApplier::Factory,
+ public rgw::auth::LocalApplier::Factory,
+ public rgw::auth::RoleApplier::Factory {
+ typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
+ RGWRados* const store;
+
+ STSEngine sts_engine;
+
+ aplptr_t create_apl_remote(CephContext* const cct,
+ const req_state* const s,
+ rgw::auth::RemoteApplier::acl_strategy_t&& acl_alg,
+ const rgw::auth::RemoteApplier::AuthInfo &info
+ ) const override {
+ auto apl = rgw::auth::add_sysreq(cct, store, s,
+ rgw::auth::RemoteApplier(cct, store, std::move(acl_alg), info,
+ cct->_conf->rgw_keystone_implicit_tenants));
+ return aplptr_t(new decltype(apl)(std::move(apl)));
+ }
+
+ aplptr_t create_apl_local(CephContext* const cct,
+ const req_state* const s,
+ const RGWUserInfo& user_info,
+ const std::string& subuser,
+ const boost::optional<uint32_t>& perm_mask) const override {
+ auto apl = rgw::auth::add_sysreq(cct, store, s,
+ rgw::auth::LocalApplier(cct, user_info, subuser, perm_mask));
+ return aplptr_t(new decltype(apl)(std::move(apl)));
+ }
+
+ aplptr_t create_apl_role(CephContext* const cct,
+ const req_state* const s,
+ const string& role_name,
+ const rgw_user& user_id,
+ const vector<std::string>& role_policies) const override {
+ auto apl = rgw::auth::add_sysreq(cct, store, s,
+ rgw::auth::RoleApplier(cct, role_name, user_id, role_policies));
+ return aplptr_t(new decltype(apl)(std::move(apl)));
+ }
+
+public:
+ STSAuthStrategy(CephContext* const cct,
+ RGWRados* const store,
+ AWSEngine::VersionAbstractor* const ver_abstractor)
+ : store(store),
+ sts_engine(cct, store, *ver_abstractor,
+ static_cast<rgw::auth::LocalApplier::Factory*>(this),
+ static_cast<rgw::auth::RemoteApplier::Factory*>(this),
+ static_cast<rgw::auth::RoleApplier::Factory*>(this)) {
+ if (cct->_conf->rgw_s3_auth_use_sts) {
+ add_engine(Control::SUFFICIENT, sts_engine);
+ }
+ }
+
+ const char* get_name() const noexcept override {
+ return "rgw::auth::s3::STSAuthStrategy";
+ }
+};
+
class ExternalAuthStrategy : public rgw::auth::Strategy,
public rgw::auth::RemoteApplier::Factory {
typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
RGWRados* const store;
- rgw::auth::ImplicitTenants& implicit_tenant_context;
using keystone_config_t = rgw::keystone::CephCtxConfig;
using keystone_cache_t = rgw::keystone::TokenCache;
aplptr_t create_apl_remote(CephContext* const cct,
const req_state* const s,
rgw::auth::RemoteApplier::acl_strategy_t&& acl_alg,
- const rgw::auth::RemoteApplier::AuthInfo info
+ const rgw::auth::RemoteApplier::AuthInfo &info
) const override {
auto apl = rgw::auth::add_sysreq(cct, store, s,
rgw::auth::RemoteApplier(cct, store, std::move(acl_alg), info,
- implicit_tenant_context,
- rgw::auth::ImplicitTenants::IMPLICIT_TENANTS_S3));
+ cct->_conf->rgw_keystone_implicit_tenants));
/* TODO(rzarzynski): replace with static_ptr. */
return aplptr_t(new decltype(apl)(std::move(apl)));
}
public:
ExternalAuthStrategy(CephContext* const cct,
RGWRados* const store,
- rgw::auth::ImplicitTenants& implicit_tenant_context,
AWSEngine::VersionAbstractor* const ver_abstractor)
: store(store),
- implicit_tenant_context(implicit_tenant_context),
ldap_engine(cct, store, *ver_abstractor,
static_cast<rgw::auth::RemoteApplier::Factory*>(this)) {
S3AnonymousEngine anonymous_engine;
ExternalAuthStrategy external_engines;
+ STSAuthStrategy sts_engine;
LocalEngine local_engine;
aplptr_t create_apl_local(CephContext* const cct,
const req_state* const s,
const RGWUserInfo& user_info,
- const std::string& subuser) const override {
+ const std::string& subuser,
+ const boost::optional<uint32_t>& perm_mask) const override {
auto apl = rgw::auth::add_sysreq(cct, store, s,
- rgw::auth::LocalApplier(cct, user_info, subuser));
+ rgw::auth::LocalApplier(cct, user_info, subuser, perm_mask));
/* TODO(rzarzynski): replace with static_ptr. */
return aplptr_t(new decltype(apl)(std::move(apl)));
}
if (&eng == &auth_order.back() && eng_map.size() > 1) {
ctrl_flag = Control::FALLBACK;
}
- const auto kv = eng_map.find(eng);
- if (kv != eng_map.end()) {
+ if (const auto kv = eng_map.find(eng);
+ kv != eng_map.end()) {
add_engine(ctrl_flag, kv->second);
}
}
}
- std::vector<std::string> parse_auth_order(CephContext* const cct)
+ auto parse_auth_order(CephContext* const cct)
{
std::vector <std::string> result;
- const std::set <boost::string_view> allowed_auth = { "external", "local" };
- std::vector <std::string> default_order = { "external", "local"};
+ const std::set <std::string_view> allowed_auth = { "sts", "external", "local" };
+ std::vector <std::string> default_order = { "sts", "external", "local" };
// supplied strings may contain a space, so let's bypass that
boost::split(result, cct->_conf->rgw_s3_auth_order,
boost::is_any_of(", "), boost::token_compress_on);
if (std::any_of(result.begin(), result.end(),
- [allowed_auth](boost::string_view s)
+ [allowed_auth](std::string_view s)
{ return allowed_auth.find(s) == allowed_auth.end();})){
return default_order;
}
}
AWSAuthStrategy(CephContext* const cct,
- rgw::auth::ImplicitTenants& implicit_tenant_context,
RGWRados* const store)
: store(store),
ver_abstractor(cct),
anonymous_engine(cct,
static_cast<rgw::auth::LocalApplier::Factory*>(this)),
- external_engines(cct, store, implicit_tenant_context, &ver_abstractor),
+ external_engines(cct, store, &ver_abstractor),
+ sts_engine(cct, store, &ver_abstractor),
local_engine(cct, store, ver_abstractor,
static_cast<rgw::auth::LocalApplier::Factory*>(this)) {
- /* The anynoymous auth. */
+ /* The anonymous auth. */
if (AllowAnonAccessT) {
add_engine(Control::SUFFICIENT, anonymous_engine);
}
auto auth_order = parse_auth_order(cct);
engine_map_t engine_map;
+
+ /* STS Auth*/
+ if (! sts_engine.is_empty()) {
+ engine_map.insert(std::make_pair("sts", std::cref(sts_engine)));
+ }
+
/* The external auth. */
if (! external_engines.is_empty()) {
engine_map.insert(std::make_pair("external", std::cref(external_engines)));
if (cct->_conf->rgw_s3_auth_use_rados) {
engine_map.insert(std::make_pair("local", std::cref(local_engine)));
}
+
add_engines(auth_order, engine_map);
}
public rgw::io::DecoratedRestfulClient<rgw::io::RestfulClient*>,
public std::enable_shared_from_this<AWSv4ComplMulti> {
using io_base_t = rgw::io::DecoratedRestfulClient<rgw::io::RestfulClient*>;
- using signing_key_t = std::array<unsigned char,
- CEPH_CRYPTO_HMACSHA256_DIGESTSIZE>;
+ using signing_key_t = sha256_digest_t;
CephContext* const cct;
signature(signature.to_string()) {
}
- ChunkMeta(const boost::string_view& signature)
+ explicit ChunkMeta(const boost::string_view& signature)
: signature(signature.to_string()) {
}
size_t recv_body(char* buf, size_t max) override;
/* rgw::auth::Completer. */
- void modify_request_state(req_state* s_rw) override;
+ void modify_request_state(const DoutPrefixProvider* dpp, req_state* s_rw) override;
bool complete() override;
/* Factories. */
/* Defined in rgw_auth_s3.cc because of get_v4_exp_payload_hash(). We need
* the constructor to be public because of the std::make_shared employed by
* the create() method. */
- AWSv4ComplSingle(const req_state* const s);
+ explicit AWSv4ComplSingle(const req_state* const s);
~AWSv4ComplSingle() {
if (sha256_hash) {
size_t recv_body(char* buf, size_t max) override;
/* rgw::auth::Completer. */
- void modify_request_state(req_state* s_rw) override;
+ void modify_request_state(const DoutPrefixProvider* dpp, req_state* s_rw) override;
bool complete() override;
/* Factories. */
boost::string_view& signedheaders, /* out */
boost::string_view& signature, /* out */
boost::string_view& date, /* out */
- bool& using_qs); /* out */
+ boost::string_view& session_token, /* out */
+ const bool using_qs); /* in */
+
+static inline bool char_needs_aws4_escaping(const char c, bool encode_slash)
+{
+ if ((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9')) {
+ return false;
+ }
+
+ switch (c) {
+ case '-':
+ case '_':
+ case '.':
+ case '~':
+ return false;
+ }
+
+ if (c == '/' && !encode_slash)
+ return false;
+
+ return true;
+}
+
+static inline std::string aws4_uri_encode(const std::string& src, bool encode_slash)
+{
+ std::string result;
+
+ for (const std::string::value_type c : src) {
+ if (char_needs_aws4_escaping(c, encode_slash)) {
+ rgw_uri_escape_char(c, result);
+ } else {
+ result.push_back(c);
+ }
+ }
+
+ return result;
+}
+
+static inline std::string aws4_uri_recode(const boost::string_view& src, bool encode_slash)
+{
+ std::string decoded = url_decode(src);
+ return aws4_uri_encode(decoded, encode_slash);
+}
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
* normalization that SigV4 typically does. This code follows the same
* approach that boto library. See auth.py:canonical_uri(...). */
- std::string canonical_uri = info.request_uri_aws4;
+ std::string canonical_uri = aws4_uri_recode(info.request_uri_aws4, false);
if (canonical_uri.empty()) {
canonical_uri = "/";
return canonical_uri;
}
+static inline const string calc_v4_payload_hash(const string& payload)
+{
+ ceph::crypto::SHA256* sha256_hash = calc_hash_sha256_open_stream();
+ calc_hash_sha256_update_stream(sha256_hash, payload.c_str(), payload.length());
+ const auto payload_hash = calc_hash_sha256_close_stream(&sha256_hash);
+ return payload_hash;
+}
+
static inline const char* get_v4_exp_payload_hash(const req_info& info)
{
- /* In AWSv4 the hash of real, transfered payload IS NOT necessary to form
+ /* In AWSv4 the hash of real, transferred payload IS NOT necessary to form
* a Canonical Request, and thus verify a Signature. x-amz-content-sha256
* header lets get the information very early -- before seeing first byte
* of HTTP body. As a consequence, we can decouple Signature verification
get_v2_signature(CephContext*,
const std::string& secret_key,
const AWSEngine::VersionAbstractor::string_to_sign_t& string_to_sign);
-
} /* namespace s3 */
} /* namespace auth */
} /* namespace rgw */