From: Radoslaw Zarzynski Date: Fri, 6 Jan 2017 11:35:11 +0000 (+0100) Subject: rgw: integrate the new EC2Engine with current S3 auth code. X-Git-Tag: v12.0.2~305^2~25 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c9b90ccf41e925ad1befe245540c529b282a8003;p=ceph.git rgw: integrate the new EC2Engine with current S3 auth code. Signed-off-by: Radoslaw Zarzynski --- diff --git a/src/rgw/rgw_auth_keystone.cc b/src/rgw/rgw_auth_keystone.cc index 5712019ab266..e715982644d5 100644 --- a/src/rgw/rgw_auth_keystone.cc +++ b/src/rgw/rgw_auth_keystone.cc @@ -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& 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 */ diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 84e8cca3fcbb..7ceeb1d60f50 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -26,6 +26,7 @@ #include "rgw_client_io.h" #include "rgw_keystone.h" +#include "rgw_auth_keystone.h" #include // 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()); + 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()); + 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; } }