[tests] test 'kudu table scan' against column privileges
This patch adds a new test scenario to verify that the
'kudu table scan ... --columns=...' CLI tool behaves as expected when
the access to a table is controlled by a fine-grained Ranger policy
granting access to particular columns only.
Change-Id: I11953680fc8c3f576b677f9e3e31d057fc2d2b34
Reviewed-on: http://gerrit.cloudera.org:8080/18936
Tested-by: Kudu Jenkins
Reviewed-by: Abhishek Chennaka <achennaka@cloudera.com>
Reviewed-by: Yifan Zhang <chinazhangyifan@163.com>
diff --git a/src/kudu/integration-tests/ts_authz-itest.cc b/src/kudu/integration-tests/ts_authz-itest.cc
index a83054a..96cfe65 100644
--- a/src/kudu/integration-tests/ts_authz-itest.cc
+++ b/src/kudu/integration-tests/ts_authz-itest.cc
@@ -18,10 +18,12 @@
#include <cstdint>
#include <cstdlib>
#include <functional>
+#include <initializer_list>
#include <memory>
#include <ostream>
#include <string>
#include <thread>
+#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
@@ -44,15 +46,18 @@
#include "kudu/integration-tests/data_gen_util.h"
#include "kudu/integration-tests/external_mini_cluster-itest-base.h"
#include "kudu/master/master.pb.h"
-#include "kudu/master/master.proxy.h"
+#include "kudu/master/master.proxy.h" // IWYU pragma: keep
#include "kudu/mini-cluster/external_mini_cluster.h"
#include "kudu/ranger/mini_ranger.h"
#include "kudu/ranger/ranger.pb.h"
#include "kudu/rpc/rpc_controller.h"
#include "kudu/security/test/mini_kdc.h"
#include "kudu/tablet/ops/write_op.h"
+#include "kudu/tools/tool_test_util.h"
#include "kudu/util/barrier.h"
+#include "kudu/util/bitset.h"
#include "kudu/util/monotime.h"
+#include "kudu/util/net/net_util.h"
#include "kudu/util/random.h"
#include "kudu/util/random_util.h"
#include "kudu/util/scoped_cleanup.h"
@@ -88,6 +93,7 @@
using kudu::rpc::RpcController;
using kudu::tablet::WritePrivileges;
using kudu::tablet::WritePrivilegeType;
+using kudu::tools::RunKuduTool;
using std::pair;
using std::string;
using std::thread;
@@ -667,6 +673,79 @@
ASSERT_OK(PerformScan({ another_column }, nullptr, table.get()));
}
+TEST_P(TSAuthzITest, TableScanCLI) {
+ SKIP_IF_SLOW_NOT_ALLOWED();
+
+ static const string kTableName = "table";
+ const string table_ident = Substitute("$0.$1", kDb, kTableName);
+ const string user = "user0";
+ ASSERT_OK(cluster_->kdc()->CreateUserPrincipal(user));
+ ASSERT_OK(cluster_->kdc()->Kinit(user));
+
+ ASSERT_OK(CreateTable(table_ident, user));
+
+ // Note: we only need privileges on the metadata for OpenTable() calls.
+ ASSERT_OK(harness_->GrantTablePrivilege(
+ kDb, kTableName, user, "METADATA", /*admin=*/false, cluster_));
+ ASSERT_OK(harness_->GrantColumnPrivilege(
+ kDb, kTableName, "col0", user, "SELECT", /*admin=*/false, cluster_));
+
+ vector<string> master_addrs;
+ for (const auto& hp : cluster_->master_rpc_addrs()) {
+ master_addrs.emplace_back(hp.ToString());
+ }
+ const auto master_addrs_str = JoinStrings(master_addrs, ",");
+
+ // Should successfully scan data in column 'col0' since granted privileged
+ // explicitly.
+ {
+ string out;
+ string err;
+ const vector<string> args{ "table",
+ "scan",
+ master_addrs_str,
+ table_ident,
+ "--columns=col0"
+ };
+ const auto s = RunKuduTool(args, &out, &err);
+ ASSERT_TRUE(s.ok()) << s.ToString() << " stderr: " << err;
+ }
+
+ // Should not be able to scan data in other columns than column 'col0' since
+ // no privilege has been granted on those.
+ for (const auto& columns : { "col1", "col0,col1", "col1,col0",
+ "col2", "col0,col2", "col2,col0",
+ "col1,col2", "col0,col1,col2", "*" }) {
+ string out;
+ string err;
+ const vector<string> args{ "table",
+ "scan",
+ master_addrs_str,
+ table_ident,
+ Substitute("--columns=$0", columns),
+ };
+ const auto s = RunKuduTool(args, &out, &err);
+ ASSERT_TRUE(s.IsRuntimeError()) << s.ToString() << " stderr: " << err;
+ ASSERT_STR_CONTAINS(s.ToString(), "process exited with non-zero status");
+ ASSERT_STR_CONTAINS(err, "Not authorized: not authorized to Scan");
+ }
+
+ // Should not be able to scan data if trying to access all the columns.
+ {
+ string out;
+ string err;
+ const vector<string> args{ "table",
+ "scan",
+ master_addrs_str,
+ table_ident,
+ };
+ const auto s = RunKuduTool(args, &out, &err);
+ ASSERT_TRUE(s.IsRuntimeError()) << s.ToString() << " stderr: " << err;
+ ASSERT_STR_CONTAINS(s.ToString(), "process exited with non-zero status");
+ ASSERT_STR_CONTAINS(err, "Not authorized: not authorized to Scan");
+ }
+}
+
INSTANTIATE_TEST_SUITE_P(AuthzProviders, TSAuthzITest,
::testing::Values(kRanger),
[] (const testing::TestParamInfo<TSAuthzITest::ParamType>& info) {