diff options
author | Yehuda Sadeh <yehuda@inktank.com> | 2012-10-30 15:52:53 -0700 |
---|---|---|
committer | Yehuda Sadeh <yehuda@inktank.com> | 2012-10-30 15:52:53 -0700 |
commit | 845e862a71c4d700430a67cd025d1b60695f23d2 (patch) | |
tree | 4843d31480a5209401362eec163e08eb1d041f4c | |
parent | 9df953cdd5086bafb14ec2e7559daf7f157c8587 (diff) | |
download | ceph-845e862a71c4d700430a67cd025d1b60695f23d2.tar.gz |
rgw: handle keystone tokens
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r-- | src/rgw/rgw_common.cc | 6 | ||||
-rw-r--r-- | src/rgw/rgw_common.h | 4 | ||||
-rw-r--r-- | src/rgw/rgw_http_client.cc | 48 | ||||
-rw-r--r-- | src/rgw/rgw_http_client.h | 6 | ||||
-rw-r--r-- | src/rgw/rgw_swift.cc | 149 | ||||
-rw-r--r-- | src/rgw/rgw_swift.h | 6 |
6 files changed, 196 insertions, 23 deletions
diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc index c0210b7964e..7b74a73ee85 100644 --- a/src/rgw/rgw_common.cc +++ b/src/rgw/rgw_common.cc @@ -88,7 +88,7 @@ is_err() const req_state::req_state(CephContext *_cct, struct RGWEnv *e) : cct(_cct), cio(NULL), op(OP_UNKNOWN), os_auth_token(NULL), - os_user(NULL), os_groups(NULL), env(e) + env(e) { enable_ops_log = env->conf->enable_ops_log; enable_usage_log = env->conf->enable_usage_log; @@ -109,8 +109,6 @@ req_state::req_state(CephContext *_cct, struct RGWEnv *e) : cct(_cct), cio(NULL) prot_flags = 0; os_auth_token = NULL; - os_user = NULL; - os_groups = NULL; time = ceph_clock_now(cct); perm_mask = 0; content_length = 0; @@ -128,8 +126,6 @@ req_state::~req_state() { delete formatter; delete bucket_acl; delete object_acl; - free(os_user); - free(os_groups); free((void *)object); free((void *)bucket_name); } diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 9b0d3c2c98f..3222e751589 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -611,8 +611,8 @@ struct req_state { int prot_flags; const char *os_auth_token; - char *os_user; - char *os_groups; + string swift_user; + string swift_groups; utime_t time; diff --git a/src/rgw/rgw_http_client.cc b/src/rgw/rgw_http_client.cc index 363b618b2c8..4c7b99c17c3 100644 --- a/src/rgw/rgw_http_client.cc +++ b/src/rgw/rgw_http_client.cc @@ -18,19 +18,59 @@ static size_t read_http_header(void *ptr, size_t size, size_t nmemb, void *_info return len; } +static size_t read_http_data(void *ptr, size_t size, size_t nmemb, void *_info) +{ + RGWHTTPClient *client = (RGWHTTPClient *)_info; + size_t len = size * nmemb; + int ret = client->read_data(ptr, size * nmemb); + if (ret < 0) { + dout(0) << "WARNING: client->read_data() returned ret=" << ret << dendl; + } + + return len; +} + int RGWHTTPClient::process(const string& url) { + int ret = 0; CURL *curl_handle; + char error_buf[CURL_ERROR_SIZE]; + curl_handle = curl_easy_init(); + + dout(20) << "sending request to " << url << dendl; + + curl_slist *h = NULL; + + list<pair<string, string> >::iterator iter; + for (iter = headers.begin(); iter != headers.end(); ++iter) { + pair<string, string>& p = *iter; + string val = p.first; + val.append(": "); + val.append(p.second); + h = curl_slist_append(h, val.c_str()); + } + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, read_http_header); - curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void *)this); - curl_easy_perform(curl_handle); + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, read_http_header); + curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void *)this); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, read_http_data); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)this); + curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, (void *)error_buf); + if (h) { + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, (void *)h); + } + CURLcode status = curl_easy_perform(curl_handle); + if (status) { + dout(0) << "curl_easy_performed returned error: " << error_buf << dendl; + ret = -EINVAL; + } curl_easy_cleanup(curl_handle); + curl_slist_free_all(h); - return 0; + return ret; } diff --git a/src/rgw/rgw_http_client.h b/src/rgw/rgw_http_client.h index 74148af1dc1..944ea89e3f3 100644 --- a/src/rgw/rgw_http_client.h +++ b/src/rgw/rgw_http_client.h @@ -5,11 +5,17 @@ class RGWHTTPClient { + list<pair<string, string> > headers; public: virtual ~RGWHTTPClient() {} RGWHTTPClient() {} + void append_header(const string& name, const string& val) { + headers.push_back(pair<string, string>(name, val)); + } + virtual int read_header(void *ptr, size_t len) { return 0; } + virtual int read_data(void *ptr, size_t len) { return 0; } int process(const string& url); }; diff --git a/src/rgw/rgw_swift.cc b/src/rgw/rgw_swift.cc index 6694dd2b935..b45f884baf1 100644 --- a/src/rgw/rgw_swift.cc +++ b/src/rgw/rgw_swift.cc @@ -2,6 +2,7 @@ #include <stdlib.h> #include <unistd.h> +#include "rgw_json.h" #include "rgw_common.h" #include "rgw_swift.h" #include "rgw_swift_auth.h" @@ -44,11 +45,11 @@ int RGWValidateSwiftToken::read_header(void *ptr, size_t len) if (strcmp(tok, "HTTP") == 0) { info->status = atoi(l); } else if (strcasecmp(tok, "X-Auth-Groups") == 0) { - info->auth_groups = strdup(l); + info->auth_groups = l; char *s = strchr(l, ','); if (s) { *s = '\0'; - info->user = strdup(l); + info->user = l; } } else if (strcasecmp(tok, "X-Auth-Ttl") == 0) { info->ttl = atoll(l); @@ -84,6 +85,129 @@ static int rgw_swift_validate_token(const char *token, struct rgw_swift_auth_inf return 0; } +class RGWValidateKeystoneToken : public RGWHTTPClient { + bufferlist *bl; +public: + RGWValidateKeystoneToken(bufferlist *_bl) : bl(_bl) {} + + int read_data(void *ptr, size_t len) { + bl->append((char *)ptr, len); + return 0; + } +}; + +class KeystoneTokenResponseParser { +public: + string tenant_name; + string user_name; + string expires; + + KeystoneTokenResponseParser() {} + + int parse(bufferlist& bl); +}; + +int KeystoneTokenResponseParser::parse(bufferlist& bl) +{ + RGWJSONParser parser; + + if (!parser.parse(bl.c_str(), bl.length())) { + dout(0) << "malformed json" << dendl; + return -EINVAL; + } + + JSONObjIter iter = parser.find_first("access"); + if (iter.end()) { + dout(0) << "token response is missing access section" << dendl; + return -EINVAL; + } + + JSONObj *access_obj = *iter; + JSONObj *user = access_obj->find_obj("user"); + if (!user) { + dout(0) << "token response is missing user section" << dendl; + return -EINVAL; + } + + if (!user->get_data("name", &user_name)) { + dout(0) << "token response is missing user name" << dendl; + return -EINVAL; + } + + JSONObj *token = access_obj->find_obj("token"); + if (!user) { + dout(0) << "missing token section in response" << dendl; + return -EINVAL; + } + + if (!token->get_data("expires", &expires)) { + dout(0) << "token response is missing expiration field" << dendl; + return -EINVAL; + } + + JSONObj *tenant = token->find_obj("tenant"); + if (!tenant) { + dout(0) << "token response is missing tenant section" << dendl; + return -EINVAL; + } + + if (!tenant->get_data("name", &tenant_name)) { + dout(0) << "tenant is missing name field" << dendl; + return -EINVAL; + } + + return 0; +} + +static int rgw_parse_keystone_token_response(bufferlist& bl, struct rgw_swift_auth_info *info) +{ + RGWJSONParser parser; + + if (!parser.parse(bl.c_str(), bl.length())) { + dout(0) << "malformed json" << dendl; + return -EINVAL; + } + + KeystoneTokenResponseParser p; + int ret = p.parse(bl); + if (ret < 0) + return ret; + + dout(0) << "validated token: " << p.tenant_name << ":" << p.user_name << " expires: " << p.expires << dendl; + + info->user = p.tenant_name; + info->status = 200; + + return 0; +} + +static int rgw_swift_validate_keystone_token(const char *token, struct rgw_swift_auth_info *info) +{ + bufferlist bl; + RGWValidateKeystoneToken validate(&bl); + + string url = g_conf->rgw_swift_keystone_url; + if (url[url.size() - 1] != '/') + url.append("/"); + url.append("v2.0/tokens/"); + url.append(token); + + validate.append_header("X-Auth-Token", g_conf->rgw_swift_keystone_admin_token); + + int ret = validate.process(url); + if (ret < 0) + return ret; + + dout(0) << "received response: " << bl.c_str() << dendl; + + ret = rgw_parse_keystone_token_response(bl, info); + if (ret < 0) + return ret; + + return 0; +} + + bool rgw_verify_swift_token(RGWRados *store, req_state *s) { if (!s->os_auth_token) @@ -99,25 +223,30 @@ bool rgw_verify_swift_token(RGWRados *store, req_state *s) struct rgw_swift_auth_info info; - memset(&info, 0, sizeof(info)); - info.status = 401; // start with access denied, validate_token might change that - int ret = rgw_swift_validate_token(s->os_auth_token, &info); + int ret; + + if (g_conf->rgw_swift_use_keystone) { + ret = rgw_swift_validate_keystone_token(s->os_auth_token, &info); + return (ret >= 0); + } + + ret = rgw_swift_validate_token(s->os_auth_token, &info); if (ret < 0) return ret; - if (!info.user) { + if (info.user.empty()) { dout(5) << "swift auth didn't authorize a user" << dendl; return false; } - s->os_user = info.user; - s->os_groups = info.auth_groups; + s->swift_user = info.user; + s->swift_groups = info.auth_groups; - string swift_user = s->os_user; + string swift_user = s->swift_user; - dout(10) << "swift user=" << s->os_user << dendl; + dout(10) << "swift user=" << s->swift_user << dendl; if (rgw_get_user_info_by_swift(store, swift_user, s->user) < 0) { dout(0) << "NOTICE: couldn't map swift user" << dendl; diff --git a/src/rgw/rgw_swift.h b/src/rgw/rgw_swift.h index a678b22065a..9cc289e1c34 100644 --- a/src/rgw/rgw_swift.h +++ b/src/rgw/rgw_swift.h @@ -8,9 +8,11 @@ class RGWRados; struct rgw_swift_auth_info { int status; - char *auth_groups; - char *user; + string auth_groups; + string user; long long ttl; + + rgw_swift_auth_info() : status(0), ttl(0) {} }; bool rgw_verify_swift_token(RGWRados *store, req_state *s); |