YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/yql/cql/ql/test/ql-role-test.cc
Line
Count
Source (jump to first uncovered line)
1
//--------------------------------------------------------------------------------------------------
2
// Copyright (c) YugaByte, Inc.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
// in compliance with the License.  You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software distributed under the License
10
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
// or implied.  See the License for the specific language governing permissions and limitations
12
// under the License.
13
//
14
//--------------------------------------------------------------------------------------------------
15
16
#include <gflags/gflags.h>
17
#include <gtest/gtest.h>
18
19
#include "yb/client/client.h"
20
#include "yb/client/permissions.h"
21
22
#include "yb/common/ql_value.h"
23
24
#include "yb/gutil/strings/substitute.h"
25
26
#include "yb/master/mini_master.h"
27
28
#include "yb/util/crypt.h"
29
#include "yb/util/status_log.h"
30
31
#include "yb/yql/cql/ql/test/ql-test-base.h"
32
33
DECLARE_bool(use_cassandra_authentication);
34
35
constexpr const char* const kDefaultCassandraUsername = "cassandra";
36
37
namespace yb {
38
namespace master {
39
class CatalogManager;
40
class Master;
41
}
42
namespace ql {
43
44
using yb::util::kBcryptHashSize;
45
using yb::util::bcrypt_hashpw;
46
using yb::util::bcrypt_checkpw;
47
using strings::Substitute;
48
using std::string;
49
50
#define EXEC_DUPLICATE_CREATE_ROLE_STMT(stmt)                           \
51
0
  EXEC_INVALID_STMT_WITH_ERROR(stmt, "Duplicate Role. ")
52
53
static const char invalid_grant_describe_error_msg[] =
54
    "Resource type DataResource does not support any of the requested permissions";
55
static const std::vector<string> all_permissions =
56
    {"ALTER", "AUTHORIZE", "CREATE", "DESCRIBE", "DROP", "MODIFY", "SELECT"};
57
static const std::vector<string> all_permissions_minus_describe =
58
    {"ALTER", "AUTHORIZE", "CREATE", "DROP", "MODIFY", "SELECT"};
59
static const std::vector<string> all_permissions_for_all_roles =
60
    {"ALTER", "AUTHORIZE", "CREATE", "DESCRIBE", "DROP"};
61
static const std::vector<string> all_permissions_for_keyspace =
62
    {"ALTER", "AUTHORIZE", "CREATE", "DROP", "MODIFY", "SELECT"};
63
static const std::vector<string> all_permissions_for_table =
64
    {"ALTER", "AUTHORIZE", "DROP", "MODIFY", "SELECT"};
65
static const std::vector<string> all_permissions_for_role =
66
    {"ALTER", "AUTHORIZE", "DROP"};
67
68
class QLTestAuthentication : public QLTestBase {
69
 public:
70
0
  QLTestAuthentication() : QLTestBase(), permissions_cache_(client_.get(), false) {}
71
72
0
  virtual void SetUp() override {
73
0
    QLTestBase::SetUp();
74
0
  }
75
76
0
  virtual void TearDown() override {
77
0
    QLTestBase::TearDown();
78
0
  }
79
80
0
  uint64_t GetPermissionsVersion() {
81
0
    CHECK_OK(client_->GetPermissions(&permissions_cache_));
82
0
    boost::optional<uint64_t> version = permissions_cache_.version();
83
0
    CHECK(version);
84
0
    return *version;
85
0
  }
86
87
  // Used to execute any statement that can modify a role (add/remove/update) or a permission.
88
  // It automatically verifies that the roles-version in the master equals to what we expect.
89
0
  void ExecuteValidModificationStmt(TestQLProcessor* processor, const string& stmt) {
90
0
    ASSERT_OK(processor->Run(stmt));
91
0
    version_++;
92
0
    if (stmt.substr(0, 4) == "DROP" || stmt.substr(0, 6) == "CREATE") {
93
      // These statements increment the role version twice, because they either grant or revoke
94
      // permissions.
95
0
      version_++;
96
0
    }
97
0
    ASSERT_EQ(GetPermissionsVersion(), version_);
98
0
  }
99
100
0
  inline const string CreateStmt(string params) {
101
0
    return "CREATE ROLE " + params;
102
0
  }
103
104
0
  inline const string CreateIfNotExistsStmt(string params) {
105
0
    return "CREATE ROLE IF NOT EXISTS " + params;
106
0
  }
107
108
0
  inline const string DropStmt(string params) {
109
0
    return "DROP ROLE " + params;
110
0
  }
111
112
0
  inline const string DropIfExistsStmt(string params) {
113
0
    return "DROP ROLE IF EXISTS " + params;
114
0
  }
115
116
0
  static const string GrantStmt(const string& role, const string& recipient) {
117
0
    return Substitute("GRANT $0 TO $1", role, recipient);
118
0
  }
119
120
0
  static const string RevokeStmt(const string& role, const string& recipient) {
121
0
    return Substitute("REVOKE $0 FROM $1", role, recipient);
122
0
  }
123
124
0
  void CreateRole(TestQLProcessor* processor, const string& role_name) {
125
126
    // SUPERUSER = false because otherwise we can't really revoke permissions.
127
0
    const string create_stmt = Substitute(
128
0
        "CREATE ROLE $0 WITH LOGIN = TRUE AND SUPERUSER = FALSE AND PASSWORD = 'TEST';", role_name);
129
0
    ExecuteValidModificationStmt(processor, create_stmt);
130
0
  }
131
132
0
  void GrantRole(TestQLProcessor* processor, const string& role, const string& recipient) {
133
0
    const string grant_stmt = GrantStmt(role, recipient);
134
0
    ExecuteValidModificationStmt(processor, grant_stmt);
135
0
  }
136
137
  // Executes a revoke role command that fails silently.
138
0
  void RevokeRoleIgnored(TestQLProcessor* processor, const string& role, const string& recipient) {
139
0
    const string revoke_stmt = RevokeStmt(role, recipient);
140
0
    ASSERT_OK(processor->Run(revoke_stmt));
141
0
  }
142
143
0
  void RevokeRole(TestQLProcessor* processor, const string& role, const string& recipient) {
144
0
    const string revoke_stmt = RevokeStmt(role, recipient);
145
0
    ExecuteValidModificationStmt(processor, revoke_stmt);
146
0
  }
147
148
0
  string SelectStmt(const string& role_name) const {
149
0
    return Substitute("SELECT * FROM system_auth.roles where role='$0';", role_name);
150
0
  }
151
152
 protected:
153
  uint64_t version_ = 0;
154
155
 private:
156
  client::internal::PermissionsCache permissions_cache_;
157
};
158
159
class TestQLPermission : public QLTestAuthentication {
160
 public:
161
0
  TestQLPermission() : QLTestAuthentication() {
162
0
    FLAGS_use_cassandra_authentication = true;
163
0
  }
164
165
  // Helper Functions
166
  void CreateTable(TestQLProcessor* processor, const string& keyspace_name,
167
0
                   const string& table_name) {
168
0
    const string create_stmt = Substitute(
169
0
        "CREATE TABLE $0.$1(id int, name varchar, primary key(id));", keyspace_name, table_name);
170
0
    Status s = processor->Run(create_stmt);
171
0
    CHECK(s.ok());
172
    // Creating a table grants all the permissions on the new table to the creator role, and this
173
    // increments role's version.
174
0
    version_++;
175
0
    ASSERT_EQ(GetPermissionsVersion(), version_);
176
0
  }
177
178
0
  void CreateKeyspace(TestQLProcessor* processor, const string& keyspace_name) {
179
0
    const string create_stmt = Substitute(
180
0
        "CREATE KEYSPACE $0;", keyspace_name);
181
0
    Status s = processor->Run(create_stmt);
182
0
    CHECK(s.ok());
183
    // Creating a keyspace grants all the permissions on the new keyspace to the creator role, and
184
    // this increments role's version.
185
0
    version_++;
186
0
    ASSERT_EQ(GetPermissionsVersion(), version_);
187
0
  }
188
189
0
  string GrantAllKeyspaces(const string& permission, const string& role_name) const {
190
0
    return Substitute("GRANT $0 ON ALL KEYSPACES TO $1;", permission, role_name);
191
0
  }
192
193
0
  string RevokeAllKeyspaces(const string& permission, const string& role_name) const {
194
0
    return Substitute("REVOKE $0 ON ALL KEYSPACES FROM $1;", permission, role_name);
195
0
  }
196
197
  string GrantKeyspace(const string& permission, const string& keyspace,
198
0
                            const string& role_name) const {
199
0
    return Substitute("GRANT $0 ON KEYSPACE $1 TO $2;", permission, keyspace, role_name);
200
0
  }
201
202
  string RevokeKeyspace(const string& permission, const string& keyspace,
203
0
                       const string& role_name) const {
204
0
    return Substitute("REVOKE $0 ON KEYSPACE $1 FROM $2;", permission, keyspace, role_name);
205
0
  }
206
207
0
  string GrantTable(const string& permission, const string& table, const string& role_name) const {
208
0
    return Substitute("GRANT $0 ON TABLE $1 TO $2;", permission, table, role_name);
209
0
  }
210
211
0
  string RevokeTable(const string& permission, const string& table, const string& role_name) const {
212
0
    return Substitute("REVOKE $0 ON TABLE $1 FROM $2;", permission, table, role_name);
213
0
  }
214
215
0
  string GrantAllRoles(const string& permission, const string& role_name) const {
216
0
    return Substitute("GRANT $0 ON ALL ROLES TO $1;", permission, role_name);
217
0
  }
218
219
0
  string RevokeAllRoles(const string& permission, const string& role_name) const {
220
0
    return Substitute("REVOKE $0 ON ALL ROLES FROM $1;", permission, role_name);
221
0
  }
222
223
  string GrantRole(const string& permission, const string& role_resource,
224
0
                   const string& role_name) const {
225
0
    return Substitute("GRANT $0 ON ROLE $1 TO $2;", permission, role_resource, role_name);
226
0
  }
227
228
0
  string SelectStmt(const string& role_name) const {
229
0
    return Substitute("SELECT * FROM system_auth.role_permissions where role='$0';", role_name);
230
0
  }
231
232
0
  string SelectStmt(const string& role_name, const string& resource) const {
233
0
    return Substitute(
234
0
        "SELECT * FROM system_auth.role_permissions where role='$0' AND resource='$1';",
235
0
        role_name, resource);
236
0
  }
237
238
  void CheckRowContents(const QLRow& row, const string& canonical_resource,
239
                        const std::vector<string> &permissions, const string& role_name) {
240
    EXPECT_EQ(role_name, row.column(0).string_value());
241
    EXPECT_EQ(canonical_resource, row.column(1).string_value());
242
243
    EXPECT_EQ(InternalType::kListValue, row.column(2).type());
244
    const QLSeqValuePB& list_value = row.column(2).list_value();
245
    EXPECT_EQ(permissions.size(), list_value.elems_size());
246
    // Create a set of the values:
247
    std::unordered_set<string> permissions_set;
248
    for (const auto& elem : list_value.elems()) {
249
      permissions_set.insert(elem.string_value());
250
    }
251
252
    for (const auto& permission : permissions) {
253
      EXPECT_TRUE(permissions_set.find(permission) != permissions_set.end());
254
    }
255
  }
256
257
  // Issues a GRANT or REVOKE PERMISSION statement and verifies that it was granted/revoked
258
  // correctly.
259
  void GrantRevokePermissionAndVerify(TestQLProcessor* processor, const string& stmt,
260
                                      const string& canonical_resource,
261
                                      const std::vector<string>& permissions,
262
0
                                      const RoleName& role_name) {
263
264
0
    LOG (INFO) << "Running statement " << stmt;
265
0
    ExecuteValidModificationStmt(processor, stmt);
266
267
0
    auto select = SelectStmt(role_name, canonical_resource);
268
0
    auto s = processor->Run(select);
269
0
    CHECK(s.ok());
270
0
    auto row_block = processor->row_block();
271
272
0
    if (permissions.empty()) {
273
0
      EXPECT_EQ(0, row_block->row_count());
274
0
      return;
275
0
    }
276
277
0
    EXPECT_EQ(1, row_block->row_count());
278
279
0
    QLRow &row = row_block->row(0);
280
0
    CheckRowContents(row, canonical_resource, permissions, role_name);
281
282
0
    std::unordered_map<std::string, uint64_t>  permission_map = {
283
0
        {"ALTER", PermissionType::ALTER_PERMISSION},
284
0
        {"CREATE", PermissionType::CREATE_PERMISSION},
285
0
        {"DROP", PermissionType::DROP_PERMISSION },
286
0
        {"SELECT", PermissionType::SELECT_PERMISSION},
287
0
        {"MODIFY", PermissionType::MODIFY_PERMISSION},
288
0
        {"AUTHORIZE", PermissionType::AUTHORIZE_PERMISSION},
289
0
        {"DESCRIBE", PermissionType::DESCRIBE_PERMISSION}
290
0
    };
291
292
0
    client::internal::PermissionsCache permissions_cache(client_.get(), false);
293
0
    ASSERT_OK(client_->GetPermissions(&permissions_cache));
294
295
0
    std::shared_ptr<client::internal::RolesPermissionsMap> roles_permissions_map =
296
0
        permissions_cache.get_roles_permissions_map();
297
298
0
    const auto& role_permissions_itr = roles_permissions_map->find(role_name);
299
300
    // Verify that the role exists in the cache.
301
0
    ASSERT_NE(role_permissions_itr, roles_permissions_map->end());
302
303
0
    const auto& role_permissions = role_permissions_itr->second;
304
305
0
    Permissions cached_permissions_bitset;
306
0
    if (canonical_resource == kRolesDataResource) {
307
0
      cached_permissions_bitset = role_permissions.all_keyspaces_permissions();
308
0
    } else if (canonical_resource == kRolesRoleResource) {
309
0
      cached_permissions_bitset = role_permissions.all_roles_permissions();
310
0
    } else {
311
      // Assert that the canonical resource exists in the cache.
312
0
      const auto& canonical_resource_itr =
313
0
          role_permissions.resource_permissions().find(canonical_resource);
314
0
      ASSERT_NE(canonical_resource_itr, role_permissions.resource_permissions().end());
315
316
0
      cached_permissions_bitset = canonical_resource_itr->second;
317
0
    }
318
319
0
    ASSERT_EQ(cached_permissions_bitset.count(), permissions.size());
320
0
    for (const string& expected_permission : permissions) {
321
0
      CHECK(cached_permissions_bitset.test(permission_map[expected_permission]))
322
0
          << "Permission " << expected_permission << " not set";
323
0
    }
324
325
0
    Permissions expected_permissions_bitset;
326
0
    for (const string& expected_permission : permissions) {
327
0
      if (expected_permission == "ALL") {
328
        // Set all the bits to 1.
329
0
        expected_permissions_bitset.set();
330
0
        break;
331
0
      }
332
0
      expected_permissions_bitset.set(permission_map[expected_permission]);
333
0
    }
334
335
0
    ASSERT_EQ(expected_permissions_bitset.to_ullong(), cached_permissions_bitset.to_ullong());
336
0
  }
337
338
};
339
340
0
TEST_F(TestQLPermission, TestGrantRevokeAll) {
341
342
  // Init the simulated cluster.
343
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
344
  // Get a processor.
345
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
346
  // Ensure permission granted to proper role.
347
0
  const string role_name = "test_role";
348
0
  const string role_name_2 = "test_role_2";
349
0
  const string role_name_3 = "test_role_3";
350
351
0
  CreateRole(processor, role_name);
352
0
  CreateRole(processor, role_name_2);
353
354
0
  const string canonical_resource_keyspaces = kRolesDataResource;
355
0
  const string grant_stmt = GrantAllKeyspaces("SELECT", role_name);
356
0
  std::vector<string> permissions_keyspaces = { "SELECT" };
357
358
0
  GrantRevokePermissionAndVerify(processor, grant_stmt, canonical_resource_keyspaces,
359
0
                                 permissions_keyspaces, role_name);
360
361
  // Ensure no permission granted to non-existent role.
362
0
  const string grant_stmt2 = GrantAllKeyspaces("MODIFY", role_name_3);
363
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt2, "Invalid Argument");
364
365
0
  LOG(INFO) << "Permissions version: " << GetPermissionsVersion();
366
367
  // Check multiple resources.
368
0
  const string canonical_resource_roles = kRolesRoleResource;
369
0
  const string grant_stmt3 = GrantAllRoles("DESCRIBE", role_name);
370
0
  std::vector<string> permissions_roles = { "DESCRIBE" };
371
0
  GrantRevokePermissionAndVerify(processor, grant_stmt3,
372
0
                                 canonical_resource_roles, permissions_roles, role_name);
373
374
0
  ExecuteValidModificationStmt(processor, grant_stmt3);
375
376
0
  auto select = SelectStmt(role_name);
377
0
  auto s = processor->Run(select);
378
0
  CHECK(s.ok());
379
380
0
  auto row_block = processor->row_block();
381
0
  EXPECT_EQ(2, row_block->row_count());  // 2 Resources found.
382
383
0
  QLRow& keyspaces_row = row_block->row(0);
384
0
  QLRow& roles_row = row_block->row(1);
385
0
  CheckRowContents(roles_row, canonical_resource_roles, permissions_roles, role_name);
386
0
  CheckRowContents(keyspaces_row, canonical_resource_keyspaces, permissions_keyspaces, role_name);
387
388
  // Grant another permission to test_role on all keyspaces.
389
0
  const auto grant_drop_all_keyspaces = GrantAllKeyspaces("DROP", role_name);
390
0
  permissions_keyspaces.push_back("DROP");
391
0
  GrantRevokePermissionAndVerify(processor, grant_drop_all_keyspaces, canonical_resource_keyspaces,
392
0
                                 permissions_keyspaces, role_name);
393
394
  // Revoke SELECT from test_role on all keyspaces.
395
0
  const auto revoke_select_all_keyspaces = RevokeAllKeyspaces("SELECT", role_name);
396
0
  permissions_keyspaces = { "DROP" };
397
0
  GrantRevokePermissionAndVerify(processor, revoke_select_all_keyspaces,
398
0
                                 canonical_resource_keyspaces, permissions_keyspaces, role_name);
399
400
  // Revoke DROP from test_role on all keyspaces.
401
0
  const auto revoke_drop_all_keyspaces = RevokeAllKeyspaces("DROP", role_name);
402
0
  permissions_keyspaces = {};
403
0
  GrantRevokePermissionAndVerify(processor, revoke_drop_all_keyspaces,
404
0
                                 canonical_resource_keyspaces, permissions_keyspaces, role_name);
405
406
  // Revoke DESCRIBE from test_role on all roles.
407
0
  const auto revoke_describe_all_roles = RevokeAllRoles("DESCRIBE", role_name);
408
0
  permissions_roles = {};
409
0
  GrantRevokePermissionAndVerify(processor, revoke_describe_all_roles,
410
0
                                 canonical_resource_roles, permissions_keyspaces, role_name);
411
412
0
  FLAGS_use_cassandra_authentication = false;
413
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt, "Unauthorized");
414
0
}
415
416
0
TEST_F(TestQLPermission, TestGrantRevokeKeyspace) {
417
  // Init the simulated cluster.
418
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
419
  // Get a processor.
420
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
421
422
0
  const string role_name = "test_role";
423
0
  const string keyspace1 = "keyspace1";
424
0
  CreateRole(processor, role_name);
425
0
  const string canonical_resource = "data/" + keyspace1;
426
0
  CreateKeyspace(processor, keyspace1);
427
428
0
  const string grant_stmt = GrantKeyspace("SELECT",  keyspace1, role_name);
429
0
  std::vector<string> permissions = { "SELECT" };
430
431
  // Ensure permission granted to proper role.
432
0
  GrantRevokePermissionAndVerify(processor, grant_stmt, canonical_resource, permissions,
433
0
                                 role_name);
434
435
  // Grant multiple permissions.
436
0
  const string grant_stmt2 = GrantKeyspace("MODIFY",  keyspace1, role_name);
437
0
  permissions.push_back("MODIFY");
438
0
  GrantRevokePermissionAndVerify(processor, grant_stmt2, canonical_resource, permissions,
439
0
                                 role_name);
440
441
0
  const string grant_stmt3 = GrantKeyspace("CREATE",  keyspace1, role_name);
442
0
  permissions.push_back("CREATE");
443
0
  GrantRevokePermissionAndVerify(processor, grant_stmt3, canonical_resource, permissions,
444
0
                                 role_name);
445
446
  // Revoke "CREATE" permission on keyspace1 from test_role.
447
0
  const auto revoke_create_stmt = RevokeKeyspace("CREATE", keyspace1, role_name);
448
0
  permissions.pop_back();
449
0
  GrantRevokePermissionAndVerify(processor, revoke_create_stmt, canonical_resource, permissions,
450
0
                                 role_name);
451
452
  // Revoke "MODIFY" permission on keyspace1 from test_role.
453
0
  const auto revoke_modify_stmt = RevokeKeyspace("MODIFY", keyspace1, role_name);
454
0
  permissions.pop_back();
455
0
  GrantRevokePermissionAndVerify(processor, revoke_modify_stmt, canonical_resource, permissions,
456
0
                                 role_name);
457
458
  // Invalid keyspace.
459
0
  const string keyspace2 = "keyspace2";
460
0
  const string grant_stmt4 = GrantKeyspace("ALTER", keyspace2, role_name);
461
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt4, "Resource Not Found");
462
463
0
  const string revoke_invalid_stmt = GrantKeyspace("ALTER", keyspace2, role_name);
464
0
  EXEC_INVALID_STMT_WITH_ERROR(revoke_invalid_stmt, "Resource Not Found");
465
466
  // Grant ALL permissions.
467
0
  const string role_name_2 = "test_role_2";
468
0
  CreateRole(processor, role_name_2);
469
0
  const string grant_stmt5 = GrantKeyspace("ALL",  keyspace1, role_name_2);
470
0
  GrantRevokePermissionAndVerify(processor, grant_stmt5, canonical_resource,
471
0
                                 all_permissions_for_keyspace, role_name_2);
472
473
  // Revoke all the permissions.
474
0
  const auto revoke_all_stmt = RevokeKeyspace("ALL", keyspace1, role_name_2);
475
0
  GrantRevokePermissionAndVerify(processor, revoke_all_stmt, canonical_resource, {}, role_name_2);
476
477
0
  FLAGS_use_cassandra_authentication = false;
478
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt, "Unauthorized");
479
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt4, "Unauthorized");
480
0
}
481
482
0
TEST_F(TestQLPermission, TestGrantToRole) {
483
  // Init the simulated cluster.
484
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
485
  // Get a processor.
486
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
487
0
  const string role_name = "test_role";
488
0
  const string role_name_2 = "test_role_2";
489
490
0
  CreateRole(processor, role_name);
491
0
  CreateRole(processor, role_name_2);
492
493
0
  const string canonical_resource = "roles/" + role_name_2;
494
0
  const string grant_stmt = GrantRole("AUTHORIZE", role_name_2, role_name);
495
0
  std::vector<string> permissions = { "AUTHORIZE" };
496
497
  // Ensure permission granted to proper role.
498
0
  GrantRevokePermissionAndVerify(processor, grant_stmt, canonical_resource, permissions, role_name);
499
500
  // Grant ALL permissions.
501
0
  const string grant_stmt2 = GrantRole("ALL", role_name_2, role_name);
502
0
  GrantRevokePermissionAndVerify(processor, grant_stmt2, canonical_resource,
503
0
                                 all_permissions_for_role, role_name);
504
505
  // Resource (role) not present.
506
0
  const string role_name_3 = "test_role_3";
507
0
  const string grant_stmt3 = GrantRole("DROP", role_name_3, role_name);
508
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt3, "Resource Not Found");
509
510
  // Lastly, create another role to verify that the roles version didn't change after all the
511
  // statements that didn't modify anything in the master.
512
0
  CreateRole(processor, "some_role");
513
514
0
  FLAGS_use_cassandra_authentication = false;
515
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt, "Unauthorized");
516
0
}
517
518
0
TEST_F(TestQLPermission, TestGrantRevokeTable) {
519
  // Init the simulated cluster.
520
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
521
  // Get a processor.
522
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
523
524
0
  const string role_name = "test_role";
525
0
  const string keyspace1 = "keyspace1";
526
0
  const string table1 = "table1";
527
528
0
  CreateRole(processor, role_name);
529
0
  CreateKeyspace(processor, keyspace1);
530
0
  CreateTable(processor, keyspace1, table1);
531
532
0
  const string canonical_resource = "data/" + keyspace1 + "/" + table1;
533
0
  const string table_name = keyspace1 + "." + table1;
534
535
  // Simple grant.
536
0
  const string grant_stmt = GrantTable("MODIFY", table_name, role_name);
537
0
  std::vector<string> permissions = { "MODIFY" };
538
539
  // Ensure permission granted to proper role.
540
0
  GrantRevokePermissionAndVerify(processor, grant_stmt, canonical_resource, permissions, role_name);
541
542
  // Grant with keyspace not provided.
543
0
  const auto grant_stmt2 = GrantTable("SELECT", "table1", role_name);
544
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt2, "Resource Not Found");
545
546
  // Grant with invalid keyspace.
547
0
  const string grant_stmt3 = GrantTable("SELECT", "keyspace2.table1", role_name);
548
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt3, "Resource Not Found");
549
550
  // Grant with invalid table.
551
0
  const string grant_stmt4 = GrantTable("SELECT", "keyspace1.table2", role_name);
552
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt4, "Resource Not Found");
553
554
  // Revoke with keyspace not provided.
555
0
  const auto invalid_revoke1 = RevokeTable("SELECT", "table1", role_name);
556
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_revoke1, "Resource Not Found");
557
558
  // Revoke with invalid keyspace.
559
0
  const auto invalid_revoke2 = RevokeTable("SELECT", "someKeyspace.table1", role_name);
560
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_revoke2, "Resource Not Found");
561
562
  // Revoke with invalid table.
563
0
  const auto invalid_revoke3 = RevokeTable("SELECT", "keyspace1.someTable", role_name);
564
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_revoke3, "Resource Not Found");
565
566
0
  const string revoke = RevokeTable("MODIFY", "keyspace1.table1", role_name);
567
  // No permissions on keyspace1.table1 should remain for role test_role.
568
0
  permissions = {};
569
0
  GrantRevokePermissionAndVerify(processor, revoke, canonical_resource, permissions, role_name);
570
571
  // Grant ALL permissions and verify that DESCRIBE is not granted.
572
0
  const string grant_stmt5 = GrantTable("ALL", table_name, role_name);
573
0
  GrantRevokePermissionAndVerify(processor, grant_stmt5, canonical_resource,
574
0
                                 all_permissions_for_table, role_name);
575
576
  // Lastly, create another role to verify that the roles version didn't change after all the
577
  // statements that didn't modify anything in the master.
578
0
  CreateRole(processor, "some_role");
579
580
0
  FLAGS_use_cassandra_authentication = false;
581
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt, "Unauthorized");
582
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt3, "Unauthorized");
583
0
}
584
585
0
TEST_F(TestQLPermission, TestGrantDescribe) {
586
  // Init the simulated cluster.
587
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
588
  // Get a processor.
589
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
590
591
0
  const string role1 = "test_role1";
592
0
  const string role2 = "test_role2";
593
0
  const string role3 = "test_role3";
594
0
  const string role4 = "test_role4";
595
0
  const string role5 = "test_role5";
596
0
  const string keyspace = "keyspace1";
597
0
  const string table = "table1";
598
599
0
  CreateRole(processor, role1);
600
0
  CreateRole(processor, role2);
601
0
  CreateRole(processor, role3);
602
0
  CreateRole(processor, role4);
603
0
  CreateRole(processor, role5);
604
0
  CreateKeyspace(processor, keyspace);
605
0
  CreateTable(processor, keyspace, table);
606
607
0
  const string canonical_resource = "data/" + keyspace + "/" + table;
608
0
  const string table_name = keyspace + "." + table;
609
610
  // Grant DESCRIBE on a table. It should fail.
611
0
  const string grant_stmt = GrantTable("DESCRIBE", table_name, role1);
612
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt, invalid_grant_describe_error_msg);
613
614
  // Grant DESCRIBE on a table that doesn't exist. It should fail with a syntax error.
615
0
  const string grant_on_invalid_table = GrantTable("DESCRIBE", "invalid_table", role1);
616
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_on_invalid_table, invalid_grant_describe_error_msg);
617
618
  // Grant DESCRIBE on a table to a role that doesn't exist. It should fail with a syntax error.
619
0
  const string grant_on_table_to_invalid_role = GrantTable("DESCRIBE", table_name, "some_role");
620
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_on_table_to_invalid_role, invalid_grant_describe_error_msg);
621
622
  // Grant DESCRIBE on a keyspace. It shold fail.
623
0
  const string grant_stmt2 = GrantKeyspace("DESCRIBE", keyspace, role1);
624
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_stmt2, invalid_grant_describe_error_msg);
625
626
  // Grant DESCRIBE on a keyspace that doesn't exist. It should fail with a syntax error.
627
0
  const string grant_on_invalid_keyspace = GrantKeyspace("DESCRIBE", "some_keyspace", role1);
628
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_on_invalid_keyspace, invalid_grant_describe_error_msg);
629
630
  // Grant DESCRIBE on a keyspace to a role that doesn't exist. It should fail with a syntax error.
631
0
  const string grant_on_keyspace_to_invalid_role = GrantKeyspace("DESCRIBE", keyspace, "some_role");
632
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_on_keyspace_to_invalid_role, invalid_grant_describe_error_msg);
633
634
  // Grant DESCRIBE on all keyspaces. It should fail.
635
0
  const string grant_on_all_keyspaces = GrantAllKeyspaces("DESCRIBE", role1);
636
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_on_all_keyspaces, invalid_grant_describe_error_msg);
637
638
  // Grant DESCRIBE on a role. It should fail.
639
0
  const string grant_on_role = GrantRole("DESCRIBE", role2, role1);
640
0
  EXEC_INVALID_STMT_WITH_ERROR(grant_on_role, invalid_grant_describe_error_msg);
641
642
  // Grant DESCRIBE on all roles. It should succeed.
643
0
  const string grant_on_all_roles = GrantAllRoles("DESCRIBE", role3);
644
0
  std::vector<string> permissions = {"DESCRIBE"};
645
0
  GrantRevokePermissionAndVerify(processor, grant_on_all_roles, kRolesRoleResource, permissions,
646
0
                                 role3);
647
648
  // Grant ALL on a role. It should succeed and all the appropriate permissions should be granted.
649
0
  const string grant_all_on_a_role = GrantRole("ALL", role4, role1);
650
0
  GrantRevokePermissionAndVerify(processor, grant_all_on_a_role,
651
0
                                 strings::Substitute("$0/$1", kRolesRoleResource, role4),
652
0
                                 all_permissions_for_role, role1);
653
654
  // Grant ALL on all roles. It should succeed and all the appropriate permissions should be
655
  // granted.
656
0
  const string grant_all_on_all_roles = GrantAllRoles("ALL", role5);
657
0
  GrantRevokePermissionAndVerify(processor, grant_all_on_all_roles, kRolesRoleResource,
658
0
                                 all_permissions_for_all_roles, role5);
659
0
}
660
661
class TestQLRole : public QLTestAuthentication {
662
 public:
663
0
  TestQLRole() : QLTestAuthentication() {
664
0
    FLAGS_use_cassandra_authentication = true;
665
0
  }
666
667
  // Check the granted roles for a role
668
  void CheckGrantedRoles(TestQLProcessor* processor, const string& role_name,
669
                  const std::unordered_set<string>& roles) {
670
    auto select = SelectStmt(role_name);
671
    Status s = processor->Run(select);
672
    CHECK(s.ok());
673
    auto row_block = processor->row_block();
674
    EXPECT_EQ(1, row_block->row_count());
675
676
    QLRow &row = row_block->row(0);
677
678
    EXPECT_EQ(InternalType::kListValue, row.column(3).type());
679
    QLSeqValuePB list_value = row.column(3).list_value();
680
    EXPECT_EQ(roles.size(), list_value.elems_size());
681
    for (int i = 0; i < list_value.elems_size(); i++) {
682
      EXPECT_TRUE(roles.find(list_value.elems(i).string_value()) != roles.end());
683
    }
684
  }
685
686
  void CheckCreateAndDropRole(TestQLProcessor* processor, const string& role_name,
687
                              const char* password, const bool is_superuser,
688
0
                              const bool can_login) {
689
690
0
    const string is_superuser_str = (is_superuser) ? "true" : "false";
691
0
    const string can_login_str = (can_login) ? "true" : "false";
692
0
    const string password_str = (password == nullptr) ? "" : Substitute(
693
0
        "AND PASSWORD =  '$0'", password);
694
695
    // Create the role
696
0
    const string create_stmt = Substitute(
697
0
        "CREATE ROLE $0 WITH LOGIN = $1 $3 AND SUPERUSER = $2;", role_name,
698
0
        can_login_str, is_superuser_str, password_str);
699
700
0
    ExecuteValidModificationStmt(processor, create_stmt);
701
702
0
    auto select = "SELECT * FROM system_auth.roles;";
703
0
    auto s = processor->Run(select);
704
0
    CHECK(s.ok());
705
0
    auto row_block = processor->row_block();
706
0
    EXPECT_EQ(2, row_block->row_count());
707
0
    QLRow &row = row_block->row(0);
708
709
0
    EXPECT_EQ(role_name, row.column(0).string_value());
710
0
    EXPECT_EQ(can_login, row.column(1).bool_value());
711
0
    EXPECT_EQ(is_superuser, row.column(2).bool_value());
712
713
0
    if (password  == nullptr) {
714
0
      EXPECT_TRUE(row.column(4).IsNull());
715
0
    } else {
716
0
      char hash[kBcryptHashSize];
717
0
      bcrypt_hashpw(password, hash);
718
0
      const auto &saved_hash = row.column(4).string_value();
719
0
      bool password_match = true;
720
0
      if (bcrypt_checkpw(password, saved_hash.c_str())) {
721
0
        password_match = false;
722
0
      }
723
0
      EXPECT_EQ(true, password_match);
724
0
    }
725
0
    const string drop_stmt = Substitute("DROP ROLE $0;", role_name);
726
0
    ExecuteValidModificationStmt(processor, drop_stmt);
727
728
    // Check that only default cassandra role exists
729
0
    auto select_after_drop = "SELECT * FROM system_auth.roles;";
730
0
    s = processor->Run(select_after_drop);
731
732
0
    CHECK(s.ok());
733
0
    auto row_block_after_drop = processor->row_block();
734
0
    EXPECT_EQ(1, row_block_after_drop->row_count());
735
0
    row = row_block_after_drop->row(0);
736
0
    EXPECT_EQ("cassandra", row.column(0).string_value());
737
0
  }
738
};
739
740
0
TEST_F(TestQLRole, TestGrantRole) {
741
  // Init the simulated cluster.
742
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
743
744
  // Get a processor.
745
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
746
0
  const string role_1 = "role1";
747
0
  const string role_2 = "role2";
748
0
  const string role_3 = "role3";
749
0
  const string role_4 = "role4";
750
0
  const string role_5 = "role5";
751
0
  const string role_6 = "role6";
752
0
  const string role_7 = "role7";
753
754
0
  CreateRole(processor, role_1);
755
0
  CreateRole(processor, role_2);
756
0
  CreateRole(processor, role_3);
757
758
0
  CreateRole(processor, role_5);
759
0
  CreateRole(processor, role_6);
760
0
  CreateRole(processor, role_7);
761
762
  // Single Role Granted
763
0
  GrantRole(processor, role_1, role_2);
764
0
  std::unordered_set<string> roles ( {role_1} );
765
0
  CheckGrantedRoles(processor, role_2, roles);
766
767
  // Multiple Roles Granted
768
0
  GrantRole(processor, role_3, role_2);
769
0
  roles.insert(role_3);
770
0
  CheckGrantedRoles(processor, role_2, roles);
771
772
0
  GrantRole(processor, role_5, role_3);
773
0
  GrantRole(processor, role_6, role_3);
774
0
  GrantRole(processor, role_7, role_5);
775
776
  // Same Grant Twice
777
0
  const string invalid_grant_1 = GrantStmt(role_1, role_2);
778
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_grant_1, Substitute("$0 is a member of $1", role_2, role_1));
779
780
  // Roles not present
781
0
  const string invalid_grant_2 = GrantStmt(role_1, role_4);
782
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_grant_2, Substitute("$0 doesn't exist", role_4));
783
784
0
  const string invalid_grant_3 = GrantStmt(role_4, role_2);
785
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_grant_3, Substitute("$0 doesn't exist", role_4));
786
787
0
  const auto invalid_circular_reference_grant = GrantStmt(role_1, role_1);
788
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_circular_reference_grant,
789
0
                               Substitute("$0 is a member of $1", role_1, role_1));
790
791
  // It should fail because role_3 was granted to role_2.
792
0
  const auto invalid_circular_reference_grant2 = GrantStmt(role_2, role_3);
793
  // The message is backwards, but that's what Apache Cassandra outputs.
794
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_circular_reference_grant2,
795
0
                               Substitute("$0 is a member of $1", role_3, role_2));
796
797
0
  CreateRole(processor, role_4);
798
  // Single Role Granted
799
0
  GrantRole(processor, role_4, role_3);
800
0
  roles = {role_4, role_5, role_6};
801
0
  CheckGrantedRoles(processor, role_3, roles);
802
803
  // It should fail because role_3 was granted to role_2, and role_4 granted to role3.
804
0
  const auto invalid_circular_reference_grant3 = GrantStmt(role_4, role_2);
805
  // The message is backwards, but that's what Apache Cassandra outputs.
806
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_circular_reference_grant3,
807
0
                               Substitute("$0 is a member of $1", role_2, role_4));
808
809
  // It should fail because role_4 was granted to role_3, and role_3 to role_2.
810
0
  const auto invalid_circular_reference_grant4 = GrantStmt(role_2, role_4);
811
  // The message is backwards, but that's what Apache Cassandra outputs.
812
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_circular_reference_grant4,
813
0
                               Substitute("$0 is a member of $1", role_4, role_2));
814
815
  // It should fail because role_7 -> role_5 -> role_3 -> role_2.
816
0
  const auto invalid_circular_reference_grant5 = GrantStmt(role_2, role_7);
817
  // The message is backwards, but that's what Apache Cassandra outputs.
818
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_circular_reference_grant5,
819
0
                               Substitute("$0 is a member of $1", role_7, role_2));
820
821
  // Lastly, create another role to verify that the roles version didn't change after all the
822
  // statements that didn't modify anything in the master.
823
0
  CreateRole(processor, "some_role");
824
0
}
825
826
0
TEST_F(TestQLRole, TestRevokeRole) {
827
  // Init the simulated cluster.
828
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
829
830
  // Get a processor.
831
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
832
0
  const string role1 = "role1";
833
0
  const string role2 = "role2";
834
0
  const string role3 = "role3";
835
0
  const string role4 = "role4";
836
0
  CreateRole(processor, role1);
837
0
  CreateRole(processor, role2);
838
0
  CreateRole(processor, role3);
839
840
  // Grant roles role1 and role3 to role2.
841
0
  GrantRole(processor, role1, role2);
842
0
  GrantRole(processor, role3, role2);
843
844
0
  std::unordered_set<string> roles ( {role1, role3} );
845
0
  CheckGrantedRoles(processor, role2, roles);
846
847
  // Revoke role1 from role2.
848
0
  RevokeRole(processor, role1, role2);
849
850
  // Verify that the only granted role to role2 is role3.
851
0
  roles = {role3};
852
0
  CheckGrantedRoles(processor, role2, roles);
853
854
  // Revoke the last granted role and verify it.
855
0
  RevokeRole(processor, role3, role2);
856
0
  roles = {};
857
0
  CheckGrantedRoles(processor, role2, roles);
858
859
  // Revoke role from itself. It should fail silently.
860
0
  RevokeRoleIgnored(processor, role1, role1);
861
862
  // Lastly, create another role to verify that the roles version didn't change after all the
863
  // statements that didn't modify anything in the master.
864
0
  CreateRole(processor, "some_role");
865
866
  // Try to revoke it again. It should fail.
867
0
  const auto invalid_revoke = RevokeStmt(role3, role2);
868
0
  EXEC_INVALID_STMT_WITH_ERROR(
869
0
      invalid_revoke, Substitute("$0 is not a member of $1", role2, role3));
870
0
}
871
872
0
TEST_F(TestQLRole, TestRoleQuerySimple) {
873
  // Init the simulated cluster.
874
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
875
876
  // Get a processor.
877
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
878
0
  CheckCreateAndDropRole(processor, "test_role1", "test_pw", true, true);
879
  // Test no password set
880
0
  CheckCreateAndDropRole(processor, "test_role2", nullptr, false, true);
881
0
}
882
883
0
TEST_F(TestQLRole, TestQLCreateRoleSimple) {
884
  // Init the simulated cluster.
885
0
  ASSERT_NO_FATALS (CreateSimulatedCluster());
886
887
  // Get an available processor.
888
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
889
890
  // Valid Create Role Statements
891
0
  const string role1 = "manager1;";
892
0
  const string role2 = "\"manager2\";";
893
0
  const string role3 = "'manager3';";
894
0
  const string role4 = "manager4 WITH PASSWORD = '!3@Ab' AND LOGIN = false AND SUPERUSER = true;";
895
0
  const string role5 = "manager5 WITH SUPERUSER = false AND PASSWORD =  '!3@Ab' AND LOGIN = true;";
896
0
  const string role6 = "manager6 WITH LOGIN = true;";
897
0
  const string role7 = "manager7 WITH PASSWORD = '!3@Ab';";
898
0
  const string role8 = "manager8 WITH SUPERUSER = true";
899
0
  const string role12 = "'mAnaGer3';";
900
901
  // Invalid Create Role Statements : Duplicate Attributes
902
0
  const string role9 = "manager9 WITH PASSWORD = '!3@Ab' AND PASSWORD = '!3@ss';";
903
0
  const string role10 = "manager10 WITH LOGIN = true AND PASSWORD = '!3@ss' and LOGIN = true;";
904
0
  const string role11 = "manager11 WITH SUPERUSER = false AND SUPERUSER = true;";
905
0
  const string role13 = "manager12 WITH LOGIN = true AND LOGIN = true;";
906
907
  // Options unsupported
908
0
  const string role14 = "manager13 WITH OPTIONS = { 'opt_1' : 'opt_val_1'};";
909
0
  const string role15 = "manager14 WITH SUPERUSER = false AND OPTIONS = { 'opt_1' : 'opt_val_1'};";
910
911
  // Create role1, role_name is simple identifier
912
0
  ExecuteValidModificationStmt(processor, CreateStmt(role1));
913
914
  // Create role2, role_name is quoted identifier
915
0
  ExecuteValidModificationStmt(processor, CreateStmt(role2));
916
917
  // Create role3, role_name is string
918
0
  ExecuteValidModificationStmt(processor, CreateStmt(role3));
919
920
  // Create role4, all attributes are present
921
0
  ExecuteValidModificationStmt(processor, CreateStmt(role4));
922
923
  // Create role5, permute the attributes
924
0
  ExecuteValidModificationStmt(processor, CreateStmt(role5));
925
926
  // Create role6, only attribute LOGIN
927
0
  ExecuteValidModificationStmt(processor, CreateStmt(role6));
928
929
  // Create role7, only attribute PASSWORD
930
0
  ExecuteValidModificationStmt(processor, CreateStmt(role7));
931
932
  // Create role8, only attribute SUPERUSER
933
0
  ExecuteValidModificationStmt(processor, CreateStmt(role8));
934
935
  // Create role12, role_name preserves capitalization
936
0
  ExecuteValidModificationStmt(processor, CreateStmt(role12));
937
938
  // Verify that all 'CREATE TABLE' statements fail for tables that have already been created.
939
940
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role1));
941
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role2));
942
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role3));
943
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role4));
944
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role5));
945
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role6));
946
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role7));
947
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role8));
948
0
  EXEC_DUPLICATE_CREATE_ROLE_STMT(CreateStmt(role12));
949
950
  // Verify that all 'CREATE TABLE IF EXISTS' statements succeed for tables that have already been
951
  // created.
952
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role1));
953
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role2));
954
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role3));
955
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role4));
956
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role5));
957
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role6));
958
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role7));
959
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role8));
960
0
  EXEC_VALID_STMT(CreateIfNotExistsStmt(role12));
961
962
  // Invalid Statements
963
0
  EXEC_INVALID_STMT_WITH_ERROR(CreateStmt(role9), "Invalid Role Definition");
964
0
  EXEC_INVALID_STMT_WITH_ERROR(CreateStmt(role10), "Invalid Role Definition");
965
0
  EXEC_INVALID_STMT_WITH_ERROR(CreateStmt(role11), "Invalid Role Definition");
966
0
  EXEC_INVALID_STMT_WITH_ERROR(CreateStmt(role13), "Invalid Role Definition");
967
968
  // Single role_option
969
0
  EXEC_INVALID_STMT_WITH_ERROR(CreateStmt(role14), "Feature Not Supported");
970
971
  // Multiple role_options
972
0
  EXEC_INVALID_STMT_WITH_ERROR(CreateStmt(role15), "Feature Not Supported");
973
974
  // Lastly, create another role to verify that the roles version didn't change after all the
975
  // statements that didn't modify anything in the master.
976
0
  CreateRole(processor, "another_role");
977
978
  // Flag Test:
979
0
  FLAGS_use_cassandra_authentication = false;;
980
0
  EXEC_INVALID_STMT_WITH_ERROR(CreateStmt(role4), "Unauthorized");  // Valid, but unauthorized
981
0
  EXEC_INVALID_STMT_WITH_ERROR(CreateStmt(role9), "Unauthorized");  // Invalid and unauthorized
982
0
}
983
984
0
TEST_F(TestQLRole, TestQLDropRoleSimple) {
985
  // Init the simulated cluster.
986
0
  ASSERT_NO_FATALS (CreateSimulatedCluster());
987
988
  // Get an available processor.
989
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
990
991
  // Valid Create Role Statements
992
0
  const string role1 = "manager1;";
993
0
  const string role2 = "\"manager2\";";
994
0
  const string role3 = "'manager3';";
995
996
0
  ExecuteValidModificationStmt(processor, CreateStmt(role1));        // Create role
997
0
  ExecuteValidModificationStmt(processor, CreateStmt(role2));        // Create role
998
0
  ExecuteValidModificationStmt(processor, CreateStmt(role3));        // Create role
999
1000
  // Check all variants of role_name
1001
0
  ExecuteValidModificationStmt(processor, DropStmt(role1));          // Drop role
1002
0
  ExecuteValidModificationStmt(processor, DropStmt(role2));          // Drop role
1003
0
  ExecuteValidModificationStmt(processor, DropStmt(role3));          // Drop role
1004
1005
  // Check if subsequent drop generates errors
1006
0
  EXEC_INVALID_STMT_WITH_ERROR(DropStmt(role1), "Role Not Found");
1007
0
  EXEC_INVALID_STMT_WITH_ERROR(DropStmt(role2), "Role Not Found");
1008
0
  EXEC_INVALID_STMT_WITH_ERROR(DropStmt(role3), "Role Not Found");
1009
1010
  // These statements will not change the roles' version in the master.
1011
0
  EXEC_VALID_STMT(DropIfExistsStmt(role1));   // Check if exists
1012
0
  EXEC_VALID_STMT(DropIfExistsStmt(role2));   // Check if exists
1013
0
  EXEC_VALID_STMT(DropIfExistsStmt(role3));   // Check if exists
1014
1015
  // Lastly, create another role to verify that the roles version didn't change after all the
1016
  // statements that didn't modify anything in the master.
1017
0
  CreateRole(processor, "some_role");
1018
1019
0
  FLAGS_use_cassandra_authentication = false;
1020
0
  EXEC_INVALID_STMT_WITH_ERROR(DropStmt(role1), "Unauthorized");
1021
0
}
1022
1023
// Test that whenever we remove a role, this role is removed from the member_of field of all the
1024
// other roles.
1025
0
TEST_F(TestQLRole, TestQLDroppedRoleIsRemovedFromMemberOfField) {
1026
  // Init the simulated cluster.
1027
0
  ASSERT_NO_FATALS (CreateSimulatedCluster());
1028
1029
  // Get an available processor.
1030
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
1031
1032
  // Valid Create Role Statements
1033
0
  const string role1 = "r1";
1034
0
  const string role2 = "r2";
1035
0
  const string role3 = "r3";
1036
1037
0
  CreateRole(processor, role1);
1038
0
  CreateRole(processor, role2);
1039
0
  CreateRole(processor, role3);
1040
1041
0
  GrantRole(processor, role1, role2);
1042
0
  std::unordered_set<string> roles ( {role1} );
1043
0
  CheckGrantedRoles(processor, role2, roles);
1044
1045
0
  GrantRole(processor, role1, role3);
1046
0
  CheckGrantedRoles(processor, role3, roles);
1047
1048
0
  ExecuteValidModificationStmt(processor, DropStmt(role1));          // Drop role
1049
1050
0
  roles = {};
1051
0
  CheckGrantedRoles(processor, role2, roles);
1052
1053
0
  roles = {};
1054
0
  CheckGrantedRoles(processor, role3, roles);
1055
0
}
1056
1057
// When a mutation doesn't get committed or aborted during a GRANT or REVOKE request, subsequent
1058
// requests will time out.
1059
0
TEST_F(TestQLRole, TestMutationsGetCommittedOrAborted) {
1060
  // Init the simulated cluster.
1061
0
  ASSERT_NO_FATALS(CreateSimulatedCluster());
1062
  // Get a processor.
1063
0
  TestQLProcessor* processor = GetQLProcessor(kDefaultCassandraUsername);
1064
  // Ensure permission granted to proper role
1065
0
  const string role1 = "test_role_1";
1066
0
  const string role2 = "test_role_2";
1067
1068
0
  CreateRole(processor, role1);
1069
0
  CreateRole(processor, role2);
1070
1071
0
  GrantRole(processor, role1, role2);
1072
1073
  // Same Grant Twice
1074
0
  const auto invalid_grant = GrantStmt(role1, role2);
1075
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_grant, Substitute("$0 is a member of $1", role2, role1));
1076
1077
  // Verify that the same invalid operation fails instead of timing out.
1078
0
  EXEC_INVALID_STMT_WITH_ERROR(invalid_grant, Substitute("$0 is a member of $1", role2, role1));
1079
1080
0
  RevokeRole(processor, role1, role2);
1081
1082
  // Revoke it again.
1083
0
  const auto invalid_revoke = RevokeStmt(role1, role2);
1084
0
  EXEC_INVALID_STMT_WITH_ERROR(
1085
0
      invalid_revoke, Substitute("$0 is not a member of $1", role2, role1));
1086
1087
  // If the mutation was ended properly, this request shouldn't time out.
1088
0
  EXEC_INVALID_STMT_WITH_ERROR(
1089
0
      invalid_revoke, Substitute("$0 is not a member of $1", role2, role1));
1090
1091
  // Lastly, create another role to verify that the roles version didn't change after all the
1092
  // statements that didn't modify anything in the master.
1093
0
  CreateRole(processor, "another_role");
1094
0
}
1095
1096
} // namespace ql
1097
} // namespace yb