]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rgw: integrate the new EC2Engine with current S3 auth code.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Fri, 6 Jan 2017 11:35:11 +0000 (12:35 +0100)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Fri, 24 Mar 2017 15:55:22 +0000 (16:55 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_auth_keystone.cc
src/rgw/rgw_rest_s3.cc

index 5712019ab266113ed22c05eced31b3e2129707fd..e715982644d57bdc8153f3e105b252b057ebb3ac 100644 (file)
@@ -390,6 +390,44 @@ bool EC2Engine::is_time_skew_ok(const utime_t& header_time,
   }
 }
 
+EC2Engine::acl_strategy_t
+EC2Engine::get_acl_strategy(const EC2Engine::token_envelope_t&) 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;
+}
+
+EC2Engine::auth_info_t
+EC2Engine::get_creds_info(const EC2Engine::token_envelope_t& token,
+                          const std::vector<std::string>& admin_roles
+                         ) const noexcept
+{
+  using acct_privilege_t = \
+    rgw::auth::RemoteApplier::AuthInfo::acct_privilege_t;
+
+  /* Check whether the user has an admin status. */
+  acct_privilege_t level = acct_privilege_t::IS_PLAIN_ACCT;
+  for (const auto& admin_role : admin_roles) {
+    if (token.has_role(admin_role)) {
+      level = acct_privilege_t::IS_ADMIN_ACCT;
+      break;
+    }
+  }
+
+  return auth_info_t {
+    /* Suggested account name for the authenticated user. */
+    rgw_user(token.get_project_id()),
+    /* User's display name (aka real name). */
+    token.get_project_name(),
+    /* Keystone doesn't support RGW's subuser concept, so we cannot cut down
+     * the access rights through the perm_mask. At least at this layer. */
+    RGW_PERM_FULL_CONTROL,
+    level,
+    TYPE_KEYSTONE,
+  };
+}
+
 rgw::auth::Engine::result_t EC2Engine::authenticate(std::string access_key_id,
                                                     std::string signature,
                                                     std::string expires,
@@ -431,6 +469,10 @@ rgw::auth::Engine::result_t EC2Engine::authenticate(std::string access_key_id,
     return std::make_pair(nullptr, nullptr);
   }
 
+  if (! is_time_skew_ok(header_time, qsr)) {
+    throw -ERR_REQUEST_TIME_SKEWED;
+  }
+
   /* check if we have a valid role */
   bool found = false;
   for (const auto& role : accepted_roles.plain) {
@@ -440,44 +482,21 @@ rgw::auth::Engine::result_t EC2Engine::authenticate(std::string access_key_id,
     }
   }
 
-  if (!found) {
+  if (! found) {
     ldout(cct, 5) << "s3 keystone: user does not hold a matching role;"
                      " required roles: "
                   << cct->_conf->rgw_keystone_accepted_roles << dendl;
-  }
-
-  /* everything seems fine, continue with this user */
-  ldout(cct, 5) << "s3 keystone: validated token: " << t.get_project_name()
-                << ":" << t.get_user_name()
-                << " expires: " << t.get_expires() << dendl;
-#if 0
-  return 0;
-}
-
-  /* Check for necessary roles. */
-  for (const auto& role : accepted_roles.plain) {
-    if (t.has_role(role) == true) {
-      ldout(cct, 0) << "validated token: " << t.get_project_name()
-                    << ":" << t.get_user_name()
-                    << " expires: " << t.get_expires() << dendl;
-
-      auto apl = apl_factory->create_apl_remote(cct, get_acl_strategy(t),
-                                            get_creds_info(t, roles.admin));
-      return std::make_pair(std::move(apl), nullptr);
-    }
-  }
-
-  ldout(cct, 0) << "user does not hold a matching role; required roles: "
-                << g_conf->rgw_keystone_accepted_roles << dendl;
-
-  //return std::make_pair(nullptr, nullptr);
-#endif
+    return std::make_pair(nullptr, nullptr);
+  } else {
+    /* everything seems fine, continue with this user */
+    ldout(cct, 5) << "s3 keystone: validated token: " << t.get_project_name()
+                  << ":" << t.get_user_name()
+                  << " expires: " << t.get_expires() << dendl;
 
-  if (! is_time_skew_ok(header_time, qsr)) {
-    throw -ERR_REQUEST_TIME_SKEWED;
+    auto apl = apl_factory->create_apl_remote(cct, s, get_acl_strategy(t),
+                                              get_creds_info(t, accepted_roles.admin));
+    return std::make_pair(std::move(apl), nullptr);
   }
-
-  throw -ERR_INVALID_ACCESS_KEY;
 }
 
 }; /* namespace keystone */
index 84e8cca3fcbb8c85de9f6af1731805f517a390f2..7ceeb1d60f50200bea43de7b671214d3ae01687d 100644 (file)
@@ -26,6 +26,7 @@
 #include "rgw_client_io.h"
 
 #include "rgw_keystone.h"
+#include "rgw_auth_keystone.h"
 
 #include <typeinfo> // for 'typeid'
 
@@ -1828,38 +1829,40 @@ int RGWPostObj_ObjStore_S3::get_policy()
          store->ctx()->_conf->rgw_keystone_url.empty())
       {
        // keystone
-       int external_auth_result = -EINVAL;
        dout(20) << "s3 keystone: trying keystone auth" << dendl;
 
-       RGW_Auth_S3_Keystone_ValidateToken keystone_validator(store->ctx());
-       external_auth_result =
-         keystone_validator.validate_s3token(s3_access_key,
-                                             string(encoded_policy.c_str(),
-                                                   encoded_policy.length()),
-                                             received_signature_str);
-
-       if (external_auth_result < 0) {
-         ldout(s->cct, 0) << "User lookup failed!" << dendl;
-         err_msg = "Bad access key / signature";
-         return -EACCES;
-       }
+        /* FIXME: stop overriding the aplfact and extr from parent scope.
+         * This will be possible when other S3 engines are ported. */
+        rgw::auth::s3::S3AuthFactory aplfact(store);
+        rgw::auth::s3::RGWS3V2Extractor extr;
 
-       string project_id = keystone_validator.response.get_project_id();
-       rgw_user uid(project_id);
-
-       user_info.user_id = project_id;
-       user_info.display_name = keystone_validator.response.get_project_name();
-
-       /* try to store user if it not already exists */
-       if (rgw_get_user_info_by_uid(store, uid, user_info) < 0) {
-         int ret = rgw_store_user_info(store, user_info, NULL, NULL, real_time(), true);
-         if (ret < 0) {
-           ldout(store->ctx(), 10)
-             << "NOTICE: failed to store new user's info: ret="
-             << ret << dendl;
-         }
-         s->perm_mask = RGW_PERM_FULL_CONTROL;
-       }
+        using keystone_config_t = rgw::keystone::CephCtxConfig;
+        using keystone_cache_t = rgw::keystone::TokenCache;
+        using EC2Engine = rgw::auth::keystone::EC2Engine;
+
+        EC2Engine keystone_s3(s->cct, &extr, &aplfact,
+                              keystone_config_t::get_instance(),
+                              keystone_cache_t::get_instance<keystone_config_t>());
+        try {
+          auto result = keystone_s3.authenticate(s);
+          auto& applier = result.first;
+          if (! applier) {
+            return -EACCES;
+          } else {
+            try {
+              applier->load_acct_info(user_info);
+              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) << "keystone auth engine threw err=" << err << dendl;
+          return err;
+        }
       } else if (ldap.is_applicable()) {
         try {
           auto applier = ldap.authenticate();
@@ -3995,52 +3998,38 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
   if (store->ctx()->_conf->rgw_s3_auth_use_keystone
       && !store->ctx()->_conf->rgw_keystone_url.empty()) {
     dout(20) << "s3 keystone: trying keystone auth" << dendl;
-
-    RGW_Auth_S3_Keystone_ValidateToken keystone_validator(store->ctx());
-    string token;
-
-    if (!rgw_create_s3_canonical_header(s->info,
-                                        &s->header_time, token, qsr)) {
-      dout(10) << "failed to create auth header\n" << token << dendl;
-      external_auth_result = -EPERM;
-    } else {
-      external_auth_result = keystone_validator.validate_s3token(auth_id, token,
-                                                           auth_sign);
-      if (external_auth_result == 0) {
-       // Check for time skew first
-       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;
-         return -ERR_REQUEST_TIME_SKEWED;
-       }
-
-        string project_id = keystone_validator.response.get_project_id();
-        s->user->user_id = project_id;
-        s->user->display_name = keystone_validator.response.get_project_name(); // wow.
-
-        rgw_user uid(project_id);
-        /* try to store user if it not already exists */
-        if (rgw_get_user_info_by_uid(store, uid, *(s->user)) < 0) {
-          int ret = rgw_store_user_info(store, *(s->user), NULL, NULL, real_time(), true);
-          if (ret < 0)
-            dout(10) << "NOTICE: failed to store new user's info: ret="
-                    << ret << dendl;
+    /* FIXME: the factory and extractor will be shared across all external
+     * engines after making the transition to S3ExternalAuthStrategy. */
+    rgw::auth::s3::S3AuthFactory aplfact(store);
+    rgw::auth::s3::RGWS3V2Extractor extr;
+
+    using keystone_config_t = rgw::keystone::CephCtxConfig;
+    using keystone_cache_t = rgw::keystone::TokenCache;
+    using EC2Engine = rgw::auth::keystone::EC2Engine;
+
+    EC2Engine keystone_s3(s->cct, &extr, &aplfact,
+                          keystone_config_t::get_instance(),
+                          keystone_cache_t::get_instance<keystone_config_t>());
+    try {
+      auto result = keystone_s3.authenticate(s);
+      auto& applier = result.first;
+      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;
         }
-
-        s->perm_mask = RGW_PERM_FULL_CONTROL;
       }
+    } catch (int err) {
+      ldout(s->cct, 5) << "keystone auth engine threw err=" << err << dendl;
+      external_auth_result = err;
     }
   }