]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: Rework of s3 v2 local authentication code. 10448/head
authorPritha Srivastava <prsrivas@redhat.com>
Wed, 27 Jul 2016 05:24:22 +0000 (10:54 +0530)
committerPritha Srivastava <prsrivas@redhat.com>
Fri, 12 Aug 2016 12:23:55 +0000 (17:53 +0530)
The v2 local auth code has been reworked based on the new new authentication infrastructure.

Signed-off-by: Pritha Srivastava <prsrivas@redhat.com>
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h
src/rgw/rgw_user.cc

index eb20db812d7a649fa4916d48ca9df7f0e223a5e8..e464ddb002d3b1e73ae304d15dea461ef1ae157c 100644 (file)
@@ -1714,8 +1714,8 @@ int RGWPostObj_ObjStore_S3::get_policy()
     op_ret = rgw_get_user_info_by_access_key(store, s3_access_key, user_info);
     if (op_ret < 0) {
       S3AuthFactory aplfact(store, s->account_name);
-      RGWGetPolicyLDAPTokenExtractor token_extr(s3_access_key);
-      RGWLDAPAuthEngine ldap(s->cct, store, token_extr, &aplfact);
+      RGWGetPolicyV2Extractor extr(s3_access_key, received_signature_str);
+      RGWLDAPAuthEngine ldap(s->cct, store, extr, &aplfact);
         // try external authenticators
       if (store->ctx()->_conf->rgw_s3_auth_use_keystone &&
          store->ctx()->_conf->rgw_keystone_url.empty())
@@ -1754,13 +1754,22 @@ int RGWPostObj_ObjStore_S3::get_policy()
          s->perm_mask = RGW_PERM_FULL_CONTROL;
        }
   } else if (ldap.is_applicable()) {
-    auto applier = ldap.authenticate();
-    if (! applier) {
+    try {
+      auto applier = ldap.authenticate();
+      if (! applier) {
+        return -EACCES;
+      }
+
+      try {
+        applier->load_acct_info(*s->user);
+        s->perm_mask = applier->get_perm_mask();
+        applier->modify_request_state(s);
+        s->auth_identity = std::move(applier);
+      } catch (int err) {
+        return -EACCES;
+      }
+    } catch (int err) {
       return -EACCES;
-    } else {
-      applier->load_acct_info(*s->user);
-      s->perm_mask = applier->get_perm_mask();
-      s->auth_identity = std::move(applier);
     }
       } else {
        return -EACCES;
@@ -3949,91 +3958,57 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
   }
 
   S3AuthFactory aplfact(store, s->account_name);
-  RGWLDAPTokenExtractor token_extr(s);
-  RGWLDAPAuthEngine ldap(s->cct, store, token_extr, &aplfact);
+  RGWS3V2Extractor extr(s);
+  RGWLDAPAuthEngine ldap(s->cct, store, extr, &aplfact);
 
   if (ldap.is_applicable()) {
-    auto applier = ldap.authenticate();
-    if (!applier) {
-      external_auth_result = -EACCES;
-    } else {
-      applier->load_acct_info(*s->user);
-      s->perm_mask = applier->get_perm_mask();
-      s->auth_identity = std::move(applier);
-      external_auth_result = 0;
+    try {
+      auto applier = ldap.authenticate();
+      if (! applier) {
+        external_auth_result = -EACCES;
+      } else {
+        try {
+          applier->load_acct_info(*s->user);
+          s->perm_mask = applier->get_perm_mask();
+          applier->modify_request_state(s);
+          s->auth_identity = std::move(applier);
+          external_auth_result = 0;
+        } catch (int err) {
+          ldout(s->cct, 5) << "applier threw err=" << err << dendl;
+          external_auth_result = err;
+        }
+      }
+    } catch (int err) {
+      ldout(s->cct, 5) << "ldap auth engine threw err=" << err << dendl;
+      external_auth_result = err;
     }
   }
 
-  /* keystone failed (or not enabled); check if we want to use rados backend */
-  if (!store->ctx()->_conf->rgw_s3_auth_use_rados
-      && external_auth_result < 0)
-    return external_auth_result;
-
   /* now try rados backend, but only if keystone did not succeed */
   if (external_auth_result < 0) {
-    /* get the user info */
-    if (rgw_get_user_info_by_access_key(store, auth_id, *(s->user)) < 0) {
-      dout(5) << "error reading user info, uid=" << auth_id
-              << " can't authenticate" << dendl;
-      return external_auth_result;
-    }
+      RGWS3V2LocalAuthEngine localauth(s, store, extr, &aplfact);
 
-    /* now verify  signature */
-    string auth_hdr;
-    if (!rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr,
-                                       qsr)) {
-      dout(10) << "failed to create auth header\n" << auth_hdr << dendl;
-      return -EPERM;
-    }
-    dout(10) << "auth_hdr:\n" << auth_hdr << dendl;
-
-    time_t req_sec = s->header_time.sec();
-    if ((req_sec < now - RGW_AUTH_GRACE_MINS * 60 ||
-        req_sec > now + RGW_AUTH_GRACE_MINS * 60) && !qsr) {
-      dout(10) << "req_sec=" << req_sec << " now=" << now
-               << "; now - RGW_AUTH_GRACE_MINS=" << now - RGW_AUTH_GRACE_MINS * 60
-               << "; now + RGW_AUTH_GRACE_MINS=" << now + RGW_AUTH_GRACE_MINS * 60
-               << dendl;
-      dout(0)  << "NOTICE: request time skew too big now=" << utime_t(now, 0)
-               << " req_time=" << s->header_time
-               << dendl;
-      return -ERR_REQUEST_TIME_SKEWED;
-    }
-
-    map<string, RGWAccessKey>::iterator iter =
-      s->user->access_keys.find(auth_id);
-    if (iter == s->user->access_keys.end()) {
-      dout(0) << "ERROR: access key not encoded in user info" << dendl;
-      return -EPERM;
-    }
-    RGWAccessKey& k = iter->second;
-
-    if (!k.subuser.empty()) {
-      map<string, RGWSubUser>::iterator uiter =
-       s->user->subusers.find(k.subuser);
-      if (uiter == s->user->subusers.end()) {
-       dout(0) << "NOTICE: could not find subuser: " << k.subuser << dendl;
-       return -EPERM;
+      if (! localauth.is_applicable()) {
+        return external_auth_result;
+      }
+      try {
+        auto applier = localauth.authenticate();
+        if (! applier) {
+          return external_auth_result;
+        }
+        try {
+          applier->load_acct_info(*s->user);
+          s->perm_mask = applier->get_perm_mask();
+          applier->modify_request_state(s);
+          s->auth_identity = std::move(applier);
+        } catch (int err) {
+          ldout(s->cct, 5) << "applier threw err=" << err << dendl;
+          return err;
+        }
+      } catch (int err) {
+          ldout(s->cct, 5) << "local auth engine threw err=" << err << dendl;
+          return err;
       }
-      RGWSubUser& subuser = uiter->second;
-      s->perm_mask = subuser.perm_mask;
-    } else
-      s->perm_mask = RGW_PERM_FULL_CONTROL;
-
-    string digest;
-    int ret = rgw_get_s3_header_digest(auth_hdr, k.key, digest);
-    if (ret < 0) {
-      return -EPERM;
-    }
-
-    dout(15) << "calculated digest=" << digest << dendl;
-    dout(15) << "auth_sign=" << auth_sign << dendl;
-    dout(15) << "compare=" << auth_sign.compare(digest) << dendl;
-
-    if (auth_sign != digest) {
-      return -ERR_SIGNATURE_NO_MATCH;
-    }
-
     if (s->user->system) {
       s->system_request = true;
       dout(20) << "system request" << dendl;
@@ -4042,7 +4017,7 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
       RGWUserInfo effective_user;
       if (!effective_uid.empty()) {
         rgw_user euid(effective_uid);
-        ret = rgw_get_user_info_by_uid(store, euid, effective_user);
+        int ret = rgw_get_user_info_by_uid(store, euid, effective_user);
         if (ret < 0) {
           ldout(s->cct, 0) << "User lookup failed!" << dendl;
           return -EACCES;
@@ -4329,9 +4304,9 @@ std::mutex RGWLDAPAuthEngine::mtx;
 
 void RGWLDAPAuthEngine::init(CephContext* const cct)
 {
-  if (!ldh) {
+  if (! ldh) {
     std::lock_guard<std::mutex> lck(mtx);
-    if (!ldh) {
+    if (! ldh) {
       const string& ldap_uri = cct->_conf->rgw_ldap_uri;
       const string& ldap_binddn = cct->_conf->rgw_ldap_binddn;
       const string& ldap_searchdn = cct->_conf->rgw_ldap_searchdn;
@@ -4368,34 +4343,34 @@ RGWLDAPAuthEngine::get_creds_info(const rgw::RGWToken& token) const noexcept
 
 bool RGWLDAPAuthEngine::is_applicable() const noexcept
 {
-  if (!RGWTokenBasedAuthEngine::is_applicable()) {
+  if (! RGWS3V2AuthEngine::is_applicable()) {
     return false;
   }
 
-  if (!cct->_conf->rgw_s3_auth_use_ldap ||
+  if (! cct->_conf->rgw_s3_auth_use_ldap ||
       cct->_conf->rgw_ldap_uri.empty()) {
     return false;
   }
 
-  if(!base64_token.valid()) {
-    return false;
-  }
-
   return true;
 }
 
 RGWAuthApplier::aplptr_t RGWLDAPAuthEngine::authenticate() const
 {
+  if(! base64_token.valid()) {
+    return nullptr;
+  }
+  //TODO: Uncomment, when we have a migration plan in place.
   //Check if a user of type other than 'ldap' is already present, if yes, then
   //return error.
-  RGWUserInfo user_info;
+  /*RGWUserInfo user_info;
   user_info.user_id = base64_token.id;
   if (rgw_get_user_info_by_uid(store, user_info.user_id, user_info) >= 0) {
     if (user_info.type != TYPE_LDAP) {
       ldout(cct, 10) << "ERROR: User id of type: " << user_info.type << " is already present" << dendl;
       return nullptr;
     }
-  }
+  }*/
 
   if (ldh->auth(base64_token.id, base64_token.key) != 0) {
     return nullptr;
@@ -4404,17 +4379,111 @@ RGWAuthApplier::aplptr_t RGWLDAPAuthEngine::authenticate() const
   return apl_factory->create_apl_remote(cct, get_acl_strategy(), get_creds_info(base64_token));
 }
 
-std::string RGWLDAPTokenExtractor::get_token() const
+void RGWS3V2Extractor::get_auth_keys(std::string& access_key_id,
+                                      std::string& signature,
+                                      std::string& expires,
+                                      bool& qsr) const
 {
-  string token = "";
-  if (!s->http_auth || !(*s->http_auth)) {
-    token = s->info.args.get("AWSAccessKeyId");
+  qsr = false;
+  if (! s->http_auth || !(*s->http_auth)) {
+    access_key_id = s->info.args.get("AWSAccessKeyId");
+    signature = s->info.args.get("Signature");
+    expires = s->info.args.get("Expires");
+    qsr = true;
   } else {
     string auth_str(s->http_auth + 4);
     int pos = auth_str.rfind(':');
-    if (pos >=0 ) {
-      token = auth_str.substr(0, pos);
+    if (pos >= 0) {
+      access_key_id = auth_str.substr(0, pos);
+      signature = auth_str.substr(pos + 1);
+    }
+  }
+}
+
+bool RGWS3V2LocalAuthEngine::is_applicable() const noexcept
+{
+  if (! RGWS3V2AuthEngine::is_applicable()) {
+    return false;
+  }
+  if (! s->cct->_conf->rgw_s3_auth_use_rados) {
+    return false;
+  }
+
+  return true;
+}
+
+RGWAuthApplier::aplptr_t RGWS3V2LocalAuthEngine::authenticate() const
+{
+  if (access_key_id.empty() || signature.empty()) {
+    ldout(s->cct, 5) << "access_key_id or signature is empty" << dendl;
+    throw -EINVAL;
+  }
+
+  time_t now;
+  time(&now);
+  if (! expires.empty()) {
+    time_t exp = atoll(expires.c_str());
+    if (now >= exp) {
+      throw -EPERM;
+    }
+  }
+  /* get the user info */
+  string access_key = access_key_id;
+  if (rgw_get_user_info_by_access_key(store, access_key, *(s->user)) < 0) {
+      ldout(s->cct, 5) << "error reading user info, uid=" << access_key_id
+              << " can't authenticate" << dendl;
+      return nullptr;
+  }
+  //TODO: Uncomment, when we have a migration plan in place.
+  /*else {
+    if (s->user->type != TYPE_RGW) {
+      ldout(cct, 10) << "ERROR: User id of type: " << s->user->type << " is present" << dendl;
+      throw -EPERM;
     }
+  }*/
+
+  /* now verify  signature */
+  string auth_hdr;
+  if (! rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr,
+        qsr)) {
+    ldout(s->cct, 10) << "failed to create auth header\n" << auth_hdr << dendl;
+    throw -EPERM;
+  }
+  ldout(s->cct, 10) << "auth_hdr:\n" << auth_hdr << dendl;
+
+  time_t req_sec = s->header_time.sec();
+  if ((req_sec < now - RGW_AUTH_GRACE_MINS * 60 ||
+      req_sec > now + RGW_AUTH_GRACE_MINS * 60) && !qsr) {
+    ldout(s->cct, 10) << "req_sec=" << req_sec << " now=" << now
+             << "; now - RGW_AUTH_GRACE_MINS=" << now - RGW_AUTH_GRACE_MINS * 60
+             << "; now + RGW_AUTH_GRACE_MINS=" << now + RGW_AUTH_GRACE_MINS * 60
+             << dendl;
+    ldout(s->cct, 0)  << "NOTICE: request time skew too big now=" << utime_t(now, 0)
+             << " req_time=" << s->header_time
+             << dendl;
+    throw -ERR_REQUEST_TIME_SKEWED;
+  }
+
+  map<string, RGWAccessKey>::iterator iter = s->user->access_keys.find(access_key_id);
+  if (iter == s->user->access_keys.end()) {
+    ldout(s->cct, 0) << "ERROR: access key not encoded in user info" << dendl;
+    throw -EPERM;
+  }
+  RGWAccessKey& k = iter->second;
+
+  string digest;
+  int ret = rgw_get_s3_header_digest(auth_hdr, k.key, digest);
+  if (ret < 0) {
+    throw -EPERM;
   }
-  return token;
+
+  ldout(s->cct, 15) << "calculated digest=" << digest << dendl;
+  ldout(s->cct, 15) << "auth_sign=" << signature << dendl;
+  ldout(s->cct, 15) << "compare=" << signature.compare(digest) << dendl;
+
+  if (signature != digest) {
+    throw -ERR_SIGNATURE_NO_MATCH;
+  }
+
+  return apl_factory->create_apl_local(cct, *(s->user), k.subuser);
 }
index 80e58f2892f1de3baceeb84ebbd0fef9bfa91d15..81d71240989a0dcf4d4c05de9f221f917c91ddbc 100644 (file)
@@ -645,7 +645,48 @@ static inline int valid_s3_bucket_name(const string& name, bool relaxed=false)
   return 0;
 }
 
-class RGWLDAPAuthEngine: RGWTokenBasedAuthEngine
+class RGWS3V2AuthEngine : public RGWAuthEngine {
+protected:
+  std::string access_key_id;
+  std::string signature;
+  std::string expires;
+  bool qsr;
+
+public:
+  class Extractor {
+  public:
+    virtual ~Extractor() {};
+    virtual void get_auth_keys(std::string& access_key_id,
+                                std::string& signature,
+                                std::string& expires,
+                                bool& qsr) const = 0;
+  };
+
+  RGWS3V2AuthEngine(CephContext* const cct, const Extractor& extr)
+    : RGWAuthEngine(cct) {
+    extr.get_auth_keys(access_key_id, signature, expires, qsr);
+  }
+
+  bool is_applicable() const noexcept override {
+    return ! (access_key_id.empty() && signature.empty());
+  }
+};
+
+class RGWS3V2Extractor : public RGWS3V2AuthEngine::Extractor {
+protected:
+  const req_state* const s;
+
+public:
+  RGWS3V2Extractor(const req_state * const s)
+    : s(s) {}
+
+  void get_auth_keys(std::string& access_key_id,
+                      std::string& signature,
+                      std::string& expires,
+                      bool& qsr) const override;
+};
+
+class RGWLDAPAuthEngine: RGWS3V2AuthEngine
 {
   static rgw::LDAPHelper* ldh;
   static std::mutex mtx;
@@ -665,11 +706,11 @@ public:
                     RGWRados* const store,
                     Extractor &ex,
                     const RGWRemoteAuthApplier::Factory * const apl_factory)
-    : RGWTokenBasedAuthEngine(cct, ex),
+    : RGWS3V2AuthEngine(cct, ex),
       store(store),
       apl_factory(apl_factory) {
       init(cct);
-      base64_token = rgw::from_base64(token);
+      base64_token = rgw::from_base64(access_key_id);
   }
   const char* get_name() const noexcept override {
     return "RGWLDAPAuthEngine";
@@ -678,42 +719,65 @@ public:
   RGWAuthApplier::aplptr_t authenticate() const override;
 };
 
-class RGWLDAPTokenExtractor : public RGWTokenBasedAuthEngine::Extractor {
+class RGWS3V2LocalAuthEngine: RGWS3V2AuthEngine
+{
 protected:
-  const req_state * const s;
+  req_state* const s;
+  RGWRados* const store;
+  const RGWLocalAuthApplier::Factory* const apl_factory;
 
 public:
-  RGWLDAPTokenExtractor(const req_state * const s)
-    : s(s) {
+  RGWS3V2LocalAuthEngine(req_state* const s,
+                          RGWRados* const store,
+                          const Extractor& extr,
+                          const RGWLocalAuthApplier::Factory * const apl_factory)
+    : RGWS3V2AuthEngine(s->cct, extr),
+      s(s),
+      store(store),
+      apl_factory(apl_factory) {
+  }
+
+  const char* get_name() const noexcept override {
+    return "RGWS3V2LocalAuthEngine";
   }
-  std::string get_token() const override;
+  bool is_applicable() const noexcept override;
+  RGWAuthApplier::aplptr_t authenticate() const override;
 };
 
-class RGWGetPolicyLDAPTokenExtractor : public RGWTokenBasedAuthEngine::Extractor {
+class RGWGetPolicyV2Extractor:public RGWS3V2AuthEngine::Extractor {
+private:
   std::string access_key_id;
+  std::string signature;
+
 public:
-  RGWGetPolicyLDAPTokenExtractor(std::string access_key_id) {
-    access_key_id = std::move(access_key_id);
+  RGWGetPolicyV2Extractor(std::string access_key_id, std::string signature) {
+    access_key_id = std::move(access_key_id),
+    signature = std::move(signature);
   }
 
-  std::string get_token() const {
-    return access_key_id;
+  void get_auth_keys(std::string& access_key_id,
+                      std::string& signature,
+                      std::string& expires,
+                      bool& qsr) const override {
+    access_key_id = this->access_key_id;
+    signature = this->signature;
   }
 };
 
-class S3AuthFactory : public RGWRemoteAuthApplier::Factory {
+class S3AuthFactory : public RGWRemoteAuthApplier::Factory,
+                      public RGWLocalAuthApplier::Factory {
   typedef RGWAuthApplier::aplptr_t aplptr_t;
-  RGWRados * const store;
+  RGWRados* const store;
   const std::string acct_override;
 
 public:
-  S3AuthFactory(RGWRados * const store,
+  S3AuthFactory(RGWRados* const store,
                 const std::string& acct_override)
     : store(store),
       acct_override(acct_override) {
   }
 
-  aplptr_t create_apl_remote(CephContext * const cct,
+  aplptr_t create_apl_remote(CephContext* const cct,
                              RGWRemoteAuthApplier::acl_strategy_t&& acl_alg,
                              const RGWRemoteAuthApplier::AuthInfo info
                             ) const override {
@@ -722,5 +786,13 @@ public:
         RGWRemoteAuthApplier(cct, store, std::move(acl_alg), info),
         store, acct_override));
   }
+  aplptr_t create_apl_local(CephContext* const cct,
+                            const RGWUserInfo& user_info,
+                            const std::string& subuser) const override {
+      return aplptr_t(
+        new RGWThirdPartyAccountAuthApplier<RGWLocalAuthApplier>(
+          RGWLocalAuthApplier(cct, user_info, subuser),
+          store, acct_override));
+    }
 };
 #endif /* CEPH_RGW_REST_S3_H */
index 5aa2b7d74a951c7f520026ef1b0318fecbfb9aed..d4104c45b24602f816f7fe6b0f54161077101815 100644 (file)
@@ -1917,6 +1917,7 @@ int RGWUser::execute_add(RGWUserAdminOpState& op_state, std::string *err_msg)
   user_id = uid;
   user_info.user_id = user_id;
   user_info.display_name = display_name;
+  user_info.type = TYPE_RGW;
 
   if (!user_email.empty())
     user_info.user_email = user_email;