OmniSciDB  340b00dbf6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SysCatalog.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019 MapD Technologies, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
25 #include "SysCatalog.h"
26 #include <algorithm>
27 #include <cassert>
28 #include <exception>
29 #include <list>
30 #include <memory>
31 #include <random>
32 #include <sstream>
33 #include <string_view>
34 #include "Catalog.h"
35 
36 #include "Catalog/AuthMetadata.h"
38 
39 #include <boost/algorithm/string/predicate.hpp>
40 #include <boost/filesystem.hpp>
41 #include <boost/range/adaptor/map.hpp>
42 #include <boost/version.hpp>
43 
44 #include "../Parser/ParserNode.h"
45 #include "../Shared/File.h"
46 #include "../Shared/StringTransform.h"
47 #include "../Shared/measure.h"
48 #include "MapDRelease.h"
49 #include "RWLocks.h"
50 #include "bcrypt.h"
51 
52 using std::list;
53 using std::map;
54 using std::pair;
55 using std::runtime_error;
56 using std::string;
57 using std::vector;
58 
59 using namespace std::string_literals;
60 
61 extern bool g_enable_fsi;
62 
63 namespace {
64 
65 std::string hash_with_bcrypt(const std::string& pwd) {
66  char salt[BCRYPT_HASHSIZE], hash[BCRYPT_HASHSIZE];
67  CHECK(bcrypt_gensalt(-1, salt) == 0);
68  CHECK(bcrypt_hashpw(pwd.c_str(), salt, hash) == 0);
69  return std::string(hash, BCRYPT_HASHSIZE);
70 }
71 
72 } // namespace
73 
74 namespace Catalog_Namespace {
75 
76 thread_local bool SysCatalog::thread_holds_read_lock = false;
77 
78 using sys_read_lock = read_lock<SysCatalog>;
81 
82 auto CommonFileOperations::assembleCatalogName(std::string const& name) {
83  return base_path_ + "/mapd_catalogs/" + name;
84 };
85 
86 void CommonFileOperations::removeCatalogByFullPath(std::string const& full_path) {
87  boost::filesystem::remove(full_path);
88 }
89 
90 void CommonFileOperations::removeCatalogByName(std::string const& name) {
91  boost::filesystem::remove(assembleCatalogName(name));
92 };
93 
94 auto CommonFileOperations::duplicateAndRenameCatalog(std::string const& current_name,
95  std::string const& new_name) {
96  auto full_current_path = assembleCatalogName(current_name);
97  auto full_new_path = assembleCatalogName(new_name);
98 
99  try {
100  boost::filesystem::copy_file(full_current_path, full_new_path);
101  } catch (std::exception& e) {
102  std::string err_message{"Could not copy file " + full_current_path + " to " +
103  full_new_path + " exception was " + e.what()};
104  LOG(ERROR) << err_message;
105  throw std::runtime_error(err_message);
106  }
107 
108  return std::make_pair(full_current_path, full_new_path);
109 };
110 
111 void SysCatalog::init(const std::string& basePath,
112  std::shared_ptr<Data_Namespace::DataMgr> dataMgr,
113  const AuthMetadata& authMetadata,
114  std::shared_ptr<Calcite> calcite,
115  bool is_new_db,
116  bool aggregator,
117  const std::vector<LeafHostInfo>& string_dict_hosts) {
118  {
121 
122  basePath_ = basePath;
123  dataMgr_ = dataMgr;
124  authMetadata_ = &authMetadata;
125  pki_server_.reset(new PkiServer(*authMetadata_));
126  calciteMgr_ = calcite;
127  string_dict_hosts_ = string_dict_hosts;
128  aggregator_ = aggregator;
129  bool db_exists =
130  boost::filesystem::exists(basePath_ + "/mapd_catalogs/" + OMNISCI_SYSTEM_CATALOG);
131  sqliteConnector_.reset(
132  new SqliteConnector(OMNISCI_SYSTEM_CATALOG, basePath_ + "/mapd_catalogs/"));
133  if (is_new_db) {
134  initDB();
135  } else {
136  if (!db_exists) {
137  importDataFromOldMapdDB();
138  }
139  checkAndExecuteMigrations();
140  }
141  buildRoleMap();
142  buildUserRoleMap();
143  buildObjectDescriptorMap();
144  }
145 }
146 
147 SysCatalog::~SysCatalog() {
149  for (auto grantee = granteeMap_.begin(); grantee != granteeMap_.end(); ++grantee) {
150  delete grantee->second;
151  }
152  granteeMap_.clear();
153  for (ObjectRoleDescriptorMap::iterator objectIt = objectDescriptorMap_.begin();
154  objectIt != objectDescriptorMap_.end();) {
155  ObjectRoleDescriptorMap::iterator eraseIt = objectIt++;
156  delete eraseIt->second;
157  }
158  objectDescriptorMap_.clear();
159 }
160 
161 void SysCatalog::initDB() {
163  sqliteConnector_->query("BEGIN TRANSACTION");
164  try {
165  sqliteConnector_->query(
166  "CREATE TABLE mapd_users (userid integer primary key, name text unique, "
167  "passwd_hash text, issuper boolean, default_db integer references "
168  "mapd_databases, can_login boolean)");
169  sqliteConnector_->query_with_text_params(
170  "INSERT INTO mapd_users VALUES (?, ?, ?, 1, NULL, 1)",
171  std::vector<std::string>{OMNISCI_ROOT_USER_ID_STR,
174  sqliteConnector_->query(
175  "CREATE TABLE mapd_databases (dbid integer primary key, name text unique, owner "
176  "integer references mapd_users)");
177  sqliteConnector_->query(
178  "CREATE TABLE mapd_roles(roleName text, userName text, UNIQUE(roleName, "
179  "userName))");
180  sqliteConnector_->query(
181  "CREATE TABLE mapd_object_permissions ("
182  "roleName text, "
183  "roleType bool, "
184  "dbId integer references mapd_databases, "
185  "objectName text, "
186  "objectId integer, "
187  "objectPermissionsType integer, "
188  "objectPermissions integer, "
189  "objectOwnerId integer, UNIQUE(roleName, objectPermissionsType, dbId, "
190  "objectId))");
191  } catch (const std::exception&) {
192  sqliteConnector_->query("ROLLBACK TRANSACTION");
193  throw;
194  }
195  sqliteConnector_->query("END TRANSACTION");
196  createDatabase(OMNISCI_DEFAULT_DB, OMNISCI_ROOT_USER_ID);
197  createRole_unsafe(OMNISCI_ROOT_USER, true);
198 }
199 
200 void SysCatalog::checkAndExecuteMigrations() {
201  migratePrivileged_old();
202  createUserRoles();
203  migratePrivileges();
204  migrateDBAccessPrivileges();
205  updateUserSchema(); // must come before updatePasswordsToHashes()
206  updatePasswordsToHashes();
207  updateBlankPasswordsToRandom(); // must come after updatePasswordsToHashes()
208  updateSupportUserDeactivation();
209  addAdminUserRole();
210 }
211 
212 void SysCatalog::updateUserSchema() {
214 
215  // check to see if the new column already exists
216  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
217  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
218  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
219  if (col_name == "default_db") {
220  return; // new column already exists
221  }
222  }
223 
224  // create the new column
225  sqliteConnector_->query("BEGIN TRANSACTION");
226  try {
227  sqliteConnector_->query(
228  "ALTER TABLE mapd_users ADD COLUMN default_db INTEGER REFERENCES mapd_databases");
229  } catch (const std::exception& e) {
230  sqliteConnector_->query("ROLLBACK TRANSACTION");
231  throw;
232  }
233  sqliteConnector_->query("END TRANSACTION");
234 }
235 
236 void SysCatalog::importDataFromOldMapdDB() {
238  std::string mapd_db_path = basePath_ + "/mapd_catalogs/mapd";
239  sqliteConnector_->query("ATTACH DATABASE `" + mapd_db_path + "` as old_cat");
240  sqliteConnector_->query("BEGIN TRANSACTION");
241  LOG(INFO) << "Moving global metadata into a separate catalog";
242  try {
243  auto moveTableIfExists = [conn = sqliteConnector_.get()](const std::string& tableName,
244  bool deleteOld = true) {
245  conn->query("SELECT sql FROM old_cat.sqlite_master WHERE type='table' AND name='" +
246  tableName + "'");
247  if (conn->getNumRows() != 0) {
248  conn->query(conn->getData<string>(0, 0));
249  conn->query("INSERT INTO " + tableName + " SELECT * FROM old_cat." + tableName);
250  if (deleteOld) {
251  conn->query("DROP TABLE old_cat." + tableName);
252  }
253  }
254  };
255  moveTableIfExists("mapd_users");
256  moveTableIfExists("mapd_databases");
257  moveTableIfExists("mapd_roles");
258  moveTableIfExists("mapd_object_permissions");
259  moveTableIfExists("mapd_privileges");
260  moveTableIfExists("mapd_version_history", false);
261  } catch (const std::exception& e) {
262  LOG(ERROR) << "Failed to move global metadata into a separate catalog: " << e.what();
263  sqliteConnector_->query("ROLLBACK TRANSACTION");
264  try {
265  sqliteConnector_->query("DETACH DATABASE old_cat");
266  } catch (const std::exception&) {
267  // nothing to do here
268  }
269  throw;
270  }
271  sqliteConnector_->query("END TRANSACTION");
272  const std::string sys_catalog_path =
273  basePath_ + "/mapd_catalogs/" + OMNISCI_SYSTEM_CATALOG;
274  LOG(INFO) << "Global metadata has been successfully moved into a separate catalog: "
275  << sys_catalog_path
276  << ". Using this database with an older version of omnisci_server "
277  "is now impossible.";
278  try {
279  sqliteConnector_->query("DETACH DATABASE old_cat");
280  } catch (const std::exception&) {
281  // nothing to do here
282  }
283 }
284 
285 void SysCatalog::createUserRoles() {
287  sqliteConnector_->query("BEGIN TRANSACTION");
288  try {
289  sqliteConnector_->query(
290  "SELECT name FROM sqlite_master WHERE type='table' AND name='mapd_roles'");
291  if (sqliteConnector_->getNumRows() != 0) {
292  // already done
293  sqliteConnector_->query("END TRANSACTION");
294  return;
295  }
296  sqliteConnector_->query(
297  "CREATE TABLE mapd_roles(roleName text, userName text, UNIQUE(roleName, "
298  "userName))");
299  // need to account for old conversions where we are building and moving
300  // from pre version 4.0 and 'mapd' was default superuser
301  sqliteConnector_->query("SELECT name FROM mapd_users WHERE name NOT IN ( \'" +
302  OMNISCI_ROOT_USER + "\', 'mapd')");
303  size_t numRows = sqliteConnector_->getNumRows();
304  vector<string> user_names;
305  for (size_t i = 0; i < numRows; ++i) {
306  user_names.push_back(sqliteConnector_->getData<string>(i, 0));
307  }
308  for (const auto& user_name : user_names) {
309  // for each user, create a fake role with the same name
310  sqliteConnector_->query_with_text_params(
311  "INSERT INTO mapd_roles(roleName, userName) VALUES (?, ?)",
312  vector<string>{user_name, user_name});
313  }
314  } catch (const std::exception&) {
315  sqliteConnector_->query("ROLLBACK TRANSACTION");
316  throw;
317  }
318  sqliteConnector_->query("END TRANSACTION");
319 }
320 
321 namespace {
322 
323 void deleteObjectPrivileges(std::unique_ptr<SqliteConnector>& sqliteConnector,
324  std::string roleName,
325  bool userRole,
326  DBObject& object) {
327  DBObjectKey key = object.getObjectKey();
328 
329  sqliteConnector->query_with_text_params(
330  "DELETE FROM mapd_object_permissions WHERE roleName = ?1 and roleType = ?2 and "
331  "objectPermissionsType = ?3 and "
332  "dbId = "
333  "?4 "
334  "and objectId = ?5",
335  std::vector<std::string>{roleName,
336  std::to_string(userRole),
338  std::to_string(key.dbId),
339  std::to_string(key.objectId)});
340 }
341 
342 void insertOrUpdateObjectPrivileges(std::unique_ptr<SqliteConnector>& sqliteConnector,
343  std::string roleName,
344  bool userRole,
345  DBObject& object) {
346  DBObjectKey key = object.getObjectKey();
347 
348  sqliteConnector->query_with_text_params(
349  "INSERT OR REPLACE INTO mapd_object_permissions("
350  "roleName, "
351  "roleType, "
352  "objectPermissionsType, "
353  "dbId, "
354  "objectId, "
355  "objectPermissions, "
356  "objectOwnerId,"
357  "objectName) "
358  "VALUES (?1, ?2, ?3, "
359  "?4, ?5, ?6, ?7, ?8)",
360  std::vector<std::string>{
361  roleName, // roleName
362  userRole ? "1" : "0", // roleType
363  std::to_string(key.permissionType), // permissionType
364  std::to_string(key.dbId), // dbId
365  std::to_string(key.objectId), // objectId
366  std::to_string(object.getPrivileges().privileges), // objectPrivileges
367  std::to_string(object.getOwner()), // objectOwnerId
368  object.getName() // name
369  });
370 }
371 
372 } // namespace
373 
374 void SysCatalog::migratePrivileges() {
376  sqliteConnector_->query("BEGIN TRANSACTION");
377  try {
378  sqliteConnector_->query(
379  "SELECT name FROM sqlite_master WHERE type='table' AND "
380  "name='mapd_object_permissions'");
381  if (sqliteConnector_->getNumRows() != 0) {
382  // already done
383  sqliteConnector_->query("END TRANSACTION");
384  return;
385  }
386 
387  sqliteConnector_->query(
388  "CREATE TABLE IF NOT EXISTS mapd_object_permissions ("
389  "roleName text, "
390  "roleType bool, "
391  "dbId integer references mapd_databases, "
392  "objectName text, "
393  "objectId integer, "
394  "objectPermissionsType integer, "
395  "objectPermissions integer, "
396  "objectOwnerId integer, UNIQUE(roleName, objectPermissionsType, dbId, "
397  "objectId))");
398 
399  // get the list of databases and their grantees
400  sqliteConnector_->query(
401  "SELECT userid, dbid FROM mapd_privileges WHERE select_priv = 1 and insert_priv "
402  "= 1");
403  size_t numRows = sqliteConnector_->getNumRows();
404  vector<pair<int, int>> db_grantees(numRows);
405  for (size_t i = 0; i < numRows; ++i) {
406  db_grantees[i].first = sqliteConnector_->getData<int>(i, 0);
407  db_grantees[i].second = sqliteConnector_->getData<int>(i, 1);
408  }
409  // map user names to user ids
410  sqliteConnector_->query("select userid, name from mapd_users");
411  numRows = sqliteConnector_->getNumRows();
412  std::unordered_map<int, string> users_by_id;
413  std::unordered_map<int, bool> user_has_privs;
414  for (size_t i = 0; i < numRows; ++i) {
415  users_by_id[sqliteConnector_->getData<int>(i, 0)] =
416  sqliteConnector_->getData<string>(i, 1);
417  user_has_privs[sqliteConnector_->getData<int>(i, 0)] = false;
418  }
419  // map db names to db ids
420  sqliteConnector_->query("select dbid, name from mapd_databases");
421  numRows = sqliteConnector_->getNumRows();
422  std::unordered_map<int, string> dbs_by_id;
423  for (size_t i = 0; i < numRows; ++i) {
424  dbs_by_id[sqliteConnector_->getData<int>(i, 0)] =
425  sqliteConnector_->getData<string>(i, 1);
426  }
427  // migrate old privileges to new privileges: if user had insert access to database, he
428  // was a grantee
429  for (const auto& grantee : db_grantees) {
430  user_has_privs[grantee.first] = true;
431  auto dbName = dbs_by_id[grantee.second];
432  {
433  // table level permissions
434  DBObjectKey key;
436  key.dbId = grantee.second;
438  object.setName(dbName);
440  sqliteConnector_, users_by_id[grantee.first], true, object);
441  }
442 
443  {
444  // dashboard level permissions
445  DBObjectKey key;
447  key.dbId = grantee.second;
448  DBObject object(
450  object.setName(dbName);
452  sqliteConnector_, users_by_id[grantee.first], true, object);
453  }
454 
455  {
456  // view level permissions
457  DBObjectKey key;
459  key.dbId = grantee.second;
461  object.setName(dbName);
463  sqliteConnector_, users_by_id[grantee.first], true, object);
464  }
465  }
466  for (auto user : user_has_privs) {
467  auto dbName = dbs_by_id[0];
468  if (user.second == false && user.first != OMNISCI_ROOT_USER_ID) {
469  {
470  DBObjectKey key;
472  key.dbId = 0;
474  object.setName(dbName);
476  sqliteConnector_, users_by_id[user.first], true, object);
477  }
478  }
479  }
480  } catch (const std::exception&) {
481  sqliteConnector_->query("ROLLBACK TRANSACTION");
482  throw;
483  }
484  sqliteConnector_->query("END TRANSACTION");
485 }
486 
487 void SysCatalog::addAdminUserRole() {
489  sqliteConnector_->query("BEGIN TRANSACTION");
490  try {
491  sqliteConnector_->query(
492  "SELECT roleName FROM mapd_object_permissions WHERE roleName = \'" +
493  OMNISCI_ROOT_USER + "\'");
494  if (sqliteConnector_->getNumRows() != 0) {
495  // already done
496  sqliteConnector_->query("END TRANSACTION");
497  return;
498  }
499 
500  createRole_unsafe(OMNISCI_ROOT_USER, true);
501  } catch (const std::exception&) {
502  sqliteConnector_->query("ROLLBACK TRANSACTION");
503  throw;
504  }
505  sqliteConnector_->query("END TRANSACTION");
506 }
507 
508 void SysCatalog::updatePasswordsToHashes() {
510  sqliteConnector_->query("BEGIN TRANSACTION");
511  try {
512  sqliteConnector_->query(
513  "SELECT name FROM sqlite_master WHERE type='table' AND name='mapd_users'");
514  if (sqliteConnector_->getNumRows() == 0) {
515  // Nothing to update
516  sqliteConnector_->query("END TRANSACTION");
517  return;
518  }
519  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
520  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
521  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
522  if (col_name == "passwd_hash") {
523  sqliteConnector_->query("END TRANSACTION");
524  return;
525  }
526  }
527  // Alas, SQLite can't drop columns so we have to recreate the table
528  // (or, optionally, add the new column and reset the old one to a bunch of nulls)
529  sqliteConnector_->query("SELECT userid, passwd FROM mapd_users");
530  auto numRows = sqliteConnector_->getNumRows();
531  vector<std::string> users, passwords;
532  for (size_t i = 0; i < numRows; i++) {
533  users.push_back(sqliteConnector_->getData<std::string>(i, 0));
534  passwords.push_back(sqliteConnector_->getData<std::string>(i, 1));
535  }
536  sqliteConnector_->query(
537  "CREATE TABLE mapd_users_tmp (userid integer primary key, name text unique, "
538  "passwd_hash text, issuper boolean, default_db integer references "
539  "mapd_databases)");
540  sqliteConnector_->query(
541  "INSERT INTO mapd_users_tmp(userid, name, passwd_hash, issuper, default_db) "
542  "SELECT userid, name, null, issuper, default_db FROM mapd_users");
543  for (size_t i = 0; i < users.size(); ++i) {
544  sqliteConnector_->query_with_text_params(
545  "UPDATE mapd_users_tmp SET passwd_hash = ? WHERE userid = ?",
546  std::vector<std::string>{hash_with_bcrypt(passwords[i]), users[i]});
547  }
548  sqliteConnector_->query("DROP TABLE mapd_users");
549  sqliteConnector_->query("ALTER TABLE mapd_users_tmp RENAME TO mapd_users");
550  } catch (const std::exception& e) {
551  LOG(ERROR) << "Failed to hash passwords: " << e.what();
552  sqliteConnector_->query("ROLLBACK TRANSACTION");
553  throw;
554  }
555  sqliteConnector_->query("END TRANSACTION");
556  sqliteConnector_->query("VACUUM"); // physically delete plain text passwords
557  LOG(INFO) << "Passwords were successfully hashed";
558 }
559 
560 void SysCatalog::updateBlankPasswordsToRandom() {
561  const std::string UPDATE_BLANK_PASSWORDS_TO_RANDOM = "update_blank_passwords_to_random";
562  sqliteConnector_->query_with_text_params(
563  "SELECT migration_history FROM mapd_version_history WHERE migration_history = ?",
564  std::vector<std::string>{UPDATE_BLANK_PASSWORDS_TO_RANDOM});
565  if (sqliteConnector_->getNumRows()) {
566  return;
567  }
568 
570  sqliteConnector_->query("BEGIN TRANSACTION");
571  try {
572  sqliteConnector_->query(
573  "SELECT userid, passwd_hash, name FROM mapd_users WHERE name <> 'mapd'");
574  auto numRows = sqliteConnector_->getNumRows();
575  vector<std::string> users, passwords, names;
576  for (size_t i = 0; i < numRows; i++) {
577  users.push_back(sqliteConnector_->getData<std::string>(i, 0));
578  passwords.push_back(sqliteConnector_->getData<std::string>(i, 1));
579  names.push_back(sqliteConnector_->getData<std::string>(i, 2));
580  }
581  for (size_t i = 0; i < users.size(); ++i) {
582  int pwd_check_result = bcrypt_checkpw("", passwords[i].c_str());
583  // if the check fails there is a good chance that data on disc is broken
584  CHECK(pwd_check_result >= 0);
585  if (pwd_check_result != 0) {
586  continue;
587  }
588  LOG(WARNING) << "resetting blank password for user " << names[i] << " (" << users[i]
589  << ") to a random password";
590  sqliteConnector_->query_with_text_params(
591  "UPDATE mapd_users SET passwd_hash = ? WHERE userid = ?",
592  std::vector<std::string>{hash_with_bcrypt(generate_random_string(72)),
593  users[i]});
594  }
595  sqliteConnector_->query_with_text_params(
596  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
597  std::vector<std::string>{std::to_string(MAPD_VERSION),
598  UPDATE_BLANK_PASSWORDS_TO_RANDOM});
599  } catch (const std::exception& e) {
600  LOG(ERROR) << "Failed to fix blank passwords: " << e.what();
601  sqliteConnector_->query("ROLLBACK TRANSACTION");
602  throw;
603  }
604  sqliteConnector_->query("END TRANSACTION");
605 }
606 
607 void SysCatalog::updateSupportUserDeactivation() {
608  const std::string UPDATE_SUPPORT_USER_DEACTIVATION = "update_support_user_deactivation";
610  // check to see if the new column already exists
611  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
612  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
613  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
614  if (col_name == "can_login") {
615  return; // new column already exists
616  }
617  }
618  sqliteConnector_->query("BEGIN TRANSACTION");
619  try {
620  sqliteConnector_->query("ALTER TABLE mapd_users ADD COLUMN can_login BOOLEAN");
621  sqliteConnector_->query("UPDATE mapd_users SET can_login = true");
622  sqliteConnector_->query_with_text_params(
623  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
624  std::vector<std::string>{std::to_string(MAPD_VERSION),
625  UPDATE_SUPPORT_USER_DEACTIVATION});
626  } catch (const std::exception& e) {
627  LOG(ERROR) << "Failed to add support for user deactivation: " << e.what();
628  sqliteConnector_->query("ROLLBACK TRANSACTION");
629  throw;
630  }
631  sqliteConnector_->query("END TRANSACTION");
632 }
633 
634 void SysCatalog::migrateDBAccessPrivileges() {
636  sqliteConnector_->query("BEGIN TRANSACTION");
637  try {
638  sqliteConnector_->query(
639  "select name from sqlite_master WHERE type='table' AND "
640  "name='mapd_version_history'");
641  if (sqliteConnector_->getNumRows() == 0) {
642  sqliteConnector_->query(
643  "CREATE TABLE mapd_version_history(version integer, migration_history text "
644  "unique)");
645  } else {
646  sqliteConnector_->query(
647  "select * from mapd_version_history where migration_history = "
648  "'db_access_privileges'");
649  if (sqliteConnector_->getNumRows() != 0) {
650  // both privileges migrated
651  // no need for further execution
652  sqliteConnector_->query("END TRANSACTION");
653  return;
654  }
655  }
656  // Insert check for migration
657  sqliteConnector_->query_with_text_params(
658  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
659  std::vector<std::string>{std::to_string(MAPD_VERSION), "db_access_privileges"});
660 
661  sqliteConnector_->query("select dbid, name from mapd_databases");
662  std::unordered_map<int, string> databases;
663  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
664  databases[sqliteConnector_->getData<int>(i, 0)] =
665  sqliteConnector_->getData<string>(i, 1);
666  }
667 
668  sqliteConnector_->query("select userid, name from mapd_users");
669  std::unordered_map<int, string> users;
670  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
671  users[sqliteConnector_->getData<int>(i, 0)] =
672  sqliteConnector_->getData<string>(i, 1);
673  }
674 
675  // All existing users by default will be granted DB Access permissions
676  // and view sql editor privileges
677  DBMetadata dbmeta;
678  for (auto db_ : databases) {
679  CHECK(SysCatalog::instance().getMetadataForDB(db_.second, dbmeta));
680  for (auto user : users) {
681  if (user.first != OMNISCI_ROOT_USER_ID) {
682  {
683  DBObjectKey key;
685  key.dbId = dbmeta.dbId;
686 
687  // access permission;
688  DBObject object_access(key, AccessPrivileges::ACCESS, dbmeta.dbOwner);
690  object_access.setName(dbmeta.dbName);
691  // sql_editor permission
692  DBObject object_editor(
695  object_editor.setName(dbmeta.dbName);
696  object_editor.updatePrivileges(object_access);
698  sqliteConnector_, user.second, true, object_editor);
699  }
700  }
701  }
702  }
703  } catch (const std::exception& e) {
704  LOG(ERROR) << "Failed to migrate db access privileges: " << e.what();
705  sqliteConnector_->query("ROLLBACK TRANSACTION");
706  throw;
707  }
708  sqliteConnector_->query("END TRANSACTION");
709  LOG(INFO) << "Successfully migrated db access privileges";
710 }
711 
712 void SysCatalog::migratePrivileged_old() {
714 
715  sqliteConnector_->query("BEGIN TRANSACTION");
716  try {
717  sqliteConnector_->query(
718  "CREATE TABLE IF NOT EXISTS mapd_privileges (userid integer references "
719  "mapd_users, dbid integer references "
720  "mapd_databases, select_priv boolean, insert_priv boolean, UNIQUE(userid, "
721  "dbid))");
722  } catch (const std::exception& e) {
723  sqliteConnector_->query("ROLLBACK TRANSACTION");
724  throw;
725  }
726  sqliteConnector_->query("END TRANSACTION");
727 }
728 
729 std::shared_ptr<Catalog> SysCatalog::login(std::string& dbname,
730  std::string& username,
731  const std::string& password,
732  UserMetadata& user_meta,
733  bool check_password) {
734  // NOTE(sy): The dbname isn't const because getMetadataWithDefaultDB()
735  // can reset it. The username isn't const because SamlServer's
736  // login()/authenticate_user() can reset it.
737 
739  if (check_password) {
740  loginImpl(username, password, user_meta);
741  } else { // not checking for password so user must exist
742  if (!getMetadataForUser(username, user_meta)) {
743  throw std::runtime_error("Invalid credentials.");
744  }
745  }
746  // we should have a user and user_meta by now
747  if (!user_meta.can_login) {
748  throw std::runtime_error("Unauthorized Access: User " + username + " is deactivated");
749  }
751  getMetadataWithDefaultDB(dbname, username, db_meta, user_meta);
752  return Catalog::get(
753  basePath_, db_meta, dataMgr_, string_dict_hosts_, calciteMgr_, false);
754 }
755 
756 // loginImpl() with no EE code and no SAML code
757 void SysCatalog::loginImpl(std::string& username,
758  const std::string& password,
759  UserMetadata& user_meta) {
760  if (!checkPasswordForUser(password, username, user_meta)) {
761  throw std::runtime_error("Authentication failure");
762  }
763 }
764 
765 std::shared_ptr<Catalog> SysCatalog::switchDatabase(std::string& dbname,
766  const std::string& username) {
767  DBMetadata db_meta;
768  UserMetadata user_meta;
769 
770  getMetadataWithDefaultDB(dbname, username, db_meta, user_meta);
771 
772  // NOTE(max): register database in Catalog that early to allow ldap
773  // and saml create default user and role privileges on databases
774  auto cat =
775  Catalog::get(basePath_, db_meta, dataMgr_, string_dict_hosts_, calciteMgr_, false);
776 
777  DBObject dbObject(dbname, DatabaseDBObjectType);
778  dbObject.loadKey();
780  if (!checkPrivileges(user_meta, std::vector<DBObject>{dbObject})) {
781  throw std::runtime_error("Unauthorized Access: user " + username +
782  " is not allowed to access database " + dbname + ".");
783  }
784 
785  return cat;
786 }
787 
788 void SysCatalog::check_for_session_encryption(const std::string& pki_cert,
789  std::string& session) {
790  if (!pki_server_->inUse()) {
791  return;
792  }
793  pki_server_->encrypt_session(pki_cert, session);
794 }
795 
796 void SysCatalog::createUser(const string& name,
797  const string& passwd,
798  bool issuper,
799  const std::string& dbname,
800  bool can_login) {
803 
804  UserMetadata user;
805  if (getMetadataForUser(name, user)) {
806  throw runtime_error("User " + name + " already exists.");
807  }
808  if (getGrantee(name)) {
809  throw runtime_error(
810  "User name " + name +
811  " is same as one of existing grantees. User and role names should be unique.");
812  }
813  sqliteConnector_->query("BEGIN TRANSACTION");
814  try {
815  std::vector<std::string> vals;
816  if (!dbname.empty()) {
817  DBMetadata db;
818  if (!SysCatalog::instance().getMetadataForDB(dbname, db)) {
819  throw runtime_error("DEFAULT_DB " + dbname + " not found.");
820  }
821  vals = {name,
822  hash_with_bcrypt(passwd),
823  std::to_string(issuper),
824  std::to_string(db.dbId),
825  std::to_string(can_login)};
826  sqliteConnector_->query_with_text_params(
827  "INSERT INTO mapd_users (name, passwd_hash, issuper, default_db, can_login) "
828  "VALUES (?, ?, ?, ?, ?)",
829  vals);
830  } else {
831  vals = {name,
832  hash_with_bcrypt(passwd),
833  std::to_string(issuper),
834  std::to_string(can_login)};
835  sqliteConnector_->query_with_text_params(
836  "INSERT INTO mapd_users (name, passwd_hash, issuper, can_login) "
837  "VALUES (?, ?, ?, ?)",
838  vals);
839  }
840  createRole_unsafe(name, true);
841  } catch (const std::exception& e) {
842  sqliteConnector_->query("ROLLBACK TRANSACTION");
843  throw;
844  }
845  sqliteConnector_->query("END TRANSACTION");
846 }
847 
848 void SysCatalog::dropUser(const string& name) {
851 
852  sqliteConnector_->query("BEGIN TRANSACTION");
853  try {
854  UserMetadata user;
855  if (!getMetadataForUser(name, user)) {
856  throw runtime_error("User " + name + " does not exist.");
857  }
858  dropRole_unsafe(name);
859  deleteObjectDescriptorMap(name);
860  const std::string& roleName(name);
861  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE userName = ?",
862  roleName);
863  sqliteConnector_->query("DELETE FROM mapd_users WHERE userid = " +
864  std::to_string(user.userId));
865  sqliteConnector_->query("DELETE FROM mapd_privileges WHERE userid = " +
866  std::to_string(user.userId));
867  } catch (const std::exception& e) {
868  sqliteConnector_->query("ROLLBACK TRANSACTION");
869  throw;
870  }
871  sqliteConnector_->query("END TRANSACTION");
872 }
873 
874 std::vector<std::shared_ptr<Catalog>> SysCatalog::getCatalogsForAllDbs() {
875  std::vector<std::shared_ptr<Catalog>> catalogs{};
876  const auto& db_metadata_list = getAllDBMetadata();
877  for (const auto& db_metadata : db_metadata_list) {
878  catalogs.emplace_back(Catalog::get(
879  basePath_, db_metadata, dataMgr_, string_dict_hosts_, calciteMgr_, false));
880  }
881  return catalogs;
882 }
883 
884 namespace { // anonymous namespace
885 
886 auto append_with_commas = [](string& s, const string& t) {
887  if (!s.empty()) {
888  s += ", ";
889  }
890  s += t;
891 };
892 
893 } // anonymous namespace
894 
895 void SysCatalog::alterUser(const int32_t userid,
896  const string* passwd,
897  bool* issuper,
898  const string* dbname,
899  bool* can_login) {
901  sqliteConnector_->query("BEGIN TRANSACTION");
902  try {
903  string sql;
904  std::vector<std::string> values;
905  if (passwd != nullptr) {
906  append_with_commas(sql, "passwd_hash = ?");
907  values.push_back(hash_with_bcrypt(*passwd));
908  }
909  if (issuper != nullptr) {
910  append_with_commas(sql, "issuper = ?");
911  values.push_back(std::to_string(*issuper));
912  }
913  if (dbname != nullptr) {
914  if (!dbname->empty()) {
915  append_with_commas(sql, "default_db = ?");
916  DBMetadata db;
917  if (!SysCatalog::instance().getMetadataForDB(*dbname, db)) {
918  throw runtime_error(string("DEFAULT_DB ") + *dbname + " not found.");
919  }
920  values.push_back(std::to_string(db.dbId));
921  } else {
922  append_with_commas(sql, "default_db = NULL");
923  }
924  }
925  if (can_login != nullptr) {
926  append_with_commas(sql, "can_login = ?");
927  values.push_back(std::to_string(*can_login));
928  }
929 
930  sql = "UPDATE mapd_users SET " + sql + " WHERE userid = ?";
931  values.push_back(std::to_string(userid));
932 
933  sqliteConnector_->query_with_text_params(sql, values);
934  } catch (const std::exception& e) {
935  sqliteConnector_->query("ROLLBACK TRANSACTION");
936  throw;
937  }
938  sqliteConnector_->query("END TRANSACTION");
939 }
940 
941 auto SysCatalog::yieldTransactionStreamer() {
942  return
943  [](auto& db_connector, auto on_success, auto on_failure, auto&&... query_requests) {
944  auto query_runner = [&db_connector](auto&&... query_reqs) {
945  [[gnu::unused]] int throw_away[] = {
946  (db_connector->query_with_text_params(
947  std::forward<decltype(query_reqs)>(query_reqs)),
948  0)...};
949  };
950 
951  db_connector->query("BEGIN TRANSACTION");
952  try {
953  query_runner(std::forward<decltype(query_requests)>(query_requests)...);
954  on_success();
955  } catch (std::exception&) {
956  db_connector->query("ROLLBACK TRANSACTION");
957  on_failure();
958  throw;
959  }
960  db_connector->query("END TRANSACTION");
961  };
962 }
963 
964 void SysCatalog::updateUserRoleName(const std::string& roleName,
965  const std::string& newName) {
967 
968  auto it = granteeMap_.find(to_upper(roleName));
969  if (it != granteeMap_.end()) {
970  it->second->setName(newName);
971  std::swap(granteeMap_[to_upper(newName)], it->second);
972  granteeMap_.erase(it);
973  }
974 }
975 
976 void SysCatalog::renameUser(std::string const& old_name, std::string const& new_name) {
977  using namespace std::string_literals;
980 
981  UserMetadata old_user;
982  if (!getMetadataForUser(old_name, old_user)) {
983  throw std::runtime_error("User " + old_name + " doesn't exist.");
984  }
985 
986  UserMetadata new_user;
987  if (getMetadataForUser(new_name, new_user)) {
988  throw std::runtime_error("User " + new_name + " already exists.");
989  }
990 
991  if (getGrantee(new_name)) {
992  throw runtime_error(
993  "User name " + new_name +
994  " is same as one of existing grantees. User and role names should be unique.");
995  }
996 
997  auto transaction_streamer = yieldTransactionStreamer();
998  auto failure_handler = [] {};
999  auto success_handler = [this, &old_name, &new_name] {
1000  updateUserRoleName(old_name, new_name);
1001  };
1002  auto q1 = {"UPDATE mapd_users SET name=?1 where name=?2;"s, new_name, old_name};
1003  auto q2 = {"UPDATE mapd_object_permissions set roleName=?1 WHERE roleName=?2;"s,
1004  new_name,
1005  old_name};
1006  transaction_streamer(sqliteConnector_, success_handler, failure_handler, q1, q2);
1007 }
1008 
1009 void SysCatalog::renameDatabase(std::string const& old_name,
1010  std::string const& new_name) {
1011  using namespace std::string_literals;
1012  sys_write_lock write_lock(this);
1014 
1015  DBMetadata new_db;
1016  if (getMetadataForDB(new_name, new_db)) {
1017  throw std::runtime_error("Database " + new_name + " already exists.");
1018  }
1019  if (to_upper(new_name) == to_upper(OMNISCI_SYSTEM_CATALOG)) {
1020  throw std::runtime_error("Database name " + new_name + "is reserved.");
1021  }
1022 
1023  DBMetadata old_db;
1024  if (!getMetadataForDB(old_name, old_db)) {
1025  throw std::runtime_error("Database " + old_name + " does not exists.");
1026  }
1027 
1028  Catalog::remove(old_db.dbName);
1029 
1030  std::string old_catalog_path, new_catalog_path;
1031  std::tie(old_catalog_path, new_catalog_path) =
1032  duplicateAndRenameCatalog(old_name, new_name);
1033 
1034  auto transaction_streamer = yieldTransactionStreamer();
1035  auto failure_handler = [this, new_catalog_path] {
1036  removeCatalogByFullPath(new_catalog_path);
1037  };
1038  auto success_handler = [this, old_catalog_path] {
1039  removeCatalogByFullPath(old_catalog_path);
1040  };
1041 
1042  auto q1 = {"UPDATE mapd_databases SET name=?1 WHERE name=?2;"s, new_name, old_name};
1043  auto q2 = {
1044  "UPDATE mapd_object_permissions SET objectName=?1 WHERE objectNAME=?2 and (objectPermissionsType=?3 or objectId = -1) and dbId=?4;"s,
1045  new_name,
1046  old_name,
1048  std::to_string(old_db.dbId)};
1049 
1050  transaction_streamer(sqliteConnector_, success_handler, failure_handler, q1, q2);
1051 }
1052 
1053 void SysCatalog::createDatabase(const string& name, int owner) {
1054  sys_write_lock write_lock(this);
1056 
1057  DBMetadata db;
1058  if (getMetadataForDB(name, db)) {
1059  throw runtime_error("Database " + name + " already exists.");
1060  }
1061  if (to_upper(name) == to_upper(OMNISCI_SYSTEM_CATALOG)) {
1062  throw runtime_error("Database name " + name + " is reserved.");
1063  }
1064 
1065  std::unique_ptr<SqliteConnector> dbConn(
1066  new SqliteConnector(name, basePath_ + "/mapd_catalogs/"));
1067  // NOTE(max): it's okay to run this in a separate transaction. If we fail later
1068  // we delete the database anyways.
1069  // If we run it in the same transaction as SysCatalog functions, then Catalog
1070  // constructor won't find the tables we have just created.
1071  dbConn->query("BEGIN TRANSACTION");
1072  try {
1073  dbConn->query(
1074  "CREATE TABLE mapd_tables (tableid integer primary key, name text unique, userid "
1075  "integer, ncolumns integer, "
1076  "isview boolean, "
1077  "fragments text, frag_type integer, max_frag_rows integer, max_chunk_size "
1078  "bigint, "
1079  "frag_page_size integer, "
1080  "max_rows bigint, partitions text, shard_column_id integer, shard integer, "
1081  "sort_column_id integer default 0, storage_type text default '',"
1082  "num_shards integer, key_metainfo TEXT, version_num "
1083  "BIGINT DEFAULT 1) ");
1084  dbConn->query(
1085  "CREATE TABLE mapd_columns (tableid integer references mapd_tables, columnid "
1086  "integer, name text, coltype "
1087  "integer, colsubtype integer, coldim integer, colscale integer, is_notnull "
1088  "boolean, compression integer, "
1089  "comp_param integer, size integer, chunks text, is_systemcol boolean, "
1090  "is_virtualcol boolean, virtual_expr "
1091  "text, is_deletedcol boolean, version_num BIGINT, "
1092  "primary key(tableid, columnid), unique(tableid, name))");
1093  dbConn->query(
1094  "CREATE TABLE mapd_views (tableid integer references mapd_tables, sql text)");
1095  dbConn->query(
1096  "CREATE TABLE mapd_dashboards (id integer primary key autoincrement, name text , "
1097  "userid integer references mapd_users, state text, image_hash text, update_time "
1098  "timestamp, "
1099  "metadata text, UNIQUE(userid, name) )");
1100  dbConn->query(
1101  "CREATE TABLE mapd_links (linkid integer primary key, userid integer references "
1102  "mapd_users, "
1103  "link text unique, view_state text, update_time timestamp, view_metadata text)");
1104  dbConn->query(
1105  "CREATE TABLE mapd_dictionaries (dictid integer primary key, name text unique, "
1106  "nbits int, is_shared boolean, "
1107  "refcount int, version_num BIGINT DEFAULT 1)");
1108  dbConn->query(
1109  "CREATE TABLE mapd_logical_to_physical(logical_table_id integer, "
1110  "physical_table_id "
1111  "integer)");
1112  dbConn->query("CREATE TABLE mapd_record_ownership_marker (dummy integer)");
1113  dbConn->query_with_text_params(
1114  "INSERT INTO mapd_record_ownership_marker (dummy) VALUES (?1)",
1115  std::vector<std::string>{std::to_string(owner)});
1116 
1117  if (g_enable_fsi) {
1118  dbConn->query(Catalog::getForeignServerSchema());
1119  dbConn->query(Catalog::getForeignTableSchema());
1120  }
1121  } catch (const std::exception&) {
1122  dbConn->query("ROLLBACK TRANSACTION");
1123  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1124  throw;
1125  }
1126  dbConn->query("END TRANSACTION");
1127 
1128  std::shared_ptr<Catalog> cat;
1129  // Now update SysCatalog with privileges and the new database
1130  sqliteConnector_->query("BEGIN TRANSACTION");
1131  try {
1132  sqliteConnector_->query_with_text_param(
1133  "INSERT INTO mapd_databases (name, owner) VALUES (?, " + std::to_string(owner) +
1134  ")",
1135  name);
1136  CHECK(getMetadataForDB(name, db));
1137  cat = Catalog::get(basePath_, db, dataMgr_, string_dict_hosts_, calciteMgr_, true);
1138  if (owner != OMNISCI_ROOT_USER_ID) {
1140  object.loadKey(*cat);
1141  UserMetadata user;
1142  CHECK(getMetadataForUserById(owner, user));
1143  grantAllOnDatabase_unsafe(user.userName, object, *cat);
1144  }
1145  } catch (const std::exception&) {
1146  sqliteConnector_->query("ROLLBACK TRANSACTION");
1147  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1148  throw;
1149  }
1150  sqliteConnector_->query("END TRANSACTION");
1151 
1152  if (g_enable_fsi) {
1153  try {
1154  cat->createDefaultServersIfNotExists();
1155  } catch (...) {
1156  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1157  throw;
1158  }
1159  }
1160 }
1161 
1162 void SysCatalog::dropDatabase(const DBMetadata& db) {
1163  sys_write_lock write_lock(this);
1165  auto cat =
1166  Catalog::get(basePath_, db, dataMgr_, string_dict_hosts_, calciteMgr_, false);
1167  sqliteConnector_->query("BEGIN TRANSACTION");
1168  try {
1169  // remove this database ID from any users that have it set as their default database
1170  sqliteConnector_->query_with_text_param(
1171  "UPDATE mapd_users SET default_db = NULL WHERE default_db = ?",
1172  std::to_string(db.dbId));
1173  /* revoke object privileges to all tables of the database being dropped */
1174  const auto tables = cat->getAllTableMetadata();
1175  for (const auto table : tables) {
1176  if (table->shard >= 0) {
1177  // skip shards, they're not standalone tables
1178  continue;
1179  }
1180  revokeDBObjectPrivilegesFromAll_unsafe(
1181  DBObject(table->tableName, TableDBObjectType), cat.get());
1182  }
1183  const auto dashboards = cat->getAllDashboardsMetadata();
1184  for (const auto dashboard : dashboards) {
1185  revokeDBObjectPrivilegesFromAll_unsafe(
1186  DBObject(dashboard->dashboardId, DashboardDBObjectType), cat.get());
1187  }
1188  /* revoke object privileges to the database being dropped */
1189  for (const auto& grantee : granteeMap_) {
1190  if (grantee.second->hasAnyPrivilegesOnDb(db.dbId, true)) {
1191  revokeAllOnDatabase_unsafe(grantee.second->getName(), db.dbId, grantee.second);
1192  }
1193  }
1194  sqliteConnector_->query_with_text_param("DELETE FROM mapd_databases WHERE dbid = ?",
1195  std::to_string(db.dbId));
1196  cat->eraseDBData();
1197  Catalog::remove(db.dbName);
1198  } catch (const std::exception&) {
1199  sqliteConnector_->query("ROLLBACK TRANSACTION");
1200  throw;
1201  }
1202  sqliteConnector_->query("END TRANSACTION");
1203 }
1204 
1205 // checkPasswordForUser() with no EE code
1206 bool SysCatalog::checkPasswordForUser(const std::string& passwd,
1207  std::string& name,
1208  UserMetadata& user) {
1209  return checkPasswordForUserImpl(passwd, name, user);
1210 }
1211 
1212 bool SysCatalog::checkPasswordForUserImpl(const std::string& passwd,
1213  std::string& name,
1214  UserMetadata& user) {
1215  if (!getMetadataForUser(name, user)) {
1216  // Check password against some fake hash just to waste time so that response times
1217  // for invalid password and invalid user are similar and a caller can't say the
1218  // difference
1219  char fake_hash[BCRYPT_HASHSIZE];
1220  CHECK(bcrypt_gensalt(-1, fake_hash) == 0);
1221  bcrypt_checkpw(passwd.c_str(), fake_hash);
1222  LOG(WARNING) << "Local login failed";
1223  return false;
1224  }
1225  int pwd_check_result = bcrypt_checkpw(passwd.c_str(), user.passwd_hash.c_str());
1226  // if the check fails there is a good chance that data on disc is broken
1227  CHECK(pwd_check_result >= 0);
1228  return pwd_check_result == 0;
1229 }
1230 
1231 static bool parseUserMetadataFromSQLite(const std::unique_ptr<SqliteConnector>& conn,
1232  UserMetadata& user) {
1233  int numRows = conn->getNumRows();
1234  if (numRows == 0) {
1235  return false;
1236  }
1237  user.userId = conn->getData<int>(0, 0);
1238  user.userName = conn->getData<string>(0, 1);
1239  user.passwd_hash = conn->getData<string>(0, 2);
1240  user.isSuper = conn->getData<bool>(0, 3);
1241  user.defaultDbId = conn->isNull(0, 4) ? -1 : conn->getData<int>(0, 4);
1242  if (conn->isNull(0, 5)) {
1243  LOG(WARNING)
1244  << "User property 'can_login' not set for user " << user.userName
1245  << ". Disabling login ability. Set the users login ability with \"ALTER USER "
1246  << user.userName << " (can_login='true');\".";
1247  }
1248  user.can_login = conn->isNull(0, 5) ? false : conn->getData<bool>(0, 5);
1249  return true;
1250 }
1251 
1252 bool SysCatalog::getMetadataForUser(const string& name, UserMetadata& user) {
1254  sqliteConnector_->query_with_text_param(
1255  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users "
1256  "WHERE name = ?",
1257  name);
1258  return parseUserMetadataFromSQLite(sqliteConnector_, user);
1259 }
1260 
1261 bool SysCatalog::getMetadataForUserById(const int32_t idIn, UserMetadata& user) {
1263  sqliteConnector_->query_with_text_param(
1264  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users "
1265  "WHERE userid = ?",
1266  std::to_string(idIn));
1267  return parseUserMetadataFromSQLite(sqliteConnector_, user);
1268 }
1269 
1270 list<DBMetadata> SysCatalog::getAllDBMetadata() {
1272  sqliteConnector_->query("SELECT dbid, name, owner FROM mapd_databases");
1273  int numRows = sqliteConnector_->getNumRows();
1274  list<DBMetadata> db_list;
1275  for (int r = 0; r < numRows; ++r) {
1276  DBMetadata db;
1277  db.dbId = sqliteConnector_->getData<int>(r, 0);
1278  db.dbName = sqliteConnector_->getData<string>(r, 1);
1279  db.dbOwner = sqliteConnector_->getData<int>(r, 2);
1280  db_list.push_back(db);
1281  }
1282  return db_list;
1283 }
1284 
1285 namespace {
1286 
1287 auto get_users(std::unique_ptr<SqliteConnector>& sqliteConnector,
1288  const int32_t dbId = -1) {
1289  sqliteConnector->query("SELECT userid, name, issuper, can_login FROM mapd_users");
1290  int numRows = sqliteConnector->getNumRows();
1291  list<UserMetadata> user_list;
1292  const bool return_all_users = dbId == -1;
1293  auto has_any_privilege = [&return_all_users, &dbId](const std::string& name) {
1294  if (!return_all_users) {
1295  const auto grantee = SysCatalog::instance().getUserGrantee(name);
1296  return grantee ? grantee->hasAnyPrivilegesOnDb(dbId, false) : false;
1297  }
1298  return true;
1299  };
1300  auto add_user = [&user_list, &has_any_privilege](const int32_t id,
1301  const std::string& name,
1302  const bool super,
1303  const bool can_login) {
1304  if (has_any_privilege(name)) {
1305  user_list.emplace_back(id, name, "", super, -1, can_login);
1306  };
1307  };
1308  for (int r = 0; r < numRows; ++r) {
1309  add_user(sqliteConnector->getData<int>(r, 0),
1310  sqliteConnector->getData<string>(r, 1),
1311  sqliteConnector->getData<bool>(r, 2),
1312  sqliteConnector->getData<bool>(r, 3));
1313  }
1314  return user_list;
1315 }
1316 
1317 } // namespace
1318 
1319 list<UserMetadata> SysCatalog::getAllUserMetadata(const int64_t dbId) {
1320  // this call is to return users that have some form of permissions to objects in the db
1321  // sadly mapd_object_permissions table is also misused to manage user roles.
1323  return get_users(sqliteConnector_, dbId);
1324 }
1325 
1326 list<UserMetadata> SysCatalog::getAllUserMetadata() {
1328  return get_users(sqliteConnector_);
1329 }
1330 
1331 void SysCatalog::getMetadataWithDefaultDB(std::string& dbname,
1332  const std::string& username,
1334  UserMetadata& user_meta) {
1335  if (!getMetadataForUser(username, user_meta)) {
1336  throw std::runtime_error("Invalid credentials.");
1337  }
1338 
1339  if (!dbname.empty()) {
1340  if (!getMetadataForDB(dbname, db_meta)) {
1341  throw std::runtime_error("Database name " + dbname + " does not exist.");
1342  }
1343  // loaded the requested database
1344  } else {
1345  if (user_meta.defaultDbId != -1) {
1346  if (!getMetadataForDBById(user_meta.defaultDbId, db_meta)) {
1347  throw std::runtime_error(
1348  "Server error: User #" + std::to_string(user_meta.userId) + " " +
1349  user_meta.userName + " has invalid default_db #" +
1350  std::to_string(user_meta.defaultDbId) + " which does not exist.");
1351  }
1352  dbname = db_meta.dbName;
1353  // loaded the user's default database
1354  } else {
1355  if (!getMetadataForDB(OMNISCI_DEFAULT_DB, db_meta)) {
1356  throw std::runtime_error(std::string("Database ") + OMNISCI_DEFAULT_DB +
1357  " does not exist.");
1358  }
1359  dbname = OMNISCI_DEFAULT_DB;
1360  // loaded the mapd database by default
1361  }
1362  }
1363 }
1364 
1365 bool SysCatalog::getMetadataForDB(const string& name, DBMetadata& db) {
1367  sqliteConnector_->query_with_text_param(
1368  "SELECT dbid, name, owner FROM mapd_databases WHERE name = ?", name);
1369  int numRows = sqliteConnector_->getNumRows();
1370  if (numRows == 0) {
1371  return false;
1372  }
1373  db.dbId = sqliteConnector_->getData<int>(0, 0);
1374  db.dbName = sqliteConnector_->getData<string>(0, 1);
1375  db.dbOwner = sqliteConnector_->getData<int>(0, 2);
1376  return true;
1377 }
1378 
1379 bool SysCatalog::getMetadataForDBById(const int32_t idIn, DBMetadata& db) {
1381  sqliteConnector_->query_with_text_param(
1382  "SELECT dbid, name, owner FROM mapd_databases WHERE dbid = ?",
1383  std::to_string(idIn));
1384  int numRows = sqliteConnector_->getNumRows();
1385  if (numRows == 0) {
1386  return false;
1387  }
1388  db.dbId = sqliteConnector_->getData<int>(0, 0);
1389  db.dbName = sqliteConnector_->getData<string>(0, 1);
1390  db.dbOwner = sqliteConnector_->getData<int>(0, 2);
1391  return true;
1392 }
1393 
1394 DBSummaryList SysCatalog::getDatabaseListForUser(const UserMetadata& user) {
1395  DBSummaryList ret;
1396 
1397  std::list<Catalog_Namespace::DBMetadata> db_list = getAllDBMetadata();
1398  std::list<Catalog_Namespace::UserMetadata> user_list = getAllUserMetadata();
1399 
1400  for (auto d : db_list) {
1401  DBObject dbObject(d.dbName, DatabaseDBObjectType);
1402  dbObject.loadKey();
1404  if (!checkPrivileges(user, std::vector<DBObject>{dbObject})) {
1405  continue;
1406  }
1407  for (auto u : user_list) {
1408  if (d.dbOwner == u.userId) {
1409  ret.emplace_back(DBSummary{d.dbName, u.userName});
1410  break;
1411  }
1412  }
1413  }
1414 
1415  return ret;
1416 }
1417 
1418 void SysCatalog::createDBObject(const UserMetadata& user,
1419  const std::string& objectName,
1421  const Catalog_Namespace::Catalog& catalog,
1422  int32_t objectId) {
1423  sys_write_lock write_lock(this);
1425 
1426  DBObject object =
1427  objectId == -1 ? DBObject(objectName, type) : DBObject(objectId, type);
1428  object.loadKey(catalog);
1429  switch (type) {
1430  case TableDBObjectType:
1431  object.setPrivileges(AccessPrivileges::ALL_TABLE);
1432  break;
1433  case DashboardDBObjectType:
1434  object.setPrivileges(AccessPrivileges::ALL_DASHBOARD);
1435  break;
1436  case ServerDBObjectType:
1437  object.setPrivileges(AccessPrivileges::ALL_SERVER);
1438  break;
1439  default:
1440  object.setPrivileges(AccessPrivileges::ALL_DATABASE);
1441  break;
1442  }
1443  object.setOwner(user.userId);
1444  sqliteConnector_->query("BEGIN TRANSACTION");
1445  try {
1446  if (!user.isSuper) { // no need to grant to suser, has all privs by default
1447  grantDBObjectPrivileges_unsafe(user.userName, object, catalog);
1448  auto* grantee = instance().getUserGrantee(user.userName);
1449  if (!grantee) {
1450  throw runtime_error("User " + user.userName + " does not exist.");
1451  }
1452  grantee->grantPrivileges(object);
1453  }
1454  } catch (std::exception& e) {
1455  sqliteConnector_->query("ROLLBACK TRANSACTION");
1456  throw;
1457  }
1458  sqliteConnector_->query("END TRANSACTION");
1459 }
1460 
1461 void SysCatalog::renameDBObject(const std::string& objectName,
1462  const std::string& newName,
1464  int32_t objectId,
1465  const Catalog_Namespace::Catalog& catalog) {
1466  sys_write_lock write_lock(this);
1467  DBObject new_object(newName, type);
1468  DBObjectKey key;
1469  key.dbId = catalog.getCurrentDB().dbId;
1470  key.objectId = objectId;
1471  key.permissionType = type;
1472  new_object.setObjectKey(key);
1473  auto objdescs =
1474  getMetadataForObject(key.dbId, static_cast<int32_t>(type), key.objectId);
1475  for (auto obj : objdescs) {
1476  Grantee* grnt = getGrantee(obj->roleName);
1477  if (grnt) {
1478  grnt->renameDbObject(new_object);
1479  }
1480  }
1481  renameObjectsInDescriptorMap(new_object, catalog);
1482 }
1483 
1484 void SysCatalog::grantDBObjectPrivilegesBatch_unsafe(
1485  const vector<string>& grantees,
1486  const vector<DBObject>& objects,
1487  const Catalog_Namespace::Catalog& catalog) {
1488  for (const auto& grantee : grantees) {
1489  for (const auto& object : objects) {
1490  grantDBObjectPrivileges_unsafe(grantee, object, catalog);
1491  }
1492  }
1493 }
1494 
1495 // GRANT INSERT ON TABLE payroll_table TO payroll_dept_role;
1496 void SysCatalog::grantDBObjectPrivileges_unsafe(
1497  const std::string& granteeName,
1498  DBObject object,
1499  const Catalog_Namespace::Catalog& catalog) {
1500  object.loadKey(catalog);
1501  if (object.getPrivileges().hasPermission(DatabasePrivileges::ALL) &&
1502  object.getObjectKey().permissionType == DatabaseDBObjectType) {
1503  return grantAllOnDatabase_unsafe(granteeName, object, catalog);
1504  }
1505 
1506  sys_write_lock write_lock(this);
1507 
1508  UserMetadata user_meta;
1509  if (instance().getMetadataForUser(granteeName, user_meta)) {
1510  if (user_meta.isSuper) {
1511  // super doesn't have explicit privileges so nothing to do
1512  return;
1513  }
1514  }
1515  auto* grantee = instance().getGrantee(granteeName);
1516  if (!grantee) {
1517  throw runtime_error("Request to grant privileges to " + granteeName +
1518  " failed because role or user with this name does not exist.");
1519  }
1520  grantee->grantPrivileges(object);
1521 
1522  /* apply grant privileges statement to sqlite DB */
1523  std::vector<std::string> objectKey = object.toString();
1524  object.resetPrivileges();
1525  grantee->getPrivileges(object, true);
1526 
1529  sqliteConnector_, granteeName, grantee->isUser(), object);
1530  updateObjectDescriptorMap(granteeName, object, grantee->isUser(), catalog);
1531 }
1532 
1533 void SysCatalog::grantAllOnDatabase_unsafe(const std::string& roleName,
1534  DBObject& object,
1535  const Catalog_Namespace::Catalog& catalog) {
1536  // It's a separate use case because it's easier for implementation to convert ALL ON
1537  // DATABASE into ALL ON DASHBOARDS, ALL ON VIEWS and ALL ON TABLES
1538  // Add DB Access privileges
1539  DBObject tmp_object = object;
1542  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1545  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1548  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1550  tmp_object.setPermissionType(ViewDBObjectType);
1551  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1552 
1553  if (g_enable_fsi) {
1556  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1557  }
1558 
1561  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1562  return;
1563 }
1564 
1565 void SysCatalog::revokeDBObjectPrivilegesBatch_unsafe(
1566  const vector<string>& grantees,
1567  const vector<DBObject>& objects,
1568  const Catalog_Namespace::Catalog& catalog) {
1569  for (const auto& grantee : grantees) {
1570  for (const auto& object : objects) {
1571  revokeDBObjectPrivileges_unsafe(grantee, object, catalog);
1572  }
1573  }
1574 }
1575 
1576 void SysCatalog::revokeDBObjectPrivilegesFromAllBatch_unsafe(
1577  vector<DBObject>& objects,
1578  Catalog_Namespace::Catalog* catalog) {
1579  for (const auto& object : objects) {
1580  revokeDBObjectPrivilegesFromAll_unsafe(object, catalog);
1581  }
1582 }
1583 
1584 // REVOKE INSERT ON TABLE payroll_table FROM payroll_dept_role;
1585 void SysCatalog::revokeDBObjectPrivileges_unsafe(
1586  const std::string& granteeName,
1587  DBObject object,
1588  const Catalog_Namespace::Catalog& catalog) {
1589  sys_write_lock write_lock(this);
1590 
1591  UserMetadata user_meta;
1592  if (instance().getMetadataForUser(granteeName, user_meta)) {
1593  if (user_meta.isSuper) {
1594  // super doesn't have explicit privileges so nothing to do
1595  return;
1596  }
1597  }
1598  auto* grantee = getGrantee(granteeName);
1599  if (!grantee) {
1600  throw runtime_error("Request to revoke privileges from " + granteeName +
1601  " failed because role or user with this name does not exist.");
1602  }
1603  object.loadKey(catalog);
1604 
1605  if (object.getPrivileges().hasPermission(DatabasePrivileges::ALL) &&
1606  object.getObjectKey().permissionType == DatabaseDBObjectType) {
1607  return revokeAllOnDatabase_unsafe(granteeName, object.getObjectKey().dbId, grantee);
1608  }
1609 
1610  auto ret_object = grantee->revokePrivileges(object);
1611  if (ret_object) {
1614  sqliteConnector_, granteeName, grantee->isUser(), *ret_object);
1615  updateObjectDescriptorMap(granteeName, *ret_object, grantee->isUser(), catalog);
1616  } else {
1618  deleteObjectPrivileges(sqliteConnector_, granteeName, grantee->isUser(), object);
1619  deleteObjectDescriptorMap(granteeName, object, catalog);
1620  }
1621 }
1622 
1623 void SysCatalog::revokeAllOnDatabase_unsafe(const std::string& roleName,
1624  int32_t dbId,
1625  Grantee* grantee) {
1627  sqliteConnector_->query_with_text_params(
1628  "DELETE FROM mapd_object_permissions WHERE roleName = ?1 and dbId = ?2",
1629  std::vector<std::string>{roleName, std::to_string(dbId)});
1630  grantee->revokeAllOnDatabase(dbId);
1631  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
1632  if (d->second->roleName == roleName && d->second->dbId == dbId) {
1633  delete d->second;
1634  d = objectDescriptorMap_.erase(d);
1635  } else {
1636  d++;
1637  }
1638  }
1639 }
1640 
1641 void SysCatalog::revokeDBObjectPrivilegesFromAll_unsafe(DBObject dbObject,
1642  Catalog* catalog) {
1643  sys_write_lock write_lock(this);
1644  dbObject.loadKey(*catalog);
1645  auto privs = (dbObject.getObjectKey().permissionType == TableDBObjectType)
1650  dbObject.setPrivileges(privs);
1651  for (const auto& grantee : granteeMap_) {
1652  if (grantee.second->findDbObject(dbObject.getObjectKey(), true)) {
1653  revokeDBObjectPrivileges_unsafe(grantee.second->getName(), dbObject, *catalog);
1654  }
1655  }
1656 }
1657 
1658 bool SysCatalog::verifyDBObjectOwnership(const UserMetadata& user,
1659  DBObject object,
1660  const Catalog_Namespace::Catalog& catalog) {
1661  sys_read_lock read_lock(this);
1662 
1663  auto* grantee = instance().getUserGrantee(user.userName);
1664  if (grantee) {
1665  object.loadKey(catalog);
1666  auto* found_object = grantee->findDbObject(object.getObjectKey(), false);
1667  if (found_object && found_object->getOwner() == user.userId) {
1668  return true;
1669  }
1670  }
1671  return false;
1672 }
1673 
1674 void SysCatalog::changeDBObjectOwnership(const UserMetadata& new_owner,
1675  const UserMetadata& previous_owner,
1676  DBObject object,
1677  const Catalog_Namespace::Catalog& catalog,
1678  bool revoke_privileges) {
1679  sys_write_lock write_lock(this);
1681  object.loadKey(catalog);
1682  switch (object.getType()) {
1683  case TableDBObjectType:
1684  object.setPrivileges(AccessPrivileges::ALL_TABLE);
1685  break;
1686  case DashboardDBObjectType:
1687  object.setPrivileges(AccessPrivileges::ALL_DASHBOARD);
1688  break;
1689  case ServerDBObjectType:
1690  object.setPrivileges(AccessPrivileges::ALL_SERVER);
1691  break;
1692  case DatabaseDBObjectType:
1693  object.setPrivileges(AccessPrivileges::ALL_DATABASE);
1694  break;
1695  case ViewDBObjectType:
1696  object.setPrivileges(AccessPrivileges::ALL_VIEW);
1697  break;
1698  default:
1699  UNREACHABLE(); // unkown object type
1700  break;
1701  }
1702  sqliteConnector_->query("BEGIN TRANSACTION");
1703  try {
1704  if (!new_owner.isSuper) { // no need to grant to suser, has all privs by default
1705  grantDBObjectPrivileges_unsafe(new_owner.userName, object, catalog);
1706  }
1707  if (!previous_owner.isSuper && revoke_privileges) { // no need to revoke from suser
1708  revokeDBObjectPrivileges_unsafe(previous_owner.userName, object, catalog);
1709  }
1710  } catch (std::exception& e) {
1711  sqliteConnector_->query("ROLLBACK TRANSACTION");
1712  throw;
1713  }
1714  sqliteConnector_->query("END TRANSACTION");
1715  object.setOwner(new_owner.userId); // change owner if no exceptions happen
1716 }
1717 
1718 void SysCatalog::getDBObjectPrivileges(const std::string& granteeName,
1719  DBObject& object,
1720  const Catalog_Namespace::Catalog& catalog) const {
1721  sys_read_lock read_lock(this);
1722  UserMetadata user_meta;
1723 
1724  if (instance().getMetadataForUser(granteeName, user_meta)) {
1725  if (user_meta.isSuper) {
1726  throw runtime_error(
1727  "Request to show privileges from " + granteeName +
1728  " failed because user is super user and has all privileges by default.");
1729  }
1730  }
1731  auto* grantee = instance().getGrantee(granteeName);
1732  if (!grantee) {
1733  throw runtime_error("Request to show privileges for " + granteeName +
1734  " failed because role or user with this name does not exist.");
1735  }
1736  object.loadKey(catalog);
1737  grantee->getPrivileges(object, true);
1738 }
1739 
1740 void SysCatalog::createRole_unsafe(const std::string& roleName,
1741  const bool userPrivateRole) {
1742  sys_write_lock write_lock(this);
1743 
1744  auto* grantee = getGrantee(roleName);
1745  if (grantee) {
1746  throw std::runtime_error("CREATE ROLE " + roleName +
1747  " failed because grantee with this name already exists.");
1748  }
1749  if (userPrivateRole) {
1750  grantee = new User(roleName);
1751  } else {
1752  grantee = new Role(roleName);
1753  }
1754  granteeMap_[to_upper(roleName)] = grantee;
1755 
1756  // NOTE (max): Why create an empty privileges record for a role?
1757  /* grant none privileges to this role and add it to sqlite DB */
1759  DBObjectKey objKey;
1760  // 0 is an id that does not exist
1761  objKey.dbId = 0;
1763  dbObject.setObjectKey(objKey);
1764  grantee->grantPrivileges(dbObject);
1765 
1767  insertOrUpdateObjectPrivileges(sqliteConnector_, roleName, userPrivateRole, dbObject);
1768 }
1769 
1770 void SysCatalog::dropRole_unsafe(const std::string& roleName) {
1771  sys_write_lock write_lock(this);
1772 
1773  // it may very well be a user "role", so keep it generic
1774  auto* rl = getGrantee(roleName);
1775  if (rl) { // admin super user may not exist in roles
1776  delete rl;
1777  }
1778  granteeMap_.erase(to_upper(roleName));
1779 
1781  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE roleName = ?",
1782  roleName);
1783  sqliteConnector_->query_with_text_param(
1784  "DELETE FROM mapd_object_permissions WHERE roleName = ?", roleName);
1785 }
1786 
1787 void SysCatalog::grantRoleBatch_unsafe(const std::vector<std::string>& roles,
1788  const std::vector<std::string>& grantees) {
1789  for (const auto& role : roles) {
1790  for (const auto& grantee : grantees) {
1791  grantRole_unsafe(role, grantee);
1792  }
1793  }
1794 }
1795 
1796 // GRANT ROLE payroll_dept_role TO joe;
1797 void SysCatalog::grantRole_unsafe(const std::string& roleName,
1798  const std::string& granteeName) {
1799  auto* rl = getRoleGrantee(roleName);
1800  if (!rl) {
1801  throw runtime_error("Request to grant role " + roleName +
1802  " failed because role with this name does not exist.");
1803  }
1804  auto* grantee = getGrantee(granteeName);
1805  if (!grantee) {
1806  throw runtime_error("Request to grant role " + roleName + " failed because grantee " +
1807  granteeName + " does not exist.");
1808  }
1809  sys_write_lock write_lock(this);
1810  if (!grantee->hasRole(rl, true)) {
1811  grantee->grantRole(rl);
1813  sqliteConnector_->query_with_text_params(
1814  "INSERT INTO mapd_roles(roleName, userName) VALUES (?, ?)",
1815  std::vector<std::string>{rl->getName(), grantee->getName()});
1816  }
1817 }
1818 
1819 void SysCatalog::revokeRoleBatch_unsafe(const std::vector<std::string>& roles,
1820  const std::vector<std::string>& grantees) {
1821  for (const auto& role : roles) {
1822  for (const auto& grantee : grantees) {
1823  revokeRole_unsafe(role, grantee);
1824  }
1825  }
1826 }
1827 
1828 // REVOKE ROLE payroll_dept_role FROM joe;
1829 void SysCatalog::revokeRole_unsafe(const std::string& roleName,
1830  const std::string& granteeName) {
1831  auto* rl = getRoleGrantee(roleName);
1832  if (!rl) {
1833  throw runtime_error("Request to revoke role " + roleName +
1834  " failed because role with this name does not exist.");
1835  }
1836  auto* grantee = getGrantee(granteeName);
1837  if (!grantee) {
1838  throw runtime_error("Request to revoke role from " + granteeName +
1839  " failed because grantee with this name does not exist.");
1840  }
1841  sys_write_lock write_lock(this);
1842  grantee->revokeRole(rl);
1844  sqliteConnector_->query_with_text_params(
1845  "DELETE FROM mapd_roles WHERE roleName = ? AND userName = ?",
1846  std::vector<std::string>{rl->getName(), grantee->getName()});
1847 }
1848 
1849 // Update or add element in ObjectRoleDescriptorMap
1850 void SysCatalog::updateObjectDescriptorMap(const std::string& roleName,
1851  DBObject& object,
1852  bool roleType,
1854  bool present = false;
1855  auto privs = object.getPrivileges();
1856  sys_write_lock write_lock(this);
1857  auto range = objectDescriptorMap_.equal_range(
1858  std::to_string(cat.getCurrentDB().dbId) + ":" +
1859  std::to_string(object.getObjectKey().permissionType) + ":" +
1860  std::to_string(object.getObjectKey().objectId));
1861  for (auto d = range.first; d != range.second; ++d) {
1862  if (d->second->roleName == roleName) {
1863  // overwrite permissions
1864  d->second->privs = privs;
1865  present = true;
1866  }
1867  }
1868  if (!present) {
1870  od->roleName = roleName;
1871  od->roleType = roleType;
1872  od->objectType = object.getObjectKey().permissionType;
1873  od->dbId = object.getObjectKey().dbId;
1874  od->objectId = object.getObjectKey().objectId;
1875  od->privs = object.getPrivileges();
1876  od->objectOwnerId = object.getOwner();
1877  od->objectName = object.getName();
1878  objectDescriptorMap_.insert(ObjectRoleDescriptorMap::value_type(
1879  std::to_string(od->dbId) + ":" + std::to_string(od->objectType) + ":" +
1880  std::to_string(od->objectId),
1881  od));
1882  }
1883 }
1884 
1885 // rename object descriptors
1886 void SysCatalog::renameObjectsInDescriptorMap(DBObject& object,
1888  sys_write_lock write_lock(this);
1890  auto range = objectDescriptorMap_.equal_range(
1891  std::to_string(cat.getCurrentDB().dbId) + ":" +
1892  std::to_string(object.getObjectKey().permissionType) + ":" +
1893  std::to_string(object.getObjectKey().objectId));
1894  for (auto d = range.first; d != range.second; ++d) {
1895  // rename object
1896  d->second->objectName = object.getName();
1897  }
1898 
1899  sqliteConnector_->query("BEGIN TRANSACTION");
1900  try {
1901  sqliteConnector_->query_with_text_params(
1902  "UPDATE mapd_object_permissions SET objectName = ?1 WHERE "
1903  "dbId = ?2 AND objectId = ?3",
1904  std::vector<std::string>{object.getName(),
1906  std::to_string(object.getObjectKey().objectId)});
1907  } catch (const std::exception& e) {
1908  sqliteConnector_->query("ROLLBACK TRANSACTION");
1909  throw;
1910  }
1911  sqliteConnector_->query("END TRANSACTION");
1912 }
1913 
1914 // Remove user/role from ObjectRoleDescriptorMap
1915 void SysCatalog::deleteObjectDescriptorMap(const std::string& roleName) {
1916  sys_write_lock write_lock(this);
1917 
1918  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
1919  if (d->second->roleName == roleName) {
1920  delete d->second;
1921  d = objectDescriptorMap_.erase(d);
1922  } else {
1923  d++;
1924  }
1925  }
1926 }
1927 
1928 // Remove element from ObjectRoleDescriptorMap
1929 void SysCatalog::deleteObjectDescriptorMap(const std::string& roleName,
1930  DBObject& object,
1931  const Catalog_Namespace::Catalog& cat) {
1932  sys_write_lock write_lock(this);
1933  auto range = objectDescriptorMap_.equal_range(
1934  std::to_string(cat.getCurrentDB().dbId) + ":" +
1935  std::to_string(object.getObjectKey().permissionType) + ":" +
1936  std::to_string(object.getObjectKey().objectId));
1937  for (auto d = range.first; d != range.second;) {
1938  // remove the entry
1939  if (d->second->roleName == roleName) {
1940  delete d->second;
1941  d = objectDescriptorMap_.erase(d);
1942  } else {
1943  d++;
1944  }
1945  }
1946 }
1947 
1948 bool SysCatalog::hasAnyPrivileges(const UserMetadata& user,
1949  std::vector<DBObject>& privObjects) {
1950  sys_read_lock read_lock(this);
1951  if (user.isSuper) {
1952  return true;
1953  }
1954  auto* user_rl = instance().getUserGrantee(user.userName);
1955  if (!user_rl) {
1956  throw runtime_error("User " + user.userName + " does not exist.");
1957  }
1958  for (std::vector<DBObject>::iterator objectIt = privObjects.begin();
1959  objectIt != privObjects.end();
1960  ++objectIt) {
1961  if (!user_rl->hasAnyPrivileges(*objectIt, false)) {
1962  return false;
1963  }
1964  }
1965  return true;
1966 }
1967 
1968 bool SysCatalog::checkPrivileges(const UserMetadata& user,
1969  const std::vector<DBObject>& privObjects) const {
1970  sys_read_lock read_lock(this);
1971  if (user.isSuper) {
1972  return true;
1973  }
1974 
1975  auto* user_rl = instance().getUserGrantee(user.userName);
1976  if (!user_rl) {
1977  throw runtime_error("User " + user.userName + " does not exist.");
1978  }
1979  for (auto& object : privObjects) {
1980  if (!user_rl->checkPrivileges(object)) {
1981  return false;
1982  }
1983  }
1984  return true;
1985 }
1986 
1987 bool SysCatalog::checkPrivileges(const std::string& userName,
1988  const std::vector<DBObject>& privObjects) const {
1989  UserMetadata user;
1990  if (!instance().getMetadataForUser(userName, user)) {
1991  throw runtime_error("Request to check privileges for user " + userName +
1992  " failed because user with this name does not exist.");
1993  }
1994  return (checkPrivileges(user, privObjects));
1995 }
1996 
1997 Grantee* SysCatalog::getGrantee(const std::string& name) const {
1998  sys_read_lock read_lock(this);
1999  auto grantee = granteeMap_.find(to_upper(name));
2000  if (grantee == granteeMap_.end()) { // check to make sure role exists
2001  return nullptr;
2002  }
2003  return grantee->second; // returns pointer to role
2004 }
2005 
2006 Role* SysCatalog::getRoleGrantee(const std::string& name) const {
2007  return dynamic_cast<Role*>(getGrantee(name));
2008 }
2009 
2010 User* SysCatalog::getUserGrantee(const std::string& name) const {
2011  return dynamic_cast<User*>(getGrantee(name));
2012 }
2013 
2014 std::vector<ObjectRoleDescriptor*>
2015 SysCatalog::getMetadataForObject(int32_t dbId, int32_t dbType, int32_t objectId) const {
2016  sys_read_lock read_lock(this);
2017  std::vector<ObjectRoleDescriptor*> objectsList;
2018 
2019  auto range = objectDescriptorMap_.equal_range(std::to_string(dbId) + ":" +
2020  std::to_string(dbType) + ":" +
2021  std::to_string(objectId));
2022  for (auto d = range.first; d != range.second; ++d) {
2023  objectsList.push_back(d->second);
2024  }
2025  return objectsList; // return pointers to objects
2026 }
2027 
2028 bool SysCatalog::isRoleGrantedToGrantee(const std::string& granteeName,
2029  const std::string& roleName,
2030  bool only_direct) const {
2031  sys_read_lock read_lock(this);
2032  if (roleName == granteeName) {
2033  return true;
2034  }
2035  bool is_role_granted = false;
2036  auto* target_role = instance().getRoleGrantee(roleName);
2037  auto has_role = [&](auto grantee_rl) {
2038  is_role_granted = target_role && grantee_rl->hasRole(target_role, only_direct);
2039  };
2040  if (auto* user_role = instance().getUserGrantee(granteeName); user_role) {
2041  has_role(user_role);
2042  } else if (auto* role = instance().getRoleGrantee(granteeName); role) {
2043  has_role(role);
2044  } else {
2045  CHECK(false);
2046  }
2047  return is_role_granted;
2048 }
2049 
2050 bool SysCatalog::isDashboardSystemRole(const std::string& roleName) {
2051  return boost::algorithm::ends_with(roleName, SYSTEM_ROLE_TAG);
2052 }
2053 
2054 std::vector<std::string> SysCatalog::getRoles(const std::string& userName,
2055  const int32_t dbId) {
2056  sys_sqlite_lock sqlite_lock(this);
2057  std::string sql =
2058  "SELECT DISTINCT roleName FROM mapd_object_permissions WHERE "
2059  "objectPermissions<>0 "
2060  "AND roleType=0 AND dbId=" +
2061  std::to_string(dbId);
2062  sqliteConnector_->query(sql);
2063  int numRows = sqliteConnector_->getNumRows();
2064  std::vector<std::string> roles(0);
2065  for (int r = 0; r < numRows; ++r) {
2066  auto roleName = sqliteConnector_->getData<string>(r, 0);
2067  if (isRoleGrantedToGrantee(userName, roleName, false) &&
2068  !isDashboardSystemRole(roleName)) {
2069  roles.push_back(roleName);
2070  }
2071  }
2072  return roles;
2073 }
2074 
2075 std::vector<std::string> SysCatalog::getRoles(bool userPrivateRole,
2076  bool isSuper,
2077  const std::string& userName) {
2078  sys_read_lock read_lock(this);
2079  std::vector<std::string> roles;
2080  for (auto& grantee : granteeMap_) {
2081  if (!userPrivateRole && grantee.second->isUser()) {
2082  continue;
2083  }
2084  if (!isSuper && !isRoleGrantedToGrantee(userName, grantee.second->getName(), false)) {
2085  continue;
2086  }
2087  if (isDashboardSystemRole(grantee.second->getName())) {
2088  continue;
2089  }
2090  roles.push_back(grantee.second->getName());
2091  }
2092  return roles;
2093 }
2094 
2095 void SysCatalog::revokeDashboardSystemRole(const std::string roleName,
2096  const std::vector<std::string> grantees) {
2097  auto* rl = getRoleGrantee(roleName);
2098  for (auto granteeName : grantees) {
2099  const auto* grantee = SysCatalog::instance().getGrantee(granteeName);
2100  if (rl && grantee->hasRole(rl, true)) {
2101  // Grantees existence have been already validated
2102  SysCatalog::instance().revokeRole(roleName, granteeName);
2103  }
2104  }
2105 }
2106 
2107 void SysCatalog::buildRoleMap() {
2108  sys_write_lock write_lock(this);
2109  sys_sqlite_lock sqlite_lock(this);
2110  string roleQuery(
2111  "SELECT roleName, roleType, objectPermissionsType, dbId, objectId, "
2112  "objectPermissions, objectOwnerId, objectName "
2113  "from mapd_object_permissions");
2114  sqliteConnector_->query(roleQuery);
2115  size_t numRows = sqliteConnector_->getNumRows();
2116  std::vector<std::string> objectKeyStr(4);
2117  DBObjectKey objectKey;
2118  AccessPrivileges privs;
2119  bool userPrivateRole{false};
2120  for (size_t r = 0; r < numRows; ++r) {
2121  std::string roleName = sqliteConnector_->getData<string>(r, 0);
2122  userPrivateRole = sqliteConnector_->getData<bool>(r, 1);
2123  DBObjectType permissionType =
2124  static_cast<DBObjectType>(sqliteConnector_->getData<int>(r, 2));
2125  objectKeyStr[0] = sqliteConnector_->getData<string>(r, 2);
2126  objectKeyStr[1] = sqliteConnector_->getData<string>(r, 3);
2127  objectKeyStr[2] = sqliteConnector_->getData<string>(r, 4);
2128  objectKey = DBObjectKey::fromString(objectKeyStr, permissionType);
2129  privs.privileges = sqliteConnector_->getData<int>(r, 5);
2130  int32_t owner = sqliteConnector_->getData<int>(r, 6);
2131  std::string name = sqliteConnector_->getData<string>(r, 7);
2132 
2133  DBObject dbObject(objectKey, privs, owner);
2134  dbObject.setName(name);
2135  if (-1 == objectKey.objectId) {
2136  dbObject.setObjectType(DBObjectType::DatabaseDBObjectType);
2137  } else {
2138  dbObject.setObjectType(permissionType);
2139  }
2140 
2141  auto* rl = getGrantee(roleName);
2142  if (!rl) {
2143  if (userPrivateRole) {
2144  rl = new User(roleName);
2145  } else {
2146  rl = new Role(roleName);
2147  }
2148  granteeMap_[to_upper(roleName)] = rl;
2149  }
2150  rl->grantPrivileges(dbObject);
2151  }
2152 }
2153 
2154 void SysCatalog::populateRoleDbObjects(const std::vector<DBObject>& objects) {
2155  sys_write_lock write_lock(this);
2156  sys_sqlite_lock sqlite_lock(this);
2157  sqliteConnector_->query("BEGIN TRANSACTION");
2158  try {
2159  for (auto dbobject : objects) {
2160  UserMetadata user;
2161  CHECK(getMetadataForUserById(dbobject.getOwner(), user));
2162  auto* grantee = getUserGrantee(user.userName);
2163  if (grantee) {
2165  sqliteConnector_, grantee->getName(), true, dbobject);
2166  grantee->grantPrivileges(dbobject);
2167  }
2168  }
2169 
2170  } catch (const std::exception& e) {
2171  sqliteConnector_->query("ROLLBACK TRANSACTION");
2172  throw;
2173  }
2174  sqliteConnector_->query("END TRANSACTION");
2175 }
2176 
2177 void SysCatalog::buildUserRoleMap() {
2178  sys_write_lock write_lock(this);
2179  sys_sqlite_lock sqlite_lock(this);
2180  std::vector<std::pair<std::string, std::string>> granteeRooles;
2181  string userRoleQuery("SELECT roleName, userName from mapd_roles");
2182  sqliteConnector_->query(userRoleQuery);
2183  size_t numRows = sqliteConnector_->getNumRows();
2184  for (size_t r = 0; r < numRows; ++r) {
2185  std::string roleName = sqliteConnector_->getData<string>(r, 0);
2186  std::string userName = sqliteConnector_->getData<string>(r, 1);
2187  // required for declared nomenclature before v4.0.0
2188  if ((boost::equals(roleName, "mapd_default_suser_role") &&
2189  boost::equals(userName, OMNISCI_ROOT_USER)) ||
2190  (boost::equals(roleName, "mapd_default_user_role") &&
2191  !boost::equals(userName, "mapd_default_user_role"))) {
2192  // grouprole already exists with roleName==userName in mapd_roles table
2193  // ignore duplicate instances of userRole which exists before v4.0.0
2194  continue;
2195  }
2196  auto* rl = getGrantee(roleName);
2197  if (!rl) {
2198  throw runtime_error("Data inconsistency when building role map. Role " + roleName +
2199  " from db not found in the map.");
2200  }
2201  std::pair<std::string, std::string> roleVecElem(roleName, userName);
2202  granteeRooles.push_back(roleVecElem);
2203  }
2204 
2205  for (size_t i = 0; i < granteeRooles.size(); i++) {
2206  std::string roleName = granteeRooles[i].first;
2207  std::string granteeName = granteeRooles[i].second;
2208  auto* grantee = getGrantee(granteeName);
2209  if (!grantee) {
2210  throw runtime_error("Data inconsistency when building role map. Grantee " +
2211  granteeName + " not found in the map.");
2212  }
2213  if (granteeName == roleName) {
2214  continue;
2215  }
2216  Role* rl = dynamic_cast<Role*>(getGrantee(roleName));
2217  if (!rl) {
2218  throw runtime_error("Data inconsistency when building role map. Role " + roleName +
2219  " not found in the map.");
2220  }
2221  grantee->grantRole(rl);
2222  }
2223 }
2224 
2225 void SysCatalog::buildObjectDescriptorMap() {
2226  sys_write_lock write_lock(this);
2227  sys_sqlite_lock sqlite_lock(this);
2228  string objectQuery(
2229  "SELECT roleName, roleType, objectPermissionsType, dbId, objectId, "
2230  "objectPermissions, objectOwnerId, objectName "
2231  "from mapd_object_permissions");
2232  sqliteConnector_->query(objectQuery);
2233  size_t numRows = sqliteConnector_->getNumRows();
2234  for (size_t r = 0; r < numRows; ++r) {
2236  od->roleName = sqliteConnector_->getData<string>(r, 0);
2237  od->roleType = sqliteConnector_->getData<bool>(r, 1);
2238  od->objectType = sqliteConnector_->getData<int>(r, 2);
2239  od->dbId = sqliteConnector_->getData<int>(r, 3);
2240  od->objectId = sqliteConnector_->getData<int>(r, 4);
2241  od->privs.privileges = sqliteConnector_->getData<int>(r, 5);
2242  od->objectOwnerId = sqliteConnector_->getData<int>(r, 6);
2243  od->objectName = sqliteConnector_->getData<string>(r, 7);
2244  objectDescriptorMap_.insert(ObjectRoleDescriptorMap::value_type(
2245  std::to_string(od->dbId) + ":" + std::to_string(od->objectType) + ":" +
2246  std::to_string(od->objectId),
2247  od));
2248  }
2249 }
2250 
2251 template <typename F, typename... Args>
2252 void SysCatalog::execInTransaction(F&& f, Args&&... args) {
2253  sys_write_lock write_lock(this);
2254  sys_sqlite_lock sqlite_lock(this);
2255  sqliteConnector_->query("BEGIN TRANSACTION");
2256  try {
2257  (this->*f)(std::forward<Args>(args)...);
2258  } catch (std::exception&) {
2259  sqliteConnector_->query("ROLLBACK TRANSACTION");
2260  throw;
2261  }
2262  sqliteConnector_->query("END TRANSACTION");
2263 }
2264 
2265 void SysCatalog::createRole(const std::string& roleName, const bool& userPrivateRole) {
2266  execInTransaction(&SysCatalog::createRole_unsafe, roleName, userPrivateRole);
2267 }
2268 
2269 void SysCatalog::dropRole(const std::string& roleName) {
2270  execInTransaction(&SysCatalog::dropRole_unsafe, roleName);
2271 }
2272 
2273 void SysCatalog::grantRoleBatch(const std::vector<std::string>& roles,
2274  const std::vector<std::string>& grantees) {
2275  execInTransaction(&SysCatalog::grantRoleBatch_unsafe, roles, grantees);
2276 }
2277 
2278 void SysCatalog::grantRole(const std::string& role, const std::string& grantee) {
2279  execInTransaction(&SysCatalog::grantRole_unsafe, role, grantee);
2280 }
2281 
2282 void SysCatalog::revokeRoleBatch(const std::vector<std::string>& roles,
2283  const std::vector<std::string>& grantees) {
2284  execInTransaction(&SysCatalog::revokeRoleBatch_unsafe, roles, grantees);
2285 }
2286 
2287 void SysCatalog::revokeRole(const std::string& role, const std::string& grantee) {
2288  execInTransaction(&SysCatalog::revokeRole_unsafe, role, grantee);
2289 }
2290 
2291 void SysCatalog::grantDBObjectPrivileges(const string& grantee,
2292  const DBObject& object,
2293  const Catalog_Namespace::Catalog& catalog) {
2294  execInTransaction(
2295  &SysCatalog::grantDBObjectPrivileges_unsafe, grantee, object, catalog);
2296 }
2297 
2298 void SysCatalog::grantDBObjectPrivilegesBatch(const vector<string>& grantees,
2299  const vector<DBObject>& objects,
2300  const Catalog_Namespace::Catalog& catalog) {
2301  execInTransaction(
2302  &SysCatalog::grantDBObjectPrivilegesBatch_unsafe, grantees, objects, catalog);
2303 }
2304 
2305 void SysCatalog::revokeDBObjectPrivileges(const string& grantee,
2306  const DBObject& object,
2307  const Catalog_Namespace::Catalog& catalog) {
2308  execInTransaction(
2309  &SysCatalog::revokeDBObjectPrivileges_unsafe, grantee, object, catalog);
2310 }
2311 
2312 void SysCatalog::revokeDBObjectPrivilegesBatch(
2313  const vector<string>& grantees,
2314  const vector<DBObject>& objects,
2315  const Catalog_Namespace::Catalog& catalog) {
2316  execInTransaction(
2317  &SysCatalog::revokeDBObjectPrivilegesBatch_unsafe, grantees, objects, catalog);
2318 }
2319 
2320 void SysCatalog::revokeDBObjectPrivilegesFromAll(DBObject object, Catalog* catalog) {
2321  execInTransaction(&SysCatalog::revokeDBObjectPrivilegesFromAll_unsafe, object, catalog);
2322 }
2323 
2324 void SysCatalog::revokeDBObjectPrivilegesFromAllBatch(vector<DBObject>& objects,
2325  Catalog* catalog) {
2326  execInTransaction(
2327  &SysCatalog::revokeDBObjectPrivilegesFromAllBatch_unsafe, objects, catalog);
2328 }
2329 
2330 void SysCatalog::syncUserWithRemoteProvider(const std::string& user_name,
2331  std::vector<std::string> idp_roles,
2332  bool* is_super) {
2333  UserMetadata user_meta;
2334  bool is_super_user = is_super ? *is_super : false;
2335  if (!getMetadataForUser(user_name, user_meta)) {
2336  createUser(user_name, generate_random_string(72), is_super_user, "", true);
2337  LOG(INFO) << "User " << user_name << " has been created by remote identity provider"
2338  << " with IS_SUPER = " << (is_super_user ? "'TRUE'" : "'FALSE'");
2339  } else if (is_super && is_super_user != user_meta.isSuper) {
2340  alterUser(user_meta.userId, nullptr, is_super, nullptr, nullptr);
2341  LOG(INFO) << "IS_SUPER for user " << user_name << " has been changed to "
2342  << (is_super_user ? "TRUE" : "FALSE") << " by remote identity provider";
2343  }
2344  std::vector<std::string> current_roles = {};
2345  auto* user_rl = getUserGrantee(user_name);
2346  if (user_rl) {
2347  current_roles = user_rl->getRoles();
2348  }
2349  std::transform(
2350  current_roles.begin(), current_roles.end(), current_roles.begin(), to_upper);
2351  std::transform(idp_roles.begin(), idp_roles.end(), idp_roles.begin(), to_upper);
2352  std::list<std::string> roles_revoked, roles_granted;
2353  // first remove obsolete ones
2354  for (auto& current_role_name : current_roles) {
2355  if (std::find(idp_roles.begin(), idp_roles.end(), current_role_name) ==
2356  idp_roles.end()) {
2357  revokeRole(current_role_name, user_name);
2358  roles_revoked.push_back(current_role_name);
2359  }
2360  }
2361  for (auto& role_name : idp_roles) {
2362  if (std::find(current_roles.begin(), current_roles.end(), role_name) ==
2363  current_roles.end()) {
2364  auto* rl = getRoleGrantee(role_name);
2365  if (rl) {
2366  grantRole(role_name, user_name);
2367  roles_granted.push_back(role_name);
2368  } else {
2369  LOG(WARNING) << "Error synchronizing roles for user " << user_name << ": role "
2370  << role_name << " does not exist";
2371  }
2372  }
2373  }
2374  if (roles_granted.empty() && roles_revoked.empty()) {
2375  LOG(INFO) << "Roles for user " << user_name
2376  << " are up to date with remote identity provider";
2377  } else {
2378  if (!roles_revoked.empty()) {
2379  LOG(INFO) << "Roles revoked during synchronization with identity provider for user "
2380  << user_name << ": " << join(roles_revoked, " ");
2381  }
2382  if (!roles_granted.empty()) {
2383  LOG(INFO) << "Roles granted during synchronization with identity provider for user "
2384  << user_name << ": " << join(roles_granted, " ");
2385  }
2386  }
2387 }
2388 
2389 std::unordered_map<std::string, std::vector<std::string>>
2390 SysCatalog::getGranteesOfSharedDashboards(const std::vector<std::string>& dashboard_ids) {
2391  sys_sqlite_lock sqlite_lock(this);
2392  std::unordered_map<std::string, std::vector<std::string>> active_grantees;
2393  sqliteConnector_->query("BEGIN TRANSACTION");
2394  try {
2395  for (auto dash : dashboard_ids) {
2396  std::vector<std::string> grantees = {};
2397  sqliteConnector_->query_with_text_params(
2398  "SELECT roleName FROM mapd_object_permissions WHERE objectPermissions NOT IN "
2399  "(0,1) AND objectPermissionsType = ? AND objectId = ?",
2400  std::vector<std::string>{
2401  std::to_string(static_cast<int32_t>(DashboardDBObjectType)), dash});
2402  int num_rows = sqliteConnector_->getNumRows();
2403  if (num_rows == 0) {
2404  // no grantees
2405  continue;
2406  } else {
2407  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
2408  grantees.push_back(sqliteConnector_->getData<string>(i, 0));
2409  }
2410  active_grantees[dash] = grantees;
2411  }
2412  }
2413  } catch (const std::exception& e) {
2414  sqliteConnector_->query("ROLLBACK TRANSACTION");
2415  throw;
2416  }
2417  sqliteConnector_->query("END TRANSACTION");
2418  return active_grantees;
2419 }
2420 
2421 } // namespace Catalog_Namespace
static const AccessPrivileges VIEW_SQL_EDITOR
Definition: DBObject.h:153
std::string cat(Ts &&...args)
DBObjectKey getObjectKey() const
Definition: DBObject.h:211
class for a per-database catalog. also includes metadata for the current database and the current use...
Definition: Catalog.h:97
static const AccessPrivileges ALL_DATABASE
Definition: DBObject.h:152
DBObjectType
Definition: DBObject.h:42
void updatePrivileges(const DBObject &object)
Definition: DBObject.cpp:141
static const AccessPrivileges ALL_TABLE_MIGRATE
Definition: DBObject.h:157
#define LOG(tag)
Definition: Logger.h:188
static const int32_t ALL
Definition: DBObject.h:79
std::string join(T const &container, std::string const &delim)
specifies the object_roles content in-memory of a row in mapd_object_permissions table ...
#define UNREACHABLE()
Definition: Logger.h:241
void setObjectKey(const DBObjectKey &objectKey)
Definition: DBObject.h:215
const std::string OMNISCI_SYSTEM_CATALOG
Definition: SysCatalog.h:55
Definition: Grantee.h:70
int32_t objectId
Definition: DBObject.h:57
void setName(std::string name)
Definition: DBObject.h:208
Definition: Grantee.h:76
void setPrivileges(const AccessPrivileges &privs)
Definition: DBObject.h:217
std::string to_string(char const *&&v)
static const AccessPrivileges ALL_VIEW
Definition: DBObject.h:178
This file contains the class specification and related data structures for Catalog.
static DBObjectKey fromString(const std::vector< std::string > &key, const DBObjectType &type)
Definition: DBObject.cpp:259
This file contains the class specification and related data structures for SysCatalog.
static bool parseUserMetadataFromSQLite(const std::unique_ptr< SqliteConnector > &conn, UserMetadata &user)
void setPermissionType(const DBObjectType &permissionType)
Definition: DBObject.cpp:149
const DBMetadata & getCurrentDB() const
Definition: Catalog.h:210
void init(LogOptions const &log_opts)
Definition: Logger.cpp:280
const std::string OMNISCI_DEFAULT_DB
Definition: SysCatalog.h:56
std::string generate_random_string(const size_t len)
virtual void revokeAllOnDatabase(int32_t dbId)
Definition: Grantee.cpp:279
std::string hash_with_bcrypt(const std::string &pwd)
Definition: SysCatalog.cpp:65
static const int32_t MAPD_VERSION
Definition: release.h:33
static const AccessPrivileges ALL_DASHBOARD_MIGRATE
Definition: DBObject.h:169
static const AccessPrivileges ALL_SERVER
Definition: DBObject.h:188
static const AccessPrivileges NONE
Definition: DBObject.h:149
static const std::string SYSTEM_ROLE_TAG("#dash_system_role")
specifies the content in-memory of a row in the dashboard
std::string to_upper(const std::string &str)
void loadKey()
Definition: DBObject.cpp:179
void setObjectType(const DBObjectType &objectType)
Definition: DBObject.cpp:152
const std::string OMNISCI_ROOT_USER
Definition: SysCatalog.h:57
static const AccessPrivileges ALL_VIEW_MIGRATE
Definition: DBObject.h:177
const std::string OMNISCI_ROOT_PASSWD_DEFAULT
Definition: SysCatalog.h:60
const int OMNISCI_ROOT_USER_ID
Definition: SysCatalog.h:58
int32_t dbId
Definition: DBObject.h:56
static const AccessPrivileges ALL_DASHBOARD
Definition: DBObject.h:170
static const AccessPrivileges ACCESS
Definition: DBObject.h:154
static const AccessPrivileges ALL_TABLE
Definition: DBObject.h:158
const std::string OMNISCI_ROOT_USER_ID_STR
Definition: SysCatalog.h:59
mapd_shared_lock< mapd_shared_mutex > read_lock
void insertOrUpdateObjectPrivileges(std::unique_ptr< SqliteConnector > &sqliteConnector, std::string roleName, bool userRole, DBObject &object)
Definition: SysCatalog.cpp:342
auto get_users(std::unique_ptr< SqliteConnector > &sqliteConnector, const int32_t dbId=-1)
#define CHECK(condition)
Definition: Logger.h:197
std::list< DBSummary > DBSummaryList
Definition: SysCatalog.h:118
int32_t permissionType
Definition: DBObject.h:55
void deleteObjectPrivileges(std::unique_ptr< SqliteConnector > &sqliteConnector, std::string roleName, bool userRole, DBObject &object)
Definition: SysCatalog.cpp:323
mapd_unique_lock< mapd_shared_mutex > write_lock
int64_t privileges
Definition: DBObject.h:134
string name
Definition: setup.py:35
read_lock< SysCatalog > sys_read_lock
Definition: Catalog.cpp:111
bool g_enable_fsi
Definition: Catalog.cpp:91
virtual void renameDbObject(const DBObject &object)
Definition: Grantee.cpp:108
std::atomic< bool > isSuper
Definition: SysCatalog.h:94