]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: Rework of s3 LDAP Authentication code. 10307/head
authorPritha Srivastava <prsrivas@redhat.com>
Thu, 14 Jul 2016 10:33:48 +0000 (16:03 +0530)
committerPritha Srivastava <prsrivas@redhat.com>
Mon, 1 Aug 2016 06:59:28 +0000 (12:29 +0530)
The LDAP authentication code has been reworked based
on the new authentication infrastructure.

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

index b5771021b80655e302920bd21935789171c1f2de..fb265281213c379d6ece180c4532806f7d5d929e 100644 (file)
@@ -149,6 +149,11 @@ void RGWRemoteAuthApplier::create_account(const rgw_user& acct_user,
 {
   rgw_user new_acct_user = acct_user;
 
+  if (info.acct_type) {
+    //ldap/keystone for s3 users
+    user_info.type = info.acct_type;
+  }
+
   /* Administrator may enforce creating new accounts within their own tenants.
    * The config parameter name is kept due to legacy. */
   if (new_acct_user.tenant.empty() && g_conf->rgw_keystone_implicit_tenants) {
index efcd654425fe1c08431a5ba308faf56fa58da7bf..d1ec8fc41849f3b3b1ffcc30c033f479d4440018 100644 (file)
@@ -117,16 +117,19 @@ public:
     const std::string acct_name;
     const uint32_t perm_mask;
     const bool is_admin;
+    const uint32_t acct_type;
 
   public:
     AuthInfo(const rgw_user& acct_user,
              const std::string& acct_name,
              const uint32_t perm_mask,
-             const bool is_admin)
+             const bool is_admin,
+             const uint32_t acct_type=TYPE_NONE)
     : acct_user(acct_user),
       acct_name(acct_name),
       perm_mask(perm_mask),
-      is_admin(is_admin) {
+      is_admin(is_admin),
+      acct_type(acct_type) {
     }
   };
 
index f669ea43cc27975a219ec1c8635cf84a2f81be71..23559c8819c55438b9eb862abacd61d1147f0157 100644 (file)
@@ -527,6 +527,14 @@ void encode_json(const char *name, const RGWUserCaps& val, Formatter *f);
 
 void decode_json_obj(obj_version& v, JSONObj *obj);
 
+enum RGWUserSourceType
+{
+  TYPE_NONE=0,
+  TYPE_RGW=1,
+  TYPE_KEYSTONE=2,
+  TYPE_LDAP=3
+};
+
 struct RGWUserInfo
 {
   uint64_t auid;
@@ -547,6 +555,7 @@ struct RGWUserInfo
   RGWQuotaInfo bucket_quota;
   map<int, string> temp_url_keys;
   RGWQuotaInfo user_quota;
+  uint32_t type;
 
   RGWUserInfo()
     : auid(0),
@@ -554,7 +563,8 @@ struct RGWUserInfo
       max_buckets(RGW_DEFAULT_MAX_BUCKETS),
       op_mask(RGW_OP_TYPE_ALL),
       admin(0),
-      system(0) {
+      system(0),
+      type(TYPE_NONE) {
   }
 
   RGWAccessKey* get_key0() {
@@ -565,7 +575,7 @@ struct RGWUserInfo
   }
 
   void encode(bufferlist& bl) const {
-     ENCODE_START(18, 9, bl);
+     ENCODE_START(19, 9, bl);
      ::encode(auid, bl);
      string access_key;
      string secret_key;
@@ -605,10 +615,11 @@ struct RGWUserInfo
      ::encode(user_quota, bl);
      ::encode(user_id.tenant, bl);
      ::encode(admin, bl);
+     ::encode(type, bl);
      ENCODE_FINISH(bl);
   }
   void decode(bufferlist::iterator& bl) {
-     DECODE_START_LEGACY_COMPAT_LEN_32(18, 9, 9, bl);
+     DECODE_START_LEGACY_COMPAT_LEN_32(19, 9, 9, bl);
      if (struct_v >= 2) ::decode(auid, bl);
      else auid = CEPH_AUTH_UID_DEFAULT;
      string access_key;
@@ -678,6 +689,9 @@ struct RGWUserInfo
     if (struct_v >= 18) {
       ::decode(admin, bl);
     }
+    if (struct_v >= 19) {
+      ::decode(type, bl);
+    }
     DECODE_FINISH(bl);
   }
   void dump(Formatter *f) const;
@@ -727,7 +741,7 @@ struct rgw_bucket {
   }
 
   void encode(bufferlist& bl) const {
-     ENCODE_START(8, 3, bl);
+     ENCODE_START(9, 3, bl);
     ::encode(name, bl);
     ::encode(data_pool, bl);
     ::encode(marker, bl);
@@ -738,7 +752,7 @@ struct rgw_bucket {
     ENCODE_FINISH(bl);
   }
   void decode(bufferlist::iterator& bl) {
-    DECODE_START_LEGACY_COMPAT_LEN(8, 3, 3, bl);
+    DECODE_START_LEGACY_COMPAT_LEN(9, 3, 3, bl);
     ::decode(name, bl);
     ::decode(data_pool, bl);
     if (struct_v >= 2) {
index 78be0a13f84181790ce20510fea5a616f77db8fd..115cbf232d649f4456295c67b61382e75bf407b0 100644 (file)
@@ -427,6 +427,26 @@ void RGWUserInfo::dump(Formatter *f) const
   encode_json("bucket_quota", bucket_quota, f);
   encode_json("user_quota", user_quota, f);
   encode_json("temp_url_keys", temp_url_keys, f);
+
+  string user_source_type;
+  switch ((RGWUserSourceType)type) {
+  case TYPE_RGW:
+    user_source_type = "rgw";
+    break;
+  case TYPE_KEYSTONE:
+    user_source_type = "keystone";
+    break;
+  case TYPE_LDAP:
+    user_source_type = "ldap";
+    break;
+  case TYPE_NONE:
+    user_source_type = "none";
+    break;
+  default:
+    user_source_type = "none";
+    break;
+  }
+  encode_json("type", user_source_type, f);
 }
 
 
@@ -484,6 +504,18 @@ void RGWUserInfo::decode_json(JSONObj *obj)
   JSONDecoder::decode_json("bucket_quota", bucket_quota, obj);
   JSONDecoder::decode_json("user_quota", user_quota, obj);
   JSONDecoder::decode_json("temp_url_keys", temp_url_keys, obj);
+
+  string user_source_type;
+  JSONDecoder::decode_json("type", user_source_type, obj);
+  if (user_source_type == "rgw") {
+    type = TYPE_RGW;
+  } else if (user_source_type == "keystone") {
+    type = TYPE_KEYSTONE;
+  } else if (user_source_type == "ldap") {
+    type = TYPE_LDAP;
+  } else if (user_source_type == "none") {
+    type = TYPE_NONE;
+  }
 }
 
 void RGWQuotaInfo::dump(Formatter *f) const
index 23267199c78bdf0b0da6f61cd8cffc4121b7a65d..345c0a39eada163e49d9d351d79f0d05cf0c8a8a 100644 (file)
@@ -1705,11 +1705,13 @@ int RGWPostObj_ObjStore_S3::get_policy()
       err_msg = "Missing signature";
       return -EINVAL;
     }
-
     RGWUserInfo user_info;
 
     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);
+      RGWLDAPTokenExtractor token_extr(s);
+      RGWLDAPAuthEngine ldap(s->cct, store, token_extr, &aplfact);
         // try external authenticators
       if (store->ctx()->_conf->rgw_s3_auth_use_keystone &&
          store->ctx()->_conf->rgw_keystone_url.empty())
@@ -1747,53 +1749,15 @@ int RGWPostObj_ObjStore_S3::get_policy()
          }
          s->perm_mask = RGW_PERM_FULL_CONTROL;
        }
-      } else if (store->ctx()->_conf->rgw_s3_auth_use_ldap &&
-                (! store->ctx()->_conf->rgw_ldap_uri.empty())) {
-
-       ldout(store->ctx(), 15)
-         << __func__ << " LDAP auth uri="
-         << store->ctx()->_conf->rgw_ldap_uri
-         << dendl;
-
-       RGWToken token{from_base64(s3_access_key)};
-       if (! token.valid())
-         return -EACCES;
-
-       rgw::LDAPHelper *ldh = RGW_Auth_S3::get_ldap_ctx(store);
-       if (unlikely(!ldh)) {
-         ldout(store->ctx(), 0)
-           << __func__ << " RGW_Auth_S3::get_ldap_ctx() failed"
-           << dendl;
-         return -EACCES;
-       }
-
-       ldout(store->ctx(), 10)
-         << __func__ << " try LDAP auth uri="
-         << store->ctx()->_conf->rgw_ldap_uri
-         << " token.id=" << token.id
-         << dendl;
-
-       if (ldh->auth(token.id, token.key) != 0)
-         return -EACCES;
-
-       /* ok, succeeded */
-       user_info.user_id = token.id;
-       user_info.display_name = token.id; // cn?
-
-       /* create local account, if none exists */
-       if (rgw_get_user_info_by_uid(store, user_info.user_id,
-                                       user_info) < 0) {
-         int ret = rgw_store_user_info(store, user_info, nullptr, nullptr,
-                                       real_time(), true);
-         if (ret < 0) {
-           ldout(store->ctx(), 10)
-             << "NOTICE: failed to store new user's info: ret=" << ret
-             << dendl;
-         }
-       }
-
-       /* set request perms */
-       s->perm_mask = RGW_PERM_FULL_CONTROL;
+  } else if (ldap.is_applicable()) {
+    auto applier = ldap.authenticate();
+    if (! applier) {
+      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;
       }
@@ -3085,27 +3049,6 @@ int RGWHandler_REST_S3::init(RGWRados *store, struct req_state *s,
   return RGWHandler_REST::init(store, s, cio);
 }
 
-/* RGW_Auth_S3 static members */
-std::mutex RGW_Auth_S3::mtx;
-rgw::LDAPHelper* RGW_Auth_S3::ldh;
-
-/* static */
-void RGW_Auth_S3::init_impl(RGWRados* store)
-{
-  const string& ldap_uri = store->ctx()->_conf->rgw_ldap_uri;
-  const string& ldap_binddn = store->ctx()->_conf->rgw_ldap_binddn;
-  const string& ldap_searchdn = store->ctx()->_conf->rgw_ldap_searchdn;
-  const string& ldap_dnattr =
-    store->ctx()->_conf->rgw_ldap_dnattr;
-  std::string ldap_bindpw = parse_rgw_ldap_bindpw(store->ctx());
-
-  ldh = new rgw::LDAPHelper(ldap_uri, ldap_binddn, ldap_bindpw,
-                           ldap_searchdn, ldap_dnattr);
-
-  ldh->init();
-  ldh->bind();
-}
-
 /*
  * Try to validate S3 auth against keystone s3token interface
  */
@@ -3936,52 +3879,23 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
     }
   }
 
-  if ((external_auth_result < 0) &&
-      (store->ctx()->_conf->rgw_s3_auth_use_ldap) &&
-      (! store->ctx()->_conf->rgw_ldap_uri.empty())) {
+  S3AuthFactory aplfact(store, s->account_name);
+  RGWLDAPTokenExtractor token_extr(s);
+  RGWLDAPAuthEngine ldap(s->cct, store, token_extr, &aplfact);
 
-    RGW_Auth_S3::init(store);
-
-    ldout(store->ctx(), 15)
-      << __func__ << " LDAP auth uri="
-      << store->ctx()->_conf->rgw_ldap_uri
-      << dendl;
-
-    RGWToken token{from_base64(auth_id)};
-
-    if (! token.valid())
+  if (! ldap.is_applicable()) {
+    external_auth_result = -EACCES;
+  } else {
+    auto applier = ldap.authenticate();
+    if (!applier) {
       external_auth_result = -EACCES;
-    else {
-      ldout(store->ctx(), 10)
-       << __func__ << " try LDAP auth uri="
-       << store->ctx()->_conf->rgw_ldap_uri
-       << " token.id=" << token.id
-       << dendl;
-
-      if (ldh->auth(token.id, token.key) != 0)
-       external_auth_result = -EACCES;
-      else {
-       /* ok, succeeded */
-       external_auth_result = 0;
-
-       /* create local account, if none exists */
-       s->user->user_id = token.id;
-       s->user->display_name = token.id; // cn?
-       int ret = rgw_get_user_info_by_uid(store, s->user->user_id, *(s->user));
-       if (ret < 0) {
-         ret = rgw_store_user_info(store, *(s->user), nullptr, nullptr,
-                                   real_time(), true);
-         if (ret < 0) {
-           dout(10) << "NOTICE: failed to store new user's info: ret=" << ret
-                    << dendl;
-         }
-       }
-
-      /* set request perms */
-      s->perm_mask = RGW_PERM_FULL_CONTROL;
-      } /* success */
-    } /* token */
-  } /* ldap */
+    } else {
+      applier->load_acct_info(*s->user);
+      s->perm_mask = applier->get_perm_mask();
+      s->auth_identity = std::move(applier);
+      external_auth_result = 0;
+    }
+  }
 
   /* keystone failed (or not enabled); check if we want to use rados backend */
   if (!store->ctx()->_conf->rgw_s3_auth_use_rados
@@ -3997,7 +3911,7 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
       return external_auth_result;
     }
 
-    /* now verify signature */
+    /* now verify  signature */
     string auth_hdr;
     if (!rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr,
                                        qsr)) {
@@ -4342,3 +4256,98 @@ RGWOp* RGWHandler_REST_Service_S3Website::get_obj_op(bool get_data)
   op->set_get_data(get_data);
   return op;
 }
+
+rgw::LDAPHelper* RGWLDAPAuthEngine::ldh = nullptr;
+std::mutex RGWLDAPAuthEngine::mtx;
+
+void RGWLDAPAuthEngine::init(CephContext* const cct)
+{
+  if (!ldh) {
+    std::lock_guard<std::mutex> lck(mtx);
+    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;
+      const string& ldap_dnattr = cct->_conf->rgw_ldap_dnattr;
+      std::string ldap_bindpw = parse_rgw_ldap_bindpw(cct);
+
+      ldh = new rgw::LDAPHelper(ldap_uri, ldap_binddn, ldap_bindpw,
+                                ldap_searchdn, ldap_dnattr);
+
+      ldh->init();
+      ldh->bind();
+    }
+  }
+}
+
+RGWRemoteAuthApplier::acl_strategy_t RGWLDAPAuthEngine::get_acl_strategy() const
+{
+  //This is based on the assumption that the default acl strategy in
+  // get_perms_from_aclspec, will take care. Extra acl spec is not required.
+  return nullptr;
+}
+
+RGWRemoteAuthApplier::AuthInfo
+RGWLDAPAuthEngine::get_creds_info(const rgw::RGWToken& token) const noexcept
+{
+  return RGWRemoteAuthApplier::AuthInfo {
+    rgw_user(token.id),
+    token.id,
+    RGW_PERM_FULL_CONTROL,
+    true,
+    TYPE_LDAP
+  };
+}
+
+bool RGWLDAPAuthEngine::is_applicable() const noexcept
+{
+  if (!RGWTokenBasedAuthEngine::is_applicable()) {
+    return false;
+  }
+
+  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
+{
+  //Check if a user of type other than 'ldap' is already present, if yes, then
+  //return error.
+  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;
+  }
+
+  return apl_factory->create_apl_remote(cct, get_acl_strategy(), get_creds_info(base64_token));
+}
+
+std::string RGWLDAPTokenExtractor::get_token() const
+{
+  string token = "";
+  if (!s->http_auth || !(*s->http_auth)) {
+    token = s->info.args.get("AWSAccessKeyId");
+  } else {
+    string auth_str(s->http_auth + 4);
+    int pos = auth_str.rfind(':');
+    if (pos >=0 ) {
+      token = auth_str.substr(0, pos);
+    }
+  }
+  return token;
+}
index cecc14c97656d379fd7e396f73891ed7bcbeb267..9945d9ee805d3af2ea3bc57ac295fb36f5df68a8 100644 (file)
 #include "rgw_rest_conn.h"
 #include "rgw_ldap.h"
 
+#include "rgw_token.h"
+#include "include/assert.h"
+
+#include "rgw_auth.h"
+#include "rgw_auth_decoimpl.h"
+
 #define RGW_AUTH_GRACE_MINS 15
 
 void rgw_get_errno_s3(struct rgw_http_errors *e, int err_no);
@@ -417,9 +423,6 @@ public:
 
 class RGW_Auth_S3 {
 private:
-  static std::mutex mtx;
-  static rgw::LDAPHelper* ldh;
-
   static int authorize_v2(RGWRados *store, struct req_state *s);
   static int authorize_v4(RGWRados *store, struct req_state *s);
   static int authorize_v4_complete(RGWRados *store, struct req_state *s,
@@ -428,22 +431,6 @@ private:
 public:
   static int authorize(RGWRados *store, struct req_state *s);
   static int authorize_aws4_auth_complete(RGWRados *store, struct req_state *s);
-
-  static inline void init(RGWRados* store) {
-    if (! ldh) {
-      std::lock_guard<std::mutex> lck(mtx);
-      if (! ldh) {
-       init_impl(store);
-      }
-    }
-  }
-
-  static inline rgw::LDAPHelper* get_ldap_ctx(RGWRados* store) {
-    init(store);
-    return ldh;
-  }
-
-  static void init_impl(RGWRados* store);
 };
 
 class RGWHandler_Auth_S3 : public RGWHandler_REST {
@@ -627,4 +614,70 @@ static inline int valid_s3_bucket_name(const string& name, bool relaxed=false)
   return 0;
 }
 
+class RGWLDAPAuthEngine: RGWTokenBasedAuthEngine
+{
+  static rgw::LDAPHelper* ldh;
+  static std::mutex mtx;
+  rgw::RGWToken base64_token;
+
+  static void init(CephContext* const cct);
+
+protected:
+  RGWRados* const store;
+  const RGWRemoteAuthApplier::Factory * const apl_factory;
+
+  RGWRemoteAuthApplier::acl_strategy_t get_acl_strategy() const;
+  RGWRemoteAuthApplier::AuthInfo get_creds_info(const rgw::RGWToken& token) const noexcept;
+
+public:
+  RGWLDAPAuthEngine(CephContext* const cct,
+                    RGWRados* const store,
+                    Extractor &ex,
+                    const RGWRemoteAuthApplier::Factory * const apl_factory)
+    : RGWTokenBasedAuthEngine(cct, ex),
+      store(store),
+      apl_factory(apl_factory) {
+      init(cct);
+      base64_token = rgw::from_base64(token);
+  }
+  const char* get_name() const noexcept override {
+    return "RGWLDAPAuthEngine";
+  }
+  bool is_applicable() const noexcept override;
+  RGWAuthApplier::aplptr_t authenticate() const override;
+};
+
+class RGWLDAPTokenExtractor : public RGWTokenBasedAuthEngine::Extractor {
+protected:
+  const req_state * const s;
+
+public:
+  RGWLDAPTokenExtractor(const req_state * const s)
+    : s(s) {
+  }
+  std::string get_token() const override;
+};
+
+class S3AuthFactory : public RGWRemoteAuthApplier::Factory {
+  typedef RGWAuthApplier::aplptr_t aplptr_t;
+  RGWRados * const store;
+  const std::string acct_override;
+
+public:
+  S3AuthFactory(RGWRados * const store,
+                const std::string& acct_override)
+    : store(store),
+      acct_override(acct_override) {
+  }
+
+  aplptr_t create_apl_remote(CephContext * const cct,
+                             RGWRemoteAuthApplier::acl_strategy_t&& acl_alg,
+                             const RGWRemoteAuthApplier::AuthInfo info
+                            ) const override {
+    return aplptr_t(
+        new RGWThirdPartyAccountAuthApplier<RGWRemoteAuthApplier>(
+        RGWRemoteAuthApplier(cct, store, std::move(acl_alg), info),
+        store, acct_override));
+  }
+};
 #endif /* CEPH_RGW_REST_S3_H */
index 7dce9a9ef3cebb776c4800b796d24ba1a8827dfc..972c57448db2d732e830aaaf804717e4175d8b7e 100644 (file)
@@ -71,7 +71,7 @@ namespace rgw {
 
     virtual uint32_t version() const { return 1; };
 
-    bool valid() {
+    bool valid() const{
       return ((type != TOKEN_NONE) &&
              (! id.empty()) &&
              (! key.empty()));