mirror of
https://github.com/ceph/ceph
synced 2025-01-02 00:52:22 +00:00
rgw: integrate the new EC2Engine with current S3 auth code.
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
This commit is contained in:
parent
c7de0827d5
commit
c9b90ccf41
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user