]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/rgw/rgw_auth_s3.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rgw / rgw_auth_s3.h
index ed5096e36dbcef03eefc30d815852017de8713e6..e01876e21829539c4f341fbe4035b590049d0d28 100644 (file)
@@ -17,7 +17,6 @@
 #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"
@@ -32,11 +31,69 @@ static constexpr auto RGW_AUTH_GRACE = std::chrono::minutes{15};
 // 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;
@@ -48,12 +105,11 @@ class ExternalAuthStrategy : public rgw::auth::Strategy,
   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)));
   }
@@ -61,10 +117,8 @@ class ExternalAuthStrategy : public rgw::auth::Strategy,
 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)) {
 
@@ -105,14 +159,16 @@ class AWSAuthStrategy : public rgw::auth::Strategy,
 
   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)));
   }
@@ -129,25 +185,25 @@ public:
       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;
     }
@@ -155,22 +211,28 @@ public:
   }
 
   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)));
@@ -179,6 +241,7 @@ public:
     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);
   }
 
@@ -192,8 +255,7 @@ class AWSv4ComplMulti : public rgw::auth::Completer,
                         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;
 
@@ -214,7 +276,7 @@ class AWSv4ComplMulti : public rgw::auth::Completer,
         signature(signature.to_string()) {
     }
 
-    ChunkMeta(const boost::string_view& signature)
+    explicit ChunkMeta(const boost::string_view& signature)
       : signature(signature.to_string()) {
     }
 
@@ -293,7 +355,7 @@ public:
   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. */
@@ -318,7 +380,7 @@ public:
   /* 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) {
@@ -330,7 +392,7 @@ public:
   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. */
@@ -387,14 +449,58 @@ int parse_v4_credentials(const req_info& info,                     /* in */
                         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 = "/";
@@ -405,9 +511,17 @@ static inline std::string get_v4_canonical_uri(const req_info& info) {
   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
@@ -485,7 +599,6 @@ extern AWSEngine::VersionAbstractor::server_signature_t
 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 */