| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #ifndef KUDU_RPC_SASL_CLIENT_H |
| #define KUDU_RPC_SASL_CLIENT_H |
| |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include <sasl/sasl.h> |
| |
| #include "kudu/gutil/gscoped_ptr.h" |
| #include "kudu/rpc/rpc_header.pb.h" |
| #include "kudu/rpc/sasl_common.h" |
| #include "kudu/rpc/sasl_helper.h" |
| #include "kudu/util/monotime.h" |
| #include "kudu/util/status.h" |
| #include "kudu/util/net/socket.h" |
| |
| namespace kudu { |
| namespace rpc { |
| |
| using std::string; |
| |
| class ResponseHeader; |
| class SaslMessagePB; |
| class SaslMessagePB_SaslAuth; |
| |
| // Class for doing SASL negotiation with a SaslServer over a bidirectional socket. |
| // Operations on this class are NOT thread-safe. |
| class SaslClient { |
| public: |
| // Does not take ownership of the socket indicated by the fd. |
| SaslClient(string app_name, int fd); |
| ~SaslClient(); |
| |
| // Enable ANONYMOUS authentication. |
| // Must be called after Init(). |
| Status EnableAnonymous(); |
| |
| // Enable PLAIN authentication. |
| // Must be called after Init(). |
| Status EnablePlain(const string& user, const string& pass); |
| |
| // Returns mechanism negotiated by this connection. |
| // Must be called after Negotiate(). |
| SaslMechanism::Type negotiated_mechanism() const; |
| |
| // Returns the set of RPC system features supported by the remote server. |
| // Must be called after Negotiate(). |
| const std::set<RpcFeatureFlag>& server_features() const { |
| return server_features_; |
| } |
| |
| // Specify IP:port of local side of connection. |
| // Must be called before Init(). Required for some mechanisms. |
| void set_local_addr(const Sockaddr& addr); |
| |
| // Specify IP:port of remote side of connection. |
| // Must be called before Init(). Required for some mechanisms. |
| void set_remote_addr(const Sockaddr& addr); |
| |
| // Specify the fully-qualified domain name of the remote server. |
| // Must be called before Init(). Required for some mechanisms. |
| void set_server_fqdn(const string& domain_name); |
| |
| // Set deadline for connection negotiation. |
| void set_deadline(const MonoTime& deadline); |
| |
| // Get deadline for connection negotiation. |
| const MonoTime& deadline() const { return deadline_; } |
| |
| // Initialize a new SASL client. Must be called before Negotiate(). |
| // Returns OK on success, otherwise RuntimeError. |
| Status Init(const string& service_type); |
| |
| // Begin negotiation with the SASL server on the other side of the fd socket |
| // that this client was constructed with. |
| // Returns OK on success. |
| // Otherwise, it may return NotAuthorized, NotSupported, or another non-OK status. |
| Status Negotiate(); |
| |
| // SASL callback for plugin options, supported mechanisms, etc. |
| // Returns SASL_FAIL if the option is not handled, which does not fail the handshake. |
| int GetOptionCb(const char* plugin_name, const char* option, |
| const char** result, unsigned* len); |
| |
| // SASL callback for SASL_CB_USER, SASL_CB_AUTHNAME, SASL_CB_LANGUAGE |
| int SimpleCb(int id, const char** result, unsigned* len); |
| |
| // SASL callback for SASL_CB_PASS |
| int SecretCb(sasl_conn_t* conn, int id, sasl_secret_t** psecret); |
| |
| private: |
| // Encode and send the specified SASL message to the server. |
| Status SendSaslMessage(const SaslMessagePB& msg); |
| |
| // Validate that header does not indicate an error, parse param_buf into response. |
| Status ParseSaslMsgResponse(const ResponseHeader& header, const Slice& param_buf, |
| SaslMessagePB* response); |
| |
| // Send an NEGOTIATE message to the server. |
| Status SendNegotiateMessage(); |
| |
| // Send an INITIATE message to the server. |
| Status SendInitiateMessage(const SaslMessagePB_SaslAuth& auth, |
| const char* init_msg, unsigned init_msg_len); |
| |
| // Send a RESPONSE message to the server. |
| Status SendResponseMessage(const char* resp_msg, unsigned resp_msg_len); |
| |
| // Perform a client-side step of the SASL negotiation. |
| // Input is what came from the server. Output is what we will send back to the server. |
| // Return code from sasl_client_step is stored in result. |
| // Returns Status::OK if sasl_client_step returns SASL_OK or SASL_CONTINUE; otherwise, |
| // returns Status::NotAuthorized. |
| Status DoSaslStep(const string& in, const char** out, unsigned* out_len, int* result); |
| |
| // Handle case when server sends NEGOTIATE response. |
| Status HandleNegotiateResponse(const SaslMessagePB& response); |
| |
| // Handle case when server sends CHALLENGE response. |
| Status HandleChallengeResponse(const SaslMessagePB& response); |
| |
| // Handle case when server sends SUCCESS response. |
| Status HandleSuccessResponse(const SaslMessagePB& response); |
| |
| // Parse error status message from raw bytes of an ErrorStatusPB. |
| Status ParseError(const Slice& err_data); |
| |
| string app_name_; |
| Socket sock_; |
| std::vector<sasl_callback_t> callbacks_; |
| gscoped_ptr<sasl_conn_t, SaslDeleter> sasl_conn_; |
| SaslHelper helper_; |
| |
| string plain_auth_user_; |
| string plain_pass_; |
| gscoped_ptr<sasl_secret_t, FreeDeleter> psecret_; |
| |
| // The set of features supported by the server. |
| std::set<RpcFeatureFlag> server_features_; |
| |
| SaslNegotiationState::Type client_state_; |
| |
| // The mechanism we negotiated with the server. |
| SaslMechanism::Type negotiated_mech_; |
| |
| // Intra-negotiation state. |
| bool nego_ok_; // During negotiation: did we get a SASL_OK response from the SASL library? |
| bool nego_response_expected_; // During negotiation: Are we waiting for a server response? |
| |
| // Negotiation timeout deadline. |
| MonoTime deadline_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SaslClient); |
| }; |
| |
| } // namespace rpc |
| } // namespace kudu |
| |
| #endif // KUDU_RPC_SASL_CLIENT_H |