]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: Added code for auth using temp credentials returned by STS.
authorPritha Srivastava <prsrivas@redhat.com>
Thu, 14 Jun 2018 04:46:33 +0000 (10:16 +0530)
committerPritha Srivastava <prsrivas@redhat.com>
Fri, 21 Sep 2018 05:39:33 +0000 (11:09 +0530)
Signed-off-by: Pritha Srivastava <prsrivas@redhat.com>
14 files changed:
src/common/legacy_config_opts.h
src/common/options.cc
src/rgw/rgw_auth.cc
src/rgw/rgw_auth.h
src/rgw/rgw_auth_filters.h
src/rgw/rgw_auth_keystone.cc
src/rgw/rgw_auth_keystone.h
src/rgw/rgw_auth_s3.cc
src/rgw/rgw_auth_s3.h
src/rgw/rgw_common.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h
src/rgw/rgw_swift_auth.cc
src/rgw/rgw_swift_auth.h

index 7fca815d8f2bc74a9779c63b6d91d1b8edcebcc8..a9cea4ad46fb424cf6100a46635e291741188553 100644 (file)
@@ -1547,3 +1547,4 @@ OPTION(rgw_delete_multi_obj_max_num, OPT_INT) // According to AWS S3(https://doc
 OPTION(rgw_website_routing_rules_max_num, OPT_INT) // According to AWS S3, An website routing config can have up to 50 rules.
 OPTION(rgw_sts_entry, OPT_STR)
 OPTION(rgw_sts_key, OPT_STR)
+OPTION(rgw_s3_auth_use_sts, OPT_BOOL)  // should we try to use sts for s3?
index 10006540e0c8d22669045a5760ca7ba386f132a0..66bb371180b6b772c564a359e39500036c0b24ca 100644 (file)
@@ -5372,7 +5372,7 @@ std::vector<Option> get_rgw_options() {
     .set_description("Should S3 authentication use Keystone."),
 
     Option("rgw_s3_auth_order", Option::TYPE_STR, Option::LEVEL_ADVANCED)
-     .set_default("external, local")
+     .set_default("external, local, sts")
      .set_description("Authentication strategy order to use for s3 authentication")
      .set_long_description(
          "Order of authentication strategies to try for s3 authentication, the allowed "
@@ -6356,7 +6356,11 @@ std::vector<Option> get_rgw_options() {
     Option("rgw_sts_key", Option::TYPE_STR, Option::LEVEL_ADVANCED)
     .set_default("sts")
     .set_description("STS Key")
-    .set_long_description("Key used for encrypting/ decrypting session token.")
+    .set_long_description("Key used for encrypting/ decrypting session token."),
+
+    Option("rgw_s3_auth_use_sts", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+    .set_default(false)
+    .set_description("Should S3 authentication use STS."),
 
   });
 }
index b15620dc6972dbd815cb5db2bb17eea56cb5c81d..b678ff6449f9952161adfe98951c24c411e278a0 100644 (file)
@@ -529,6 +529,21 @@ void rgw::auth::LocalApplier::load_acct_info(RGWUserInfo& user_info) const /* ou
   user_info = this->user_info;
 }
 
+void rgw::auth::LocalApplier::modify_request_state(req_state* s) const
+{
+  for (auto it : role_policies) {
+    try {
+      bufferlist bl = bufferlist::static_from_string(it);
+      const rgw::IAM::Policy p(s->cct, s->user->user_id.tenant, bl);
+      s->iam_user_policies.push_back(std::move(p));
+    } catch (rgw::IAM::PolicyParseException& e) {
+      //Control shouldn't reach here as the policy has already been
+      //verified earlier
+      ldout(s->cct, 20) << "failed to parse policy: " << e.what() << dendl;
+    }
+  }
+}
+
 rgw::auth::Engine::result_t
 rgw::auth::AnonymousEngine::authenticate(const req_state* const s) const
 {
@@ -540,7 +555,8 @@ rgw::auth::AnonymousEngine::authenticate(const req_state* const s) const
 
     auto apl = \
       apl_factory->create_apl_local(cct, s, user_info,
-                                    rgw::auth::LocalApplier::NO_SUBUSER);
+                                    rgw::auth::LocalApplier::NO_SUBUSER,
+                                    boost::none);
     return result_t::grant(std::move(apl));
   }
 }
index 9673087fca11ba6607364b02c02f12e0f77c3270..d1ab958e2ab12da5a6cf77570716c4c4dbe760be 100644 (file)
@@ -454,6 +454,7 @@ class LocalApplier : public IdentityApplier {
 protected:
   const RGWUserInfo user_info;
   const std::string subuser;
+  vector<std::string> role_policies;
 
   uint32_t get_perm_mask(const std::string& subuser_name,
                          const RGWUserInfo &uinfo) const;
@@ -463,9 +464,13 @@ public:
 
   LocalApplier(CephContext* const cct,
                const RGWUserInfo& user_info,
-               std::string subuser)
+               std::string subuser,
+               const boost::optional<vector<std::string> >& role_policies)
     : user_info(user_info),
-      subuser(std::move(subuser)) {
+      subuser(std::move(subuser)){
+    if (role_policies) {
+      this->role_policies = role_policies.get();
+    }
   }
 
 
@@ -480,13 +485,15 @@ public:
   void load_acct_info(RGWUserInfo& user_info) const override; /* out */
   uint32_t get_identity_type() const override { return TYPE_RGW; }
   string get_acct_name() const override { return {}; }
+  void modify_request_state(req_state* s) const override;
 
   struct Factory {
     virtual ~Factory() {}
     virtual aplptr_t create_apl_local(CephContext* cct,
                                       const req_state* s,
                                       const RGWUserInfo& user_info,
-                                      const std::string& subuser) const = 0;
+                                      const std::string& subuser,
+                                      const boost::optional<vector<std::string> >& role_policies) const = 0;
     };
 };
 
index 79f26847e86c29b65ee5d8c1e7a7ffccd30706fe..cc6101bd8dfbe7b5c0416889f0a03f5d57450a74 100644 (file)
@@ -258,6 +258,7 @@ void SysReqApplier<T>::modify_request_state(req_state* const s) const
     s->info.args.set_system();
     s->system_request = true;
   }
+  DecoratedApplier<T>::modify_request_state(s);
 }
 
 template <typename T> static inline
index 101f031f3ad48d4af801e71f443d2a7a15d686a1..eac31efa33f7f0eb0167e5da36f821c31b21463b 100644 (file)
@@ -420,12 +420,19 @@ EC2Engine::get_creds_info(const EC2Engine::token_envelope_t& token,
 rgw::auth::Engine::result_t EC2Engine::authenticate(
   const boost::string_view& access_key_id,
   const boost::string_view& signature,
+  const boost::string_view& session_token,
   const string_to_sign_t& string_to_sign,
   const signature_factory_t&,
   const completer_factory_t& completer_factory,
   /* Passthorugh only! */
   const req_state* s) const
 {
+  //If Keystone is enabled and the request has a session token, then Keystone shouldn't authenticate it.
+  if (s->info.args.exists("X-Amz-Security-Token") ||
+      s->info.env->exists("HTTP_X_AMZ_SECURITY_TOKEN")) {
+    return result_t::deny();
+  }
+
   /* This will be initialized on the first call to this method. In C++11 it's
    * also thread-safe. */
   static const struct RolesCacher {
index feef469cb080be8a0073a084c3bab180d65ea6c9..b5cab7361bdc68bddc18547cba9686603c476940 100644 (file)
@@ -93,6 +93,7 @@ class EC2Engine : public rgw::auth::s3::AWSEngine {
                     const boost::string_view& signature) const;
   result_t authenticate(const boost::string_view& access_key_id,
                         const boost::string_view& signature,
+                        const boost::string_view& session_token,
                         const string_to_sign_t& string_to_sign,
                         const signature_factory_t&,
                         const completer_factory_t& completer_factory,
index 55893b6fe38e1f12ddf9a833a03b13d01c9a0e27..d34e6164dc23c24f2a0b7591d2c0ad4d32cb5233 100644 (file)
@@ -243,7 +243,8 @@ static inline int parse_v4_query_string(const req_info& info,              /* in
                                         boost::string_view& credential,    /* out */
                                         boost::string_view& signedheaders, /* out */
                                         boost::string_view& signature,     /* out */
-                                        boost::string_view& date)          /* out */
+                                        boost::string_view& date,          /* out */
+                                        boost::string_view& sessiontoken)  /* out */
 {
   /* auth ships with req params ... */
 
@@ -289,6 +290,13 @@ static inline int parse_v4_query_string(const req_info& info,              /* in
     return -EPERM;
   }
 
+  if (info.args.exists("X-Amz-Security-Token")) {
+    sessiontoken = info.args.get("X-Amz-Security-Token");
+    if (sessiontoken.size() == 0) {
+      return -EPERM;
+    }
+  }
+
   return 0;
 }
 
@@ -345,7 +353,8 @@ static inline int parse_v4_auth_header(const req_info& info,               /* in
                                        boost::string_view& credential,     /* out */
                                        boost::string_view& signedheaders,  /* out */
                                        boost::string_view& signature,      /* out */
-                                       boost::string_view& date)           /* out */
+                                       boost::string_view& date,           /* out */
+                                       boost::string_view& sessiontoken)   /* out */
 {
   boost::string_view input(info.env->get("HTTP_AUTHORIZATION", ""));
   try {
@@ -406,6 +415,10 @@ static inline int parse_v4_auth_header(const req_info& info,               /* in
     return -ERR_REQUEST_TIME_SKEWED;
   }
 
+  if (info.env->exists("HTTP_X_AMZ_SECURITY_TOKEN")) {
+    sessiontoken = info.env->get("HTTP_X_AMZ_SECURITY_TOKEN");
+  }
+
   return 0;
 }
 
@@ -415,16 +428,17 @@ int parse_credentials(const req_info& info,                     /* in */
                       boost::string_view& signedheaders,        /* out */
                       boost::string_view& signature,            /* out */
                       boost::string_view& date,                 /* out */
+                      boost::string_view& session_token,        /* out */
                       const bool using_qs)                      /* in */
 {
   boost::string_view credential;
   int ret;
   if (using_qs) {
     ret = parse_v4_query_string(info, credential, signedheaders,
-                                signature, date);
+                                signature, date, session_token);
   } else {
     ret = parse_v4_auth_header(info, credential, signedheaders,
-                               signature, date);
+                               signature, date, session_token);
   }
 
   if (ret < 0) {
index 0a3341385d8a249cfcb184a80c6eae86ab0e85b8..ffa845ea02fd0a0d5d40a375a833df58f6bbcd1e 100644 (file)
@@ -32,6 +32,53 @@ 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 {
+  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<vector<std::string> >& role_policies) const override {
+    auto apl = rgw::auth::add_sysreq(cct, store, s,
+      rgw::auth::LocalApplier(cct, user_info, subuser, 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)) {
+      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;
@@ -102,14 +149,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<vector<std::string> >& role_policies) 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, role_policies));
     /* TODO(rzarzynski): replace with static_ptr. */
     return aplptr_t(new decltype(apl)(std::move(apl)));
   }
@@ -137,8 +186,8 @@ public:
   {
     std::vector <std::string> result;
 
-    const std::set <std::string_view> allowed_auth = { "external", "local" };
-    std::vector <std::string> default_order = { "external", "local"};
+    const std::set <std::string_view> allowed_auth = { "external", "local", "sts" };
+    std::vector <std::string> default_order = { "external", "local", "sts"};
     // 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);
@@ -158,6 +207,7 @@ public:
       anonymous_engine(cct,
                        static_cast<rgw::auth::LocalApplier::Factory*>(this)),
       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 anonymous auth. */
@@ -175,6 +225,12 @@ public:
     if (cct->_conf->rgw_s3_auth_use_rados) {
       engine_map.insert(std::make_pair("local", std::cref(local_engine)));
     }
+
+    /* STS Auth*/
+    if (! sts_engine.is_empty()) {
+      engine_map.insert(std::make_pair("sts", std::cref(sts_engine)));
+    }
+
     add_engines(auth_order, engine_map);
   }
 
@@ -382,6 +438,7 @@ int parse_credentials(const req_info& info,                     /* in */
                       boost::string_view& signedheaders,        /* out */
                       boost::string_view& signature,            /* out */
                       boost::string_view& date,                 /* 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)
index b6102112a1e91be468a74de97c4ea7e25c9f9250..d42e4c14e1b6fd618477f89558fc7b57cefce743 100644 (file)
@@ -1869,6 +1869,7 @@ struct req_state : DoutPrefixProvider {
       std::string x_amz_algorithm;
       std::string x_amz_credential;
       std::string x_amz_date;
+      std::string x_amz_security_token;
       ceph::bufferlist encoded_policy;
     } s3_postobj_creds;
   } auth;
index 3ca4e650003085cf9581c27bab47057221dc437a..6ae089913d6d9550ebf0acdc70b0b68b60c8d2ef 100644 (file)
 #include "common/utf8.h"
 #include "common/ceph_json.h"
 #include "common/safe_io.h"
+#include "auth/Crypto.h"
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/utility/string_view.hpp>
+#include <boost/tokenizer.hpp>
 
 #include <liboath/oath.h>
 
@@ -44,6 +46,9 @@
 #include "rgw_crypt_sanitize.h"
 #include "rgw_rest_user_policy.h"
 #include "include/ceph_assert.h"
+#include "include/assert.h"
+#include "rgw_role.h"
+#include "rgw_sts.h"
 
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rgw
@@ -1822,6 +1827,8 @@ int RGWPostObj_ObjStore_S3::get_policy()
       }
     }
 
+    part_str(parts, "x-amz-security-token", &s->auth.s3_postobj_creds.x_amz_security_token);
+
     /* 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. */
@@ -3831,6 +3838,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
   boost::string_view date;
   boost::string_view credential_scope;
   boost::string_view client_signature;
+  boost::string_view session_token;
 
   int ret = rgw::auth::s3::parse_credentials(s->info,
                                              access_key_id,
@@ -3838,6 +3846,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
                                              signed_hdrs,
                                              client_signature,
                                              date,
+                                             session_token,
                                              using_qs);
   if (ret < 0) {
     throw ret;
@@ -3901,6 +3910,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
     return {
       access_key_id,
       client_signature,
+      session_token,
       std::move(string_to_sign),
       sig_factory,
       null_completer_factory
@@ -3944,6 +3954,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
       return {
         access_key_id,
         client_signature,
+        session_token,
         std::move(string_to_sign),
         sig_factory,
         cmpl_factory
@@ -3986,6 +3997,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
       return {
         access_key_id,
         client_signature,
+        session_token,
         std::move(string_to_sign),
         sig_factory,
         cmpl_factory
@@ -4011,6 +4023,7 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
 {
   boost::string_view access_key_id;
   boost::string_view signature;
+  boost::string_view session_token;
   bool qsr = false;
 
   const char* http_auth = s->info.env->get("HTTP_AUTHORIZATION");
@@ -4035,6 +4048,13 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
     if (now >= exp) {
       throw -EPERM;
     }
+    if (s->info.args.exists("X-Amz-Security-Token")) {
+      session_token = s->info.args.get("X-Amz-Security-Token");
+      if (session_token.size() == 0) {
+        throw -EPERM;
+      }
+    }
+
   } else {
     /* The "Authorization" HTTP header is being used. */
     const boost::string_view auth_str(http_auth + strlen("AWS "));
@@ -4043,6 +4063,13 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
       access_key_id = auth_str.substr(0, pos);
       signature = auth_str.substr(pos + 1);
     }
+
+    if (s->info.env->exists("HTTP_X_AMZ_SECURITY_TOKEN")) {
+      session_token = s->info.env->get("HTTP_X_AMZ_SECURITY_TOKEN");
+      if (session_token.size() == 0) {
+        throw -EPERM;
+      }
+    }
   }
 
   /* Let's canonize the HTTP headers that are covered by the AWS auth v2. */
@@ -4065,6 +4092,7 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
   return {
     std::move(access_key_id),
     std::move(signature),
+    std::move(session_token),
     std::move(string_to_sign),
     rgw::auth::s3::get_v2_signature,
     null_completer_factory
@@ -4078,6 +4106,7 @@ AWSBrowserUploadAbstractor::get_auth_data_v2(const req_state* const s) const
   return {
     s->auth.s3_postobj_creds.access_key,
     s->auth.s3_postobj_creds.signature,
+    s->auth.s3_postobj_creds.x_amz_security_token,
     s->auth.s3_postobj_creds.encoded_policy.to_str(),
     rgw::auth::s3::get_v2_signature,
     null_completer_factory
@@ -4107,6 +4136,7 @@ AWSBrowserUploadAbstractor::get_auth_data_v4(const req_state* const s) const
   return {
     access_key_id,
     s->auth.s3_postobj_creds.signature,
+    s->auth.s3_postobj_creds.x_amz_security_token,
     s->auth.s3_postobj_creds.encoded_policy.to_str(),
     sig_factory,
     null_completer_factory
@@ -4126,7 +4156,6 @@ AWSBrowserUploadAbstractor::get_auth_data(const req_state* const s) const
   }
 }
 
-
 AWSEngine::result_t
 AWSEngine::authenticate(const req_state* const s) const
 {
@@ -4138,6 +4167,7 @@ AWSEngine::authenticate(const req_state* const s) const
   } else {
     return authenticate(auth_data.access_key_id,
                        auth_data.client_signature,
+            auth_data.session_token,
                        auth_data.string_to_sign,
                         auth_data.signature_factory,
                        auth_data.completer_factory,
@@ -4202,11 +4232,18 @@ rgw::auth::Engine::result_t
 rgw::auth::s3::LDAPEngine::authenticate(
   const boost::string_view& access_key_id,
   const boost::string_view& signature,
+  const boost::string_view& session_token,
   const string_to_sign_t& string_to_sign,
   const signature_factory_t&,
   const completer_factory_t& completer_factory,
   const req_state* const s) const
 {
+  //If LDAP is enabled and the request has a session token, then LDAP shouldn't authenticate it.
+  if (s->info.args.exists("X-Amz-Security-Token") ||
+      s->info.env->exists("HTTP_X_AMZ_SECURITY_TOKEN")) {
+    return result_t::deny();
+  }
+
   /* boost filters and/or string_ref may throw on invalid input */
   rgw::RGWToken base64_token;
   try {
@@ -4252,11 +4289,18 @@ rgw::auth::Engine::result_t
 rgw::auth::s3::LocalEngine::authenticate(
   const boost::string_view& _access_key_id,
   const boost::string_view& signature,
+  const boost::string_view& session_token,
   const string_to_sign_t& string_to_sign,
   const signature_factory_t& signature_factory,
   const completer_factory_t& completer_factory,
   const req_state* const s) const
 {
+  //If LocalAuth is enabled and the request has a session token, then LocalEngine shouldn't authenticate it.
+  if (s->info.args.exists("X-Amz-Security-Token") ||
+      s->info.env->exists("HTTP_X_AMZ_SECURITY_TOKEN")) {
+    return result_t::deny();
+  }
+
   /* get the user info */
   RGWUserInfo user_info;
   /* TODO(rzarzynski): we need to have string-view taking variant. */
@@ -4297,10 +4341,151 @@ rgw::auth::s3::LocalEngine::authenticate(
     return result_t::deny(-ERR_SIGNATURE_NO_MATCH);
   }
 
-  auto apl = apl_factory->create_apl_local(cct, s, user_info, k.subuser);
+  auto apl = apl_factory->create_apl_local(cct, s, user_info, k.subuser, boost::none);
   return result_t::grant(std::move(apl), completer_factory(k.key));
 }
 
+rgw::auth::RemoteApplier::AuthInfo
+rgw::auth::s3::STSEngine::get_creds_info(const STS::SessionToken& token) const noexcept
+{
+  using acct_privilege_t = \
+    rgw::auth::RemoteApplier::AuthInfo::acct_privilege_t;
+
+  return rgw::auth::RemoteApplier::AuthInfo {
+    token.user,
+    token.acct_name,
+    token.perm_mask,
+    (token.is_admin) ? acct_privilege_t::IS_ADMIN_ACCT: acct_privilege_t::IS_PLAIN_ACCT,
+    token.acct_type
+  };
+}
+
+int
+rgw::auth::s3::STSEngine::get_session_token(const boost::string_view& session_token,
+                                            STS::SessionToken& token) const
+{
+  string decodedSessionToken = rgw::from_base64(session_token);
+
+  auto* cryptohandler = cct->get_crypto_handler(CEPH_CRYPTO_AES);
+  if (! cryptohandler) {
+    return -EINVAL;
+  }
+  string secret_s = cct->_conf->rgw_sts_key;
+  buffer::ptr secret(secret_s.c_str(), secret_s.length());
+  int ret = 0;
+  if (ret = cryptohandler->validate_secret(secret); ret < 0) {
+    ldout(cct, 0) << "ERROR: Invalid secret key" << dendl;
+    return -EINVAL;
+  }
+  string error;
+  auto* keyhandler = cryptohandler->get_key_handler(secret, error);
+  if (! keyhandler) {
+    return -EINVAL;
+  }
+  error.clear();
+
+  string decrypted_str;
+  buffer::list en_input, dec_output;
+  en_input = buffer::list::static_from_string(decodedSessionToken);
+
+  ret = keyhandler->decrypt(en_input, dec_output, &error);
+  if (ret < 0) {
+    ldout(cct, 0) << "ERROR: Decryption failed: " << error << dendl;
+    return -EPERM;
+  } else {
+    dec_output.append('\0');
+    auto iter = dec_output.cbegin();
+    decode(token, iter);
+  }
+  return 0;
+}
+
+rgw::auth::Engine::result_t
+rgw::auth::s3::STSEngine::authenticate(
+  const boost::string_view& _access_key_id,
+  const boost::string_view& signature,
+  const boost::string_view& session_token,
+  const string_to_sign_t& string_to_sign,
+  const signature_factory_t& signature_factory,
+  const completer_factory_t& completer_factory,
+  const req_state* const s) const
+{
+  STS::SessionToken token;
+  if (int ret = get_session_token(session_token, token); ret < 0) {
+    return result_t::deny(ret);
+  }
+  //Authentication
+  //Check if the token has expired
+  if (! token.expiration.empty()) {
+    std::string expiration = token.expiration;
+    if (! expiration.empty()) {
+      boost::optional<real_clock::time_point> exp = ceph::from_iso_8601(expiration, false);
+      if (exp) {
+        real_clock::time_point now = real_clock::now();
+        if (now >= *exp) {
+          ldout(cct, 0) << "ERROR: Token expired" << dendl;
+          return result_t::deny(-EPERM);
+        }
+      } else {
+        ldout(cct, 0) << "ERROR: Invalid expiration: " << expiration << dendl;
+        return result_t::deny(-EPERM);
+      }
+    }
+  }
+  //Check for signature mismatch
+  const VersionAbstractor::server_signature_t server_signature = \
+    signature_factory(cct, token.secret_access_key, string_to_sign);
+  auto compare = signature.compare(server_signature);
+
+  ldout(cct, 15) << "string_to_sign="
+                 << rgw::crypt_sanitize::log_content{string_to_sign}
+                 << dendl;
+  ldout(cct, 15) << "server signature=" << server_signature << dendl;
+  ldout(cct, 15) << "client signature=" << signature << dendl;
+  ldout(cct, 15) << "compare=" << compare << dendl;
+
+  if (compare != 0) {
+    return result_t::deny(-ERR_SIGNATURE_NO_MATCH);
+  }
+
+  // Get all the authorization info
+  RGWUserInfo user_info;
+  vector<string> role_policies;
+  if (! token.roleId.empty()) {
+    RGWRole role(s->cct, store, token.roleId);
+    if (role.get_by_id() < 0) {
+      return result_t::deny(-EPERM);
+    }
+    vector<string> role_policy_names = role.get_role_policy_names();
+    for (auto& policy_name : role_policy_names) {
+      string perm_policy;
+      if (int ret = role.get_role_policy(policy_name, perm_policy); ret == 0) {
+        role_policies.push_back(std::move(perm_policy));
+      }
+    }
+    role_policies.push_back(std::move(token.policy));
+  }
+  if (! token.user.empty()) {
+    // get user info
+    int ret = rgw_get_user_info_by_uid(store, token.user, user_info, NULL);
+    if (ret < 0) {
+      ldout(cct, 5) << "ERROR: failed reading user info: uid=" << token.user << dendl;
+      return result_t::deny(-EPERM);
+    }
+  }
+  if (token.acct_type == TYPE_RGW) {
+    string subuser;
+    auto apl = local_apl_factory->create_apl_local(cct, s, user_info, subuser, role_policies);
+    return result_t::grant(std::move(apl), completer_factory(token.secret_access_key));
+  } else if (token.acct_type == TYPE_KEYSTONE || token.acct_type == TYPE_LDAP) {
+    auto apl = remote_apl_factory->create_apl_remote(cct, s, get_acl_strategy(),
+                                            get_creds_info(token));
+    return result_t::grant(std::move(apl), completer_factory(boost::none));
+  }
+
+  return result_t::deny(-EPERM);
+}
+
 bool rgw::auth::s3::S3AnonymousEngine::is_applicable(
   const req_state* s
 ) const noexcept {
index 03a951341e7d6ae9e687071aeb640edcabc652e7..25827beb673f0f2dd4bbf1023041afed2b1b4e96 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "rgw_auth.h"
 #include "rgw_auth_filters.h"
+#include "rgw_sts.h"
 
 struct rgw_http_error {
   int http_ret;
@@ -699,6 +700,7 @@ public:
 
     using access_key_id_t = boost::string_view;
     using client_signature_t = boost::string_view;
+    using session_token_t = boost::string_view;
     using server_signature_t = basic_sstring<char, uint16_t, SIGNATURE_MAX_SIZE>;
     using string_to_sign_t = std::string;
 
@@ -720,6 +722,7 @@ public:
     struct auth_data_t {
       access_key_id_t access_key_id;
       client_signature_t client_signature;
+      session_token_t session_token;
       string_to_sign_t string_to_sign;
       signature_factory_t signature_factory;
       completer_factory_t completer_factory;
@@ -747,6 +750,7 @@ protected:
    * Replace these thing with a simple, dedicated structure. */
   virtual result_t authenticate(const boost::string_view& access_key_id,
                                 const boost::string_view& signature,
+                                const boost::string_view& session_token,
                                 const string_to_sign_t& string_to_sign,
                                 const signature_factory_t& signature_factory,
                                 const completer_factory_t& completer_factory,
@@ -822,6 +826,7 @@ protected:
 
   result_t authenticate(const boost::string_view& access_key_id,
                         const boost::string_view& signature,
+                        const boost::string_view& session_token,
                         const string_to_sign_t& string_to_sign,
                         const signature_factory_t&,
                         const completer_factory_t& completer_factory,
@@ -852,6 +857,7 @@ class LocalEngine : public AWSEngine {
 
   result_t authenticate(const boost::string_view& access_key_id,
                         const boost::string_view& signature,
+                        const boost::string_view& session_token,
                         const string_to_sign_t& string_to_sign,
                         const signature_factory_t& signature_factory,
                         const completer_factory_t& completer_factory,
@@ -873,6 +879,45 @@ public:
   }
 };
 
+class STSEngine : public AWSEngine {
+  RGWRados* const store;
+  const rgw::auth::LocalApplier::Factory* const local_apl_factory;
+  const rgw::auth::RemoteApplier::Factory* const remote_apl_factory;
+
+  using acl_strategy_t = rgw::auth::RemoteApplier::acl_strategy_t;
+  using auth_info_t = rgw::auth::RemoteApplier::AuthInfo;
+
+  acl_strategy_t get_acl_strategy() const { return nullptr; };
+  auth_info_t get_creds_info(const STS::SessionToken& token) const noexcept;
+
+  int get_session_token(const boost::string_view& session_token,
+                        STS::SessionToken& token) const;
+
+  result_t authenticate(const boost::string_view& access_key_id,
+                        const boost::string_view& signature,
+                        const boost::string_view& session_token,
+                        const string_to_sign_t& string_to_sign,
+                        const signature_factory_t& signature_factory,
+                        const completer_factory_t& completer_factory,
+                        const req_state* s) const override;
+public:
+  STSEngine(CephContext* const cct,
+              RGWRados* const store,
+              const VersionAbstractor& ver_abstractor,
+              const rgw::auth::LocalApplier::Factory* const local_apl_factory,
+              const rgw::auth::RemoteApplier::Factory* const remote_apl_factory)
+    : AWSEngine(cct, ver_abstractor),
+      store(store),
+      local_apl_factory(local_apl_factory),
+      remote_apl_factory(remote_apl_factory) {
+  }
+
+  using AWSEngine::authenticate;
+
+  const char* get_name() const noexcept override {
+    return "rgw::auth::s3::STSEngine";
+  }
+};
 
 class S3AnonymousEngine : public rgw::auth::AnonymousEngine {
   bool is_applicable(const req_state* s) const noexcept override;
@@ -910,9 +955,10 @@ public:
   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<vector<std::string> >& role_policies) const override {
       return aplptr_t(
-        new rgw::auth::LocalApplier(cct, user_info, subuser));
+        new rgw::auth::LocalApplier(cct, user_info, subuser, role_policies));
   }
 };
 
index 571a6286031efc097a32bc5971c26ea2b9e31adc..45c3b00d7fe75a3cbc2a77f9b034cad32c4b049c 100644 (file)
@@ -418,7 +418,8 @@ ExternalTokenEngine::authenticate(const std::string& token,
   }
 
   auto apl = apl_factory->create_apl_local(cct, s, tmp_uinfo,
-                                           extract_swift_subuser(swift_user));
+                                           extract_swift_subuser(swift_user),
+                                           boost::none);
   return result_t::grant(std::move(apl));
 }
 
@@ -567,7 +568,8 @@ SignedTokenEngine::authenticate(const std::string& token,
   }
 
   auto apl = apl_factory->create_apl_local(cct, s, user_info,
-                                           extract_swift_subuser(swift_user));
+                                           extract_swift_subuser(swift_user),
+                                           boost::none);
   return result_t::grant(std::move(apl));
 }
 
index d3d1e52db675102a0467752d7771d0476754e75c..2102c2fa95b1985084aa65f60091ba008be61edd 100644 (file)
@@ -21,7 +21,7 @@ class TempURLApplier : public rgw::auth::LocalApplier {
 public:
   TempURLApplier(CephContext* const cct,
                  const RGWUserInfo& user_info)
-    : LocalApplier(cct, user_info, LocalApplier::NO_SUBUSER) {
+    : LocalApplier(cct, user_info, LocalApplier::NO_SUBUSER, boost::none) {
   };
 
   void modify_request_state(req_state * s) const override; /* in/out */
@@ -200,11 +200,12 @@ class DefaultStrategy : public rgw::auth::Strategy,
   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<vector<std::string> >& role_policies) const override {
     auto apl = \
       rgw::auth::add_3rdparty(store, s->account_name,
         rgw::auth::add_sysreq(cct, store, s,
-          rgw::auth::LocalApplier(cct, user_info, subuser)));
+          rgw::auth::LocalApplier(cct, user_info, subuser, boost::none)));
     /* TODO(rzarzynski): replace with static_ptr. */
     return aplptr_t(new decltype(apl)(std::move(apl)));
   }