You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by te...@apache.org on 2017/05/30 21:31:45 UTC
hbase git commit: HBASE-17860 Implement secure native client
connection
Repository: hbase
Updated Branches:
refs/heads/HBASE-14850 ccfc68251 -> 517090a09
HBASE-17860 Implement secure native client connection
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/517090a0
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/517090a0
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/517090a0
Branch: refs/heads/HBASE-14850
Commit: 517090a09a252b28cfda7083c91e53a4888bf9e2
Parents: ccfc682
Author: tedyu <yu...@gmail.com>
Authored: Tue May 30 14:31:23 2017 -0700
Committer: tedyu <yu...@gmail.com>
Committed: Tue May 30 14:31:23 2017 -0700
----------------------------------------------------------------------
hbase-native-client/bin/start-docker.sh | 6 +-
hbase-native-client/connection/BUCK | 18 +-
.../connection/client-handler.cc | 6 +-
.../connection/connection-factory.cc | 10 +-
.../connection/connection-factory.h | 5 +-
.../connection/connection-pool-test.cc | 2 +-
.../connection/connection-pool.cc | 8 +-
.../connection/connection-pool.h | 4 +-
hbase-native-client/connection/pipeline.cc | 10 +-
hbase-native-client/connection/pipeline.h | 4 +-
hbase-native-client/connection/rpc-client.cc | 7 +-
hbase-native-client/connection/rpc-client.h | 3 +-
hbase-native-client/connection/sasl-handler.cc | 224 +++++++++++++++++++
hbase-native-client/connection/sasl-handler.h | 78 +++++++
hbase-native-client/connection/sasl-util.cc | 92 ++++++++
hbase-native-client/connection/sasl-util.h | 46 ++++
hbase-native-client/core/BUCK | 104 ++++++---
hbase-native-client/core/async-connection.cc | 4 +-
.../core/async-rpc-retrying-test.cc | 3 +-
hbase-native-client/core/location-cache-test.cc | 6 +-
hbase-native-client/docker-files/Dockerfile | 88 ++++++++
hbase-native-client/docker-files/krb5.conf | 20 ++
hbase-native-client/security/BUCK | 8 +-
hbase-native-client/security/user.h | 1 +
hbase-native-client/serde/BUCK | 56 +++--
.../serde/client-serializer-test.cc | 4 +-
hbase-native-client/serde/rpc.cc | 13 +-
hbase-native-client/serde/rpc.h | 3 +-
hbase-native-client/third-party/BUCK | 7 +-
hbase-native-client/utils/BUCK | 26 ++-
hbase-native-client/utils/user-util-test.cc | 2 +-
hbase-native-client/utils/user-util.cc | 37 ++-
hbase-native-client/utils/user-util.h | 4 +-
33 files changed, 812 insertions(+), 97 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/bin/start-docker.sh
----------------------------------------------------------------------
diff --git a/hbase-native-client/bin/start-docker.sh b/hbase-native-client/bin/start-docker.sh
index 8b017a0..53325c1 100755
--- a/hbase-native-client/bin/start-docker.sh
+++ b/hbase-native-client/bin/start-docker.sh
@@ -52,11 +52,11 @@ fi;
# Build the image
#
# This shouldn't be needed after the development environment is a little more stable.
-docker build -t hbase_native .
+docker build -t hbase_native -f docker-files/Dockerfile .
# After the image is built run the thing
-docker run -p 16050:16050/tcp \
+docker run -h="securecluster" -p 16050:16050/tcp \
-v ${BASE_DIR}/..:/usr/src/hbase \
-v ~/.m2:/root/.m2 \
- -it hbase_native /bin/bash
+ -it hbase_native /bin/bash
popd
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/BUCK
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/BUCK b/hbase-native-client/connection/BUCK
index 36111f8..c3119eb 100644
--- a/hbase-native-client/connection/BUCK
+++ b/hbase-native-client/connection/BUCK
@@ -22,6 +22,7 @@ cxx_library(
exported_headers=[
"client-dispatcher.h",
"client-handler.h",
+ "sasl-handler.h",
"connection-factory.h",
"connection-pool.h",
"connection-id.h",
@@ -31,6 +32,7 @@ cxx_library(
"response.h",
"service.h",
"rpc-client.h",
+ "sasl-util.h",
],
srcs=[
"client-dispatcher.cc",
@@ -40,6 +42,8 @@ cxx_library(
"pipeline.cc",
"request.cc",
"rpc-client.cc",
+ "sasl-handler.cc",
+ "sasl-util.cc",
],
deps=[
"//if:if",
@@ -51,8 +55,16 @@ cxx_library(
"//exceptions:exceptions",
],
compiler_flags=['-Weffc++'],
- visibility=['//core/...',],)
+ linker_flags=['-L/usr/local/lib', '-lsasl2', '-lkrb5'],
+ exported_linker_flags=['-L/usr/local/lib', '-lsasl2', '-lkrb5'],
+ visibility=[
+ '//core/...',
+ ],)
cxx_test(
name="connection-pool-test",
- srcs=["connection-pool-test.cc",],
- deps=[":connection",],)
+ srcs=[
+ "connection-pool-test.cc",
+ ],
+ deps=[
+ ":connection",
+ ],)
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/client-handler.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/client-handler.cc b/hbase-native-client/connection/client-handler.cc
index 113ebd0..e60382d 100644
--- a/hbase-native-client/connection/client-handler.cc
+++ b/hbase-native-client/connection/client-handler.cc
@@ -128,11 +128,9 @@ Future<Unit> ClientHandler::write(Context *ctx, std::unique_ptr<Request> r) {
// We need to send the header once.
// So use call_once to make sure that only one thread wins this.
std::call_once((*once_flag_), [ctx, this]() {
- VLOG(3) << "Writing RPC connection Preamble and Header to server: " << server_;
- auto pre = serde_.Preamble();
+ VLOG(3) << "Writing RPC Header to server: " << server_;
auto header = serde_.Header(user_name_);
- pre->appendChain(std::move(header));
- ctx->fireWrite(std::move(pre));
+ ctx->fireWrite(std::move(header));
});
VLOG(3) << "Writing RPC Request with call_id:"
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/connection-factory.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/connection-factory.cc b/hbase-native-client/connection/connection-factory.cc
index afa227d..9b06c84 100644
--- a/hbase-native-client/connection/connection-factory.cc
+++ b/hbase-native-client/connection/connection-factory.cc
@@ -18,9 +18,12 @@
*/
#include "connection/connection-factory.h"
+#include "connection/sasl-handler.h"
#include <chrono>
+#include <glog/logging.h>
+#include <wangle/channel/Handler.h>
#include "connection/client-dispatcher.h"
#include "connection/pipeline.h"
#include "connection/service.h"
@@ -31,10 +34,13 @@ using std::chrono::milliseconds;
using std::chrono::nanoseconds;
ConnectionFactory::ConnectionFactory(std::shared_ptr<wangle::IOThreadPoolExecutor> io_pool,
- std::shared_ptr<Codec> codec, nanoseconds connect_timeout)
+ std::shared_ptr<Codec> codec,
+ std::shared_ptr<Configuration> conf,
+ nanoseconds connect_timeout)
: connect_timeout_(connect_timeout),
io_pool_(io_pool),
- pipeline_factory_(std::make_shared<RpcPipelineFactory>(codec)) {}
+ conf_(conf),
+ pipeline_factory_(std::make_shared<RpcPipelineFactory>(codec, conf)) {}
std::shared_ptr<wangle::ClientBootstrap<SerializePipeline>> ConnectionFactory::MakeBootstrap() {
auto client = std::make_shared<wangle::ClientBootstrap<SerializePipeline>>();
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/connection-factory.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/connection-factory.h b/hbase-native-client/connection/connection-factory.h
index 1e75571..e1d7f6c 100644
--- a/hbase-native-client/connection/connection-factory.h
+++ b/hbase-native-client/connection/connection-factory.h
@@ -28,6 +28,7 @@
#include "connection/request.h"
#include "connection/response.h"
#include "connection/service.h"
+#include "security/user.h"
using std::chrono::nanoseconds;
@@ -44,7 +45,8 @@ class ConnectionFactory {
* There should only be one ConnectionFactory per client.
*/
ConnectionFactory(std::shared_ptr<wangle::IOThreadPoolExecutor> io_pool,
- std::shared_ptr<Codec> codec, nanoseconds connect_timeout = nanoseconds(0));
+ std::shared_ptr<Codec> codec, std::shared_ptr<Configuration> conf,
+ nanoseconds connect_timeout = nanoseconds(0));
/** Default Destructor */
virtual ~ConnectionFactory() = default;
@@ -65,6 +67,7 @@ class ConnectionFactory {
private:
nanoseconds connect_timeout_;
+ std::shared_ptr<Configuration> conf_;
std::shared_ptr<wangle::IOThreadPoolExecutor> io_pool_;
std::shared_ptr<RpcPipelineFactory> pipeline_factory_;
};
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/connection-pool-test.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/connection-pool-test.cc b/hbase-native-client/connection/connection-pool-test.cc
index 8ecdf29..04ec7f1 100644
--- a/hbase-native-client/connection/connection-pool-test.cc
+++ b/hbase-native-client/connection/connection-pool-test.cc
@@ -36,7 +36,7 @@ using hbase::ConnectionId;
class MockConnectionFactory : public ConnectionFactory {
public:
- MockConnectionFactory() : ConnectionFactory(nullptr, nullptr) {}
+ MockConnectionFactory() : ConnectionFactory(nullptr, nullptr, nullptr) {}
MOCK_METHOD0(MakeBootstrap, std::shared_ptr<wangle::ClientBootstrap<SerializePipeline>>());
MOCK_METHOD3(Connect, std::shared_ptr<HBaseService>(
std::shared_ptr<wangle::ClientBootstrap<SerializePipeline>>,
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/connection-pool.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/connection-pool.cc b/hbase-native-client/connection/connection-pool.cc
index 3121294..d3ac3c2 100644
--- a/hbase-native-client/connection/connection-pool.cc
+++ b/hbase-native-client/connection/connection-pool.cc
@@ -36,11 +36,13 @@ using folly::SharedMutexWritePriority;
using folly::SocketAddress;
ConnectionPool::ConnectionPool(std::shared_ptr<wangle::IOThreadPoolExecutor> io_executor,
- std::shared_ptr<Codec> codec, nanoseconds connect_timeout)
- : cf_(std::make_shared<ConnectionFactory>(io_executor, codec, connect_timeout)),
+ std::shared_ptr<Codec> codec, std::shared_ptr<Configuration> conf,
+ nanoseconds connect_timeout)
+ : cf_(std::make_shared<ConnectionFactory>(io_executor, codec, conf, connect_timeout)),
clients_(),
connections_(),
- map_mutex_() {}
+ map_mutex_(),
+ conf_(conf) {}
ConnectionPool::ConnectionPool(std::shared_ptr<ConnectionFactory> cf)
: cf_(cf), clients_(), connections_(), map_mutex_() {}
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/connection-pool.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/connection-pool.h b/hbase-native-client/connection/connection-pool.h
index 2a8f195..0582d9b 100644
--- a/hbase-native-client/connection/connection-pool.h
+++ b/hbase-native-client/connection/connection-pool.h
@@ -50,7 +50,8 @@ class ConnectionPool {
public:
/** Create connection pool wit default connection factory */
ConnectionPool(std::shared_ptr<wangle::IOThreadPoolExecutor> io_executor,
- std::shared_ptr<Codec> codec, nanoseconds connect_timeout = nanoseconds(0));
+ std::shared_ptr<Codec> codec, std::shared_ptr<Configuration> conf,
+ nanoseconds connect_timeout = nanoseconds(0));
/**
* Constructor that allows specifiying the connetion factory.
@@ -93,6 +94,7 @@ class ConnectionPool {
clients_;
folly::SharedMutexWritePriority map_mutex_;
std::shared_ptr<ConnectionFactory> cf_;
+ std::shared_ptr<Configuration> conf_;
};
} // namespace hbase
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/pipeline.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/pipeline.cc b/hbase-native-client/connection/pipeline.cc
index edada52..d27c849 100644
--- a/hbase-native-client/connection/pipeline.cc
+++ b/hbase-native-client/connection/pipeline.cc
@@ -25,13 +25,15 @@
#include <wangle/codec/LengthFieldBasedFrameDecoder.h>
#include "connection/client-handler.h"
+#include "connection/sasl-handler.h"
using namespace folly;
using namespace hbase;
using namespace wangle;
-RpcPipelineFactory::RpcPipelineFactory(std::shared_ptr<Codec> codec)
- : user_util_(), codec_(codec) {}
+RpcPipelineFactory::RpcPipelineFactory(std::shared_ptr<Codec> codec,
+ std::shared_ptr<Configuration> conf)
+ : user_util_(), codec_(codec), conf_(conf) {}
SerializePipeline::Ptr RpcPipelineFactory::newPipeline(
std::shared_ptr<AsyncTransportWrapper> sock) {
@@ -41,8 +43,10 @@ SerializePipeline::Ptr RpcPipelineFactory::newPipeline(
auto pipeline = SerializePipeline::create();
pipeline->addBack(AsyncSocketHandler{sock});
pipeline->addBack(EventBaseHandler{});
+ auto secure = security::User::IsSecurityEnabled(*conf_);
+ pipeline->addBack(SaslHandler{user_util_.user_name(secure), conf_});
pipeline->addBack(LengthFieldBasedFrameDecoder{});
- pipeline->addBack(ClientHandler{user_util_.user_name(), codec_, addr.describe()});
+ pipeline->addBack(ClientHandler{user_util_.user_name(secure), codec_, addr.describe()});
pipeline->finalize();
return pipeline;
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/pipeline.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/pipeline.h b/hbase-native-client/connection/pipeline.h
index ea40cfd..add7fe5 100644
--- a/hbase-native-client/connection/pipeline.h
+++ b/hbase-native-client/connection/pipeline.h
@@ -25,6 +25,7 @@
#include "connection/request.h"
#include "connection/response.h"
+#include "core/configuration.h"
#include "serde/codec.h"
#include "utils/user-util.h"
@@ -41,7 +42,7 @@ class RpcPipelineFactory : public wangle::PipelineFactory<SerializePipeline> {
/**
* Constructor. This will create user util.
*/
- explicit RpcPipelineFactory(std::shared_ptr<Codec> codec);
+ explicit RpcPipelineFactory(std::shared_ptr<Codec> codec, std::shared_ptr<Configuration> conf);
/**
* Create a new pipeline.
@@ -57,5 +58,6 @@ class RpcPipelineFactory : public wangle::PipelineFactory<SerializePipeline> {
private:
UserUtil user_util_;
std::shared_ptr<Codec> codec_;
+ std::shared_ptr<Configuration> conf_;
};
} // namespace hbase
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/rpc-client.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/rpc-client.cc b/hbase-native-client/connection/rpc-client.cc
index 5fa1138..57df66d 100644
--- a/hbase-native-client/connection/rpc-client.cc
+++ b/hbase-native-client/connection/rpc-client.cc
@@ -30,9 +30,10 @@ using hbase::RpcClient;
namespace hbase {
RpcClient::RpcClient(std::shared_ptr<wangle::IOThreadPoolExecutor> io_executor,
- std::shared_ptr<Codec> codec, nanoseconds connect_timeout)
- : io_executor_(io_executor) {
- cp_ = std::make_shared<ConnectionPool>(io_executor_, codec, connect_timeout);
+ std::shared_ptr<Codec> codec, std::shared_ptr<Configuration> conf,
+ nanoseconds connect_timeout)
+ : io_executor_(io_executor), conf_(conf) {
+ cp_ = std::make_shared<ConnectionPool>(io_executor_, codec, conf, connect_timeout);
}
void RpcClient::Close() { io_executor_->stop(); }
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/rpc-client.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/rpc-client.h b/hbase-native-client/connection/rpc-client.h
index d416ceb..fbb773a 100644
--- a/hbase-native-client/connection/rpc-client.h
+++ b/hbase-native-client/connection/rpc-client.h
@@ -46,7 +46,7 @@ namespace hbase {
class RpcClient {
public:
RpcClient(std::shared_ptr<wangle::IOThreadPoolExecutor> io_executor, std::shared_ptr<Codec> codec,
- nanoseconds connect_timeout = nanoseconds(0));
+ std::shared_ptr<Configuration> conf, nanoseconds connect_timeout = nanoseconds(0));
virtual ~RpcClient() { Close(); }
@@ -78,5 +78,6 @@ class RpcClient {
private:
std::shared_ptr<ConnectionPool> cp_;
std::shared_ptr<wangle::IOThreadPoolExecutor> io_executor_;
+ std::shared_ptr<Configuration> conf_;
};
} // namespace hbase
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/sasl-handler.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/sasl-handler.cc b/hbase-native-client/connection/sasl-handler.cc
new file mode 100644
index 0000000..02cddce
--- /dev/null
+++ b/hbase-native-client/connection/sasl-handler.cc
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ *
+ */
+#include "connection/sasl-handler.h"
+
+#include <glog/logging.h>
+#include <sasl/sasl.h>
+#include <sasl/saslplug.h>
+#include <sasl/saslutil.h>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <wangle/channel/Handler.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <utility>
+
+#include "connection/service.h"
+#include "security/user.h"
+using hbase::security::User;
+
+using std::chrono::nanoseconds;
+using namespace folly;
+using namespace wangle;
+using namespace hbase;
+
+SaslHandler::SaslHandler(std::string user_name, std::shared_ptr<Configuration> conf)
+ : user_name_(user_name) {
+ host_name_.clear();
+ secure_ = User::IsSecurityEnabled(*conf);
+ service_name_ = SaslUtil::ParseServiceName(conf, secure_);
+ sasl_connection_setup_started_.clear();
+ sasl_connection_setup_in_progress_.store(true);
+}
+
+SaslHandler::SaslHandler(const SaslHandler &hdlr) {
+ user_name_ = hdlr.user_name_;
+ service_name_ = hdlr.service_name_;
+ secure_ = hdlr.secure_;
+ host_name_ = hdlr.host_name_;
+ // copy-constructor sets the flags below to their initial state as opposed to getting them
+ // from the object this class is constructed from. That way, this instance is ready to do
+ // sasl stuff without issues, right from the SaslInit. Sharing a sasl session is not useful
+ // between two handler instances.
+ sasl_connection_setup_started_.clear();
+ sasl_connection_setup_in_progress_.store(true);
+ sconn_ = nullptr;
+}
+
+SaslHandler::~SaslHandler() {
+ if (nullptr != sconn_) {
+ sasl_dispose(&sconn_);
+ }
+ sconn_ = nullptr;
+}
+
+void SaslHandler::transportActive(Context *ctx) {
+ // assign hostname; needed for the sasl handshake if secure
+ folly::SocketAddress address;
+ ctx->getTransport()->getPeerAddress(&address);
+ host_name_ = address.getHostStr();
+
+ // now init the sasl library; this is once per process
+ if (secure_) {
+ sasl_util_.InitializeSaslLib();
+ }
+ // write the preamble to kick off the RPC handshake
+ VLOG(3) << "Writing RPC connection Preamble to server: " << host_name_;
+ auto preamble = RpcSerde::Preamble(secure_);
+ ctx->fireWrite(std::move(preamble));
+}
+
+void SaslHandler::read(Context *ctx, folly::IOBufQueue &buf) {
+ // if security is not on, or in case of security-on, if secure connection setup not in progress,
+ // pass it up without touching
+ if (!secure_ || !sasl_connection_setup_in_progress_.load()) {
+ ctx->fireRead(buf);
+ } else {
+ // message is for this handler; process it appropriately
+ ContinueSaslNegotiation(ctx, &buf);
+ }
+}
+
+folly::Future<folly::Unit> SaslHandler::write(Context *ctx, std::unique_ptr<folly::IOBuf> buf) {
+ // if security is on, and if secure connection setup in progress,
+ // this message is for this handler to process and respond
+ if (secure_ && sasl_connection_setup_in_progress_.load()) {
+ // store IOBuf which is to be sent to server after SASL handshake
+ iobuf_.push_back(std::move(buf));
+ if (!sasl_connection_setup_started_.test_and_set()) {
+ // for the first incoming RPC from the higher layer, trigger sasl initialization
+ return SaslInit(ctx);
+ } else {
+ // for the subsequent incoming RPCs from the higher layer, just return empty future
+ folly::Promise<folly::Unit> p_;
+ return p_.getFuture();
+ }
+ }
+ // pass the bytes recieved down without touching it
+ return ctx->fireWrite(std::move(buf));
+}
+
+folly::Future<folly::Unit> SaslHandler::WriteSaslOutput(Context *ctx, const char *out,
+ unsigned int outlen) {
+ int buffer_size = outlen + 4;
+ auto iob = IOBuf::create(buffer_size);
+ iob->append(buffer_size);
+ // Create the array output stream.
+ google::protobuf::io::ArrayOutputStream aos{iob->writableData(), buffer_size};
+ std::unique_ptr<google::protobuf::io::CodedOutputStream> coded_output =
+ std::make_unique<google::protobuf::io::CodedOutputStream>(&aos);
+ uint32_t total_size = outlen;
+ total_size = ntohl(total_size);
+ coded_output->WriteRaw(&total_size, 4);
+ coded_output->WriteRaw(out, outlen);
+ return ctx->fireWrite(std::move(iob));
+}
+
+void SaslHandler::FinishAuth(Context *ctx, folly::IOBufQueue* bufQueue) {
+ std::unique_ptr<folly::IOBuf> iob;
+ if (!bufQueue->empty()) {
+ iob = bufQueue->pop_front();
+ throw std::runtime_error("Error in the final step of handshake " +
+ std::string(reinterpret_cast<const char *>(iob->data())));
+ } else {
+ sasl_connection_setup_in_progress_.store(false);
+ // write what we buffered
+ for (size_t i = 0; i < iobuf_.size(); i++) {
+ iob = std::move(iobuf_.at(i));
+ ctx->fireWrite(std::move(iob));
+ }
+ }
+}
+
+folly::Future<folly::Unit> SaslHandler::SaslInit(Context *ctx) {
+ int rc;
+ const char *mechusing, *mechlist = "GSSAPI";
+ const char *out;
+ unsigned int outlen;
+
+ rc = sasl_client_new(service_name_.c_str(), /* The service we are using*/
+ host_name_.c_str(), NULL,
+ NULL, /* Local and remote IP address strings
+ (NULL disables mechanisms which require this info)*/
+ NULL, /*connection-specific callbacks*/
+ 0 /*security flags*/, &sconn_);
+ if (rc != SASL_OK) {
+ LOG(FATAL) << "Cannot create client (" << rc << ") ";
+ throw std::runtime_error("Cannot create client");
+ }
+ int curr_rc;
+ do {
+ curr_rc = sasl_client_start(sconn_, /* the same context from above */
+ mechlist, /* the list of mechanisms from the server */
+ NULL, /* filled in if an interaction is needed */
+ &out, /* filled in on success */
+ &outlen, /* filled in on success */
+ &mechusing);
+ } while (curr_rc == SASL_INTERACT); /* the mechanism may ask us to fill
+ in things many times. result is SASL_CONTINUE on success */
+ if (curr_rc != SASL_CONTINUE) {
+ throw std::runtime_error("Cannot start client (" + std::to_string(curr_rc) + ")");
+ }
+ folly::Future<folly::Unit> fut = WriteSaslOutput(ctx, out, outlen);
+ return fut;
+}
+
+void SaslHandler::ContinueSaslNegotiation(Context *ctx, folly::IOBufQueue* bufQueue) {
+ const char *out;
+ unsigned int outlen;
+
+ int bytes_sent = 0;
+ int bytes_received = 0;
+
+ std::unique_ptr<folly::IOBuf> iob = bufQueue->pop_front();
+ bytes_received = iob->length();
+ if (bytes_received == 0) {
+ throw std::runtime_error("Error in sasl handshake");
+ }
+ folly::io::RWPrivateCursor c(iob.get());
+ std::uint32_t status = c.readBE<std::uint32_t>();
+ std::uint32_t sz = c.readBE<std::uint32_t>();
+
+ if (status != 0 /*Status 0 is success*/) {
+ // Assumption here is that the response from server is not more than 8 * 1024
+ throw std::runtime_error("Error in sasl handshake " +
+ std::string(reinterpret_cast<char *>(c.writableData())));
+ }
+ out = nullptr;
+ outlen = 0;
+
+ int curr_rc =
+ sasl_client_step(sconn_, /* our context */
+ reinterpret_cast<char *>(c.writableData()), /* the data from the server */
+ sz, /* its length */
+ NULL, /* this should be unallocated and NULL */
+ &out, /* filled in on success */
+ &outlen); /* filled in on success */
+
+ if (curr_rc == SASL_OK || curr_rc == SASL_CONTINUE) {
+ WriteSaslOutput(ctx, out, outlen);
+ }
+ if (curr_rc == SASL_OK) {
+ FinishAuth(ctx, bufQueue);
+ }
+}
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/sasl-handler.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/sasl-handler.h b/hbase-native-client/connection/sasl-handler.h
new file mode 100644
index 0000000..f606a23
--- /dev/null
+++ b/hbase-native-client/connection/sasl-handler.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ *
+ */
+#pragma once
+
+#include <glog/logging.h>
+#include <sasl/sasl.h>
+#include <sasl/saslplug.h>
+#include <sasl/saslutil.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "connection/sasl-util.h"
+#include "connection/service.h"
+#include "security/user.h"
+#include "serde/rpc.h"
+
+namespace hbase {
+
+/**
+ * Class to perform SASL handshake with server (currently works with regionserver principals only)
+ * It is inserted between EventBaseHandler and LengthFieldBasedFrameDecoder in the pipeline
+ * SaslHandler would intercept writes to server by buffering the IOBuf's and start the handshake
+ * process
+ * (via sasl_client_XX calls provided by Cyrus)
+ * After handshake is complete, SaslHandler would send the buffered IOBuf's to server and
+ * act as pass-thru from then on
+ */
+class SaslHandler
+ : public wangle::HandlerAdapter<folly::IOBufQueue&, std::unique_ptr<folly::IOBuf>> {
+ public:
+ explicit SaslHandler(std::string user_name, std::shared_ptr<Configuration> conf);
+ SaslHandler(const SaslHandler& hdlr);
+ ~SaslHandler();
+
+ // from HandlerAdapter
+ void read(Context* ctx, folly::IOBufQueue& buf) override;
+ folly::Future<folly::Unit> write(Context* ctx, std::unique_ptr<folly::IOBuf> buf) override;
+ void transportActive(Context* ctx) override;
+
+ private:
+ // used by Cyrus
+ sasl_conn_t* sconn_ = nullptr;
+ std::string user_name_;
+ std::string service_name_;
+ std::string host_name_;
+ bool secure_;
+ std::atomic_flag sasl_connection_setup_started_;
+ std::atomic<bool> sasl_connection_setup_in_progress_{true};
+ // vector of folly::IOBuf which buffers client writes before handshake is complete
+ std::vector<std::unique_ptr<folly::IOBuf>> iobuf_;
+ SaslUtil sasl_util_;
+
+ // writes the output returned by sasl_client_XX to server
+ folly::Future<folly::Unit> WriteSaslOutput(Context* ctx, const char* out, unsigned int outlen);
+ folly::Future<folly::Unit> SaslInit(Context* ctx);
+ void FinishAuth(Context* ctx, folly::IOBufQueue* bufQueue);
+ void ContinueSaslNegotiation(Context* ctx, folly::IOBufQueue* buf);
+ std::string ParseServiceName(std::shared_ptr<Configuration> conf, bool secure);
+};
+} // namespace hbase
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/sasl-util.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/sasl-util.cc b/hbase-native-client/connection/sasl-util.cc
new file mode 100644
index 0000000..ecaf015
--- /dev/null
+++ b/hbase-native-client/connection/sasl-util.cc
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ */
+#include "connection/sasl-util.h"
+
+#include <glog/logging.h>
+#include <sasl/sasl.h>
+#include <sasl/saslplug.h>
+#include <sasl/saslutil.h>
+
+#include <string>
+
+int SaslUtil::GetPluginPath(void *context __attribute__((unused)), const char **path) {
+ *path = getenv("SASL_PATH");
+
+ if (*path == NULL) {
+ *path = kDefaultPluginDir;
+ }
+ return SASL_OK;
+}
+
+void *SaslUtil::MutexNew(void) {
+ auto m = new std::mutex();
+ return m;
+}
+
+int SaslUtil::MutexLock(void *m) {
+ (reinterpret_cast<std::mutex *>(m))->lock();
+ return SASL_OK;
+}
+
+int SaslUtil::MutexUnlock(void *m) {
+ (reinterpret_cast<std::mutex *>(m))->unlock();
+ return SASL_OK;
+}
+
+void SaslUtil::MutexDispose(void *m) {
+ std::mutex *mutex = reinterpret_cast<std::mutex *>(m);
+ delete mutex;
+}
+
+std::once_flag SaslUtil::library_inited_;
+
+void SaslUtil::InitializeSaslLib() {
+ std::call_once(library_inited_, []() {
+ sasl_set_mutex(reinterpret_cast<sasl_mutex_alloc_t *>(&SaslUtil::MutexNew),
+ reinterpret_cast<sasl_mutex_lock_t *>(&SaslUtil::MutexLock),
+ reinterpret_cast<sasl_mutex_unlock_t *>(&SaslUtil::MutexUnlock),
+ reinterpret_cast<sasl_mutex_free_t *>(&SaslUtil::MutexDispose));
+ static sasl_callback_t callbacks[] = {
+ {SASL_CB_GETPATH, (sasl_callback_ft)&SaslUtil::GetPluginPath, NULL},
+ {SASL_CB_LIST_END, NULL, NULL}};
+ int rc = sasl_client_init(callbacks);
+ if (rc != SASL_OK) {
+ throw std::runtime_error("Cannot initialize client " + std::to_string(rc));
+ }
+ });
+}
+
+std::string SaslUtil::ParseServiceName(std::shared_ptr<hbase::Configuration> conf, bool secure) {
+ if (!secure) {
+ return std::string();
+ }
+ std::string svrPrincipal = conf->Get(kServerPrincipalConfKey, "");
+ // principal is of this form: hbase/23a03935850c@EXAMPLE.COM
+ // where 23a03935850c is the host (optional)
+ std::size_t pos = svrPrincipal.find("/");
+ if (pos == std::string::npos && svrPrincipal.find("@") != std::string::npos) {
+ pos = svrPrincipal.find("@");
+ }
+ if (pos == std::string::npos) {
+ throw std::runtime_error("Couldn't retrieve service principal from conf");
+ }
+ VLOG(1) << "pos " << pos << " " << svrPrincipal;
+ std::string service_name = svrPrincipal.substr(0, pos);
+ return service_name;
+}
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/connection/sasl-util.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/connection/sasl-util.h b/hbase-native-client/connection/sasl-util.h
new file mode 100644
index 0000000..4d58d9ee
--- /dev/null
+++ b/hbase-native-client/connection/sasl-util.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ */
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <string>
+
+#include "core/configuration.h"
+
+class SaslUtil {
+ public:
+ void InitializeSaslLib(void);
+ static std::string ParseServiceName(std::shared_ptr<hbase::Configuration> conf, bool secure);
+
+ private:
+ static constexpr const char *kDefaultPluginDir = "/usr/lib/sasl2";
+ // for now the sasl handler is hardcoded to work against the regionservers only. In the future, if
+ // we
+ // need the master rpc to work, we could have a map of service names to principals to use (similar
+ // to the Java implementation)
+ static constexpr const char *kServerPrincipalConfKey = "hbase.regionserver.kerberos.principal";
+
+ static int GetPluginPath(void *context, const char **path);
+ static void *MutexNew(void);
+ static int MutexLock(void *m);
+ static int MutexUnlock(void *m);
+ static void MutexDispose(void *m);
+ static std::once_flag library_inited_;
+};
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/core/BUCK
----------------------------------------------------------------------
diff --git a/hbase-native-client/core/BUCK b/hbase-native-client/core/BUCK
index e9fc716..9cea1f6 100644
--- a/hbase-native-client/core/BUCK
+++ b/hbase-native-client/core/BUCK
@@ -92,7 +92,9 @@ cxx_library(
"//third-party:zookeeper_mt",
],
compiler_flags=['-Weffc++', '-ggdb'],
- visibility=['PUBLIC',],)
+ visibility=[
+ 'PUBLIC',
+ ],)
cxx_library(
name="conf",
exported_headers=[
@@ -105,10 +107,14 @@ cxx_library(
],
deps=["//third-party:folly"],
compiler_flags=['-Weffc++', '-ggdb'],
- visibility=['PUBLIC',],)
+ visibility=[
+ 'PUBLIC',
+ ],)
cxx_test(
name="location-cache-test",
- srcs=["location-cache-test.cc",],
+ srcs=[
+ "location-cache-test.cc",
+ ],
deps=[
":core",
"//test-util:test-util",
@@ -116,12 +122,18 @@ cxx_test(
run_test_separately=True,)
cxx_test(
name="cell-test",
- srcs=["cell-test.cc",],
- deps=[":core",],
+ srcs=[
+ "cell-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_test(
name="filter-test",
- srcs=["filter-test.cc",],
+ srcs=[
+ "filter-test.cc",
+ ],
deps=[
":core",
"//if:if",
@@ -131,17 +143,27 @@ cxx_test(
run_test_separately=True,)
cxx_test(
name="get-test",
- srcs=["get-test.cc",],
- deps=[":core",],
+ srcs=[
+ "get-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_test(
name="put-test",
- srcs=["put-test.cc",],
- deps=[":core",],
+ srcs=[
+ "put-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_test(
name="retry-test",
- srcs=["async-rpc-retrying-test.cc",],
+ srcs=[
+ "async-rpc-retrying-test.cc",
+ ],
deps=[
":core",
"//test-util:test-util",
@@ -150,32 +172,54 @@ cxx_test(
run_test_separately=True,)
cxx_test(
name="time-range-test",
- srcs=["time-range-test.cc",],
- deps=[":core",],
+ srcs=[
+ "time-range-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_test(
name="configuration-test",
- srcs=["configuration-test.cc",],
- deps=[":core",],
+ srcs=[
+ "configuration-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_test(
name="hbase-configuration-test",
- srcs=["hbase-configuration-test.cc",],
- deps=[":core",],
+ srcs=[
+ "hbase-configuration-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_test(
name="scan-test",
- srcs=["scan-test.cc",],
- deps=[":core",],
+ srcs=[
+ "scan-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_test(
name="result-test",
- srcs=["result-test.cc",],
- deps=[":core",],
+ srcs=[
+ "result-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_test(
name="request-converter-test",
- srcs=["request-converter-test.cc",],
+ srcs=[
+ "request-converter-test.cc",
+ ],
deps=[
":core",
"//connection:connection",
@@ -184,7 +228,9 @@ cxx_test(
run_test_separately=True,)
cxx_test(
name="client-test",
- srcs=["client-test.cc",],
+ srcs=[
+ "client-test.cc",
+ ],
deps=[
":core",
"//if:if",
@@ -194,10 +240,16 @@ cxx_test(
run_test_separately=True,)
cxx_test(
name="zk-util-test",
- srcs=["zk-util-test.cc",],
- deps=[":core",],
+ srcs=[
+ "zk-util-test.cc",
+ ],
+ deps=[
+ ":core",
+ ],
run_test_separately=True,)
cxx_binary(
name="simple-client",
- srcs=["simple-client.cc",],
+ srcs=[
+ "simple-client.cc",
+ ],
deps=[":core", "//connection:connection"],)
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/core/async-connection.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/core/async-connection.cc b/hbase-native-client/core/async-connection.cc
index 4642c61..ef945fb 100644
--- a/hbase-native-client/core/async-connection.cc
+++ b/hbase-native-client/core/async-connection.cc
@@ -44,8 +44,8 @@ void AsyncConnectionImpl::Init() {
} else {
LOG(WARNING) << "Not using RPC Cell Codec";
}
- rpc_client_ =
- std::make_shared<hbase::RpcClient>(io_executor_, codec, connection_conf_->connect_timeout());
+ rpc_client_ = std::make_shared<hbase::RpcClient>(io_executor_, codec, conf_,
+ connection_conf_->connect_timeout());
location_cache_ =
std::make_shared<hbase::LocationCache>(conf_, cpu_executor_, rpc_client_->connection_pool());
caller_factory_ =
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/core/async-rpc-retrying-test.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/core/async-rpc-retrying-test.cc b/hbase-native-client/core/async-rpc-retrying-test.cc
index 487c34c..11750eb 100644
--- a/hbase-native-client/core/async-rpc-retrying-test.cc
+++ b/hbase-native-client/core/async-rpc-retrying-test.cc
@@ -317,7 +317,8 @@ void runTest(std::shared_ptr<AsyncRegionLocatorBase> region_locator, std::string
auto io_executor_ = client.async_connection()->io_executor();
auto retry_executor_ = std::make_shared<wangle::IOThreadPoolExecutor>(1);
auto codec = std::make_shared<hbase::KeyValueCodec>();
- auto rpc_client = std::make_shared<RpcClient>(io_executor_, codec);
+ auto rpc_client =
+ std::make_shared<RpcClient>(io_executor_, codec, AsyncRpcRetryTest::test_util->conf());
// auto retry_event_base_ = std::make_shared<folly::ScopedEventBaseThread>(true);
std::shared_ptr<folly::HHWheelTimer> retry_timer =
folly::HHWheelTimer::newTimer(retry_executor_->getEventBase());
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/core/location-cache-test.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/core/location-cache-test.cc b/hbase-native-client/core/location-cache-test.cc
index 8d1ac5f..3253c56 100644
--- a/hbase-native-client/core/location-cache-test.cc
+++ b/hbase-native-client/core/location-cache-test.cc
@@ -52,7 +52,7 @@ TEST_F(LocationCacheTest, TestGetMetaNodeContents) {
auto cpu = std::make_shared<wangle::CPUThreadPoolExecutor>(4);
auto io = std::make_shared<wangle::IOThreadPoolExecutor>(4);
auto codec = std::make_shared<KeyValueCodec>();
- auto cp = std::make_shared<ConnectionPool>(io, codec);
+ auto cp = std::make_shared<ConnectionPool>(io, codec, LocationCacheTest::test_util_->conf());
LocationCache cache{LocationCacheTest::test_util_->conf(), cpu, cp};
auto f = cache.LocateMeta();
auto result = f.get();
@@ -68,7 +68,7 @@ TEST_F(LocationCacheTest, TestGetRegionLocation) {
auto cpu = std::make_shared<wangle::CPUThreadPoolExecutor>(4);
auto io = std::make_shared<wangle::IOThreadPoolExecutor>(4);
auto codec = std::make_shared<KeyValueCodec>();
- auto cp = std::make_shared<ConnectionPool>(io, codec);
+ auto cp = std::make_shared<ConnectionPool>(io, codec, LocationCacheTest::test_util_->conf());
LocationCache cache{LocationCacheTest::test_util_->conf(), cpu, cp};
// If there is no table this should throw an exception
@@ -87,7 +87,7 @@ TEST_F(LocationCacheTest, TestCaching) {
auto cpu = std::make_shared<wangle::CPUThreadPoolExecutor>(4);
auto io = std::make_shared<wangle::IOThreadPoolExecutor>(4);
auto codec = std::make_shared<KeyValueCodec>();
- auto cp = std::make_shared<ConnectionPool>(io, codec);
+ auto cp = std::make_shared<ConnectionPool>(io, codec, LocationCacheTest::test_util_->conf());
LocationCache cache{LocationCacheTest::test_util_->conf(), cpu, cp};
auto tn_1 = folly::to<hbase::pb::TableName>("t1");
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/docker-files/Dockerfile
----------------------------------------------------------------------
diff --git a/hbase-native-client/docker-files/Dockerfile b/hbase-native-client/docker-files/Dockerfile
new file mode 100644
index 0000000..c5f47ad
--- /dev/null
+++ b/hbase-native-client/docker-files/Dockerfile
@@ -0,0 +1,88 @@
+##
+# 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.
+
+FROM pjameson/buck-folly-watchman:20160511
+
+ARG CC=/usr/bin/gcc-5
+ARG CXX=/usr/bin/g++-5
+ARG CFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0 -fPIC -g -fno-omit-frame-pointer -O2 -pthread"
+ARG CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0 -fPIC -g -fno-omit-frame-pointer -O2 -pthread"
+
+ENV JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64/"
+
+RUN wget ftp://ftp.cyrusimap.org/cyrus-sasl/cyrus-sasl-2.1.26.tar.gz ; \
+ tar zxf cyrus-sasl-2.1.26.tar.gz ; \
+ cd cyrus-sasl-2.1.26 ; \
+ ./configure ; \
+ make ; \
+ make install ;\
+ cp /usr/local/lib/sasl2/* /usr/lib/sasl2/
+
+RUN apt-get install -y vim maven inetutils-ping python-pip doxygen graphviz clang-format && \
+ pip install yapf && \
+ apt-get -qq clean && \
+ apt-get -y -qq autoremove && \
+ rm -rf /var/lib/{apt,dpkg,cache,log}/ && \
+ rm -rf /tmp/*
+
+RUN apt-get update && \
+ apt-get install -y debconf-utils debconf-set-selections && \
+ echo "krb5-config krb5-config/kerberos_servers string localhost" | debconf-set-selections ; \
+ echo "krb5-config krb5-config/admin_server string localhost" | debconf-set-selections ; \
+ echo "krb5-config krb5-config/add_servers_realm string EXAMPLE.COM" | debconf-set-selections ; \
+ echo "krb5-config krb5-config/default_realm string EXAMPLE.COM" | debconf-set-selections ; \
+ apt-get install -y krb5-kdc krb5-admin-server ; \
+ echo "admin" > /tmp/krb-realm.pass ; \
+ echo "admin" >> /tmp/krb-realm.pass ; \
+ krb5_newrealm < /tmp/krb-realm.pass ; \
+ echo "addprinc hbase" > /tmp/krb-princ.pass ; \
+ echo "admin" >> /tmp/krb-princ.pass ; \
+ echo "admin" >> /tmp/krb-princ.pass ; \
+ kadmin.local < /tmp/krb-princ.pass ; \
+ echo 'addprinc hbase/securecluster' > /tmp/krb-princ.pass; echo 'admin' >> /tmp/krb-princ.pass ; \
+ rm hbase-host.keytab ; echo 'admin' >> /tmp/krb-princ.pass ; \
+ echo 'xst -k hbase-host.keytab hbase/securecluster@EXAMPLE.COM' >> /tmp/krb-princ.pass ; \
+ kadmin.local < /tmp/krb-princ.pass ;
+COPY docker-files/krb5.conf /etc
+
+RUN git clone https://github.com/google/protobuf.git /usr/src/protobuf && \
+ cd /usr/src/protobuf/ && \
+ git checkout 2.7.0 && \
+ mkdir gmock && \
+ ldconfig && \
+ ./autogen.sh && \
+ ./configure && \
+ make && \
+ make install && \
+ make clean && \
+ rm -rf .git && \
+ cd /usr/src && \
+ wget http://www-us.apache.org/dist/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gz && \
+ tar zxf zookeeper-3.4.8.tar.gz && \
+ rm -rf zookeeper-3.4.8.tar.gz && \
+ cd zookeeper-3.4.8 && \
+ cd src/c && \
+ ldconfig && \
+ ./configure && \
+ make && \
+ make install && \
+ make clean && \
+ ldconfig
+
+ENTRYPOINT /usr/sbin/krb5kdc -P /var/run/krb5kdc.pid && /bin/bash
+
+WORKDIR /usr/src/hbase/hbase-native-client
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/docker-files/krb5.conf
----------------------------------------------------------------------
diff --git a/hbase-native-client/docker-files/krb5.conf b/hbase-native-client/docker-files/krb5.conf
new file mode 100644
index 0000000..d449928
--- /dev/null
+++ b/hbase-native-client/docker-files/krb5.conf
@@ -0,0 +1,20 @@
+[logging]
+ default = FILE:/var/log/krb5libs.log
+ kdc = FILE:/var/log/krb5kdc.log
+ admin_server = FILE:/var/log/kadmind.log
+
+[libdefaults]
+ default_realm = EXAMPLE.COM
+ dns_lookup_realm = false
+ dns_lookup_kdc = false
+ ticket_lifetime = 24h
+ renew_lifetime = 7d
+ forwardable = true
+ rdns = false
+
+[realms]
+EXAMPLE.COM = {
+kdc = localhost
+admin_server = localhost
+}
+[domain_realm]
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/security/BUCK
----------------------------------------------------------------------
diff --git a/hbase-native-client/security/BUCK b/hbase-native-client/security/BUCK
index 7383028..f8a5695 100644
--- a/hbase-native-client/security/BUCK
+++ b/hbase-native-client/security/BUCK
@@ -19,8 +19,12 @@
# to a single server.
cxx_library(
name="security",
- exported_headers=["user.h",],
+ exported_headers=[
+ "user.h",
+ ],
srcs=[],
deps=["//core:conf"],
compiler_flags=['-Weffc++'],
- visibility=['//core/...', '//connection/...'],)
+ visibility=[
+ 'PUBLIC',
+ ],)
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/security/user.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/security/user.h b/hbase-native-client/security/user.h
index 035af31..307fc61 100644
--- a/hbase-native-client/security/user.h
+++ b/hbase-native-client/security/user.h
@@ -18,6 +18,7 @@
*/
#pragma once
+#include <glog/logging.h>
#include <mutex>
#include <string>
#include "core/configuration.h"
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/serde/BUCK
----------------------------------------------------------------------
diff --git a/hbase-native-client/serde/BUCK b/hbase-native-client/serde/BUCK
index 38e7b4d..18e949c 100644
--- a/hbase-native-client/serde/BUCK
+++ b/hbase-native-client/serde/BUCK
@@ -31,7 +31,9 @@ cxx_library(
"rpc.cc",
"zk.cc",
],
- deps=["//if:if", "//third-party:folly", "//utils:utils"],
+ deps=[
+ "//if:if", "//third-party:folly", "//utils:utils", "//security:security"
+ ],
tests=[
":client-deserializer-test",
":client-serializer-test",
@@ -41,28 +43,54 @@ cxx_library(
":region-info-deserializer-test",
],
compiler_flags=['-Weffc++'],
- visibility=['PUBLIC',],)
+ visibility=[
+ 'PUBLIC',
+ ],)
cxx_test(
name="table-name-test",
- srcs=["table-name-test.cc",],
- deps=[":serde",],)
+ srcs=[
+ "table-name-test.cc",
+ ],
+ deps=[
+ ":serde",
+ ],)
cxx_test(
name="server-name-test",
- srcs=["server-name-test.cc",],
- deps=[":serde",],)
+ srcs=[
+ "server-name-test.cc",
+ ],
+ deps=[
+ ":serde",
+ ],)
cxx_test(
name="client-serializer-test",
- srcs=["client-serializer-test.cc",],
- deps=[":serde",],)
+ srcs=[
+ "client-serializer-test.cc",
+ ],
+ deps=[
+ ":serde",
+ ],)
cxx_test(
name="client-deserializer-test",
- srcs=["client-deserializer-test.cc",],
- deps=[":serde",],)
+ srcs=[
+ "client-deserializer-test.cc",
+ ],
+ deps=[
+ ":serde",
+ ],)
cxx_test(
name="zk-deserializer-test",
- srcs=["zk-deserializer-test.cc",],
- deps=[":serde",],)
+ srcs=[
+ "zk-deserializer-test.cc",
+ ],
+ deps=[
+ ":serde",
+ ],)
cxx_test(
name="region-info-deserializer-test",
- srcs=["region-info-deserializer-test.cc",],
- deps=[":serde",],)
+ srcs=[
+ "region-info-deserializer-test.cc",
+ ],
+ deps=[
+ ":serde",
+ ],)
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/serde/client-serializer-test.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/serde/client-serializer-test.cc b/hbase-native-client/serde/client-serializer-test.cc
index 33c48f3..7d8b29c 100644
--- a/hbase-native-client/serde/client-serializer-test.cc
+++ b/hbase-native-client/serde/client-serializer-test.cc
@@ -33,7 +33,7 @@ using namespace folly::io;
TEST(RpcSerdeTest, PreambleIncludesHBas) {
RpcSerde ser{nullptr};
- auto buf = ser.Preamble();
+ auto buf = ser.Preamble(false);
const char *p = reinterpret_cast<const char *>(buf->data());
// Take the first for chars and make sure they are the
// magic string
@@ -44,7 +44,7 @@ TEST(RpcSerdeTest, PreambleIncludesHBas) {
TEST(RpcSerdeTest, PreambleIncludesVersion) {
RpcSerde ser{nullptr};
- auto buf = ser.Preamble();
+ auto buf = ser.Preamble(false);
EXPECT_EQ(0, static_cast<const uint8_t *>(buf->data())[4]);
EXPECT_EQ(80, static_cast<const uint8_t *>(buf->data())[5]);
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/serde/rpc.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/serde/rpc.cc b/hbase-native-client/serde/rpc.cc
index e657a64..968cd5b 100644
--- a/hbase-native-client/serde/rpc.cc
+++ b/hbase-native-client/serde/rpc.cc
@@ -50,6 +50,7 @@ static const std::string PREAMBLE = "HBas";
static const std::string INTERFACE = "ClientService";
static const uint8_t RPC_VERSION = 0;
static const uint8_t DEFAULT_AUTH_TYPE = 80;
+static const uint8_t KERBEROS_AUTH_TYPE = 81;
int RpcSerde::ParseDelimited(const IOBuf *buf, Message *msg) {
if (buf == nullptr || msg == nullptr) {
@@ -85,17 +86,21 @@ int RpcSerde::ParseDelimited(const IOBuf *buf, Message *msg) {
return coded_stream.CurrentPosition();
}
-RpcSerde::RpcSerde(std::shared_ptr<Codec> codec) : auth_type_(DEFAULT_AUTH_TYPE), codec_(codec) {}
+RpcSerde::RpcSerde(std::shared_ptr<Codec> codec) : codec_(codec) {}
-unique_ptr<IOBuf> RpcSerde::Preamble() {
+std::unique_ptr<IOBuf> RpcSerde::Preamble(bool secure) {
auto magic = IOBuf::copyBuffer(PREAMBLE, 0, 2);
magic->append(2);
RWPrivateCursor c(magic.get());
c.skip(4);
// Version
c.write(RPC_VERSION);
- // Standard security aka Please don't lie to me.
- c.write(auth_type_);
+ if (secure) {
+ // for now support only KERBEROS (DIGEST is not supported)
+ c.write(KERBEROS_AUTH_TYPE);
+ } else {
+ c.write(DEFAULT_AUTH_TYPE);
+ }
return magic;
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/serde/rpc.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/serde/rpc.h b/hbase-native-client/serde/rpc.h
index abebe94..15aa1ee 100644
--- a/hbase-native-client/serde/rpc.h
+++ b/hbase-native-client/serde/rpc.h
@@ -68,7 +68,7 @@ class RpcSerde {
/**
* Create a new connection preamble in a new IOBuf.
*/
- std::unique_ptr<folly::IOBuf> Preamble();
+ static std::unique_ptr<folly::IOBuf> Preamble(bool secure);
/**
* Create the header protobuf object and serialize it to a new IOBuf.
@@ -119,7 +119,6 @@ class RpcSerde {
private:
/* data */
- uint8_t auth_type_;
std::shared_ptr<Codec> codec_;
std::unique_ptr<pb::VersionInfo> CreateVersionInfo();
};
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/third-party/BUCK
----------------------------------------------------------------------
diff --git a/hbase-native-client/third-party/BUCK b/hbase-native-client/third-party/BUCK
index f37eb4e..418323b 100644
--- a/hbase-native-client/third-party/BUCK
+++ b/hbase-native-client/third-party/BUCK
@@ -91,7 +91,8 @@ wangle = add_system_libs(
genrule(
name="gen_zk",
out="gen_zk",
- bash="mkdir -p $OUT && wget http://www-us.apache.org/dist/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gz && tar zxf zookeeper-3.4.8.tar.gz && rm -rf zookeeper-3.4.8.tar.gz && cd zookeeper-3.4.8 && cd src/c && ./configure --prefix=$OUT && make && make install && cd $OUT && rm -rf zookeeper-3.4.8*"
+ bash=
+ "mkdir -p $OUT && wget http://www-us.apache.org/dist/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gz && tar zxf zookeeper-3.4.8.tar.gz && rm -rf zookeeper-3.4.8.tar.gz && cd zookeeper-3.4.8 && cd src/c && ./configure --prefix=$OUT && make && make install && cd $OUT && rm -rf zookeeper-3.4.8*"
)
cxx_library(
name='google-test',
@@ -112,4 +113,6 @@ cxx_library(
('googletest/googlemock', 'src/*.cc'),
]),
exported_deps=dynamic_rules,
- visibility=['PUBLIC',],)
+ visibility=[
+ 'PUBLIC',
+ ],)
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/utils/BUCK
----------------------------------------------------------------------
diff --git a/hbase-native-client/utils/BUCK b/hbase-native-client/utils/BUCK
index 04e2b67..ed8e114 100644
--- a/hbase-native-client/utils/BUCK
+++ b/hbase-native-client/utils/BUCK
@@ -26,15 +26,29 @@ cxx_library(
"version.h",
],
srcs=["bytes-util.cc", "connection-util.cc", "user-util.cc"],
- deps=['//third-party:folly',],
+ deps=[
+ '//third-party:folly',
+ ],
tests=[":user-util-test"],
- visibility=['PUBLIC',],
+ linker_flags=['-L/usr/local/lib', '-lkrb5'],
+ exported_linker_flags=['-L/usr/local/lib', '-lkrb5'],
+ visibility=[
+ 'PUBLIC',
+ ],
compiler_flags=['-Weffc++'],)
cxx_test(
name="user-util-test",
- srcs=["user-util-test.cc",],
- deps=[":utils",],)
+ srcs=[
+ "user-util-test.cc",
+ ],
+ deps=[
+ ":utils",
+ ],)
cxx_test(
name="bytes-util-test",
- srcs=["bytes-util-test.cc",],
- deps=[":utils",],)
+ srcs=[
+ "bytes-util-test.cc",
+ ],
+ deps=[
+ ":utils",
+ ],)
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/utils/user-util-test.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/utils/user-util-test.cc b/hbase-native-client/utils/user-util-test.cc
index 7c11d8c..aa3fa45 100644
--- a/hbase-native-client/utils/user-util-test.cc
+++ b/hbase-native-client/utils/user-util-test.cc
@@ -28,7 +28,7 @@ using namespace hbase;
TEST(TestUserUtil, TestGetSomething) {
UserUtil u_util;
- string name = u_util.user_name();
+ string name = u_util.user_name(false);
// TODO shell out to whoami to check this.
ASSERT_GT(name.length(), 0);
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/utils/user-util.cc
----------------------------------------------------------------------
diff --git a/hbase-native-client/utils/user-util.cc b/hbase-native-client/utils/user-util.cc
index 9e170e0..71f0012 100644
--- a/hbase-native-client/utils/user-util.cc
+++ b/hbase-native-client/utils/user-util.cc
@@ -20,6 +20,7 @@
#include "utils/user-util.h"
#include <folly/Logging.h>
+#include <krb5/krb5.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
@@ -27,14 +28,14 @@
using namespace hbase;
using namespace std;
-UserUtil::UserUtil() : once_flag_{}, user_name_{"drwho"} {}
+UserUtil::UserUtil() : once_flag_{} {}
-string UserUtil::user_name() {
- std::call_once(once_flag_, [this]() { compute_user_name(); });
+string UserUtil::user_name(bool secure) {
+ std::call_once(once_flag_, [this, secure]() { compute_user_name(secure); });
return user_name_;
}
-void UserUtil::compute_user_name() {
+void UserUtil::compute_user_name(bool secure) {
// According to the man page of getpwuid
// this should never be free'd
//
@@ -45,4 +46,32 @@ void UserUtil::compute_user_name() {
if (passwd && passwd->pw_name) {
user_name_ = string{passwd->pw_name};
}
+ if (!secure) return;
+ krb5_context ctx;
+ krb5_error_code ret = krb5_init_context(&ctx);
+ if (ret != 0) {
+ throw std::runtime_error("cannot init krb ctx " + std::to_string(ret));
+ }
+ krb5_ccache ccache;
+ ret = krb5_cc_default(ctx, &ccache);
+ if (ret != 0) {
+ throw std::runtime_error("cannot get default cache " + std::to_string(ret));
+ }
+ // Here is sample principal: hbase/23a03935850c@EXAMPLE.COM
+ // There may be one (user) or two (user/host) components before the @ sign
+ krb5_principal princ;
+ ret = krb5_cc_get_principal(ctx, ccache, &princ);
+ if (ret != 0) {
+ throw std::runtime_error("cannot get default principal " + std::to_string(ret));
+ }
+ user_name_ = princ->data->data;
+ if (krb5_princ_size(ctx, princ) >= 2) {
+ user_name_ += "/";
+ user_name_ += static_cast<char *>(princ->data[1].data);
+ }
+ user_name_ += "@";
+ user_name_ += princ->realm.data;
+ VLOG(1) << "user " << user_name_;
+ krb5_free_principal(ctx, princ);
+ krb5_free_context(ctx);
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/517090a0/hbase-native-client/utils/user-util.h
----------------------------------------------------------------------
diff --git a/hbase-native-client/utils/user-util.h b/hbase-native-client/utils/user-util.h
index 6f8fce1..6258c85 100644
--- a/hbase-native-client/utils/user-util.h
+++ b/hbase-native-client/utils/user-util.h
@@ -41,13 +41,13 @@ class UserUtil {
* Get the username of the user owning this process. This is thread safe and
* lockless for every invocation other than the first one.
*/
- std::string user_name();
+ std::string user_name(bool secure = false);
private:
/**
* Compute the username. This will block.
*/
- void compute_user_name();
+ void compute_user_name(bool secure);
std::once_flag once_flag_;
std::string user_name_;
};