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