diff options
author | Yehuda Sadeh <yehuda@inktank.com> | 2012-11-05 17:29:52 -0800 |
---|---|---|
committer | Yehuda Sadeh <yehuda@inktank.com> | 2012-11-08 13:24:29 -0800 |
commit | ff8c2380b37b853975fa64a71ab8bad5daed6515 (patch) | |
tree | 29a328becabcc97926847e70eccd60a38036dbb8 | |
parent | b69da4b8dbc5dedcbe13991c856d3b7be259ff78 (diff) | |
download | ceph-ff8c2380b37b853975fa64a71ab8bad5daed6515.tar.gz |
rgw: keystone tokens revocation thread
Use a thread to invalidate revoked tokens.
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r-- | src/common/config_opts.h | 1 | ||||
-rw-r--r-- | src/rgw/rgw_rest_swift.cc | 2 | ||||
-rw-r--r-- | src/rgw/rgw_swift.cc | 226 | ||||
-rw-r--r-- | src/rgw/rgw_swift.h | 64 |
4 files changed, 196 insertions, 97 deletions
diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 6a3117947c6..c9c5b4943b6 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -428,6 +428,7 @@ OPTION(rgw_keystone_url, OPT_STR, "") // url for keystone server OPTION(rgw_keystone_admin_token, OPT_STR, "") // keystone admin token (shared secret) OPTION(rgw_keystone_operator_roles, OPT_STR, "swiftoperator, admin") // roles required to serve requests 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_admin_entry, OPT_STR, "admin") // entry point for which a url is considered an admin request OPTION(rgw_enforce_swift_acls, OPT_BOOL, true) OPTION(rgw_print_continue, OPT_BOOL, true) // enable if 100-Continue works diff --git a/src/rgw/rgw_rest_swift.cc b/src/rgw/rgw_rest_swift.cc index d3d45e5525c..753adc86e42 100644 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@ -610,7 +610,7 @@ RGWOp *RGWHandler_ObjStore_Obj_SWIFT::op_copy() int RGWHandler_ObjStore_SWIFT::authorize() { - bool authorized = rgw_verify_swift_token(store, s); + bool authorized = rgw_swift->verify_swift_token(store, s); if (!authorized) return -EPERM; diff --git a/src/rgw/rgw_swift.cc b/src/rgw/rgw_swift.cc index df075e97b7e..060b435dfa4 100644 --- a/src/rgw/rgw_swift.cc +++ b/src/rgw/rgw_swift.cc @@ -21,12 +21,13 @@ static list<string> roles_list; class RGWKeystoneTokenCache; class RGWValidateSwiftToken : public RGWHTTPClient { + CephContext *cct; struct rgw_swift_auth_info *info; protected: - RGWValidateSwiftToken() {} + RGWValidateSwiftToken() : cct(NULL), info(NULL) {} public: - RGWValidateSwiftToken(struct rgw_swift_auth_info *_info) : info(_info) {} + RGWValidateSwiftToken(CephContext *_cct, struct rgw_swift_auth_info *_info) : cct(_cct), info(_info) {} int read_header(void *ptr, size_t len); @@ -39,7 +40,7 @@ int RGWValidateSwiftToken::read_header(void *ptr, size_t len) char *s = (char *)ptr, *end = (char *)ptr + len; char *p = line; - dout(10) << "read_http_header" << dendl; + ldout(cct, 10) << "read_http_header" << dendl; while (s != end) { if (*s == '\r') { @@ -48,7 +49,7 @@ int RGWValidateSwiftToken::read_header(void *ptr, size_t len) } if (*s == '\n') { *p = '\0'; - dout(10) << "os_auth:" << line << dendl; + ldout(cct, 10) << "os_auth:" << line << dendl; // TODO: fill whatever data required here char *l = line; char *tok = strsep(&l, " \t:"); @@ -76,7 +77,7 @@ int RGWValidateSwiftToken::read_header(void *ptr, size_t len) return 0; } -static int rgw_swift_validate_token(const char *token, struct rgw_swift_auth_info *info) +int RGWSwift::validate_token(const char *token, struct rgw_swift_auth_info *info) { if (g_conf->rgw_swift_auth_url.empty()) return -EINVAL; @@ -88,9 +89,9 @@ static int rgw_swift_validate_token(const char *token, struct rgw_swift_auth_inf char url_buf[auth_url.size() + 1 + strlen(token) + 1]; sprintf(url_buf, "%s/%s", auth_url.c_str(), token); - RGWValidateSwiftToken validate(info); + RGWValidateSwiftToken validate(cct, info); - dout(10) << "rgw_swift_validate_token url=" << url_buf << dendl; + ldout(cct, 10) << "rgw_swift_validate_token url=" << url_buf << dendl; int ret = validate.process(url_buf); if (ret < 0) @@ -99,74 +100,55 @@ static int rgw_swift_validate_token(const char *token, struct rgw_swift_auth_inf return 0; } -class KeystoneToken { -public: - string tenant_name; - string tenant_id; - string user_name; - time_t expiration; - - map<string, bool> roles; - - KeystoneToken() {} - - int parse(bufferlist& bl); - - bool expired() { - uint64_t now = ceph_clock_now(NULL).sec(); - return (now < (uint64_t)expiration); - } -}; - -int KeystoneToken::parse(bufferlist& bl) +int KeystoneToken::parse(CephContext *cct, bufferlist& bl) { RGWJSONParser parser; if (!parser.parse(bl.c_str(), bl.length())) { - dout(0) << "malformed json" << dendl; + ldout(cct, 0) << "malformed json" << dendl; return -EINVAL; } JSONObjIter iter = parser.find_first("access"); if (iter.end()) { - dout(0) << "token response is missing access section" << dendl; + ldout(cct, 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; + ldout(cct, 0) << "token response is missing user section" << dendl; return -EINVAL; } if (!user->get_data("username", &user_name)) { - dout(0) << "token response is missing user username field" << dendl; + ldout(cct, 0) << "token response is missing user username field" << dendl; return -EINVAL; } JSONObj *roles_obj = user->find_obj("roles"); if (!roles_obj) { - dout(0) << "token response is missing roles section, or section empty" << dendl; + ldout(cct, 0) << "token response is missing roles section, or section empty" << dendl; return -EINVAL; } JSONObjIter riter = roles_obj->find_first(); if (riter.end()) { - dout(0) << "token response has an empty roles list" << dendl; + ldout(cct, 0) << "token response has an empty roles list" << dendl; return -EINVAL; } for (; !riter.end(); ++riter) { JSONObj *role_obj = *riter; if (!role_obj) { - dout(0) << "ERROR: role object is NULL" << dendl; + ldout(cct, 0) << "ERROR: role object is NULL" << dendl; return -EINVAL; } JSONObj *role_name = role_obj->find_obj("name"); if (!role_name) { - dout(0) << "token response is missing role name section" << dendl; + ldout(cct, 0) << "token response is missing role name section" << dendl; return -EINVAL; } string role = role_name->get_data(); @@ -175,20 +157,20 @@ int KeystoneToken::parse(bufferlist& bl) JSONObj *token = access_obj->find_obj("token"); if (!token) { - dout(0) << "missing token section in response" << dendl; + ldout(cct, 0) << "missing token section in response" << dendl; return -EINVAL; } string expires; if (!token->get_data("expires", &expires)) { - dout(0) << "token response is missing expiration field" << dendl; + ldout(cct, 0) << "token response is missing expiration field" << dendl; return -EINVAL; } struct tm t; if (!parse_iso8601(expires.c_str(), &t)) { - dout(0) << "failed to parse token expiration (" << expires << ")" << dendl; + ldout(cct, 0) << "failed to parse token expiration (" << expires << ")" << dendl; return -EINVAL; } @@ -196,18 +178,18 @@ int KeystoneToken::parse(bufferlist& bl) JSONObj *tenant = token->find_obj("tenant"); if (!tenant) { - dout(0) << "token response is missing tenant section" << dendl; + ldout(cct, 0) << "token response is missing tenant section" << dendl; return -EINVAL; } if (!tenant->get_data("id", &tenant_id)) { - dout(0) << "tenant is missing id field" << dendl; + ldout(cct, 0) << "tenant is missing id field" << dendl; return -EINVAL; } if (!tenant->get_data("name", &tenant_name)) { - dout(0) << "tenant is missing name field" << dendl; + ldout(cct, 0) << "tenant is missing name field" << dendl; return -EINVAL; } @@ -220,6 +202,8 @@ struct token_entry { }; class RGWKeystoneTokenCache { + CephContext *cct; + map<string, token_entry> tokens; list<string> tokens_lru; @@ -228,7 +212,7 @@ class RGWKeystoneTokenCache { size_t max; public: - RGWKeystoneTokenCache(int _max) : lock("RGWKeystoneTokenCache"), max(_max) {} + RGWKeystoneTokenCache(CephContext *_cct, int _max) : cct(_cct), lock("RGWKeystoneTokenCache"), max(_max) {} bool find(const string& token_id, KeystoneToken& token); void add(const string& token_id, KeystoneToken& token); @@ -297,7 +281,7 @@ void RGWKeystoneTokenCache::invalidate(const string& token_id) if (iter == tokens.end()) return; - dout(20) << "invalidating revoked token id=" << token_id << dendl; + ldout(cct, 20) << "invalidating revoked token id=" << token_id << dendl; token_entry& e = iter->second; tokens_lru.erase(e.lru_iter); tokens.erase(iter); @@ -326,21 +310,22 @@ public: return 0; } }; -static int open_cms_envelope(string& src, string& dst) + +static int open_cms_envelope(CephContext *cct, string& src, string& dst) { #define BEGIN_CMS "-----BEGIN CMS-----" #define END_CMS "-----END CMS-----" int start = src.find(BEGIN_CMS); if (start < 0) { - dout(0) << "failed to find " << BEGIN_CMS << " in response" << dendl; + ldout(cct, 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; + ldout(cct, 0) << "failed to find " << END_CMS << " in response" << dendl; return -EINVAL; } @@ -362,7 +347,7 @@ static int open_cms_envelope(string& src, string& dst) return 0; } -static int decode_b64_cms(const string& signed_b64, bufferlist& bl) +static int decode_b64_cms(CephContext *cct, const string& signed_b64, bufferlist& bl) { bufferptr signed_ber(signed_b64.size() * 2); char *dest = signed_ber.c_str(); @@ -378,7 +363,7 @@ static int decode_b64_cms(const string& signed_b64, bufferlist& bl) } int ret = ceph_unarmor(dest, dest + signed_ber.length(), buf, buf + signed_b64.size()); if (ret < 0) { - dout(0) << "ceph_unarmor() failed, ret=" << ret << dendl; + ldout(cct, 0) << "ceph_unarmor() failed, ret=" << ret << dendl; return ret; } @@ -387,7 +372,7 @@ static int decode_b64_cms(const string& signed_b64, bufferlist& bl) ret = ceph_decode_cms(signed_ber_bl, bl); if (ret < 0) { - dout(0) << "ceph_decode_cms returned " << ret << dendl; + ldout(cct, 0) << "ceph_decode_cms returned " << ret << dendl; return ret; } @@ -395,14 +380,14 @@ static int decode_b64_cms(const string& signed_b64, bufferlist& bl) } -static int rgw_check_revoked() +int RGWSwift::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; + ldout(cct, 0) << "ERROR: keystone url is not configured" << dendl; return -EINVAL; } if (url[url.size() - 1] != '/') @@ -417,18 +402,18 @@ static int rgw_check_revoked() bl.append((char)0); // NULL terminate for debug output - dout(10) << "request returned " << bl.c_str() << dendl; + ldout(cct, 10) << "request returned " << bl.c_str() << dendl; RGWJSONParser parser; if (!parser.parse(bl.c_str(), bl.length())) { - dout(0) << "malformed json" << dendl; + ldout(cct, 0) << "malformed json" << dendl; return -EINVAL; } JSONObjIter iter = parser.find_first("signed"); if (iter.end()) { - dout(0) << "revoked tokens response is missing signed section" << dendl; + ldout(cct, 0) << "revoked tokens response is missing signed section" << dendl; return -EINVAL; } @@ -436,32 +421,32 @@ static int rgw_check_revoked() string signed_str = signed_obj->get_data(); - dout(10) << "signed=" << signed_str << dendl; + ldout(cct, 10) << "signed=" << signed_str << dendl; string signed_b64; - ret = open_cms_envelope(signed_str, signed_b64); + ret = open_cms_envelope(cct, signed_str, signed_b64); if (ret < 0) return ret; - dout(10) << "content=" << signed_b64 << dendl; + ldout(cct, 10) << "content=" << signed_b64 << dendl; bufferlist json; - ret = decode_b64_cms(signed_b64, json); + ret = decode_b64_cms(cct, signed_b64, json); if (ret < 0) { return ret; } - dout(10) << "ceph_decode_cms: decoded: " << json.c_str() << dendl; + ldout(cct, 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; + ldout(cct, 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; + ldout(cct, 0) << "no revoked section in json" << dendl; return -EINVAL; } @@ -473,7 +458,7 @@ static int rgw_check_revoked() JSONObj *token = o->find_obj("id"); if (!token) { - dout(0) << "bad token in array, missing id" << dendl; + ldout(cct, 0) << "bad token in array, missing id" << dendl; continue; } @@ -491,10 +476,9 @@ static void rgw_set_keystone_token_auth_info(KeystoneToken& token, struct rgw_sw info->status = 200; } -static int rgw_parse_keystone_token_response(const string& token, bufferlist& bl, struct rgw_swift_auth_info *info) +int RGWSwift::parse_keystone_token_response(const string& token, bufferlist& bl, struct rgw_swift_auth_info *info, KeystoneToken& t) { - KeystoneToken t; - int ret = t.parse(bl); + int ret = t.parse(cct, bl); if (ret < 0) return ret; @@ -509,27 +493,27 @@ static int rgw_parse_keystone_token_response(const string& token, bufferlist& bl } if (!found) { - dout(0) << "user does not hold a matching role; required roles: " << g_conf->rgw_keystone_operator_roles << dendl; + ldout(cct, 0) << "user does not hold a matching role; required roles: " << g_conf->rgw_keystone_operator_roles << dendl; return -EPERM; } - dout(0) << "validated token: " << t.tenant_name << ":" << t.user_name << " expires: " << t.expiration << dendl; + ldout(cct, 0) << "validated token: " << t.tenant_name << ":" << t.user_name << " expires: " << t.expiration << dendl; rgw_set_keystone_token_auth_info(t, info); return 0; } -static int update_user_info(RGWRados *store, struct rgw_swift_auth_info *info, RGWUserInfo& user_info) +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) { - dout(0) << "NOTICE: couldn't map swift user" << dendl; + 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, true); if (ret < 0) { - dout(0) << "ERROR: failed to store new user's info: ret=" << ret << dendl; + ldout(cct, 0) << "ERROR: failed to store new user's info: ret=" << ret << dendl; return ret; } } @@ -560,36 +544,37 @@ static void get_token_id(const string& token, string& token_id) char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5); token_id = calc_md5; - - dout(0) << "token_id=" << token_id << dendl; } -static bool decode_pki_token(const string& token, bufferlist& bl) +static bool decode_pki_token(CephContext *cct, const string& token, bufferlist& bl) { if (!is_pki_token(token)) return false; - int ret = decode_b64_cms(token, bl); + int ret = decode_b64_cms(cct, token, bl); if (ret < 0) return false; - dout(20) << "successfully decoded pki token" << dendl; + ldout(cct, 20) << "successfully decoded pki token" << dendl; return true; } -static int rgw_swift_validate_keystone_token(RGWRados *store, const string& token, struct rgw_swift_auth_info *info, - RGWUserInfo& rgw_user) +int RGWSwift::validate_keystone_token(RGWRados *store, const string& token, struct rgw_swift_auth_info *info, + RGWUserInfo& rgw_user) { KeystoneToken t; - rgw_check_revoked(); - string token_id; get_token_id(token, token_id); + ldout(cct, 20) << "token_id=" << token_id << dendl; + if (keystone_token_cache->find(token_id, t)) { rgw_set_keystone_token_auth_info(t, info); + + ldout(cct, 20) << "cached token.tenant_id=" << t.tenant_id << dendl; + int ret = update_user_info(store, info, rgw_user); if (ret < 0) return ret; @@ -599,12 +584,12 @@ static int rgw_swift_validate_keystone_token(RGWRados *store, const string& toke bufferlist bl; - if (!decode_pki_token(token, bl)) { + if (!decode_pki_token(cct, token, bl)) { RGWValidateKeystoneToken validate(&bl); string url = g_conf->rgw_keystone_url; if (url.empty()) { - dout(0) << "ERROR: keystone url is not configured" << dendl; + ldout(cct, 0) << "ERROR: keystone url is not configured" << dendl; return -EINVAL; } if (url[url.size() - 1] != '/') @@ -621,14 +606,12 @@ static int rgw_swift_validate_keystone_token(RGWRados *store, const string& toke bl.append((char)0); // NULL terminate for debug output - dout(20) << "received response: " << bl.c_str() << dendl; + ldout(cct, 20) << "received response: " << bl.c_str() << dendl; - int ret = rgw_parse_keystone_token_response(token, bl, info); + int ret = parse_keystone_token_response(token, bl, info, t); if (ret < 0) return ret; - keystone_token_cache->add(token_id, t); - ret = update_user_info(store, info, rgw_user); if (ret < 0) return ret; @@ -637,7 +620,7 @@ static int rgw_swift_validate_keystone_token(RGWRados *store, const string& toke } -bool rgw_verify_swift_token(RGWRados *store, req_state *s) +bool RGWSwift::verify_swift_token(RGWRados *store, req_state *s) { if (!s->os_auth_token) return false; @@ -657,16 +640,16 @@ bool rgw_verify_swift_token(RGWRados *store, req_state *s) int ret; if (g_conf->rgw_swift_use_keystone) { - ret = rgw_swift_validate_keystone_token(store, s->os_auth_token, &info, s->user); + ret = validate_keystone_token(store, s->os_auth_token, &info, s->user); return (ret >= 0); } - ret = rgw_swift_validate_token(s->os_auth_token, &info); + ret = validate_token(s->os_auth_token, &info); if (ret < 0) return ret; if (info.user.empty()) { - dout(5) << "swift auth didn't authorize a user" << dendl; + ldout(cct, 5) << "swift auth didn't authorize a user" << dendl; return false; } @@ -675,29 +658,82 @@ bool rgw_verify_swift_token(RGWRados *store, req_state *s) string swift_user = s->swift_user; - dout(10) << "swift user=" << s->swift_user << dendl; + ldout(cct, 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; + ldout(cct, 0) << "NOTICE: couldn't map swift user" << dendl; return false; } - dout(10) << "user_id=" << s->user.user_id << dendl; + ldout(cct, 10) << "user_id=" << s->user.user_id << dendl; return true; } -void swift_init(CephContext *cct) +void RGWSwift::init() { get_str_list(cct->_conf->rgw_keystone_operator_roles, roles_list); - keystone_token_cache = new RGWKeystoneTokenCache(cct->_conf->rgw_keystone_token_cache_size); + keystone_token_cache = new RGWKeystoneTokenCache(cct, cct->_conf->rgw_keystone_token_cache_size); + + keystone_revoke_thread = new KeystoneRevokeThread(cct, this); + keystone_revoke_thread->create(); } -void swift_finalize() +void RGWSwift::finalize() { delete keystone_token_cache; keystone_token_cache = NULL; + + down_flag.set(1); + if (keystone_revoke_thread) { + keystone_revoke_thread->stop(); + keystone_revoke_thread->join(); + } + delete keystone_revoke_thread; + keystone_revoke_thread = NULL; +} + +RGWSwift *rgw_swift = NULL; + +void swift_init(CephContext *cct) +{ + rgw_swift = new RGWSwift(cct); +} + +void swift_finalize() +{ + delete rgw_swift; +} + +bool RGWSwift::going_down() +{ + return (down_flag.read() != 0); +} + +void *RGWSwift::KeystoneRevokeThread::entry() { + do { + dout(2) << "keystone revoke thread: start" << dendl; + int r = swift->check_revoked(); + if (r < 0) { + dout(0) << "ERROR: keystone revocation processing returned error r=" << r << dendl; + } + + if (swift->going_down()) + break; + + lock.Lock(); + cond.WaitInterval(cct, lock, utime_t(cct->_conf->rgw_keystone_revocation_interval, 0)); + lock.Unlock(); + } while (!swift->going_down()); + + return NULL; +} + +void RGWSwift::KeystoneRevokeThread::stop() +{ + Mutex::Locker l(lock); + cond.Signal(); } diff --git a/src/rgw/rgw_swift.h b/src/rgw/rgw_swift.h index 80149b62393..bdca5b46283 100644 --- a/src/rgw/rgw_swift.h +++ b/src/rgw/rgw_swift.h @@ -3,6 +3,7 @@ #define CEPH_RGW_SWIFT_H #include "rgw_common.h" +#include "common/Cond.h" class RGWRados; @@ -16,8 +17,69 @@ struct rgw_swift_auth_info { rgw_swift_auth_info() : status(0), ttl(0) {} }; -bool rgw_verify_swift_token(RGWRados *store, req_state *s); +class KeystoneToken { +public: + string tenant_name; + string tenant_id; + string user_name; + time_t expiration; + map<string, bool> roles; + + KeystoneToken() {} + + int parse(CephContext *cct, bufferlist& bl); + + bool expired() { + uint64_t now = ceph_clock_now(NULL).sec(); + return (now < (uint64_t)expiration); + } +}; + +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, + RGWUserInfo& rgw_user); + + int parse_keystone_token_response(const string& token, bufferlist& bl, struct rgw_swift_auth_info *info, + KeystoneToken& t); + int update_user_info(RGWRados *store, struct rgw_swift_auth_info *info, RGWUserInfo& user_info); + + class KeystoneRevokeThread : public Thread { + CephContext *cct; + RGWSwift *swift; + Mutex lock; + Cond cond; + + public: + KeystoneRevokeThread(CephContext *_cct, RGWSwift *_swift) : cct(_cct), swift(_swift), lock("KeystoneRevokeThread") {} + void *entry(); + void stop(); + }; + + KeystoneRevokeThread *keystone_revoke_thread; + + void init(); + void finalize(); +protected: + int check_revoked(); +public: + + RGWSwift(CephContext *_cct) : cct(_cct) { + init(); + } + ~RGWSwift() { + finalize(); + } + + bool verify_swift_token(RGWRados *store, req_state *s); + bool going_down(); +}; + +extern RGWSwift *rgw_swift; void swift_init(CephContext *cct); void swift_finalize(); |