summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYehuda Sadeh <yehuda@inktank.com>2012-10-30 15:52:53 -0700
committerYehuda Sadeh <yehuda@inktank.com>2012-10-30 15:52:53 -0700
commit845e862a71c4d700430a67cd025d1b60695f23d2 (patch)
tree4843d31480a5209401362eec163e08eb1d041f4c
parent9df953cdd5086bafb14ec2e7559daf7f157c8587 (diff)
downloadceph-845e862a71c4d700430a67cd025d1b60695f23d2.tar.gz
rgw: handle keystone tokens
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r--src/rgw/rgw_common.cc6
-rw-r--r--src/rgw/rgw_common.h4
-rw-r--r--src/rgw/rgw_http_client.cc48
-rw-r--r--src/rgw/rgw_http_client.h6
-rw-r--r--src/rgw/rgw_swift.cc149
-rw-r--r--src/rgw/rgw_swift.h6
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);