]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rgw: introduce the rgw::auth::RemoteApplier interface.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Wed, 26 Oct 2016 16:09:07 +0000 (18:09 +0200)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Fri, 24 Mar 2017 15:31:43 +0000 (16:31 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_auth.cc
src/rgw/rgw_auth.h

index 75ba0c329cac45b58dca779ce0686ed0f20c86fb..7f1458b10a2f455909766a8781f0345e2e0f7d58 100644 (file)
@@ -556,3 +556,122 @@ rgw::auth::Strategy::add_engine(const Control ctrl_flag,
 {
   auth_stack.push_back(std::make_pair(std::cref(engine), ctrl_flag));
 }
+
+
+/* rgw::auth::RemoteAuthApplier */
+uint32_t rgw::auth::RemoteApplier::get_perms_from_aclspec(const aclspec_t& aclspec) const
+{
+  uint32_t perm = 0;
+
+  /* For backward compatibility with ACLOwner. */
+  perm |= rgw_perms_from_aclspec_default_strategy(info.acct_user,
+                                                  aclspec);
+
+  /* We also need to cover cases where rgw_keystone_implicit_tenants
+   * was enabled. */
+  if (info.acct_user.tenant.empty()) {
+    const rgw_user tenanted_acct_user(info.acct_user.id, info.acct_user.id);
+
+    perm |= rgw_perms_from_aclspec_default_strategy(tenanted_acct_user,
+                                                    aclspec);
+  }
+
+  /* Now it's a time for invoking additional strategy that was supplied by
+   * a specific auth engine. */
+  if (extra_acl_strategy) {
+    perm |= extra_acl_strategy(aclspec);
+  }
+
+  ldout(cct, 20) << "from ACL got perm=" << perm << dendl;
+  return perm;
+}
+
+bool rgw::auth::RemoteApplier::is_admin_of(const rgw_user& uid) const
+{
+  return info.is_admin;
+}
+
+bool rgw::auth::RemoteApplier::is_owner_of(const rgw_user& uid) const
+{
+  if (info.acct_user.tenant.empty()) {
+    const rgw_user tenanted_acct_user(info.acct_user.id, info.acct_user.id);
+
+    if (tenanted_acct_user == uid) {
+      return true;
+    }
+  }
+
+  return info.acct_user == uid;
+}
+
+void rgw::auth::RemoteApplier::to_str(std::ostream& out) const
+{
+  out << "rgw::auth::RemoteApplier(acct_user=" << info.acct_user
+      << ", acct_name=" << info.acct_name
+      << ", perm_mask=" << info.perm_mask
+      << ", is_admin=" << info.is_admin << ")";
+}
+
+void rgw::auth::RemoteApplier::create_account(const rgw_user& acct_user,
+                                              RGWUserInfo& user_info) const      /* out */
+{
+  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) {
+    new_acct_user.tenant = new_acct_user.id;
+  }
+
+  user_info.user_id = new_acct_user;
+  user_info.display_name = info.acct_name;
+
+  int ret = rgw_store_user_info(store, user_info, nullptr, nullptr,
+                                real_time(), true);
+  if (ret < 0) {
+    ldout(cct, 0) << "ERROR: failed to store new user info: user="
+                  << user_info.user_id << " ret=" << ret << dendl;
+    throw ret;
+  }
+}
+
+/* TODO(rzarzynski): we need to handle display_name changes. */
+void rgw::auth::RemoteApplier::load_acct_info(RGWUserInfo& user_info) const      /* out */
+{
+  /* It's supposed that RGWRemoteAuthApplier tries to load account info
+   * that belongs to the authenticated identity. Another policy may be
+   * applied by using a RGWThirdPartyAccountAuthApplier decorator. */
+  const rgw_user& acct_user = info.acct_user;
+
+  /* Normally, empty "tenant" field of acct_user means the authenticated
+   * identity has the legacy, global tenant. However, due to inclusion
+   * of multi-tenancy, we got some special compatibility kludge for remote
+   * backends like Keystone.
+   * If the global tenant is the requested one, we try the same tenant as
+   * the user name first. If that RGWUserInfo exists, we use it. This way,
+   * migrated OpenStack users can get their namespaced containers and nobody's
+   * the wiser.
+   * If that fails, we look up in the requested (possibly empty) tenant.
+   * If that fails too, we create the account within the global or separated
+   * namespace depending on rgw_keystone_implicit_tenants. */
+  if (acct_user.tenant.empty()) {
+    const rgw_user tenanted_uid(acct_user.id, acct_user.id);
+
+    if (rgw_get_user_info_by_uid(store, tenanted_uid, user_info) >= 0) {
+      /* Succeeded. */
+      return;
+    }
+  }
+
+  if (rgw_get_user_info_by_uid(store, acct_user, user_info) < 0) {
+    ldout(cct, 0) << "NOTICE: couldn't map swift user " << acct_user << dendl;
+    create_account(acct_user, user_info);
+  }
+
+  /* Succeeded if we are here (create_account() hasn't throwed). */
+}
index be35fbaa03e539d2875bec9088b75af32c41169a..1eece8b80c19c6d6db05b68e55b8c79700adc9b9 100644 (file)
@@ -551,6 +551,92 @@ protected:
   void add_engine(Control ctrl_flag, const Engine& engine) noexcept;
 };
 
+
+/* rgw::auth::RemoteApplier targets those authentication engines which don't
+ * need to ask the RADOS store while performing the auth process. Instead,
+ * they obtain credentials from an external source like Keystone or LDAP.
+ *
+ * As the authenticated user may not have an account yet, RGWRemoteAuthApplier
+ * must be able to create it basing on data passed by an auth engine. Those
+ * data will be used to fill RGWUserInfo structure. */
+class RemoteApplier : public IdentityApplier {
+public:
+  class AuthInfo {
+    friend class RemoteApplier;
+  protected:
+    const rgw_user acct_user;
+    const std::string acct_name;
+    const uint32_t perm_mask;
+    const bool is_admin;
+    const uint32_t acct_type;
+
+  public:
+    enum class acct_privilege_t {
+      IS_ADMIN_ACCT,
+      IS_PLAIN_ACCT
+    };
+
+    AuthInfo(const rgw_user& acct_user,
+             const std::string& acct_name,
+             const uint32_t perm_mask,
+             const acct_privilege_t level,
+             const uint32_t acct_type=TYPE_NONE)
+    : acct_user(acct_user),
+      acct_name(acct_name),
+      perm_mask(perm_mask),
+      is_admin(acct_privilege_t::IS_ADMIN_ACCT == level),
+      acct_type(acct_type) {
+    }
+  };
+
+  using aclspec_t = RGWIdentityApplier::aclspec_t;
+  typedef std::function<uint32_t(const aclspec_t&)> acl_strategy_t;
+
+protected:
+  CephContext* const cct;
+
+  /* Read-write is intensional here due to RGWUserInfo creation process. */
+  RGWRados* const store;
+
+  /* Supplemental strategy for extracting permissions from ACLs. Its results
+   * will be combined (ORed) with a default strategy that is responsible for
+   * handling backward compatibility. */
+  const acl_strategy_t extra_acl_strategy;
+
+  const AuthInfo info;
+
+  virtual void create_account(const rgw_user& acct_user,
+                              RGWUserInfo& user_info) const;          /* out */
+
+public:
+  RemoteApplier(CephContext* const cct,
+                RGWRados* const store,
+                acl_strategy_t&& extra_acl_strategy,
+                const AuthInfo& info)
+    : cct(cct),
+      store(store),
+      extra_acl_strategy(std::move(extra_acl_strategy)),
+      info(info) {
+  }
+
+  uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override;
+  bool is_admin_of(const rgw_user& uid) const override;
+  bool is_owner_of(const rgw_user& uid) const override;
+  uint32_t get_perm_mask() const override { return info.perm_mask; }
+  void to_str(std::ostream& out) const override;
+  void load_acct_info(RGWUserInfo& user_info) const override; /* out */
+
+  struct Factory {
+    virtual ~Factory() {}
+    /* Providing r-value reference here is required intensionally. Callee is
+     * thus disallowed to handle std::function in a way that could inhibit
+     * the move behaviour (like forgetting about std::moving a l-value). */
+    virtual aplptr_t create_apl_remote(CephContext * const cct,
+                                       acl_strategy_t&& extra_acl_strategy,
+                                       const AuthInfo info) const = 0;
+  };
+};
+
 } /* namespace auth */
 } /* namespace rgw */