Skip to content

Commit 8339f67

Browse files
mattgaraandrewseidl
authored andcommitted
Add privilege commands for foreign server
Implements: * GRANT CREATE SERVER ON DATABASE <dbName> TO <entityList>; * GRANT DROP SERVER ON DATABASE <dbName> TO <entityList>; * GRANT DROP ON SERVER <serverName> TO <entityList>; * REVOKE CREATE SERVER ON DATABASE <dbName> FROM <entityList>; * REVOKE DROP SERVER ON DATABASE <dbName> FROM <entityList>; * REVOKE DROP ON SERVER <serverName> FROM <entityList>;
1 parent df3589f commit 8339f67

15 files changed

+596
-67
lines changed

Catalog/Catalog.cpp

+40-32
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ void Catalog::createFsiSchemasAndDefaultServers() {
614614
"id integer primary key, "
615615
"name text unique, "
616616
"data_wrapper_type text, "
617+
"owner_user_id integer, "
617618
"options text)");
618619
createDefaultServersIfNotExists();
619620
sqliteConnector_.query(
@@ -721,7 +722,8 @@ void Catalog::recordOwnershipOfObjectsInObjectPermissions() {
721722
{DatabaseDBObjectType, AccessPrivileges::ALL_DATABASE},
722723
{TableDBObjectType, AccessPrivileges::ALL_TABLE},
723724
{DashboardDBObjectType, AccessPrivileges::ALL_DASHBOARD},
724-
{ViewDBObjectType, AccessPrivileges::ALL_VIEW}};
725+
{ViewDBObjectType, AccessPrivileges::ALL_VIEW},
726+
{ServerDBObjectType, AccessPrivileges::ALL_SERVER}};
725727

726728
// grant owner all permissions on DB
727729
DBObjectKey key;
@@ -2396,10 +2398,12 @@ void Catalog::createForeignServerNoLocks(
23962398

23972399
if (sqliteConnector_.getNumRows() == 0) {
23982400
sqliteConnector_.query_with_text_params(
2399-
"INSERT INTO omnisci_foreign_servers (name, data_wrapper_type, options) "
2400-
"VALUES (?, ?, ?)",
2401+
"INSERT INTO omnisci_foreign_servers (name, data_wrapper_type, owner_user_id, "
2402+
"options) "
2403+
"VALUES (?, ?, ?, ?)",
24012404
std::vector<std::string>{foreign_server->name,
24022405
foreign_server->data_wrapper.name,
2406+
std::to_string(foreign_server->user_id),
24032407
foreign_server->getOptionsAsJsonString()});
24042408
sqliteConnector_.query_with_text_params(
24052409
"SELECT id from omnisci_foreign_servers where name = ?",
@@ -2417,37 +2421,40 @@ void Catalog::createForeignServerNoLocks(
24172421
foreignServerMapById_[foreign_server_shared->id] = foreign_server_shared;
24182422
}
24192423

2420-
foreign_storage::ForeignServer* Catalog::getForeignServer(const std::string& server_name,
2421-
const bool skip_cache) {
2424+
foreign_storage::ForeignServer* Catalog::getForeignServer(
2425+
const std::string& server_name) const {
24222426
foreign_storage::ForeignServer* foreign_server = nullptr;
2423-
if (!skip_cache) {
2424-
cat_read_lock read_lock(this);
2425-
if (foreignServerMap_.find(server_name) != foreignServerMap_.end()) {
2426-
foreign_server = foreignServerMap_.find(server_name)->second.get();
2427-
}
2428-
} else {
2429-
cat_write_lock write_lock(this);
2430-
cat_sqlite_lock sqlite_lock(this);
2427+
cat_read_lock read_lock(this);
2428+
if (foreignServerMap_.find(server_name) != foreignServerMap_.end()) {
2429+
foreign_server = foreignServerMap_.find(server_name)->second.get();
2430+
}
2431+
return foreign_server;
2432+
}
24312433

2432-
sqliteConnector_.query_with_text_params(
2433-
"SELECT id, name, data_wrapper_type, options "
2434-
"FROM omnisci_foreign_servers WHERE name = ?",
2435-
std::vector<std::string>{server_name});
2436-
if (sqliteConnector_.getNumRows() > 0) {
2437-
auto server = std::make_shared<foreign_storage::ForeignServer>(
2438-
foreign_storage::DataWrapper{sqliteConnector_.getData<std::string>(0, 2)});
2439-
server->id = sqliteConnector_.getData<int>(0, 0);
2440-
server->name = sqliteConnector_.getData<std::string>(0, 1);
2441-
server->populateOptionsMap(sqliteConnector_.getData<std::string>(0, 3));
2442-
foreign_server = server.get();
2443-
foreignServerMap_[server->name] = server;
2444-
foreignServerMapById_[server->id] = server;
2445-
}
2434+
foreign_storage::ForeignServer* Catalog::getForeignServerSkipCache(
2435+
const std::string& server_name) {
2436+
foreign_storage::ForeignServer* foreign_server = nullptr;
2437+
cat_write_lock write_lock(this);
2438+
cat_sqlite_lock sqlite_lock(this);
2439+
sqliteConnector_.query_with_text_params(
2440+
"SELECT id, name, data_wrapper_type, options, owner_user_id "
2441+
"FROM omnisci_foreign_servers WHERE name = ?",
2442+
std::vector<std::string>{server_name});
2443+
if (sqliteConnector_.getNumRows() > 0) {
2444+
auto server = std::make_shared<foreign_storage::ForeignServer>(
2445+
foreign_storage::DataWrapper{sqliteConnector_.getData<std::string>(0, 2)});
2446+
server->id = sqliteConnector_.getData<int>(0, 0);
2447+
server->name = sqliteConnector_.getData<std::string>(0, 1);
2448+
server->user_id = sqliteConnector_.getData<std::int32_t>(0, 4);
2449+
server->populateOptionsMap(sqliteConnector_.getData<std::string>(0, 3));
2450+
foreign_server = server.get();
2451+
foreignServerMap_[server->name] = server;
2452+
foreignServerMapById_[server->id] = server;
24462453
}
24472454
return foreign_server;
24482455
}
24492456

2450-
void Catalog::dropForeignServer(const std::string& server_name, bool if_exists) {
2457+
void Catalog::dropForeignServer(const std::string& server_name) {
24512458
cat_write_lock write_lock(this);
24522459
cat_sqlite_lock sqlite_lock(this);
24532460

@@ -2471,9 +2478,6 @@ void Catalog::dropForeignServer(const std::string& server_name, bool if_exists)
24712478
std::vector<std::string>{server_name});
24722479
foreignServerMap_.erase(server_name);
24732480
foreignServerMapById_.erase(server_id);
2474-
} else if (!if_exists) {
2475-
throw std::runtime_error{"Foreign server with name \"" + server_name +
2476-
"\" does not exist."};
24772481
}
24782482
}
24792483

@@ -3451,14 +3455,16 @@ void Catalog::vacuumDeletedRows(const TableDescriptor* td) const {
34513455

34523456
void Catalog::buildForeignServerMap() {
34533457
sqliteConnector_.query(
3454-
"SELECT id, name, data_wrapper_type, options FROM omnisci_foreign_servers");
3458+
"SELECT id, name, data_wrapper_type, options, owner_user_id FROM "
3459+
"omnisci_foreign_servers");
34553460
auto num_rows = sqliteConnector_.getNumRows();
34563461
for (size_t row = 0; row < num_rows; row++) {
34573462
auto foreign_server = std::make_shared<foreign_storage::ForeignServer>(
34583463
foreign_storage::DataWrapper{sqliteConnector_.getData<std::string>(row, 2)});
34593464
foreign_server->id = sqliteConnector_.getData<int>(row, 0);
34603465
foreign_server->name = sqliteConnector_.getData<std::string>(row, 1);
34613466
foreign_server->populateOptionsMap(sqliteConnector_.getData<std::string>(row, 3));
3467+
foreign_server->user_id = sqliteConnector_.getData<std::int32_t>(row, 4);
34623468
foreignServerMap_[foreign_server->name] = foreign_server;
34633469
foreignServerMapById_[foreign_server->id] = foreign_server;
34643470
}
@@ -3490,6 +3496,7 @@ void Catalog::createDefaultServersIfNotExists() {
34903496
local_csv_server
34913497
->options[std::string{foreign_storage::ForeignServer::STORAGE_TYPE_KEY}] =
34923498
foreign_storage::ForeignServer::LOCAL_FILE_STORAGE_TYPE;
3499+
local_csv_server->user_id = OMNISCI_ROOT_USER_ID;
34933500
local_csv_server->options[std::string{foreign_storage::ForeignServer::BASE_PATH_KEY}] =
34943501
"/";
34953502
local_csv_server->validate();
@@ -3501,6 +3508,7 @@ void Catalog::createDefaultServersIfNotExists() {
35013508
local_parquet_server
35023509
->options[std::string{foreign_storage::ForeignServer::STORAGE_TYPE_KEY}] =
35033510
foreign_storage::ForeignServer::LOCAL_FILE_STORAGE_TYPE;
3511+
local_parquet_server->user_id = OMNISCI_ROOT_USER_ID;
35043512
local_parquet_server
35053513
->options[std::string{foreign_storage::ForeignServer::BASE_PATH_KEY}] = "/";
35063514
local_parquet_server->validate();

Catalog/Catalog.h

+14-10
Original file line numberDiff line numberDiff line change
@@ -248,25 +248,29 @@ class Catalog final {
248248
* Gets a pointer to a struct containing foreign server details.
249249
*
250250
* @param server_name - Name of foreign server whose details will be fetched
251-
* @param skip_cache - flag indicating whether or not to skip in-memory cache of foreign
252-
* server struct when attempting to fetch foreign server details. This flag is mainly
253-
* used for testing
254251
* @return pointer to a struct containing foreign server details. nullptr is returned if
255252
* no foreign server exists with the given name
256253
*/
257-
foreign_storage::ForeignServer* getForeignServer(const std::string& server_name,
258-
const bool skip_cache = false);
254+
foreign_storage::ForeignServer* getForeignServer(const std::string& server_name) const;
255+
256+
/**
257+
* Gets a pointer to a struct containing foreign server details.
258+
* Skip in-memory cache of foreign server struct when attempting to fetch foreign server
259+
* details. This is mainly used for testing.
260+
*
261+
* @param server_name - Name of foreign server whose details will be fetched
262+
* @return pointer to a struct containing foreign server details. nullptr is returned if
263+
* no foreign server exists with the given name
264+
*/
265+
foreign_storage::ForeignServer* getForeignServerSkipCache(
266+
const std::string& server_name);
259267

260268
/**
261269
* Drops/deletes a foreign server DB object.
262270
*
263271
* @param server_name - Name of foreign server that will be deleted
264-
* @param if_exists - flag indicating whether or not an attempt to delete a foreign
265-
* server should occur if a server with the same name does not exists. An exception is
266-
* thrown if this flag is set to "false" and an attempt is made to delete a nonexistent
267-
* foreign server
268272
*/
269-
void dropForeignServer(const std::string& server_name, bool if_exists);
273+
void dropForeignServer(const std::string& server_name);
270274

271275
/**
272276
* Creates default local file servers (if they don't already exist).

Catalog/DBObject.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ const AccessPrivileges AccessPrivileges::DELETE_FROM_VIEW =
6969
const AccessPrivileges AccessPrivileges::TRUNCATE_VIEW =
7070
AccessPrivileges(ViewPrivileges::TRUNCATE_VIEW);
7171

72+
const AccessPrivileges AccessPrivileges::ALL_SERVER =
73+
AccessPrivileges(ServerPrivileges::ALL);
74+
const AccessPrivileges AccessPrivileges::CREATE_SERVER =
75+
AccessPrivileges(ServerPrivileges::CREATE_SERVER);
76+
const AccessPrivileges AccessPrivileges::DROP_SERVER =
77+
AccessPrivileges(ServerPrivileges::DROP_SERVER);
78+
7279
std::string ObjectPermissionTypeToString(DBObjectType type) {
7380
switch (type) {
7481
case DatabaseDBObjectType:
@@ -79,6 +86,8 @@ std::string ObjectPermissionTypeToString(DBObjectType type) {
7986
return "DASHBOARD";
8087
case ViewDBObjectType:
8188
return "VIEW";
89+
case ServerDBObjectType:
90+
return "SERVER";
8291
default:
8392
CHECK(false);
8493
}
@@ -94,6 +103,8 @@ DBObjectType DBObjectTypeFromString(const std::string& type) {
94103
return DashboardDBObjectType;
95104
} else if (type.compare("VIEW") == 0) {
96105
return ViewDBObjectType;
106+
} else if (type.compare("SERVER") == 0) {
107+
return ServerDBObjectType;
97108
} else {
98109
throw std::runtime_error("DB object type " + type + " is not supported.");
99110
}
@@ -151,6 +162,7 @@ std::vector<std::string> DBObject::toString() const {
151162
case TableDBObjectType:
152163
case DashboardDBObjectType:
153164
case ViewDBObjectType:
165+
case ServerDBObjectType:
154166
objectKey.push_back(std::to_string(objectKey_.permissionType));
155167
objectKey.push_back(std::to_string(objectKey_.dbId));
156168
objectKey.push_back(std::to_string(objectKey_.objectId));
@@ -183,6 +195,23 @@ void DBObject::loadKey(const Catalog_Namespace::Catalog& catalog) {
183195
loadKey();
184196
break;
185197
}
198+
case ServerDBObjectType: {
199+
objectKey_.dbId = catalog.getCurrentDB().dbId;
200+
201+
if (!getName().empty()) {
202+
auto server = catalog.getForeignServer(getName());
203+
if (!server) {
204+
throw std::runtime_error("Failure generating DB object key. Server " +
205+
getName() + " does not exist.");
206+
}
207+
objectKey_.objectId = server->id;
208+
ownerId_ = server->user_id;
209+
} else {
210+
ownerId_ = catalog.getCurrentDB().dbOwner;
211+
}
212+
213+
break;
214+
}
186215
case ViewDBObjectType:
187216
case TableDBObjectType: {
188217
objectKey_.dbId = catalog.getCurrentDB().dbId;
@@ -233,6 +262,7 @@ DBObjectKey DBObjectKey::fromString(const std::vector<std::string>& key,
233262
objectKey.permissionType = std::stoi(key[0]);
234263
objectKey.dbId = std::stoi(key[1]);
235264
break;
265+
case ServerDBObjectType:
236266
case TableDBObjectType:
237267
case ViewDBObjectType:
238268
case DashboardDBObjectType:

Catalog/DBObject.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ enum DBObjectType {
4444
DatabaseDBObjectType,
4545
TableDBObjectType,
4646
DashboardDBObjectType,
47-
ViewDBObjectType
47+
ViewDBObjectType,
48+
ServerDBObjectType
4849
};
4950

5051
std::string DBObjectTypeToString(DBObjectType type);
@@ -122,6 +123,12 @@ struct ViewPrivileges {
122123
CREATE_VIEW | DROP_VIEW | SELECT_FROM_VIEW | INSERT_INTO_VIEW;
123124
};
124125

126+
struct ServerPrivileges {
127+
static const int32_t ALL = -1;
128+
static const int32_t CREATE_SERVER = 1 << 0;
129+
static const int32_t DROP_SERVER = 1 << 1;
130+
};
131+
125132
struct AccessPrivileges {
126133
int64_t privileges;
127134

@@ -175,6 +182,11 @@ struct AccessPrivileges {
175182
static const AccessPrivileges UPDATE_IN_VIEW;
176183
static const AccessPrivileges DELETE_FROM_VIEW;
177184
static const AccessPrivileges TRUNCATE_VIEW;
185+
186+
// server permissions
187+
static const AccessPrivileges ALL_SERVER;
188+
static const AccessPrivileges CREATE_SERVER;
189+
static const AccessPrivileges DROP_SERVER;
178190
};
179191

180192
class DBObject {

Catalog/DdlCommandExecutor.cpp

+42-9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <boost/algorithm/string/predicate.hpp>
2020

2121
#include "Catalog/Catalog.h"
22+
#include "Catalog/SysCatalog.h"
2223
#include "LockMgr/LockMgr.h"
2324
#include "Parser/ParserNode.h"
2425
#include "Shared/StringTransform.h"
@@ -69,20 +70,39 @@ CreateForeignServerCommand::CreateForeignServerCommand(
6970
}
7071

7172
void CreateForeignServerCommand::execute(TQueryResult& _return) {
72-
std::string_view server_name = ddl_payload["serverName"].GetString();
73+
std::string server_name = ddl_payload["serverName"].GetString();
7374
if (boost::iequals(server_name.substr(0, 7), "omnisci")) {
7475
throw std::runtime_error{"Server names cannot start with \"omnisci\"."};
7576
}
77+
bool if_not_exists = ddl_payload["ifNotExists"].GetBool();
78+
if (session_ptr->getCatalog().getForeignServer(server_name)) {
79+
if (if_not_exists) {
80+
return;
81+
} else {
82+
throw std::runtime_error{"A foreign server with name \"" + server_name +
83+
"\" already exists."};
84+
}
85+
}
86+
// check access privileges
87+
if (!session_ptr->checkDBAccessPrivileges(DBObjectType::ServerDBObjectType,
88+
AccessPrivileges::CREATE_SERVER)) {
89+
throw std::runtime_error("Server " + std::string(server_name) +
90+
" will not be created. User has no create privileges.");
91+
}
7692

77-
// TODO: add permissions check and ownership
93+
auto& current_user = session_ptr->get_currentUser();
7894
auto foreign_server = std::make_unique<foreign_storage::ForeignServer>(
7995
foreign_storage::DataWrapper{ddl_payload["dataWrapper"].GetString()});
8096
foreign_server->name = server_name;
97+
foreign_server->user_id = current_user.userId;
8198
foreign_server->populateOptionsMap(ddl_payload["options"]);
8299
foreign_server->validate();
83100

84-
session_ptr->getCatalog().createForeignServer(std::move(foreign_server),
85-
ddl_payload["ifNotExists"].GetBool());
101+
auto& catalog = session_ptr->getCatalog();
102+
catalog.createForeignServer(std::move(foreign_server),
103+
ddl_payload["ifNotExists"].GetBool());
104+
Catalog_Namespace::SysCatalog::instance().createDBObject(
105+
current_user, server_name, ServerDBObjectType, catalog);
86106
}
87107

88108
DropForeignServerCommand::DropForeignServerCommand(
@@ -96,14 +116,27 @@ DropForeignServerCommand::DropForeignServerCommand(
96116
}
97117

98118
void DropForeignServerCommand::execute(TQueryResult& _return) {
99-
std::string_view server_name = ddl_payload["serverName"].GetString();
119+
std::string server_name = ddl_payload["serverName"].GetString();
100120
if (boost::iequals(server_name.substr(0, 7), "omnisci")) {
101121
throw std::runtime_error{"OmniSci default servers cannot be dropped."};
102122
}
103-
104-
// TODO: add permissions check
105-
session_ptr->getCatalog().dropForeignServer(ddl_payload["serverName"].GetString(),
106-
ddl_payload["ifExists"].GetBool());
123+
bool if_exists = ddl_payload["ifExists"].GetBool();
124+
if (!session_ptr->getCatalog().getForeignServer(server_name)) {
125+
if (if_exists) {
126+
return;
127+
} else {
128+
throw std::runtime_error{"Foreign server with name \"" + server_name +
129+
"\" does not exist."};
130+
}
131+
}
132+
// check access privileges
133+
if (!session_ptr->checkDBAccessPrivileges(DBObjectType::ServerDBObjectType,
134+
AccessPrivileges::DROP_SERVER,
135+
server_name.data())) {
136+
throw std::runtime_error("Server " + server_name +
137+
" will not be dropped. User has no DROP SERVER privileges.");
138+
}
139+
session_ptr->getCatalog().dropForeignServer(ddl_payload["serverName"].GetString());
107140
}
108141

109142
SQLTypes JsonColumnSqlType::getSqlType(const rapidjson::Value& data_type) {

Catalog/ForeignServer.h

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct ForeignServer : public OptionsContainer {
5656
int id;
5757
std::string name;
5858
DataWrapper data_wrapper;
59+
int32_t user_id;
5960

6061
ForeignServer(const DataWrapper& data_wrapper) : data_wrapper(data_wrapper) {}
6162

0 commit comments

Comments
 (0)