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