mds: move session setup into ms_handle_authentication

Signed-off-by: Sage Weil <sage@redhat.com>
This commit is contained in:
Sage Weil 2018-09-11 14:38:05 -05:00
parent 67d2f3b901
commit ecbd4a8aa8
2 changed files with 88 additions and 80 deletions

View File

@ -1323,14 +1323,12 @@ bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
return true;
}
AuthCapsInfo caps_info;
EntityName name;
uint64_t global_id;
if (auto keys = monc->rotating_secrets.get(); keys) {
is_valid = authorize_handler->verify_authorizer(
cct, keys,
authorizer_data, authorizer_reply, name, global_id, caps_info,
authorizer_data, authorizer_reply,
con->peer_name, con->peer_global_id,
con->peer_caps_info,
session_key, challenge);
} else {
dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
@ -1338,84 +1336,93 @@ bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
}
if (is_valid) {
entity_name_t n(con->get_peer_type(), global_id);
// We allow connections and assign Session instances to connections
// even if we have not been assigned a rank, because clients with
// "allow *" are allowed to connect and do 'tell' operations before
// we have a rank.
Session *s = NULL;
if (mds_rank) {
// If we do hold a rank, see if this is an existing client establishing
// a new connection, rather than a new client
s = mds_rank->sessionmap.get_session(n);
}
// Wire up a Session* to this connection
// It doesn't go into a SessionMap instance until it sends an explicit
// request to open a session (initial state of Session is `closed`)
if (!s) {
s = new Session(con);
s->info.auth_name = name;
s->info.inst.addr = con->get_peer_addr();
s->info.inst.name = n;
dout(10) << " new session " << s << " for " << s->info.inst << " con " << con << dendl;
con->set_priv(RefCountedPtr{s, false});
if (mds_rank) {
mds_rank->kick_waiters_for_any_client_connection();
}
} else {
dout(10) << " existing session " << s << " for " << s->info.inst
<< " existing con " << s->get_connection()
<< ", new/authorizing con " << con << dendl;
con->set_priv(RefCountedPtr{s});
// Wait until we fully accept the connection before setting
// s->connection. In particular, if there are multiple incoming
// connection attempts, they will all get their authorizer
// validated, but some of them may "lose the race" and get
// dropped. We only want to consider the winner(s). See
// ms_handle_accept(). This is important for Sessions we replay
// from the journal on recovery that don't have established
// messenger state; we want the con from only the winning
// connect attempt(s). (Normal reconnects that don't follow MDS
// recovery are reconnected to the existing con by the
// messenger.)
}
if (caps_info.allow_all) {
// Flag for auth providers that don't provide cap strings
s->auth_caps.set_allow_all();
} else {
auto p = caps_info.caps.cbegin();
string auth_cap_str;
try {
decode(auth_cap_str, p);
dout(10) << __func__ << ": parsing auth_cap_str='" << auth_cap_str << "'" << dendl;
std::ostringstream errstr;
if (!s->auth_caps.parse(g_ceph_context, auth_cap_str, &errstr)) {
dout(1) << __func__ << ": auth cap parse error: " << errstr.str()
<< " parsing '" << auth_cap_str << "'" << dendl;
clog->warn() << name << " mds cap '" << auth_cap_str
<< "' does not parse: " << errstr.str();
is_valid = false;
}
} catch (buffer::error& e) {
// Assume legacy auth, defaults to:
// * permit all filesystem ops
// * permit no `tell` ops
dout(1) << __func__ << ": cannot decode auth caps bl of length " << caps_info.caps.length() << dendl;
is_valid = false;
}
}
ms_handle_authentication(con);
}
return true; // we made a decision (see is_valid)
return true;
}
int MDSDaemon::ms_handle_authentication(Connection *con)
{
int ret = 0;
entity_name_t n(con->get_peer_type(), con->get_peer_global_id());
// We allow connections and assign Session instances to connections
// even if we have not been assigned a rank, because clients with
// "allow *" are allowed to connect and do 'tell' operations before
// we have a rank.
Session *s = NULL;
if (mds_rank) {
// If we do hold a rank, see if this is an existing client establishing
// a new connection, rather than a new client
s = mds_rank->sessionmap.get_session(n);
}
// Wire up a Session* to this connection
// It doesn't go into a SessionMap instance until it sends an explicit
// request to open a session (initial state of Session is `closed`)
if (!s) {
s = new Session(con);
s->info.auth_name = con->get_peer_entity_name();
s->info.inst.addr = con->get_peer_addr();
s->info.inst.name = n;
dout(10) << " new session " << s << " for " << s->info.inst
<< " con " << con << dendl;
con->set_priv(RefCountedPtr{s, false});
if (mds_rank) {
mds_rank->kick_waiters_for_any_client_connection();
}
} else {
dout(10) << " existing session " << s << " for " << s->info.inst
<< " existing con " << s->get_connection()
<< ", new/authorizing con " << con << dendl;
con->set_priv(RefCountedPtr{s});
// Wait until we fully accept the connection before setting
// s->connection. In particular, if there are multiple incoming
// connection attempts, they will all get their authorizer
// validated, but some of them may "lose the race" and get
// dropped. We only want to consider the winner(s). See
// ms_handle_accept(). This is important for Sessions we replay
// from the journal on recovery that don't have established
// messenger state; we want the con from only the winning
// connect attempt(s). (Normal reconnects that don't follow MDS
// recovery are reconnected to the existing con by the
// messenger.)
}
AuthCapsInfo &caps_info = con->get_peer_caps_info();
if (caps_info.allow_all) {
// Flag for auth providers that don't provide cap strings
s->auth_caps.set_allow_all();
} else {
auto p = caps_info.caps.cbegin();
string auth_cap_str;
try {
decode(auth_cap_str, p);
dout(10) << __func__ << ": parsing auth_cap_str='" << auth_cap_str << "'"
<< dendl;
std::ostringstream errstr;
if (!s->auth_caps.parse(g_ceph_context, auth_cap_str, &errstr)) {
dout(1) << __func__ << ": auth cap parse error: " << errstr.str()
<< " parsing '" << auth_cap_str << "'" << dendl;
clog->warn() << name << " mds cap '" << auth_cap_str
<< "' does not parse: " << errstr.str();
ret = -EPERM;
} else {
ret = 1;
}
} catch (buffer::error& e) {
// Assume legacy auth, defaults to:
// * permit all filesystem ops
// * permit no `tell` ops
dout(1) << __func__ << ": cannot decode auth caps bl of length "
<< caps_info.caps.length() << dendl;
ret = -EPERM;
}
}
return ret;
}
void MDSDaemon::ms_handle_accept(Connection *con)
{

View File

@ -115,6 +115,7 @@ class MDSDaemon : public Dispatcher, public md_config_obs_t {
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
bool& isvalid, CryptoKey& session_key,
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
int ms_handle_authentication(Connection *con) override;
void ms_handle_accept(Connection *con) override;
void ms_handle_connect(Connection *con) override;
bool ms_handle_reset(Connection *con) override;