auth: comprehensive overhaul (not working yet)

This commit is contained in:
Yehuda Sadeh 2009-09-15 12:49:52 -07:00
parent a57a8ebbbd
commit f82e57cfaa
6 changed files with 278 additions and 166 deletions

View File

@ -182,7 +182,7 @@ bool AuthTicketsManager::verify_service_ticket_reply(CryptoKey& secret,
*
* ticket, {timestamp, nonce}^session_key
*/
bool AuthTicketHandler::build_authorizer(bufferlist& bl, AuthorizeContext& ctx)
bool AuthTicketHandler::build_authorizer(bufferlist& bl, AuthContext& ctx)
{
ctx.timestamp = g_clock.now();
@ -202,7 +202,7 @@ bool AuthTicketHandler::build_authorizer(bufferlist& bl, AuthorizeContext& ctx)
*
* ticket, {timestamp, nonce}^session_key
*/
bool AuthTicketsManager::build_authorizer(uint32_t service_id, bufferlist& bl, AuthorizeContext& ctx)
bool AuthTicketsManager::build_authorizer(uint32_t service_id, bufferlist& bl, AuthContext& ctx)
{
map<uint32_t, AuthTicketHandler>::iterator iter = tickets_map.find(service_id);
if (iter == tickets_map.end())
@ -257,7 +257,7 @@ bool AuthTicketHandler::decode_reply_authorizer(bufferlist::iterator& indata, Au
/*
* PRINCIPAL: verify reply is authentic
*/
bool AuthTicketHandler::verify_reply_authorizer(AuthorizeContext& ctx, AuthAuthorizeReply& reply)
bool AuthTicketHandler::verify_reply_authorizer(AuthContext& ctx, AuthAuthorizeReply& reply)
{
if (ctx.timestamp == reply.timestamp) {
return true;

View File

@ -20,7 +20,7 @@
class Cond;
struct AuthorizeContext {
struct AuthContext {
int status;
int id;
utime_t timestamp;
@ -168,9 +168,9 @@ struct AuthTicketHandler {
bool get_session_keys(uint32_t keys, entity_addr_t& principal_addr, bufferlist& bl);
#endif
// to access the service
bool build_authorizer(bufferlist& bl, AuthorizeContext& ctx);
bool build_authorizer(bufferlist& bl, AuthContext& ctx);
bool decode_reply_authorizer(bufferlist::iterator& indata, AuthAuthorizeReply& reply);
bool verify_reply_authorizer(AuthorizeContext& ctx, AuthAuthorizeReply& reply);
bool verify_reply_authorizer(AuthContext& ctx, AuthAuthorizeReply& reply);
bool has_key() { return has_key_flag; }
};
@ -184,7 +184,7 @@ struct AuthTicketsManager {
bool get_session_keys(uint32_t keys, entity_addr_t& principal_addr, bufferlist& bl);
AuthTicketHandler& get_handler(uint32_t type) { return tickets_map[type]; }
bool build_authorizer(uint32_t service_id, bufferlist& bl, AuthorizeContext& context);
bool build_authorizer(uint32_t service_id, bufferlist& bl, AuthContext& context);
};
struct AuthServiceTicketRequest {

View File

@ -21,7 +21,7 @@
#include "messages/MAuth.h"
#include "messages/MAuthReply.h"
int AuthClientHandler::generate_authenticate_request(bufferlist& bl)
int AuthClientAuthenticateHandler::generate_authenticate_request(bufferlist& bl)
{
dout(0) << "status=" << status << dendl;
if (status < 0) {
@ -62,33 +62,44 @@ int AuthClientHandler::generate_authenticate_request(bufferlist& bl)
return 0;
}
AuthClientProtocolHandler *AuthClientHandler::_get_proto_handler(uint32_t id)
{
map<uint32_t, AuthClientProtocolHandler *>::iterator iter = handlers_map.find(id);
if (iter == handlers_map.end())
return NULL;
return iter->second;
}
uint32_t AuthClientHandler::_add_proto_handler(AuthClientProtocolHandler *handler)
{
uint32_t id = max_proto_handlers++;
handlers_map[id] = handler;
return id;
}
int AuthClientHandler::handle_response(Message *response)
{
bufferlist bl;
int ret;
#if 0
char buf[4096];
const char *s = bl.c_str();
int pos = 0;
for (unsigned int i=0; i<bl.length() && pos<sizeof(buf) - 8; i++) {
pos += snprintf(&buf[pos], sizeof(buf)-pos, "%.2x ", (int)(unsigned char)s[i]);
if (i && !(i%8))
pos += snprintf(&buf[pos], sizeof(buf)-pos, " ");
if (i && !(i%16))
pos += snprintf(&buf[pos], sizeof(buf)-pos, "\n");
}
dout(0) << "result_buf=" << buf << dendl;
#endif
MAuthReply* m = (MAuthReply *)response;
bl = m->result_bl;
ret = m->result;
got_authenticate_response = true;
CephXPremable pre;
bufferlist::iterator iter = bl.begin();
::decode(pre, iter);
AuthClientProtocolHandler *handler = _get_proto_handler(pre.trans_id);
if (!handler)
return -EINVAL;
return handler->handle_response(ret, iter);
}
int AuthClientAuthenticateHandler::_handle_response(int ret, bufferlist::iterator& iter)
{
if (ret != 0 && ret != -EAGAIN) {
response_state = request_state;
@ -121,10 +132,10 @@ int AuthClientHandler::handle_response(Message *response)
return -EAGAIN;
}
int AuthClientHandler::generate_cephx_authenticate_request(bufferlist& bl)
int AuthClientAuthenticateHandler::generate_cephx_authenticate_request(bufferlist& bl)
{
CephXRequestHeader header;
AuthTicketHandler& ticket_handler = tickets.get_handler(CEPHX_PRINCIPAL_AUTH);
AuthTicketHandler& ticket_handler = client->tickets.get_handler(CEPHX_PRINCIPAL_AUTH);
if (!ticket_handler.has_key()) {
dout(0) << "auth ticket: doesn't have key" << dendl;
/* we first need to get the principle/auth session key */
@ -134,7 +145,7 @@ int AuthClientHandler::generate_cephx_authenticate_request(bufferlist& bl)
::encode(header, bl);
CryptoKey key;
AuthBlob blob;
build_service_ticket_request(name, addr, CEPHX_PRINCIPAL_AUTH,
build_service_ticket_request(client->name, client->addr, CEPHX_PRINCIPAL_AUTH,
false, key, blob, bl);
cephx_request_state = 1;
return 0;
@ -152,32 +163,41 @@ int AuthClientHandler::generate_cephx_authenticate_request(bufferlist& bl)
header.request_type = CEPHX_GET_PRINCIPAL_SESSION_KEY;
::encode(header, bl);
build_service_ticket_request(name, addr, want,
build_service_ticket_request(client->name, client->addr, want,
true, ticket_handler.session_key, ticket_handler.ticket, bl);
return 0;
}
int AuthClientHandler::generate_cephx_authorize_request(uint32_t service_id, bufferlist& bl, AuthorizeContext& ctx)
int AuthClientAuthorizeHandler::_build_request()
{
CephXRequestHeader header;
if (!(have & service_id)) {
if (!(client->have & service_id)) {
dout(0) << "can't authorize: missing service key" << dendl;
return -EPERM;
}
header.request_type = CEPHX_OPEN_SESSION;
bufferlist& bl = msg->get_auth_payload();
::encode(header, bl);
//AuthorizeContext& ctx = context_map.create();
utime_t now;
if (!tickets.build_authorizer(service_id, bl, ctx))
#if 0
if (!client->tickets.build_authorizer(service_id, bl, ctx))
return -EINVAL;
#endif
return 0;
}
int AuthClientHandler::handle_cephx_response(bufferlist::iterator& indata)
int AuthClientAuthorizeHandler::_handle_response(int ret, bufferlist::iterator& iter)
{
/* FIXME: implement */
return 0;
}
int AuthClientAuthenticateHandler::handle_cephx_response(bufferlist::iterator& indata)
{
int ret = 0;
struct CephXResponseHeader header;
@ -194,10 +214,10 @@ int AuthClientHandler::handle_cephx_response(bufferlist::iterator& indata)
#define PRINCIPAL_SECRET "123456789ABCDEF0"
{
bufferptr p(PRINCIPAL_SECRET, sizeof(PRINCIPAL_SECRET) - 1);
secret.set_secret(CEPH_SECRET_AES, p);
client->secret.set_secret(CEPH_SECRET_AES, p);
// AuthTicketHandler& ticket_handler = tickets.get_handler(CEPHX_PRINCIPAL_AUTH);
if (!tickets.verify_service_ticket_reply(secret, indata)) {
if (!client->tickets.verify_service_ticket_reply(client->secret, indata)) {
dout(0) << "could not verify service_ticket reply" << dendl;
return -EPERM;
}
@ -211,9 +231,9 @@ int AuthClientHandler::handle_cephx_response(bufferlist::iterator& indata)
cephx_response_state = 2;
dout(0) << "CEPHX_GET_PRINCIPAL_SESSION_KEY" << dendl;
{
AuthTicketHandler& ticket_handler = tickets.get_handler(CEPHX_PRINCIPAL_AUTH);
AuthTicketHandler& ticket_handler = client->tickets.get_handler(CEPHX_PRINCIPAL_AUTH);
if (!tickets.verify_service_ticket_reply(ticket_handler.session_key, indata)) {
if (!client->tickets.verify_service_ticket_reply(ticket_handler.session_key, indata)) {
dout(0) << "could not verify service_ticket reply" << dendl;
return -EPERM;
}
@ -223,13 +243,13 @@ int AuthClientHandler::handle_cephx_response(bufferlist::iterator& indata)
case CEPHX_OPEN_SESSION:
{
AuthTicketHandler& ticket_handler = tickets.get_handler(CEPHX_PRINCIPAL_AUTH);
AuthTicketHandler& ticket_handler = client->tickets.get_handler(CEPHX_PRINCIPAL_AUTH);
AuthAuthorizeReply reply;
if (!ticket_handler.decode_reply_authorizer(indata, reply)) {
ret = -EINVAL;
break;
}
AuthorizeContext *ctx = context_map.get(reply.trans_id);
AuthContext *ctx = client->context_map.get(reply.trans_id);
if (!ctx) {
ret = -EINVAL;
break;
@ -254,8 +274,8 @@ int AuthClientHandler::handle_cephx_response(bufferlist::iterator& indata)
return ret;
}
bool AuthClientHandler::request_pending() {
dout(0) << "request_pending(): cephx_request_state=" << cephx_request_state << " cephx_response_state=" << cephx_response_state << dendl;
bool AuthClientAuthenticateHandler::request_pending() {
dout(0) << "request_pending(): request_state=" << cephx_request_state << " cephx_response_state=" << cephx_response_state << dendl;
return (request_state != response_state) || (cephx_request_state != cephx_response_state);
}
@ -267,40 +287,68 @@ int AuthClientHandler::start_session(AuthClient *client, double timeout)
Mutex::Locker l(lock);
this->client = client;
dout(10) << "start_session" << dendl;
_reset();
AuthClientAuthenticateHandler handler(this, want, have);
int err;
do {
status = 0;
int err = _do_authenticate_request(timeout);
dout(0) << "_do_authenticate_request returned " << err << dendl;
err = handler.build_request();
if (err < 0)
return err;
} while (status == -EAGAIN);
err = handler.do_request(timeout);
dout(0) << "handler.do_request returned " << err << dendl;
if (err < 0)
return err;
return status;
} while (err == -EAGAIN);
return err;
}
AuthClientProtocolHandler::AuthClientProtocolHandler(AuthClientHandler *client) :
msg(NULL), got_response(false), got_timeout(false),
timeout_event(NULL)
{
this->client = client;
reset();
id = client->_add_proto_handler(this);
}
AuthClientProtocolHandler::~AuthClientProtocolHandler()
{
if (msg)
delete msg;
}
int AuthClientProtocolHandler::build_request()
{
msg = new MAuth;
if (!msg)
return -ENOMEM;
bufferlist& bl = msg->get_auth_payload();
CephXPremable pre;
pre.trans_id = id;
::encode(pre, bl);
int ret = _build_request();
return ret;
}
int AuthClientHandler::authorize(uint32_t service_id, double timeout)
{
MAuth *msg = new MAuth;
if (!msg)
return NULL;
bufferlist& bl = msg->get_auth_payload();
AuthClientAuthorizeHandler handler(this, service_id);
AuthorizeContext& ctx = context_map.create();
int ret = handler.build_request();
if (ret < 0)
return ret;
int err = generate_cephx_authorize_request(service_id, bl, ctx);
if (err < 0) {
context_map.remove(ctx.id);
}
ret = handler.do_request(timeout);
Cond cond;
ctx.cond = &cond;
err = _do_request_generic(timeout, msg, cond);
return err;
return ret;
}
void AuthClientHandler::tick()
@ -312,83 +360,84 @@ void AuthClientHandler::tick()
}
Message *AuthClientHandler::build_authenticate_request()
int AuthClientAuthenticateHandler::_build_request()
{
MAuth *msg = new MAuth;
msg = new MAuth;
if (!msg)
return NULL;
return -ENOMEM;
bufferlist& bl = msg->get_auth_payload();
if (generate_authenticate_request(bl) < 0) {
int ret = generate_authenticate_request(bl);
if (ret < 0) {
delete msg;
return NULL;
}
return msg;
return ret;
}
int AuthClientHandler::_do_authenticate_request(double timeout)
#if 0
int AuthClientAuthenticateHandler::_do_request()
{
Message *msg = build_authenticate_request();
if (!msg)
return -EIO;
Cond request_cond;
cur_request_cond = &request_cond;
got_authenticate_response = false;
int ret = _do_request_generic(timeout, msg, request_cond);
cur_request_cond = NULL;
int ret = _do_request_generic(timeout, msg);
return ret;
}
#endif
int AuthClientHandler::_do_request_generic(double timeout, Message *msg, Cond& request_cond)
int AuthClientProtocolHandler::do_request(double timeout)
{
client->send_message(msg);
got_response = false;
client->client->send_message(msg);
// schedule timeout?
assert(timeout_event == 0);
timeout_event = new C_OpTimeout(this, timeout);
timer.add_event_after(timeout, timeout_event);
client->timer.add_event_after(timeout, timeout_event);
dout(0) << "got_authenticate_response=" << got_authenticate_response << " got_timeout=" << got_authenticate_timeout << dendl;
dout(0) << "got_response=" << got_response << " got_timeout=" << got_timeout << dendl;
request_cond.Wait(lock);
cond.Wait(client->lock);
// finish.
timer.cancel_event(timeout_event);
client->timer.cancel_event(timeout_event);
timeout_event = NULL;
return 0;
}
void AuthClientHandler::_authenticate_request_timeout(double timeout)
void AuthClientProtocolHandler::_request_timeout(double timeout)
{
Mutex::Locker l(lock);
dout(10) << "_op_timeout" << dendl;
Mutex::Locker l(client->lock);
dout(10) << "_request_timeout" << dendl;
timeout_event = 0;
if (!got_authenticate_response) {
got_authenticate_timeout = 1;
assert(cur_request_cond);
cur_request_cond->Signal();
if (!got_response) {
got_timeout = 1;
cond.Signal();
}
status = -ETIMEDOUT;
}
void AuthClientHandler::handle_auth_reply(MAuthReply *m)
int AuthClientProtocolHandler::handle_response(int ret, bufferlist::iterator& iter)
{
Mutex::Locker l(lock);
Mutex::Locker l(client->lock);
status = handle_response(m);
cur_request_cond->Signal();
got_response = true;
status = _handle_response(ret, iter);
cond.Signal();
return status;
}
AuthorizeContext& AuthorizeContextMap::create()
AuthContext& AuthContextMap::create()
{
Mutex::Locker l(lock);
AuthorizeContext& ctx = m[max_id];
AuthContext& ctx = m[max_id];
ctx.id = max_id;
ctx.cond = NULL;
++max_id;
@ -396,18 +445,19 @@ AuthorizeContext& AuthorizeContextMap::create()
return ctx;
}
void AuthorizeContextMap::remove(int id)
void AuthContextMap::remove(int id)
{
std::map<int, AuthorizeContext>::iterator iter = m.find(id);
Mutex::Locker l(lock);
std::map<int, AuthContext>::iterator iter = m.find(id);
if (iter != m.end()) {
m.erase(iter);
}
}
AuthorizeContext *AuthorizeContextMap::get(int id)
AuthContext *AuthContextMap::get(int id)
{
Mutex::Locker l(lock);
std::map<int, AuthorizeContext>::iterator iter = m.find(id);
std::map<int, AuthContext>::iterator iter = m.find(id);
if (iter != m.end())
return &iter->second;

View File

@ -24,109 +24,156 @@
#include "common/Timer.h"
class MAuth;
class MAuthReply;
class Message;
class AuthClient;
class AuthorizeContextMap {
map<int, AuthorizeContext> m;
class AuthContextMap {
map<int, AuthContext> m;
Mutex lock;
int max_id;
public:
AuthorizeContextMap() : lock("AuthorizeMap") {}
AuthorizeContext& create();
AuthContextMap() : lock("AuthorizeMap") {}
AuthContext& create();
void remove(int id);
AuthorizeContext *get(int id);
AuthContext *get(int id);
};
class AuthClientHandler {
Mutex lock;
Cond keys_cond;
Cond *cur_request_cond;
Context *timeout_event;
class AuthClientHandler;
uint32_t want;
uint32_t have;
class AuthClientProtocolHandler {
class C_OpTimeout : public Context {
protected:
AuthClientProtocolHandler *client;
double timeout;
public:
C_OpTimeout(AuthClientProtocolHandler *handler, double to) :
client(handler), timeout(to) {
}
void finish(int r) {
if (r >= 0) client->_request_timeout(timeout);
}
};
protected:
AuthClientHandler *client;
MAuth *msg;
bool got_response;
bool got_timeout;
Context *timeout_event;
uint32_t id;
// session state
int status;
virtual void _reset() {}
void reset() {
status = 0;
_reset();
}
Cond cond;
virtual int _handle_response(int ret, bufferlist::iterator& iter) = 0;
virtual int _build_request() = 0;
void _request_timeout(double timeout);
public:
AuthClientProtocolHandler(AuthClientHandler *ch);
virtual ~AuthClientProtocolHandler();
int build_request();
int handle_response(int ret, bufferlist::iterator& iter);
int do_request(double timeout);
};
class AuthClientAuthenticateHandler : public AuthClientProtocolHandler {
int request_state;
int response_state;
int status;
int cephx_request_state;
int cephx_response_state;
bool got_authenticate_response;
bool got_authenticate_timeout;
EntityName name;
entity_addr_t addr;
/* envelope protocol parameters */
uint64_t server_challenge;
/* envelope protocol */
int generate_authenticate_request(bufferlist& bl);
/* auth protocol */
int generate_cephx_authenticate_request(bufferlist& bl);
int handle_cephx_response(bufferlist::iterator& indata);
uint32_t want;
uint32_t have;
protected:
void reset() {
request_state = 0;
response_state = 0;
cephx_request_state = 0;
cephx_response_state = 0;
timeout_event = NULL;
}
bool request_pending();
int _build_request();
int _handle_response(int ret, bufferlist::iterator& iter);
public:
AuthClientAuthenticateHandler(AuthClientHandler *client, uint32_t _want, uint32_t _have) :
AuthClientProtocolHandler(client), want(_want), have(_have) {}
};
class AuthClientAuthorizeHandler : public AuthClientProtocolHandler {
uint32_t service_id;
protected:
int _build_request();
int _handle_response(int ret, bufferlist::iterator& iter);
public:
AuthClientAuthorizeHandler(AuthClientHandler *client, uint32_t sid) : AuthClientProtocolHandler(client), service_id(sid) {}
};
class AuthClientHandler {
friend class AuthClientProtocolHandler;
Mutex lock;
Cond keys_cond;
/* ceph-x protocol */
utime_t auth_ts;
AuthTicketsManager tickets;
CryptoKey secret;
AuthClient *client;
AuthorizeContextMap context_map;
bool request_pending();
Message *build_authenticate_request();
int generate_authenticate_request(bufferlist& bl);
int handle_response(Message *response);
/* cephx requests */
int generate_cephx_authenticate_request(bufferlist& bl);
int generate_cephx_authorize_request(uint32_t service_id, bufferlist& bl, AuthorizeContext& ctx);
/* cephx responses */
int handle_cephx_response(bufferlist::iterator& indata);
void _reset() {
request_state = 0;
response_state = 0;
status = 0;
cephx_request_state = 0;
cephx_response_state = 0;
got_authenticate_response = false;
got_authenticate_timeout = false;
timeout_event = NULL;
cur_request_cond = NULL;
}
SafeTimer timer;
class C_OpTimeout : public Context {
protected:
AuthClientHandler *client_handler;
double timeout;
public:
C_OpTimeout(AuthClientHandler *handler, double to) :
client_handler(handler), timeout(to) {
}
void finish(int r) {
if (r >= 0) client_handler->_authenticate_request_timeout(timeout);
}
};
uint32_t max_proto_handlers;
map<uint32_t, AuthClientProtocolHandler *> handlers_map;
AuthClientProtocolHandler *_get_proto_handler(uint32_t id);
uint32_t _add_proto_handler(AuthClientProtocolHandler *handler);
void _authenticate_request_timeout(double timeout);
int _do_authenticate_request(double timeout);
int _do_request_generic(double timeout, Message *msg, Cond& request_cond);
public:
EntityName name;
entity_addr_t addr;
uint32_t want;
uint32_t have;
CryptoKey secret;
AuthContextMap context_map;
AuthTicketsManager tickets;
AuthClientHandler() : lock("AuthClientHandler::lock"),
want(0), have(0), client(NULL), timer(lock) {
_reset();
}
client(NULL), timer(lock), max_proto_handlers(0) { }
void set_want_keys(__u32 keys) {
Mutex::Locker l(lock);
@ -149,9 +196,10 @@ public:
return (want & have) == have;
}
int handle_response(Message *response);
int start_session(AuthClient *client, double timeout);
int authorize(uint32_t service_id, double timeout);
void handle_auth_reply(MAuthReply *m);
void tick();
};

View File

@ -25,6 +25,19 @@ using namespace std;
class Monitor;
struct CephXPremable {
uint32_t trans_id;
void encode(bufferlist& bl) const {
::encode(trans_id, bl);
}
void decode(bufferlist::iterator& bl) {
::decode(trans_id, bl);
}
};
WRITE_CLASS_ENCODER(CephXPremable)
/*
Ceph X-Envelope protocol
*/
@ -190,6 +203,7 @@ WRITE_CLASS_ENCODER(CephXRequestHeader);
struct CephXResponseHeader {
uint16_t request_type;
uint32_t trans_id;
int32_t status;
void encode(bufferlist& bl) const {

View File

@ -172,7 +172,7 @@ bool MonClient::ms_dispatch(Message *m)
return true;
case CEPH_MSG_AUTH_REPLY:
auth.handle_auth_reply((MAuthReply*)m);
auth.handle_response((MAuthReply*)m);
delete m;
return true;