return false;
}
-int KeystoneToken::parse(CephContext *cct, bufferlist& bl)
+int KeystoneToken::parse(CephContext * const cct,
+ const string& token_str,
+ bufferlist& bl)
{
JSONParser parser;
if (!parser.parse(bl.c_str(), bl.length())) {
/* Token structure doesn't follow Identity API v2, so the token
* must be in v3. Otherwise we can assume it's wrongly formatted. */
JSONDecoder::decode_json("token", *this, &parser, true);
+ token.id = token_str;
}
} else if (version == KeystoneApiVersion::VER_2) {
if (!JSONDecoder::decode_json("token", *this, &parser)) {
/* If the token cannot be parsed according to V2, try V3. */
JSONDecoder::decode_json("access", *this, &parser, true);
+ } else {
+ /* v3 suceeded. We have to fill token.id from external input as it
+ * isn't a part of the JSON response anymore. It has been moved
+ * to X-Subject-Token HTTP header instead. */
+ token.id = token_str;
}
} else {
return -ENOTSUP;
return true;
}
-void RGWKeystoneTokenCache::add(const string& token_id, KeystoneToken& token)
+bool RGWKeystoneTokenCache::find_admin(KeystoneToken& token)
+{
+ Mutex::Locker l(lock);
+
+ return find(admin_token_id, token);
+}
+
+void RGWKeystoneTokenCache::add(const string& token_id,
+ const KeystoneToken& token)
{
lock.Lock();
map<string, token_entry>::iterator iter = tokens.find(token_id);
lock.Unlock();
}
+void RGWKeystoneTokenCache::add_admin(const KeystoneToken& token)
+{
+ Mutex::Locker l(lock);
+
+ get_token_id(token.token.id, admin_token_id);
+ add(admin_token_id, token);
+}
+
void RGWKeystoneTokenCache::invalidate(const string& token_id)
{
Mutex::Locker l(lock);
uint64_t now = ceph_clock_now(NULL).sec();
return (now >= (uint64_t)get_expires());
}
- int parse(CephContext *cct, bufferlist& bl);
+ int parse(CephContext *cct,
+ const string& token_str,
+ bufferlist& bl /* in */);
void decode_json(JSONObj *access_obj);
};
-struct token_entry {
- KeystoneToken token;
- list<string>::iterator lru_iter;
-};
-
class RGWKeystoneTokenCache {
+ struct token_entry {
+ KeystoneToken token;
+ list<string>::iterator lru_iter;
+ };
+
CephContext *cct;
+ string admin_token_id;
map<string, token_entry> tokens;
list<string> tokens_lru;
size_t max;
public:
- RGWKeystoneTokenCache(CephContext *_cct, int _max) : cct(_cct), lock("RGWKeystoneTokenCache"), max(_max) {}
+ RGWKeystoneTokenCache(CephContext *_cct, int _max)
+ : cct(_cct),
+ lock("RGWKeystoneTokenCache", true /* recursive */),
+ max(_max) {
+ }
bool find(const string& token_id, KeystoneToken& token);
- void add(const string& token_id, KeystoneToken& token);
+ bool find_admin(KeystoneToken& token);
+ void add(const string& token_id, const KeystoneToken& token);
+ void add_admin(const KeystoneToken& token);
void invalidate(const string& token_id);
};
}
/* now parse response */
- if (response.parse(cct, rx_buffer) < 0) {
+ if (response.parse(cct, string(), rx_buffer) < 0) {
dout(2) << "s3 keystone: token parsing failed" << dendl;
return -EPERM;
}
{
std::string token_url;
- if (get_keystone_url(cct, token_url) < 0)
+ if (get_keystone_url(cct, token_url) < 0) {
return -EINVAL;
+ }
+
if (!cct->_conf->rgw_keystone_admin_token.empty()) {
token = cct->_conf->rgw_keystone_admin_token;
return 0;
}
+
+ KeystoneToken t;
+
+ /* Try cache first. */
+ if (keystone_token_cache->find_admin(t)) {
+ ldout(cct, 20) << "found cached admin token" << dendl;
+ token = t.token.id;
+ return 0;
+ }
+
bufferlist token_bl;
RGWGetKeystoneAdminToken token_req(cct, &token_bl);
token_req.append_header("Content-Type", "application/json");
token_req.set_post_data(ss.str());
token_req.set_send_length(ss.str().length());
token_url.append("v2.0/tokens");
- int ret = token_req.process("POST", token_url.c_str());
- if (ret < 0)
- return ret;
- KeystoneToken t;
- if (t.parse(cct, token_bl) != 0)
- return -EINVAL;
- token = t.token.id;
- return 0;
+
} else if (keystone_version == KeystoneApiVersion::VER_3) {
KeystoneAdminTokenRequestVer3 req_serializer(cct);
req_serializer.dump(&jf);
token_req.set_post_data(ss.str());
token_req.set_send_length(ss.str().length());
token_url.append("v3/auth/tokens");
- int ret = token_req.process("POST", token_url.c_str());
- if (ret < 0)
- return ret;
- token = token_req.get_subject_token();
- return 0;
+ } else {
+ return -ENOTSUP;
+ }
+
+ const int ret = token_req.process("POST", token_url.c_str());
+ if (ret < 0) {
+ return ret;
}
- return -EINVAL;
+ if (t.parse(cct, token_req.get_subject_token(), token_bl) != 0) {
+ return -EINVAL;
+ }
+
+ keystone_token_cache->add_admin(t);
+ token = t.token.id;
+ return 0;
}
info->status = 200;
}
-int RGWSwift::parse_keystone_token_response(const string& token, bufferlist& bl, struct rgw_swift_auth_info *info, KeystoneToken& t)
+int RGWSwift::parse_keystone_token_response(const string& token,
+ bufferlist& bl,
+ struct rgw_swift_auth_info *info,
+ KeystoneToken& t)
{
- int ret = t.parse(cct, bl);
- if (ret < 0)
+ int ret = t.parse(cct, token, bl);
+ if (ret < 0) {
return ret;
+ }
bool found = false;
list<string>::iterator iter;
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,
+ 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);
int get_keystone_url(std::string& url);