};
+template <class ExtractorT>
class AWSv2AuthStrategy : public rgw::auth::Strategy,
public rgw::auth::LocalApplier::Factory {
typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
+
+ static_assert(std::is_base_of<rgw::auth::s3::Version2ndEngine::Extractor,
+ ExtractorT>::value,
+ "ExtractorT must be a subclass of rgw::auth::s3::ExtractorT");
+
RGWRados* const store;
+ ExtractorT extractor;
- rgw::auth::s3::RGWS3V2Extractor extractor;
ExternalAuthStrategy external_engines;
LocalVersion2ndEngine local_engine;
local_engine(cct, store, extractor,
static_cast<rgw::auth::LocalApplier::Factory*>(this)) {
add_engine(Control::SUFFICIENT, external_engines);
- if (cct->_conf->rgw_s3_auth_use_rados) {
- add_engine(Control::SUFFICIENT, local_engine);
- }
- }
- /* FIXME(rzarzynski): hack for S3's browsers upload. */
- AWSv2AuthStrategy(CephContext* const cct,
- RGWRados* const store,
- Version2ndEngine::Extractor* const external_extractor)
- : store(store),
- extractor(cct),
- external_engines(cct, store, external_extractor),
- local_engine(cct, store, *external_extractor,
- static_cast<rgw::auth::LocalApplier::Factory*>(this)) {
- add_engine(Control::SUFFICIENT, external_engines);
if (cct->_conf->rgw_s3_auth_use_rados) {
- add_engine(Control::SUFFICIENT, local_engine);
+ add_engine(Control::FALLBACK, local_engine);
}
}
class RGWEnv;
+/* Namespaced forward declarations. */
namespace rgw {
-namespace io {
-class BasicClient;
-}
+ namespace auth {
+ namespace s3 {
+ class RGWGetPolicyV2Extractor;
+ }
+ }
+ namespace io {
+ class BasicClient;
+ }
}
struct req_info {
std::unique_ptr<rgw::auth::Identity> identity;
std::unique_ptr<rgw::auth::Completer> completer;
+
+ /* A container for credentials of the S3's browser upload. It's necessary
+ * because: 1) the ::authenticate() method of auth engines and strategies
+ * take req_state only; 2) auth strategies live much longer than RGWOps -
+ * there is no way to pass additional data dependencies through ctors. */
+ class {
+ /* Writer. */
+ friend class RGWPostObj_ObjStore_S3;
+ /* Reader. */
+ friend class rgw::auth::s3::RGWGetPolicyV2Extractor;
+
+ std::string access_key;
+ std::string signature;
+ ceph::bufferlist encoded_policy;
+ } s3_postobj_creds;
} auth;
std::unique_ptr<RGWAccessControlPolicy> user_acl;
return 0;
}
-static std::string to_string(ceph::bufferlist& bl)
-{
- return std::string(bl.c_str(),
- static_cast<std::string::size_type>(bl.length()));
-}
-
int RGWPostObj_ObjStore_S3::get_policy()
{
- bufferlist encoded_policy;
-
- if (part_bl("policy", &encoded_policy)) {
+ if (part_bl("policy", &s->auth.s3_postobj_creds.encoded_policy)) {
// check that the signature matches the encoded policy
- string s3_access_key;
- if (!part_str("AWSAccessKeyId", &s3_access_key)) {
+ if (! part_str("AWSAccessKeyId", &s->auth.s3_postobj_creds.access_key)) {
ldout(s->cct, 0) << "No S3 access key found!" << dendl;
err_msg = "Missing access key";
return -EINVAL;
}
string received_signature_str;
- if (!part_str("signature", &received_signature_str)) {
+ if (! part_str("signature", &s->auth.s3_postobj_creds.signature)) {
ldout(s->cct, 0) << "No signature found!" << dendl;
err_msg = "Missing signature";
return -EINVAL;
}
- rgw::auth::s3::RGWGetPolicyV2Extractor extr(s3_access_key,
- received_signature_str,
- to_string(encoded_policy));
- /* FIXME: this is a makeshift solution. The browser upload authenication will be
+ /* FIXME: this is a makeshift solution. The browser upload authentication will be
* handled by an instance of rgw::auth::Completer spawned in Handler's authorize()
- * method. Thus creating a strategy per request won't be necessary. */
- const rgw::auth::s3::AWSv2AuthStrategy strategy(g_ceph_context, store, &extr);
+ * method. */
+ static const rgw::auth::s3::AWSv2AuthStrategy<
+ rgw::auth::s3::RGWGetPolicyV2Extractor> strategy(g_ceph_context, store);
try {
auto result = strategy.authenticate(s);
if (result.get_status() != decltype(result)::Status::GRANTED) {
ceph::bufferlist decoded_policy;
try {
- decoded_policy.decode_base64(encoded_policy);
+ decoded_policy.decode_base64(s->auth.s3_postobj_creds.encoded_policy);
} catch (buffer::error& err) {
ldout(s->cct, 0) << "failed to decode_base64 policy" << dendl;
err_msg = "Could not decode policy";
{
/* TODO(rzarzynski): this will be moved to the S3 handlers -- in exactly
* way like we currently have in the case of Swift API. */
- static const rgw::auth::s3::AWSv2AuthStrategy strategy(g_ceph_context, store);
+ static const rgw::auth::s3::AWSv2AuthStrategy<rgw::auth::s3::RGWS3V2Extractor> strategy(g_ceph_context, store);
try {
auto result = strategy.authenticate(s);
if (result.get_status() != decltype(result)::Status::GRANTED) {
class RGWGetPolicyV2Extractor : public Version2ndEngine::Extractor {
-private:
- std::string access_key_id;
- std::string signature;
- std::string string_to_sign;
+ static std::string to_string(ceph::bufferlist bl) {
+ return std::string(bl.c_str(),
+ static_cast<std::string::size_type>(bl.length()));
+ }
public:
- RGWGetPolicyV2Extractor(std::string access_key_id,
- std::string signature,
- std::string string_to_sign)
- : access_key_id(std::move(access_key_id)),
- signature(std::move(signature)),
- string_to_sign(std::move(string_to_sign)) {
+ RGWGetPolicyV2Extractor(CephContext*) {
}
std::tuple<access_key_id_t,
signature_t,
string_to_sign_t>
get_auth_data(const req_state* s) const override {
- return std::make_tuple(access_key_id, signature, string_to_sign);
+ return std::make_tuple(s->auth.s3_postobj_creds.access_key,
+ s->auth.s3_postobj_creds.signature,
+ to_string(s->auth.s3_postobj_creds.encoded_policy));
}
};