mirror of
https://github.com/ceph/ceph
synced 2025-04-23 15:56:11 +00:00
auth/cephx: add authorizer challenge
Allow the accepting side of a connection to reject an initial authorizer with a random challenge. The connecting side then has to respond with an updated authorizer proving they are able to decrypt the service's challenge and that the new authorizer was produced for this specific connection instance. The accepting side requires this challenge and response unconditionally if the client side advertises they have the feature bit. Servers wishing to require this improved level of authentication simply have to require the appropriate feature. Signed-off-by: Sage Weil <sage@redhat.com>
This commit is contained in:
parent
3dc80e5f9b
commit
f80b848d3f
@ -142,6 +142,11 @@ struct AuthAuthorizer {
|
||||
explicit AuthAuthorizer(__u32 p) : protocol(p) {}
|
||||
virtual ~AuthAuthorizer() {}
|
||||
virtual bool verify_reply(bufferlist::const_iterator& reply) = 0;
|
||||
virtual bool add_challenge(CephContext *cct, bufferlist& challenge) = 0;
|
||||
};
|
||||
|
||||
struct AuthAuthorizerChallenge {
|
||||
virtual ~AuthAuthorizerChallenge() {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -34,7 +34,9 @@ struct AuthAuthorizeHandler {
|
||||
virtual bool verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id,
|
||||
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid = NULL) = 0;
|
||||
AuthCapsInfo& caps_info, CryptoKey& session_key,
|
||||
uint64_t *auid,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) = 0;
|
||||
virtual int authorizer_session_crypto() = 0;
|
||||
};
|
||||
|
||||
|
@ -6,9 +6,12 @@
|
||||
|
||||
|
||||
|
||||
bool CephxAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid)
|
||||
bool CephxAuthorizeHandler::verify_authorizer(
|
||||
CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info,
|
||||
CryptoKey& session_key, uint64_t *auid,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
|
||||
{
|
||||
auto iter = authorizer_data.cbegin();
|
||||
|
||||
@ -19,7 +22,8 @@ bool CephxAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
|
||||
CephXServiceTicketInfo auth_ticket_info;
|
||||
|
||||
bool isvalid = cephx_verify_authorizer(cct, keys, iter, auth_ticket_info, authorizer_reply);
|
||||
bool isvalid = cephx_verify_authorizer(cct, keys, iter, auth_ticket_info, challenge,
|
||||
authorizer_reply);
|
||||
|
||||
if (isvalid) {
|
||||
caps_info = auth_ticket_info.ticket.caps;
|
||||
|
@ -23,7 +23,8 @@ struct CephxAuthorizeHandler : public AuthAuthorizeHandler {
|
||||
bool verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id,
|
||||
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid = NULL) override;
|
||||
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
|
||||
int authorizer_session_crypto() override;
|
||||
};
|
||||
|
||||
|
@ -304,6 +304,7 @@ CephXAuthorizer *CephXTicketHandler::build_authorizer(uint64_t global_id) const
|
||||
encode(service_id, a->bl);
|
||||
|
||||
encode(ticket, a->bl);
|
||||
a->base_bl = a->bl;
|
||||
|
||||
CephXAuthorize msg;
|
||||
msg.nonce = a->nonce;
|
||||
@ -390,7 +391,9 @@ bool cephx_decode_ticket(CephContext *cct, KeyStore *keys, uint32_t service_id,
|
||||
*/
|
||||
bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist::const_iterator& indata,
|
||||
CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl)
|
||||
CephXServiceTicketInfo& ticket_info,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge,
|
||||
bufferlist& reply_bl)
|
||||
{
|
||||
__u8 authorizer_v;
|
||||
uint32_t service_id;
|
||||
@ -457,6 +460,30 @@ bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (challenge) {
|
||||
auto *c = static_cast<CephXAuthorizeChallenge*>(challenge->get());
|
||||
if (!auth_msg.have_challenge || !c) {
|
||||
c = new CephXAuthorizeChallenge;
|
||||
challenge->reset(c);
|
||||
cct->random()->get_bytes((char*)&c->server_challenge, sizeof(c->server_challenge));
|
||||
ldout(cct,10) << __func__ << " adding server_challenge " << c->server_challenge
|
||||
<< dendl;
|
||||
|
||||
encode_encrypt_enc_bl(cct, *c, ticket_info.session_key, reply_bl, error);
|
||||
if (!error.empty()) {
|
||||
ldout(cct, 10) << "verify_authorizer: encode_encrypt error: " << error << dendl;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ldout(cct, 10) << __func__ << " got server_challenge+1 "
|
||||
<< auth_msg.server_challenge_plus_one
|
||||
<< " expecting " << c->server_challenge + 1 << dendl;
|
||||
if (c->server_challenge + 1 != auth_msg.server_challenge_plus_one) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reply authorizer:
|
||||
* {timestamp + 1}^session_key
|
||||
@ -493,3 +520,31 @@ bool CephXAuthorizer::verify_reply(bufferlist::const_iterator& indata)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CephXAuthorizer::add_challenge(CephContext *cct, bufferlist& challenge)
|
||||
{
|
||||
bl = base_bl;
|
||||
|
||||
CephXAuthorize msg;
|
||||
msg.nonce = nonce;
|
||||
|
||||
auto p = challenge.begin();
|
||||
if (!p.end()) {
|
||||
std::string error;
|
||||
CephXAuthorizeChallenge ch;
|
||||
decode_decrypt_enc_bl(cct, ch, session_key, challenge, error);
|
||||
if (!error.empty()) {
|
||||
ldout(cct, 0) << "failed to decrypt challenge (" << challenge.length() << " bytes): "
|
||||
<< error << dendl;
|
||||
return false;
|
||||
}
|
||||
msg.have_challenge = true;
|
||||
msg.server_challenge_plus_one = ch.server_challenge + 1;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
if (encode_encrypt(cct, msg, session_key, bl, error)) {
|
||||
ldout(cct, 0) << __func__ << " failed to encrypt authorizer: " << error << dendl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -289,12 +289,14 @@ private:
|
||||
CephContext *cct;
|
||||
public:
|
||||
uint64_t nonce;
|
||||
bufferlist base_bl;
|
||||
|
||||
explicit CephXAuthorizer(CephContext *cct_)
|
||||
: AuthAuthorizer(CEPH_AUTH_CEPHX), cct(cct_), nonce(0) {}
|
||||
|
||||
bool build_authorizer();
|
||||
bool verify_reply(bufferlist::const_iterator& reply) override;
|
||||
bool add_challenge(CephContext *cct, bufferlist& challenge) override;
|
||||
};
|
||||
|
||||
|
||||
@ -404,19 +406,44 @@ struct CephXServiceTicketInfo {
|
||||
};
|
||||
WRITE_CLASS_ENCODER(CephXServiceTicketInfo)
|
||||
|
||||
struct CephXAuthorize {
|
||||
uint64_t nonce;
|
||||
struct CephXAuthorizeChallenge : public AuthAuthorizerChallenge {
|
||||
uint64_t server_challenge;
|
||||
void encode(bufferlist& bl) const {
|
||||
using ceph::encode;
|
||||
__u8 struct_v = 1;
|
||||
encode(struct_v, bl);
|
||||
encode(server_challenge, bl);
|
||||
}
|
||||
void decode(bufferlist::const_iterator& bl) {
|
||||
using ceph::decode;
|
||||
__u8 struct_v;
|
||||
decode(struct_v, bl);
|
||||
decode(server_challenge, bl);
|
||||
}
|
||||
};
|
||||
WRITE_CLASS_ENCODER(CephXAuthorizeChallenge)
|
||||
|
||||
struct CephXAuthorize {
|
||||
uint64_t nonce;
|
||||
bool have_challenge = false;
|
||||
uint64_t server_challenge_plus_one = 0;
|
||||
void encode(bufferlist& bl) const {
|
||||
using ceph::encode;
|
||||
__u8 struct_v = 2;
|
||||
encode(struct_v, bl);
|
||||
encode(nonce, bl);
|
||||
encode(have_challenge, bl);
|
||||
encode(server_challenge_plus_one, bl);
|
||||
}
|
||||
void decode(bufferlist::const_iterator& bl) {
|
||||
using ceph::decode;
|
||||
__u8 struct_v;
|
||||
decode(struct_v, bl);
|
||||
decode(nonce, bl);
|
||||
if (struct_v >= 2) {
|
||||
decode(have_challenge, bl);
|
||||
decode(server_challenge_plus_one, bl);
|
||||
}
|
||||
}
|
||||
};
|
||||
WRITE_CLASS_ENCODER(CephXAuthorize)
|
||||
@ -431,9 +458,12 @@ bool cephx_decode_ticket(CephContext *cct, KeyStore *keys,
|
||||
/*
|
||||
* Verify authorizer and generate reply authorizer
|
||||
*/
|
||||
extern bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist::const_iterator& indata,
|
||||
CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl);
|
||||
extern bool cephx_verify_authorizer(
|
||||
CephContext *cct, KeyStore *keys,
|
||||
bufferlist::const_iterator& indata,
|
||||
CephXServiceTicketInfo& ticket_info,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge,
|
||||
bufferlist& reply_bl);
|
||||
|
||||
|
||||
|
||||
|
@ -153,7 +153,9 @@ int CephxServiceHandler::handle_request(bufferlist::const_iterator& indata, buff
|
||||
|
||||
bufferlist tmp_bl;
|
||||
CephXServiceTicketInfo auth_ticket_info;
|
||||
if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, tmp_bl)) {
|
||||
// note: no challenge here.
|
||||
if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, nullptr,
|
||||
tmp_bl)) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
|
@ -17,10 +17,13 @@
|
||||
|
||||
#define dout_subsys ceph_subsys_auth
|
||||
|
||||
bool AuthNoneAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info, CryptoKey& session_key,
|
||||
uint64_t *auid)
|
||||
bool AuthNoneAuthorizeHandler::verify_authorizer(
|
||||
CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info,
|
||||
CryptoKey& session_key,
|
||||
uint64_t *auid,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
|
||||
{
|
||||
auto iter = authorizer_data.cbegin();
|
||||
|
||||
|
@ -23,7 +23,8 @@ struct AuthNoneAuthorizeHandler : public AuthAuthorizeHandler {
|
||||
bool verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id,
|
||||
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid=NULL) override;
|
||||
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
|
||||
int authorizer_session_crypto() override;
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include "auth/Auth.h"
|
||||
|
||||
class CephContext;
|
||||
|
||||
struct AuthNoneAuthorizer : public AuthAuthorizer {
|
||||
AuthNoneAuthorizer() : AuthAuthorizer(CEPH_AUTH_NONE) { }
|
||||
bool build_authorizer(const EntityName &ename, uint64_t global_id) {
|
||||
@ -27,6 +29,7 @@ struct AuthNoneAuthorizer : public AuthAuthorizer {
|
||||
return 0;
|
||||
}
|
||||
bool verify_reply(bufferlist::const_iterator& reply) override { return true; }
|
||||
bool add_challenge(CephContext *cct, bufferlist& ch) override { return true; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -14,10 +14,13 @@
|
||||
|
||||
#include "AuthUnknownAuthorizeHandler.h"
|
||||
|
||||
bool AuthUnknownAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info, CryptoKey& session_key,
|
||||
uint64_t *auid)
|
||||
bool AuthUnknownAuthorizeHandler::verify_authorizer(
|
||||
CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info,
|
||||
CryptoKey& session_key,
|
||||
uint64_t *auid,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
|
||||
{
|
||||
// For unknown authorizers, there's nothing to verify. They're "OK" by definition. PLR
|
||||
|
||||
|
@ -23,7 +23,8 @@ struct AuthUnknownAuthorizeHandler : public AuthAuthorizeHandler {
|
||||
bool verify_authorizer(CephContext *cct, KeyStore *keys,
|
||||
bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
EntityName& entity_name, uint64_t& global_id,
|
||||
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid=NULL) override;
|
||||
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
|
||||
int authorizer_session_crypto() override;
|
||||
};
|
||||
|
||||
|
@ -93,7 +93,7 @@ struct ceph_entity_inst {
|
||||
#define CEPH_MSGR_TAG_SEQ 13 /* 64-bit int follows with seen seq number */
|
||||
#define CEPH_MSGR_TAG_KEEPALIVE2 14
|
||||
#define CEPH_MSGR_TAG_KEEPALIVE2_ACK 15 /* keepalive reply */
|
||||
|
||||
#define CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER 16 /* ceph v2 doing server challenge */
|
||||
|
||||
/*
|
||||
* connection negotiation
|
||||
|
@ -1295,7 +1295,8 @@ bool MDSDaemon::ms_handle_refused(Connection *con)
|
||||
|
||||
bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
bool& is_valid, CryptoKey& session_key)
|
||||
bool& is_valid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
|
||||
{
|
||||
Mutex::Locker l(mds_lock);
|
||||
if (stopping) {
|
||||
@ -1327,7 +1328,7 @@ bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
|
||||
is_valid = authorize_handler->verify_authorizer(
|
||||
cct, keys,
|
||||
authorizer_data, authorizer_reply, name, global_id, caps_info,
|
||||
session_key);
|
||||
session_key, nullptr, challenge);
|
||||
} else {
|
||||
dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
|
||||
is_valid = false;
|
||||
|
@ -108,7 +108,8 @@ class MDSDaemon : public Dispatcher, public md_config_obs_t {
|
||||
bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) override;
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override;
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
|
||||
void ms_handle_accept(Connection *con) override;
|
||||
void ms_handle_connect(Connection *con) override;
|
||||
bool ms_handle_reset(Connection *con) override;
|
||||
|
@ -144,13 +144,15 @@ entity_addr_t DaemonServer::get_myaddr() const
|
||||
}
|
||||
|
||||
|
||||
bool DaemonServer::ms_verify_authorizer(Connection *con,
|
||||
int peer_type,
|
||||
int protocol,
|
||||
ceph::bufferlist& authorizer_data,
|
||||
ceph::bufferlist& authorizer_reply,
|
||||
bool& is_valid,
|
||||
CryptoKey& session_key)
|
||||
bool DaemonServer::ms_verify_authorizer(
|
||||
Connection *con,
|
||||
int peer_type,
|
||||
int protocol,
|
||||
ceph::bufferlist& authorizer_data,
|
||||
ceph::bufferlist& authorizer_reply,
|
||||
bool& is_valid,
|
||||
CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
|
||||
{
|
||||
AuthAuthorizeHandler *handler = nullptr;
|
||||
if (peer_type == CEPH_ENTITY_TYPE_OSD ||
|
||||
@ -178,7 +180,9 @@ bool DaemonServer::ms_verify_authorizer(Connection *con,
|
||||
authorizer_data,
|
||||
authorizer_reply, s->entity_name,
|
||||
s->global_id, caps_info,
|
||||
session_key);
|
||||
session_key,
|
||||
nullptr,
|
||||
challenge);
|
||||
} else {
|
||||
dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
|
||||
is_valid = false;
|
||||
|
@ -124,13 +124,15 @@ public:
|
||||
bool ms_handle_refused(Connection *con) override;
|
||||
bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer,
|
||||
bool force_new) override;
|
||||
bool ms_verify_authorizer(Connection *con,
|
||||
int peer_type,
|
||||
int protocol,
|
||||
ceph::bufferlist& authorizer,
|
||||
ceph::bufferlist& authorizer_reply,
|
||||
bool& isvalid,
|
||||
CryptoKey& session_key) override;
|
||||
bool ms_verify_authorizer(
|
||||
Connection *con,
|
||||
int peer_type,
|
||||
int protocol,
|
||||
ceph::bufferlist& authorizer,
|
||||
ceph::bufferlist& authorizer_reply,
|
||||
bool& isvalid,
|
||||
CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
|
||||
|
||||
bool handle_open(MMgrOpen *m);
|
||||
bool handle_close(MMgrClose *m);
|
||||
|
@ -5780,7 +5780,8 @@ bool Monitor::ms_get_authorizer(int service_id, AuthAuthorizer **authorizer,
|
||||
bool Monitor::ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer_data,
|
||||
bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key)
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
|
||||
{
|
||||
dout(10) << "ms_verify_authorizer " << con->get_peer_addr()
|
||||
<< " " << ceph_entity_type_name(peer_type)
|
||||
@ -5799,7 +5800,7 @@ bool Monitor::ms_verify_authorizer(Connection *con, int peer_type,
|
||||
|
||||
if (authorizer_data.length()) {
|
||||
bool ret = cephx_verify_authorizer(g_ceph_context, &keyring, iter,
|
||||
auth_ticket_info, authorizer_reply);
|
||||
auth_ticket_info, challenge, authorizer_reply);
|
||||
if (ret) {
|
||||
session_key = auth_ticket_info.session_key;
|
||||
isvalid = true;
|
||||
|
@ -887,7 +887,8 @@ public:
|
||||
bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) override;
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override;
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
|
||||
bool ms_handle_reset(Connection *con) override;
|
||||
void ms_handle_remote_reset(Connection *con) override {}
|
||||
bool ms_handle_refused(Connection *con) override;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#ifndef CEPH_DISPATCHER_H
|
||||
#define CEPH_DISPATCHER_H
|
||||
|
||||
#include <memory>
|
||||
#include "include/buffer_fwd.h"
|
||||
#include "include/assert.h"
|
||||
|
||||
@ -25,6 +26,7 @@ class Connection;
|
||||
class AuthAuthorizer;
|
||||
class CryptoKey;
|
||||
class CephContext;
|
||||
class AuthAuthorizerChallenge;
|
||||
|
||||
class Dispatcher {
|
||||
public:
|
||||
@ -203,7 +205,10 @@ public:
|
||||
ceph::bufferlist& authorizer,
|
||||
ceph::bufferlist& authorizer_reply,
|
||||
bool& isvalid,
|
||||
CryptoKey& session_key) { return false; }
|
||||
CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @} //Authentication
|
||||
*/
|
||||
|
@ -805,11 +805,13 @@ public:
|
||||
*/
|
||||
bool ms_deliver_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) {
|
||||
for (list<Dispatcher*>::iterator p = dispatchers.begin();
|
||||
p != dispatchers.end();
|
||||
++p) {
|
||||
if ((*p)->ms_verify_authorizer(con, peer_type, protocol, authorizer, authorizer_reply, isvalid, session_key))
|
||||
if ((*p)->ms_verify_authorizer(con, peer_type, protocol, authorizer, authorizer_reply,
|
||||
isvalid, session_key, challenge))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -128,7 +128,8 @@ AsyncConnection::AsyncConnection(CephContext *cct, AsyncMessenger *m, DispatchQu
|
||||
recv_start(0), recv_end(0),
|
||||
last_active(ceph::coarse_mono_clock::now()),
|
||||
inactive_timeout_us(cct->_conf->ms_tcp_read_timeout*1000*1000),
|
||||
msg_left(0), cur_msg_size(0), got_bad_auth(false), authorizer(NULL), replacing(false),
|
||||
msg_left(0), cur_msg_size(0), got_bad_auth(false),
|
||||
authorizer(NULL), replacing(false),
|
||||
is_reset_from_peer(false), once_ready(false), state_buffer(NULL), state_offset(0),
|
||||
worker(w), center(&w->center)
|
||||
{
|
||||
@ -1010,8 +1011,7 @@ ssize_t AsyncConnection::_process_connection()
|
||||
|
||||
case STATE_CONNECTING_SEND_CONNECT_MSG:
|
||||
{
|
||||
if (!got_bad_auth) {
|
||||
delete authorizer;
|
||||
if (!authorizer) {
|
||||
authorizer = async_msgr->get_authorizer(peer_type, false);
|
||||
}
|
||||
bufferlist bl;
|
||||
@ -1091,6 +1091,14 @@ ssize_t AsyncConnection::_process_connection()
|
||||
}
|
||||
|
||||
authorizer_reply.append(state_buffer, connect_reply.authorizer_len);
|
||||
|
||||
if (connect_reply.tag == CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER) {
|
||||
ldout(async_msgr->cct,10) << __func__ << " connect got auth challenge" << dendl;
|
||||
authorizer->add_challenge(async_msgr->cct, authorizer_reply);
|
||||
state = STATE_CONNECTING_SEND_CONNECT_MSG;
|
||||
break;
|
||||
}
|
||||
|
||||
auto iter = authorizer_reply.cbegin();
|
||||
if (authorizer && !authorizer->verify_reply(iter)) {
|
||||
ldout(async_msgr->cct, 0) << __func__ << " failed verifying authorize reply" << dendl;
|
||||
@ -1508,12 +1516,26 @@ ssize_t AsyncConnection::handle_connect_msg(ceph_msg_connect &connect, bufferlis
|
||||
lock.unlock();
|
||||
|
||||
bool authorizer_valid;
|
||||
if (!async_msgr->verify_authorizer(this, peer_type, connect.authorizer_protocol, authorizer_bl,
|
||||
authorizer_reply, authorizer_valid, session_key) || !authorizer_valid) {
|
||||
bool need_challenge = HAVE_FEATURE(connect.features, CEPHX_V2);
|
||||
bool had_challenge = (bool)authorizer_challenge;
|
||||
if (!async_msgr->verify_authorizer(
|
||||
this, peer_type, connect.authorizer_protocol, authorizer_bl,
|
||||
authorizer_reply, authorizer_valid, session_key,
|
||||
need_challenge ? &authorizer_challenge : nullptr) ||
|
||||
!authorizer_valid) {
|
||||
lock.lock();
|
||||
ldout(async_msgr->cct,0) << __func__ << ": got bad authorizer" << dendl;
|
||||
char tag;
|
||||
if (need_challenge && !had_challenge && authorizer_challenge) {
|
||||
ldout(async_msgr->cct,0) << __func__ << ": challenging authorizer"
|
||||
<< dendl;
|
||||
assert(authorizer_reply.length());
|
||||
tag = CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER;
|
||||
} else {
|
||||
ldout(async_msgr->cct,0) << __func__ << ": got bad authorizer" << dendl;
|
||||
tag = CEPH_MSGR_TAG_BADAUTHORIZER;
|
||||
}
|
||||
session_security.reset();
|
||||
return _reply_accept(CEPH_MSGR_TAG_BADAUTHORIZER, connect, reply, authorizer_reply);
|
||||
return _reply_accept(tag, connect, reply, authorizer_reply);
|
||||
}
|
||||
|
||||
// We've verified the authorizer for this AsyncConnection, so set up the session security structure. PLR
|
||||
@ -1711,6 +1733,8 @@ ssize_t AsyncConnection::handle_connect_msg(ceph_msg_connect &connect, bufferlis
|
||||
// there shouldn't exist any buffer
|
||||
assert(recv_start == recv_end);
|
||||
|
||||
existing->authorizer_challenge.reset();
|
||||
|
||||
auto deactivate_existing = std::bind(
|
||||
[existing, new_worker, new_center, connect, reply, authorizer_reply](ConnectedSocket &cs) mutable {
|
||||
// we need to delete time event in original thread
|
||||
|
@ -368,6 +368,7 @@ class AsyncConnection : public Connection {
|
||||
Worker *worker;
|
||||
EventCenter *center;
|
||||
ceph::shared_ptr<AuthSessionHandler> session_security;
|
||||
std::unique_ptr<AuthAuthorizerChallenge> authorizer_challenge; // accept side
|
||||
|
||||
public:
|
||||
// used by eventcallback
|
||||
|
@ -383,9 +383,10 @@ public:
|
||||
* This wraps ms_deliver_verify_authorizer; we use it for AsyncConnection.
|
||||
*/
|
||||
bool verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& auth, bufferlist& auth_reply,
|
||||
bool& isvalid, CryptoKey& session_key) {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) {
|
||||
return ms_deliver_verify_authorizer(con, peer_type, protocol, auth,
|
||||
auth_reply, isvalid, session_key);
|
||||
auth_reply, isvalid, session_key, challenge);
|
||||
}
|
||||
/**
|
||||
* Increment the global sequence for this AsyncMessenger and return it.
|
||||
|
@ -351,6 +351,10 @@ int Pipe::accept()
|
||||
// used for reading in the remote acked seq on connect
|
||||
uint64_t newly_acked_seq = 0;
|
||||
|
||||
bool need_challenge = false;
|
||||
bool had_challenge = false;
|
||||
std::unique_ptr<AuthAuthorizerChallenge> authorizer_challenge;
|
||||
|
||||
recv_reset();
|
||||
|
||||
set_socket_options();
|
||||
@ -515,14 +519,27 @@ int Pipe::accept()
|
||||
|
||||
pipe_lock.Unlock();
|
||||
|
||||
if (!msgr->verify_authorizer(connection_state.get(), peer_type, connect.authorizer_protocol, authorizer,
|
||||
authorizer_reply, authorizer_valid, session_key) ||
|
||||
need_challenge = HAVE_FEATURE(connect.features, CEPHX_V2);
|
||||
had_challenge = (bool)authorizer_challenge;
|
||||
authorizer_reply.clear();
|
||||
if (!msgr->verify_authorizer(
|
||||
connection_state.get(), peer_type, connect.authorizer_protocol, authorizer,
|
||||
authorizer_reply, authorizer_valid, session_key,
|
||||
need_challenge ? &authorizer_challenge : nullptr) ||
|
||||
!authorizer_valid) {
|
||||
ldout(msgr->cct,0) << "accept: got bad authorizer" << dendl;
|
||||
pipe_lock.Lock();
|
||||
if (state != STATE_ACCEPTING)
|
||||
goto shutting_down_msgr_unlocked;
|
||||
reply.tag = CEPH_MSGR_TAG_BADAUTHORIZER;
|
||||
if (!had_challenge && need_challenge && authorizer_challenge) {
|
||||
ldout(msgr->cct,0) << "accept: challenging authorizer "
|
||||
<< authorizer_reply.length()
|
||||
<< " bytes" << dendl;
|
||||
assert(authorizer_reply.length());
|
||||
reply.tag = CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER;
|
||||
} else {
|
||||
ldout(msgr->cct,0) << "accept: got bad authorizer" << dendl;
|
||||
reply.tag = CEPH_MSGR_TAG_BADAUTHORIZER;
|
||||
}
|
||||
session_security.reset();
|
||||
goto reply;
|
||||
}
|
||||
@ -1128,8 +1145,9 @@ int Pipe::connect()
|
||||
|
||||
|
||||
while (1) {
|
||||
delete authorizer;
|
||||
authorizer = msgr->get_authorizer(peer_type, false);
|
||||
if (!authorizer) {
|
||||
authorizer = msgr->get_authorizer(peer_type, false);
|
||||
}
|
||||
bufferlist authorizer_reply;
|
||||
|
||||
ceph_msg_connect connect;
|
||||
@ -1196,6 +1214,13 @@ int Pipe::connect()
|
||||
authorizer_reply.push_back(bp);
|
||||
}
|
||||
|
||||
if (reply.tag == CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER) {
|
||||
authorizer->add_challenge(msgr->cct, authorizer_reply);
|
||||
ldout(msgr->cct,10) << " got authorizer challenge, " << authorizer_reply.length()
|
||||
<< " bytes" << dendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (authorizer) {
|
||||
auto iter = authorizer_reply.cbegin();
|
||||
if (!authorizer->verify_reply(iter)) {
|
||||
|
@ -413,9 +413,12 @@ AuthAuthorizer *SimpleMessenger::get_authorizer(int peer_type, bool force_new)
|
||||
|
||||
bool SimpleMessenger::verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer, bufferlist& authorizer_reply,
|
||||
bool& isvalid,CryptoKey& session_key)
|
||||
bool& isvalid,CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
|
||||
{
|
||||
return ms_deliver_verify_authorizer(con, peer_type, protocol, authorizer, authorizer_reply, isvalid,session_key);
|
||||
return ms_deliver_verify_authorizer(con, peer_type, protocol, authorizer, authorizer_reply,
|
||||
isvalid, session_key,
|
||||
challenge);
|
||||
}
|
||||
|
||||
ConnectionRef SimpleMessenger::get_connection(const entity_inst_t& dest)
|
||||
|
@ -347,8 +347,10 @@ public:
|
||||
/**
|
||||
* This wraps ms_deliver_verify_authorizer; we use it for Pipe.
|
||||
*/
|
||||
bool verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& auth, bufferlist& auth_reply,
|
||||
bool& isvalid,CryptoKey& session_key);
|
||||
bool verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& auth,
|
||||
bufferlist& auth_reply,
|
||||
bool& isvalid,CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge);
|
||||
/**
|
||||
* Increment the global sequence for this SimpleMessenger and return it.
|
||||
* This is for the connect protocol, although it doesn't hurt if somebody
|
||||
|
@ -6539,9 +6539,11 @@ bool OSD::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool for
|
||||
}
|
||||
|
||||
|
||||
bool OSD::ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key)
|
||||
bool OSD::ms_verify_authorizer(
|
||||
Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
|
||||
{
|
||||
AuthAuthorizeHandler *authorize_handler = 0;
|
||||
switch (peer_type) {
|
||||
@ -6573,7 +6575,7 @@ bool OSD::ms_verify_authorizer(Connection *con, int peer_type,
|
||||
isvalid = authorize_handler->verify_authorizer(
|
||||
cct, keys,
|
||||
authorizer_data, authorizer_reply, name, global_id, caps_info, session_key,
|
||||
&auid);
|
||||
&auid, challenge);
|
||||
} else {
|
||||
dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
|
||||
isvalid = false;
|
||||
|
@ -1622,7 +1622,8 @@ public:
|
||||
}
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override {
|
||||
isvalid = true;
|
||||
return true;
|
||||
}
|
||||
@ -2130,7 +2131,8 @@ private:
|
||||
bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) override;
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override;
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
|
||||
void ms_handle_connect(Connection *con) override;
|
||||
void ms_handle_fast_connect(Connection *con) override;
|
||||
void ms_handle_fast_accept(Connection *con) override;
|
||||
|
@ -113,9 +113,10 @@ public:
|
||||
* authorizer, false otherwise.
|
||||
*/
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer,
|
||||
bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override {
|
||||
int protocol, bufferlist& authorizer,
|
||||
bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override {
|
||||
/* always succeed */
|
||||
isvalid = true;
|
||||
return true;
|
||||
|
@ -115,7 +115,8 @@ public:
|
||||
virtual bool ms_verify_authorizer(Connection *con, int peer_type,
|
||||
int protocol, bufferlist& authorizer,
|
||||
bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) {
|
||||
/* always succeed */
|
||||
isvalid = true;
|
||||
return true;
|
||||
|
@ -58,7 +58,8 @@ class MessengerClient {
|
||||
bool ms_handle_refused(Connection *con) override { return false; }
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type, int protocol,
|
||||
bufferlist& authorizer, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override {
|
||||
isvalid = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -100,7 +100,8 @@ class ServerDispatcher : public Dispatcher {
|
||||
}
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type, int protocol,
|
||||
bufferlist& authorizer, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override {
|
||||
isvalid = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -203,7 +203,8 @@ class FakeDispatcher : public Dispatcher {
|
||||
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type, int protocol,
|
||||
bufferlist& authorizer, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override {
|
||||
isvalid = true;
|
||||
return true;
|
||||
}
|
||||
@ -893,7 +894,8 @@ class SyntheticDispatcher : public Dispatcher {
|
||||
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type, int protocol,
|
||||
bufferlist& authorizer, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override {
|
||||
isvalid = true;
|
||||
return true;
|
||||
}
|
||||
@ -1436,7 +1438,8 @@ class MarkdownDispatcher : public Dispatcher {
|
||||
}
|
||||
bool ms_verify_authorizer(Connection *con, int peer_type, int protocol,
|
||||
bufferlist& authorizer, bufferlist& authorizer_reply,
|
||||
bool& isvalid, CryptoKey& session_key) override {
|
||||
bool& isvalid, CryptoKey& session_key,
|
||||
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override {
|
||||
isvalid = true;
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user