]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
auth/cephx: share all tickets and connection_secret in initial reply
authorSage Weil <sage@redhat.com>
Wed, 16 Jan 2019 16:46:34 +0000 (10:46 -0600)
committerSage Weil <sage@redhat.com>
Thu, 7 Feb 2019 12:53:03 +0000 (06:53 -0600)
Previously, we would give the client the auth ticket, like a rbd TGT
(ticket granting ticket), and the client would then ask for all of the
other tickets it wants in a separate message.

Instead, have the client specify which tickets it wants up front and pass
them all at the same time.

Also, generate and share the connection_secret, which will be used for
encryption.

Signed-off-by: Sage Weil <sage@redhat.com>
src/auth/cephx/CephxClientHandler.cc
src/auth/cephx/CephxClientHandler.h
src/auth/cephx/CephxProtocol.cc
src/auth/cephx/CephxProtocol.h
src/auth/cephx/CephxServiceHandler.cc

index 64924777e5b8e9aecda59ff2dbce301222ca4f76..9d0df43a8c458b99d5e7ed25d6aac91339d9b1e9 100644 (file)
 #undef dout_prefix
 #define dout_prefix *_dout << "cephx client: "
 
+void CephxClientHandler::reset()
+{
+  ldout(cct,10) << __func__ << dendl;
+  starting = true;
+  server_challenge = 0;
+}
+
 int CephxClientHandler::build_request(bufferlist& bl) const
 {
   ldout(cct, 10) << "build_request" << dendl;
@@ -63,6 +70,9 @@ int CephxClientHandler::build_request(bufferlist& bl) const
 
     req.old_ticket = ticket_handler->ticket;
 
+    // for nautilus+ servers: request other keys at the same time
+    req.other_keys = need;
+
     if (req.old_ticket.blob.length()) {
       ldout(cct, 20) << "old ticket len=" << req.old_ticket.blob.length() << dendl;
     }
@@ -111,7 +121,7 @@ int CephxClientHandler::handle_response(
   CryptoKey *session_key,
   CryptoKey *connection_secret)
 {
-  ldout(cct, 10) << "handle_response ret = " << ret << dendl;
+  ldout(cct, 10) << this << " handle_response ret = " << ret << dendl;
   
   if (ret < 0)
     return ret; // hrm!
@@ -147,12 +157,47 @@ int CephxClientHandler::handle_response(
        return -EPERM;
       }
       ldout(cct, 10) << " want=" << want << " need=" << need << " have=" << have << dendl;
+      if (!indata.end()) {
+       bufferlist cbl, extra_tickets;
+       decode(cbl, indata);
+       decode(extra_tickets, indata);
+       ldout(cct, 10) << " got connection bl " << cbl.length()
+                      << " and extra tickets " << extra_tickets.length()
+                      << dendl;
+       if (session_key && connection_secret) {
+         CephXTicketHandler& ticket_handler =
+           tickets.get_handler(CEPH_ENTITY_TYPE_AUTH);
+         if (session_key) {
+           *session_key = ticket_handler.session_key;
+         }
+         if (cbl.length() && connection_secret) {
+           auto p = cbl.cbegin();
+           string err;
+           if (decode_decrypt(cct, *connection_secret, *session_key, p,
+                              err) < 0) {
+             lderr(cct) << __func__ << " failed to decrypt connection_secret"
+                        << dendl;
+           } else {
+             ldout(cct, 10) << " got connection_secret " << dendl;
+           }
+         }
+         if (extra_tickets.length())  {
+           auto p = extra_tickets.cbegin();
+           if (!tickets.verify_service_ticket_reply(
+                 *session_key, p)) {
+             lderr(cct) << "could not verify extra service_tickets" << dendl;
+           } else {
+             ldout(cct, 10) << " got extra service_tickets" << dendl;
+           }
+         }
+       }
+      }
       validate_tickets();
       if (_need_tickets())
        ret = -EAGAIN;
       else
        ret = 0;
-    }
+      }
     break;
 
   case CEPHX_GET_PRINCIPAL_SESSION_KEY:
index 63a4c7a513b32a74c9d557ca3541a37814960ca3..f56bc1d9137743cc8fab624142dec6fd8c4ef20b 100644 (file)
@@ -48,10 +48,7 @@ public:
     reset();
   }
 
-  void reset() override {
-    starting = true;
-    server_challenge = 0;
-  }
+  void reset() override;
   void prepare_build_request() override;
   int build_request(bufferlist& bl) const override;
   int handle_response(int ret, bufferlist::const_iterator& iter,
index 6aa99d9bb528d3cc5e37fd77c7144a6f4f319096..eca2a1e9b83263da033fa4d41a56edfbf0f6bf37 100644 (file)
@@ -56,9 +56,12 @@ bool cephx_build_service_ticket_blob(CephContext *cct, CephXSessionAuthInfo& inf
   ticket_info.ticket = info.ticket;
   ticket_info.ticket.caps = info.ticket.caps;
 
-  ldout(cct, 10) << "build_service_ticket service " << ceph_entity_type_name(info.service_id)
-          << " secret_id " << info.secret_id
-          << " ticket_info.ticket.name=" << ticket_info.ticket.name.to_str() << dendl;
+  ldout(cct, 10) << "build_service_ticket service "
+                << ceph_entity_type_name(info.service_id)
+                << " secret_id " << info.secret_id
+                << " ticket_info.ticket.name="
+                << ticket_info.ticket.name.to_str()
+                << " ticket.global_id " << info.ticket.global_id << dendl;
   blob.secret_id = info.secret_id;
   std::string error;
   if (!info.service_secret.get_secret().length())
@@ -142,8 +145,9 @@ bool cephx_build_service_ticket_reply(CephContext *cct,
  * PRINCIPAL: verify our attempt to authenticate succeeded.  fill out
  * this ServiceTicket with the result.
  */
-bool CephXTicketHandler::verify_service_ticket_reply(CryptoKey& secret,
-                                                    bufferlist::const_iterator& indata)
+bool CephXTicketHandler::verify_service_ticket_reply(
+  CryptoKey& secret,
+  bufferlist::const_iterator& indata)
 {
   __u8 service_ticket_v;
   decode(service_ticket_v, indata);
@@ -282,9 +286,6 @@ bool CephXTicketManager::verify_service_ticket_reply(CryptoKey& secret,
     handler.service_id = type;
   }
 
-  if (!indata.end())
-    return false;
-
   return true;
 }
 
index 78cb003d3378f9af11b3935e50e85d27b479379c..49793b59a88ba0f589c8e29a1d31131928e7ef5f 100644 (file)
@@ -122,23 +122,28 @@ struct CephXAuthenticate {
   uint64_t client_challenge;
   uint64_t key;
   CephXTicketBlob old_ticket;
+  uint32_t other_keys = 0;  // replaces CephXServiceTicketRequest
 
   void encode(bufferlist& bl) const {
-     using ceph::encode;
-     __u8 struct_v = 1;
-     encode(struct_v, bl);
-     encode(client_challenge, bl);
-     encode(key, bl);
-     encode(old_ticket, bl);
+    using ceph::encode;
+    __u8 struct_v = 2;
+    encode(struct_v, bl);
+    encode(client_challenge, bl);
+    encode(key, bl);
+    encode(old_ticket, bl);
+    encode(other_keys, bl);
   }
   void decode(bufferlist::const_iterator& bl) {
-     using ceph::decode;
-     __u8 struct_v;
-     decode(struct_v, bl);
-     decode(client_challenge, bl);
-     decode(key, bl);
-     decode(old_ticket, bl);
- }
+    using ceph::decode;
+    __u8 struct_v;
+    decode(struct_v, bl);
+    decode(client_challenge, bl);
+    decode(key, bl);
+    decode(old_ticket, bl);
+    if (struct_v >= 2) {
+      decode(other_keys, bl);
+    }
+  }
 };
 WRITE_CLASS_ENCODER(CephXAuthenticate)
 
index 22426d383293832868e2fc4c91201200f73ec29e..a89c15323549e7a5181ba5e0db8cfc741723c8b2 100644 (file)
@@ -52,8 +52,8 @@ int CephxServiceHandler::handle_request(
   bufferlist *result_bl,
   uint64_t *global_id,
   AuthCapsInfo *caps,
-  CryptoKey *session_key,
-  CryptoKey *connection_secret)
+  CryptoKey *psession_key,
+  CryptoKey *pconnection_secret)
 {
   int ret = 0;
 
@@ -119,6 +119,8 @@ int CephxServiceHandler::handle_request(
         should_enc_ticket = true;
       }
 
+      ldout(cct,10) << __func__ << " auth ticket global_id " << *global_id
+                   << dendl;
       info.ticket.init_timestamps(ceph_clock_now(),
                                  cct->_conf->auth_mon_ticket_ttl);
       info.ticket.name = entity_name;
@@ -128,6 +130,9 @@ int CephxServiceHandler::handle_request(
       key_server->generate_secret(session_key);
 
       info.session_key = session_key;
+      if (psession_key) {
+       *psession_key = session_key;
+      }
       info.service_id = CEPH_ENTITY_TYPE_AUTH;
       if (!key_server->get_service_secret(CEPH_ENTITY_TYPE_AUTH, info.service_secret, info.secret_id)) {
         ldout(cct, 0) << " could not get service secret for auth subsystem" << dendl;
@@ -158,6 +163,42 @@ int CephxServiceHandler::handle_request(
           ret = -EACCES;
          break;
         }
+
+       if (req.other_keys) {
+         // nautilus+ client
+         // generate a connection_secret
+         bufferlist cbl;
+         if (pconnection_secret) {
+           key_server->generate_secret(*pconnection_secret);
+           string err;
+           encode_encrypt(cct, *pconnection_secret, session_key, cbl, err);
+         }
+         encode(cbl, *result_bl);
+         // provite all of the other tickets at the same time
+         vector<CephXSessionAuthInfo> info_vec;
+         for (uint32_t service_id = 1; service_id <= req.other_keys;
+              service_id <<= 1) {
+           if (req.other_keys & service_id) {
+             ldout(cct, 10) << " adding key for service "
+                            << ceph_entity_type_name(service_id) << dendl;
+             CephXSessionAuthInfo svc_info;
+             key_server->build_session_auth_info(
+               service_id,
+               info.ticket,
+               svc_info);
+             svc_info.validity += cct->_conf->auth_service_ticket_ttl;
+             info_vec.push_back(svc_info);
+           }
+         }
+         bufferlist extra;
+         if (!info_vec.empty()) {
+           CryptoKey no_key;
+           cephx_build_service_ticket_reply(
+             cct, session_key, info_vec, false, no_key, extra);
+         }
+         encode(extra, *result_bl);
+       }
+
        // caller should try to finish authentication
        ret = 1;
       }
@@ -173,7 +214,6 @@ int CephxServiceHandler::handle_request(
       // note: no challenge here.
       if (!cephx_verify_authorizer(
            cct, key_server, indata, auth_ticket_info, nullptr,
-#warning FIXME mon connection needs connection_secret too
            nullptr,
            tmp_bl)) {
         ret = -EPERM;