Skip to content

Commit

Permalink
rgw: Allow an implicit tenant in case of Keystone
Browse files Browse the repository at this point in the history
This, unfortunately, introduces possible double lookups, but
they should be cached. Also, the logic appears somewhat convoluted,
although the intent is quite simple: if you're an OpenStack user
with a Keystone authentication, we allow an implicit tenant of
the same name as the user.

Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>

Conflicts:
	src/rgw/rgw_swift.cc
  • Loading branch information
zaitcev authored and yehudasa committed Mar 15, 2016
1 parent af4d401 commit e925948
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 31 deletions.
1 change: 1 addition & 0 deletions doc/radosgw/keystone.rst
Expand Up @@ -16,6 +16,7 @@ The following configuration options are available for Keystone integration::
rgw keystone accepted roles = {accepted user roles}
rgw keystone token cache size = {number of tokens to cache}
rgw keystone revocation interval = {number of seconds before checking revoked tickets}
rgw keystone make new tenants = {true for private tenant for each new user}
rgw s3 auth use keystone = true
nss db path = {path to nss db}

Expand Down
1 change: 1 addition & 0 deletions src/common/config_opts.h
Expand Up @@ -1240,6 +1240,7 @@ OPTION(rgw_keystone_accepted_roles, OPT_STR, "Member, admin") // roles required
OPTION(rgw_keystone_token_cache_size, OPT_INT, 10000) // max number of entries in keystone token cache
OPTION(rgw_keystone_revocation_interval, OPT_INT, 15 * 60) // seconds between tokens revocation check
OPTION(rgw_keystone_verify_ssl, OPT_BOOL, true) // should we try to verify keystone's ssl
OPTION(rgw_keystone_implicit_tenants, OPT_BOOL, false) // create new users in their own tenants of the same name
OPTION(rgw_s3_auth_use_rados, OPT_BOOL, true) // should we try to use the internal credentials for s3?
OPTION(rgw_s3_auth_use_keystone, OPT_BOOL, false) // should we try to use keystone for s3?

Expand Down
83 changes: 55 additions & 28 deletions src/rgw/rgw_swift.cc
Expand Up @@ -62,7 +62,7 @@ int RGWValidateSwiftToken::receive_header(void *ptr, size_t len)
l++;

if (strcmp(tok, "HTTP") == 0) {
info->status = atoi(l);
;
} else if (strcasecmp(tok, "X-Auth-Groups") == 0) {
info->auth_groups = l;
char *s = strchr(l, ',');
Expand Down Expand Up @@ -375,7 +375,6 @@ static void rgw_set_keystone_token_auth_info(KeystoneToken& token, struct rgw_sw
{
info->user = token.get_project_id();
info->display_name = token.get_project_name();
info->status = 200;
}

int RGWSwift::parse_keystone_token_response(const string& token,
Expand Down Expand Up @@ -413,24 +412,59 @@ int RGWSwift::parse_keystone_token_response(const string& token,

int RGWSwift::update_user_info(RGWRados *store, struct rgw_swift_auth_info *info, RGWUserInfo& user_info)
{
if (rgw_get_user_info_by_uid(store, info->user, user_info) < 0) {
ldout(cct, 0) << "NOTICE: couldn't map swift user" << dendl;
user_info.user_id = info->user;
user_info.display_name = info->display_name;

int ret = rgw_store_user_info(store, user_info, NULL, NULL, real_time(), true);
if (ret < 0) {
ldout(cct, 0) << "ERROR: failed to store new user's info: ret=" << ret << dendl;
return ret;
ldout(cct, 20) << "updating user=" << info->user << dendl; // P3 XXX
/*
* Normally once someone parsed the token, the tenant and user are set
* in rgw_swift_auth_info. If .tenant is empty in it, the client has
* authenticated with the empty legacy tenant. But when we authenticate
* with Keystone, we have a special compatibility kludge. First, we try
* the same tenant as the user. If that user 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 the user in the empty
* tenant. If neither is found, make one, and those migrating can
* set a special configurable rgw_keystone_implicit_tenants to create
* suitable tenantized users.
*/
if (info->user.tenant.empty()) {
rgw_user uid;
uid.tenant = info->user.id;
uid.id = info->user.id;
if (rgw_get_user_info_by_uid(store, uid, user_info) < 0) {
uid.tenant.clear();
if (rgw_get_user_info_by_uid(store, uid, user_info) < 0) {
ldout(cct, 0) << "NOTICE: couldn't map swift user " << uid << dendl;
if (g_conf->rgw_keystone_implicit_tenants) {
uid.tenant = info->user.id;
}
user_info.user_id = uid;
user_info.display_name = info->display_name;
int ret = rgw_store_user_info(store, user_info, NULL, NULL, real_time(), true);
if (ret < 0) {
ldout(cct, 0) << "ERROR: failed to store new user info: user=" << user_info.user_id << " ret=" << ret << dendl;
return ret;
}
}
}
} else {
if (rgw_get_user_info_by_uid(store, info->user, user_info) < 0) {
ldout(cct, 0) << "NOTICE: couldn't map swift user " << info->user << dendl;
user_info.user_id = info->user;
user_info.display_name = info->display_name;
int ret = rgw_store_user_info(store, user_info, NULL, NULL, real_time(), true);
if (ret < 0) {
ldout(cct, 0) << "ERROR: failed to store new user info: user=" << user_info.user_id << " ret=" << ret << dendl;
return ret;
}
}
}
return 0;
}

int RGWSwift::validate_keystone_token(RGWRados *store, const string& token, struct rgw_swift_auth_info *info,
int RGWSwift::validate_keystone_token(RGWRados *store, const string& token,
RGWUserInfo& rgw_user)
{
KeystoneToken t;
struct rgw_swift_auth_info info;

string token_id;
rgw_get_token_id(token, token_id);
Expand All @@ -439,11 +473,11 @@ int RGWSwift::validate_keystone_token(RGWRados *store, const string& token, stru

/* check cache first */
if (keystone_token_cache->find(token_id, t)) {
rgw_set_keystone_token_auth_info(t, info);
rgw_set_keystone_token_auth_info(t, &info);

ldout(cct, 20) << "cached token.project.id=" << t.get_project_id() << dendl;

int ret = update_user_info(store, info, rgw_user);
int ret = update_user_info(store, &info, rgw_user);
if (ret < 0)
return ret;

Expand Down Expand Up @@ -495,7 +529,7 @@ int RGWSwift::validate_keystone_token(RGWRados *store, const string& token, stru

ldout(cct, 20) << "received response: " << bl.c_str() << dendl;

int ret = parse_keystone_token_response(token, bl, info, t);
int ret = parse_keystone_token_response(token, bl, &info, t);
if (ret < 0)
return ret;

Expand All @@ -508,7 +542,7 @@ int RGWSwift::validate_keystone_token(RGWRados *store, const string& token, stru

keystone_token_cache->add(token_id, t);

ret = update_user_info(store, info, rgw_user);
ret = update_user_info(store, &info, rgw_user);
if (ret < 0)
return ret;

Expand Down Expand Up @@ -726,23 +760,17 @@ bool RGWSwift::do_verify_swift_token(RGWRados *store, req_state *s)
if (strncmp(s->os_auth_token, "AUTH_rgwtk", 10) == 0) {
int ret = rgw_swift_verify_signed_token(s->cct, store, s->os_auth_token,
*(s->user), &s->swift_user);
if (ret < 0)
return false;

return true;
return (ret >= 0);
}

struct rgw_swift_auth_info info;

info.status = 401; // start with access denied, validate_token might change that

int ret;

if (supports_keystone()) {
ret = validate_keystone_token(store, s->os_auth_token, &info, *(s->user));
int ret = validate_keystone_token(store, s->os_auth_token, *(s->user));
return (ret >= 0);
}

struct rgw_swift_auth_info info;
int ret;

ret = validate_token(s->os_auth_token, &info);
if (ret < 0)
return false;
Expand Down Expand Up @@ -847,4 +875,3 @@ void RGWSwift::KeystoneRevokeThread::stop()
Mutex::Locker l(lock);
cond.Signal();
}

5 changes: 2 additions & 3 deletions src/rgw/rgw_swift.h
Expand Up @@ -14,21 +14,20 @@ class RGWRados;
class KeystoneToken;

struct rgw_swift_auth_info {
int status;
string auth_groups;
rgw_user user;
string display_name;
long long ttl;

rgw_swift_auth_info() : status(0), ttl(0) {}
rgw_swift_auth_info() : ttl(0) {}
};

class RGWSwift {
CephContext *cct;
atomic_t down_flag;

int validate_token(const char *token, struct rgw_swift_auth_info *info);
int validate_keystone_token(RGWRados *store, const string& token, struct rgw_swift_auth_info *info,
int validate_keystone_token(RGWRados *store, const string& token,
RGWUserInfo& rgw_user);

int parse_keystone_token_response(const string& token,
Expand Down

0 comments on commit e925948

Please sign in to comment.