rgw: integrate the new EC2Engine with current S3 auth code.

Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
This commit is contained in:
Radoslaw Zarzynski 2017-01-06 12:35:11 +01:00
parent c7de0827d5
commit c9b90ccf41
2 changed files with 112 additions and 104 deletions

View 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;
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;
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);
}
/* 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
if (! is_time_skew_ok(header_time, qsr)) {
throw -ERR_REQUEST_TIME_SKEWED;
}
throw -ERR_INVALID_ACCESS_KEY;
}
}; /* namespace keystone */

View 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);
/* 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;
if (external_auth_result < 0) {
ldout(s->cct, 0) << "User lookup failed!" << dendl;
err_msg = "Bad access key / signature";
return -EACCES;
}
using keystone_config_t = rgw::keystone::CephCtxConfig;
using keystone_cache_t = rgw::keystone::TokenCache;
using EC2Engine = rgw::auth::keystone::EC2Engine;
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;
}
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;
/* 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;
RGW_Auth_S3_Keystone_ValidateToken keystone_validator(store->ctx());
string token;
using keystone_config_t = rgw::keystone::CephCtxConfig;
using keystone_cache_t = rgw::keystone::TokenCache;
using EC2Engine = rgw::auth::keystone::EC2Engine;
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;
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;
}
}