diff options
author | Yehuda Sadeh <yehuda@inktank.com> | 2012-11-02 17:00:49 -0700 |
---|---|---|
committer | Yehuda Sadeh <yehuda@inktank.com> | 2012-11-08 13:24:20 -0800 |
commit | 8249d7b3fba6cf5f90beca22fc9397a356883349 (patch) | |
tree | 8856347c35ed0a25276d0e9e3544516f85fb8a78 | |
parent | f7412fe37e15b024eb69dcb56327e51496dbf334 (diff) | |
download | ceph-8249d7b3fba6cf5f90beca22fc9397a356883349.tar.gz |
rgw: decode revocation message
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r-- | src/common/ceph_crypto_cms.cc | 5 | ||||
-rw-r--r-- | src/common/ceph_crypto_cms.h | 2 | ||||
-rw-r--r-- | src/rgw/rgw_json.cc | 19 | ||||
-rw-r--r-- | src/rgw/rgw_swift.cc | 185 |
4 files changed, 181 insertions, 30 deletions
diff --git a/src/common/ceph_crypto_cms.cc b/src/common/ceph_crypto_cms.cc index 2c4312ca57c..7c0f5537548 100644 --- a/src/common/ceph_crypto_cms.cc +++ b/src/common/ceph_crypto_cms.cc @@ -61,7 +61,7 @@ #ifndef USE_NSS -int decode_cms(bufferlist& cms_bl, bufferlist& decoded_bl) +int ceph_decode_cms(bufferlist& cms_bl, bufferlist& decoded_bl) { return -ENOTSUP; } @@ -310,7 +310,7 @@ loser: return NULL; } -int decode_cms(bufferlist& cms_bl, bufferlist& decoded_bl) +int ceph_decode_cms(bufferlist& cms_bl, bufferlist& decoded_bl) { NSSCMSMessage *cmsg = NULL; struct decodeOptionsStr decodeOptions = { 0 }; @@ -353,7 +353,6 @@ int decode_cms(bufferlist& cms_bl, bufferlist& decoded_bl) NSS_CMSMessage_Destroy(cmsg); SECITEM_FreeItem(&decodeOptions.content, PR_FALSE); - SECITEM_FreeItem(&input, PR_FALSE); return ret; } diff --git a/src/common/ceph_crypto_cms.h b/src/common/ceph_crypto_cms.h index 4152d473af7..2b29dda0f96 100644 --- a/src/common/ceph_crypto_cms.h +++ b/src/common/ceph_crypto_cms.h @@ -3,6 +3,6 @@ #include "include/buffer.h" -int decode_cms(bufferlist& cms_bl, bufferlist& decoded_bl); +int ceph_decode_cms(bufferlist& cms_bl, bufferlist& decoded_bl); #endif diff --git a/src/rgw/rgw_json.cc b/src/rgw/rgw_json.cc index 8e1aafe097c..0f91c2279e1 100644 --- a/src/rgw/rgw_json.cc +++ b/src/rgw/rgw_json.cc @@ -85,10 +85,6 @@ JSONObjIter JSONObj::find_first() { JSONObjIter iter; iter.set(children.begin(), children.end()); - cout << "count=" << children.size() << std::endl; - for (map<string, JSONObj *>:: iterator i = children.begin(); i != children.end(); ++i) { - cout << "child: " << i->first << std::endl; - } return iter; } @@ -143,16 +139,11 @@ void JSONObj::handle_value(Value v) for (unsigned j = 0; j < temp_array.size(); j++) { Value cur = temp_array[j]; - - if (cur.type() == obj_type) { - handle_value(cur); - } else { - string temp_name; - - JSONObj *child = new JSONObj; - child->init(this, cur, temp_name); - add_child(child->get_name(), child); - } + string temp_name; + + JSONObj *child = new JSONObj; + child->init(this, cur, temp_name); + add_child(child->get_name(), child); } } } diff --git a/src/rgw/rgw_swift.cc b/src/rgw/rgw_swift.cc index 1ec8160c343..e3a1adbc9d1 100644 --- a/src/rgw/rgw_swift.cc +++ b/src/rgw/rgw_swift.cc @@ -11,6 +11,9 @@ #include "include/str_list.h" +#include "common/ceph_crypto_cms.h" +#include "common/armor.h" + #define dout_subsys ceph_subsys_rgw static list<string> roles_list; @@ -98,6 +101,7 @@ static int rgw_swift_validate_token(const char *token, struct rgw_swift_auth_inf class KeystoneToken { public: + string token_id; string tenant_name; string tenant_id; string user_name; @@ -144,7 +148,7 @@ int KeystoneToken::parse(bufferlist& bl) JSONObjIter riter = user->find("roles"); if (riter.end()) { - dout(0) << "token response is missing roles section" << dendl; + dout(0) << "token response is missing roles section, or section empty" << dendl; return -EINVAL; } @@ -160,7 +164,7 @@ int KeystoneToken::parse(bufferlist& bl) } JSONObj *token = access_obj->find_obj("token"); - if (!user) { + if (!token) { dout(0) << "missing token section in response" << dendl; return -EINVAL; } @@ -207,17 +211,25 @@ struct token_entry { class RGWKeystoneTokenCache { map<string, token_entry> tokens; + map<string, map<string, token_entry>::iterator> token_id_map; list<string> tokens_lru; Mutex lock; size_t max; + void _remove_token_id(const string& token_id) { + map<string, map<string, token_entry>::iterator>::iterator iter = token_id_map.find(token_id); + if (iter != token_id_map.end()) + token_id_map.erase(iter); + } + public: RGWKeystoneTokenCache(int _max) : lock("RGWKeystoneTokenCache"), max(_max) {} bool find(const string& token_str, KeystoneToken& token); - void add(const string& token_str, KeystoneToken& token); + void add(const string& token_str, const string& token_id, KeystoneToken& token); + void invalidate(const string& token_str, const string& token_id, KeystoneToken& token); }; bool RGWKeystoneTokenCache::find(const string& token_str, KeystoneToken& token) @@ -234,6 +246,7 @@ bool RGWKeystoneTokenCache::find(const string& token_str, KeystoneToken& token) tokens_lru.erase(entry.lru_iter); if (entry.token.expired()) { + _remove_token_id(entry.token.token_id); tokens.erase(iter); lock.Unlock(); if (perfcounter) perfcounter->inc(l_rgw_keystone_token_cache_hit); @@ -243,19 +256,20 @@ bool RGWKeystoneTokenCache::find(const string& token_str, KeystoneToken& token) tokens_lru.push_front(token_str); entry.lru_iter = tokens_lru.begin(); - + lock.Unlock(); if (perfcounter) perfcounter->inc(l_rgw_keystone_token_cache_hit); return true; } -void RGWKeystoneTokenCache::add(const string& token_str, KeystoneToken& token) +void RGWKeystoneTokenCache::add(const string& token_str, const string& token_id, KeystoneToken& token) { lock.Lock(); map<string, token_entry>::iterator iter = tokens.find(token_str); if (iter != tokens.end()) { token_entry& e = iter->second; + _remove_token_id(e.token.token_id); tokens_lru.erase(e.lru_iter); } @@ -264,10 +278,13 @@ void RGWKeystoneTokenCache::add(const string& token_str, KeystoneToken& token) entry.token = token; entry.lru_iter = tokens_lru.begin(); + token_id_map[entry.token.token_id] = tokens.find(token_str); + while (tokens_lru.size() > max) { list<string>::reverse_iterator riter = tokens_lru.rbegin(); iter = tokens.find(*riter); assert(iter != tokens.end()); + _remove_token_id(*riter); tokens.erase(iter); tokens_lru.pop_back(); } @@ -288,15 +305,76 @@ public: static RGWKeystoneTokenCache *keystone_token_cache = NULL; -static void rgw_set_keystone_token_auth_info(KeystoneToken& token, struct rgw_swift_auth_info *info) +class RGWGetRevokedTokens : public RGWHTTPClient { + bufferlist *bl; +public: + RGWGetRevokedTokens(bufferlist *_bl) : bl(_bl) {} + + int read_data(void *ptr, size_t len) { + bl->append((char *)ptr, len); + return 0; + } +}; +static int open_cms_envelope(string& src, string& dst) { - info->user = token.tenant_id; - info->display_name = token.tenant_name; - info->status = 200; -} +#define BEGIN_CMS "-----BEGIN CMS-----" +#define END_CMS "-----END CMS-----" -static int rgw_parse_keystone_token_response(const string& token, bufferlist& bl, struct rgw_swift_auth_info *info) + int start = src.find(BEGIN_CMS); + if (start < 0) { + dout(0) << "failed to find " << BEGIN_CMS << " in response" << dendl; + return -EINVAL; + } + start += sizeof(BEGIN_CMS) - 1; + + int end = src.find(END_CMS); + if (end < 0) { + dout(0) << "failed to find " << END_CMS << " in response" << dendl; + return -EINVAL; + } + + string s = src.substr(start, end - start); + + int pos = 0; + + do { + int next = s.find('\n', pos); + if (next < 0) { + dst.append(s.substr(pos)); + break; + } else { + dst.append(s.substr(pos, next - pos)); + } + pos = next + 1; + } while (pos < (int)s.size()); + + return 0; +} + +static int rgw_check_revoked() { + bufferlist bl; + RGWGetRevokedTokens req(&bl); + + string url = g_conf->rgw_keystone_url; + if (url.empty()) { + dout(0) << "ERROR: keystone url is not configured" << dendl; + return -EINVAL; + } + if (url[url.size() - 1] != '/') + url.append("/"); + url.append("v2.0/tokens/revoked"); + + req.append_header("X-Auth-Token", g_conf->rgw_keystone_admin_token); + + int ret = req.process(url); + if (ret < 0) + return ret; + + bl.append((char)0); // NULL terminate + + dout(10) << "request returned " << bl.c_str() << dendl; + RGWJSONParser parser; if (!parser.parse(bl.c_str(), bl.length())) { @@ -304,6 +382,86 @@ static int rgw_parse_keystone_token_response(const string& token, bufferlist& bl return -EINVAL; } + JSONObjIter iter = parser.find_first("signed"); + if (iter.end()) { + dout(0) << "revoked tokens response is missing signed section" << dendl; + return -EINVAL; + } + + JSONObj *signed_obj = *iter; + + string signed_str = signed_obj->get_data(); + + dout(10) << "signed=" << signed_str << dendl; + + string signed_b64; + ret = open_cms_envelope(signed_str, signed_b64); + if (ret < 0) + return ret; + + dout(10) << "content=" << signed_b64 << dendl; + + bufferptr signed_ber(signed_b64.size() * 2); + char *dest = signed_ber.c_str(); + const char *src = signed_b64.c_str(); + ret = ceph_unarmor(dest, dest + signed_ber.length(), src, src + signed_b64.size()); + if (ret < 0) { + dout(0) << "ceph_unarmor() failed, ret=" << ret << dendl; + return ret; + } + + bufferlist signed_ber_bl; + signed_ber_bl.append(signed_ber); + + bufferlist json; + + ret = ceph_decode_cms(signed_ber_bl, json); + if (ret < 0) { + dout(0) << "ceph_decode_cms returned " << ret << dendl; + return ret; + } + + dout(10) << "ceph_decode_cms: decoded: " << json.c_str() << dendl; + + RGWJSONParser list_parser; + if (!list_parser.parse(json.c_str(), json.length())) { + dout(0) << "malformed json" << dendl; + return -EINVAL; + } + + JSONObjIter revoked_iter = list_parser.find_first("revoked"); + if (revoked_iter.end()) { + dout(0) << "no revoked section in json" << dendl; + return -EINVAL; + } + + JSONObj *revoked_obj = *revoked_iter; + + JSONObjIter tokens_iter = revoked_obj->find_first(); + for (; !tokens_iter.end(); ++tokens_iter) { + JSONObj *o = *tokens_iter; + + JSONObj *token = o->find_obj("id"); + if (!token) { + dout(0) << "bad token in array, missing id" << dendl; + continue; + } + + dout(20) << "token id=" << token->get_data() << dendl; + } + + return 0; +} + +static void rgw_set_keystone_token_auth_info(KeystoneToken& token, struct rgw_swift_auth_info *info) +{ + info->user = token.tenant_id; + info->display_name = token.tenant_name; + info->status = 200; +} + +static int rgw_parse_keystone_token_response(const string& token, bufferlist& bl, struct rgw_swift_auth_info *info) +{ KeystoneToken t; int ret = t.parse(bl); if (ret < 0) @@ -327,7 +485,7 @@ static int rgw_parse_keystone_token_response(const string& token, bufferlist& bl dout(0) << "validated token: " << t.tenant_name << ":" << t.user_name << " expires: " << t.expiration << dendl; rgw_set_keystone_token_auth_info(t, info); - keystone_token_cache->add(token, t); + keystone_token_cache->add(token, t.token_id, t); return 0; } @@ -352,6 +510,9 @@ static int rgw_swift_validate_keystone_token(RGWRados *store, const string& toke RGWUserInfo& rgw_user) { KeystoneToken t; + + rgw_check_revoked(); + if (keystone_token_cache->find(token, t)) { rgw_set_keystone_token_auth_info(t, info); int ret = update_user_info(store, info, rgw_user); |