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