OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Grantee.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, 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 
17 #include "Grantee.h"
18 
19 #include <stack>
20 
21 #include "Shared/misc.h"
22 
23 using std::runtime_error;
24 using std::string;
25 
26 Grantee::Grantee(const std::string& name) : name_(name) {}
27 
29  for (auto role : roles_) {
30  role->removeGrantee(this);
31  }
32  effectivePrivileges_.clear();
33  directPrivileges_.clear();
34  roles_.clear();
35 }
36 
37 std::vector<std::string> Grantee::getRoles(bool only_direct) const {
38  std::set<std::string> roles; // Sorted for human readers.
39  std::stack<const Grantee*> g;
40  g.push(this);
41  while (!g.empty()) {
42  auto r = g.top();
43  g.pop();
44  for (auto direct_role : r->roles_) {
45  g.push(direct_role);
46  roles.insert(direct_role->getName());
47  }
48  if (only_direct) {
49  break;
50  }
51  }
52  return std::vector(roles.begin(), roles.end());
53 }
54 
55 bool Grantee::hasRole(Role* role, bool only_direct) const {
56  if (only_direct) {
57  return roles_.find(role) != roles_.end();
58  } else {
59  std::stack<const Grantee*> roles;
60  roles.push(this);
61  while (!roles.empty()) {
62  auto r = roles.top();
63  roles.pop();
64  if (r == role) {
65  return true;
66  } else {
67  for (auto granted_role : r->roles_) {
68  roles.push(granted_role);
69  }
70  }
71  }
72  return false;
73  }
74 }
75 
76 void Grantee::getPrivileges(DBObject& object, bool only_direct) {
77  auto dbObject = findDbObject(object.getObjectKey(), only_direct);
78  if (!dbObject) { // not found
79  throw runtime_error("Can not get privileges because " + getName() +
80  " has no privileges to " + object.getName());
81  }
82  object.grantPrivileges(*dbObject);
83 }
84 
85 DBObject* Grantee::findDbObject(const DBObjectKey& objectKey, bool only_direct) const {
86  const DBObjectMap& privs = only_direct ? directPrivileges_ : effectivePrivileges_;
87  DBObject* dbObject = nullptr;
88  auto dbObjectIt = privs.find(objectKey);
89  if (dbObjectIt != privs.end()) {
90  dbObject = dbObjectIt->second.get();
91  }
92  return dbObject;
93 }
94 
95 bool Grantee::hasAnyPrivilegesOnDb(int32_t dbId, bool only_direct) const {
96  const DBObjectMap& privs = only_direct ? directPrivileges_ : effectivePrivileges_;
97  for (const auto& priv : privs) {
98  if (priv.second->getObjectKey().dbId == dbId) {
99  return true;
100  }
101  }
102  return false;
103 }
104 
105 void Grantee::grantPrivileges(const DBObject& object) {
106  auto* dbObject = findDbObject(object.getObjectKey(), false);
107  if (!dbObject) { // not found
108  effectivePrivileges_[object.getObjectKey()] = boost::make_unique<DBObject>(object);
109  } else { // found
110  dbObject->grantPrivileges(object);
111  }
112  dbObject = findDbObject(object.getObjectKey(), true);
113  if (!dbObject) { // not found
114  directPrivileges_[object.getObjectKey()] = boost::make_unique<DBObject>(object);
115  } else { // found
116  dbObject->grantPrivileges(object);
117  }
119 }
120 
121 void Grantee::renameDbObject(const DBObject& object) {
122  // rename direct and effective objects
123  auto directIt = directPrivileges_.find(object.getObjectKey());
124  if (directIt != directPrivileges_.end()) {
125  directIt->second->setName(object.getName());
126  }
127 
128  auto effectiveIt = effectivePrivileges_.find(object.getObjectKey());
129  if (effectiveIt != effectivePrivileges_.end()) {
130  effectiveIt->second->setName(object.getName());
131  }
132 }
133 // Revoke privileges from the object.
134 // If there are no privileges left - erase object and return nullptr.
135 // Otherwise, return the changed object.
137  auto dbObject = findDbObject(object.getObjectKey(), true);
138  if (!dbObject ||
139  !dbObject->getPrivileges().hasAny()) { // not found or has none of privileges set
140  throw runtime_error("Can not revoke privileges because " + getName() +
141  " has no privileges to " + object.getName());
142  }
143  bool object_removed = false;
144  dbObject->revokePrivileges(object);
145  if (!dbObject->getPrivileges().hasAny()) {
146  directPrivileges_.erase(object.getObjectKey());
147  object_removed = true;
148  }
149 
150  auto* cachedDbObject = findDbObject(object.getObjectKey(), false);
151  if (cachedDbObject && cachedDbObject->getPrivileges().hasAny()) {
152  cachedDbObject->revokePrivileges(object);
153  if (!cachedDbObject->getPrivileges().hasAny()) {
154  effectivePrivileges_.erase(object.getObjectKey());
155  }
156  }
157 
159 
160  return object_removed ? nullptr : dbObject;
161 }
162 
164  bool found = false;
165  for (const auto* granted_role : roles_) {
166  if (role == granted_role) {
167  found = true;
168  break;
169  }
170  }
171  if (found) {
172  throw runtime_error("Role " + role->getName() + " have been granted to " + name_ +
173  " already.");
174  }
175  checkCycles(role);
176  roles_.insert(role);
177  role->addGrantee(this);
179 }
180 
182  roles_.erase(role);
183  role->removeGrantee(this);
185 }
186 
187 static bool hasEnoughPrivs(const DBObject* real, const DBObject* requested) {
188  if (real) {
189  auto req = requested->getPrivileges().privileges;
190  auto base = real->getPrivileges().privileges;
191 
192  // ensures that all requested privileges are present
193  return req == (base & req);
194  } else {
195  return false;
196  }
197 }
198 
199 static bool hasAnyPrivs(const DBObject* real, const DBObject* /* requested*/) {
200  if (real) {
201  return real->getPrivileges().hasAny();
202  } else {
203  return false;
204  }
205 }
206 
207 bool Grantee::hasAnyPrivileges(const DBObject& objectRequested, bool only_direct) const {
208  DBObjectKey objectKey = objectRequested.getObjectKey();
209  if (hasAnyPrivs(findDbObject(objectKey, only_direct), &objectRequested)) {
210  return true;
211  }
212 
213  // if we have an object associated -> ignore it
214  if (objectKey.objectId != -1) {
215  objectKey.objectId = -1;
216  if (hasAnyPrivs(findDbObject(objectKey, only_direct), &objectRequested)) {
217  return true;
218  }
219  }
220 
221  // if we have an
222  if (objectKey.dbId != -1) {
223  objectKey.dbId = -1;
224  if (hasAnyPrivs(findDbObject(objectKey, only_direct), &objectRequested)) {
225  return true;
226  }
227  }
228  return false;
229 }
230 
231 bool Grantee::checkPrivileges(const DBObject& objectRequested) const {
232  DBObjectKey objectKey = objectRequested.getObjectKey();
233  if (hasEnoughPrivs(findDbObject(objectKey, false), &objectRequested)) {
234  return true;
235  }
236 
237  // if we have an object associated -> ignore it
238  if (objectKey.objectId != -1) {
239  objectKey.objectId = -1;
240  if (hasEnoughPrivs(findDbObject(objectKey, false), &objectRequested)) {
241  return true;
242  }
243  }
244 
245  // if we have an
246  if (objectKey.dbId != -1) {
247  objectKey.dbId = -1;
248  if (hasEnoughPrivs(findDbObject(objectKey, false), &objectRequested)) {
249  return true;
250  }
251  }
252  return false;
253 }
254 
256  for (auto& roleDbObject : *role->getDbObjects(false)) {
257  auto dbObject = findDbObject(roleDbObject.first, false);
258  if (dbObject) { // found
259  dbObject->updatePrivileges(*roleDbObject.second);
260  } else { // not found
261  effectivePrivileges_[roleDbObject.first] =
262  boost::make_unique<DBObject>(*roleDbObject.second.get());
263  }
264  }
265 }
266 
267 // Pull privileges from upper roles
269  // Zero out the effective privileges. DBObjects may still exist, but will be empty.
270  for (auto& dbObject : effectivePrivileges_) {
271  dbObject.second->resetPrivileges();
272  }
273  // Load this Grantee's direct privileges into its effective privileges.
274  for (auto it = directPrivileges_.begin(); it != directPrivileges_.end(); ++it) {
275  if (effectivePrivileges_.find(it->first) != effectivePrivileges_.end()) {
276  effectivePrivileges_[it->first]->updatePrivileges(*it->second);
277  }
278  }
279  // Load any other roles that we've been granted into the effective privileges.
280  for (auto role : roles_) {
281  if (role->getDbObjects(false)->size() > 0) {
282  updatePrivileges(role);
283  }
284  }
285  // Free any DBObjects that are still empty in the effective privileges.
286  for (auto dbObjectIt = effectivePrivileges_.begin();
287  dbObjectIt != effectivePrivileges_.end();) {
288  if (!dbObjectIt->second->getPrivileges().hasAny()) {
289  dbObjectIt = effectivePrivileges_.erase(dbObjectIt);
290  } else {
291  ++dbObjectIt;
292  }
293  }
294 }
295 
296 void Grantee::revokeAllOnDatabase(int32_t dbId) {
297  std::vector<DBObjectMap*> sources = {&effectivePrivileges_, &directPrivileges_};
298  for (auto privs : sources) {
299  for (auto iter = privs->begin(); iter != privs->end();) {
300  if (iter->first.dbId == dbId) {
301  iter = privs->erase(iter);
302  } else {
303  ++iter;
304  }
305  }
306  }
308 }
309 
310 void Grantee::checkCycles(Role* newRole) {
311  std::stack<Grantee*> grantees;
312  grantees.push(this);
313  while (!grantees.empty()) {
314  auto* grantee = grantees.top();
315  grantees.pop();
316  if (!grantee->isUser()) {
317  Role* r = dynamic_cast<Role*>(grantee);
318  CHECK(r);
319  if (r == newRole) {
320  throw runtime_error("Granting role " + newRole->getName() + " to " + getName() +
321  " creates cycle in grantee graph.");
322  }
323  for (auto g : r->getGrantees()) {
324  grantees.push(g);
325  }
326  }
327  }
328 }
329 
330 void Grantee::reassignObjectOwners(const std::set<int32_t>& old_owner_ids,
331  int32_t new_owner_id,
332  int32_t db_id) {
333  for (const auto& [object_key, object] : effectivePrivileges_) {
334  if (object_key.objectId != -1 && object_key.dbId == db_id &&
335  shared::contains(old_owner_ids, object->getOwner())) {
336  object->setOwner(new_owner_id);
337  }
338  }
339 
340  for (const auto& [object_key, object] : directPrivileges_) {
341  if (object_key.objectId != -1 && object_key.dbId == db_id &&
342  shared::contains(old_owner_ids, object->getOwner())) {
343  object->setOwner(new_owner_id);
344  }
345  }
346 }
347 
348 void Grantee::reassignObjectOwner(DBObjectKey& object_key, int32_t new_owner_id) {
349  for (const auto& [grantee_object_key, object] : effectivePrivileges_) {
350  if (grantee_object_key == object_key) {
351  object->setOwner(new_owner_id);
352  }
353  }
354 
355  for (const auto& [grantee_object_key, object] : directPrivileges_) {
356  if (grantee_object_key == object_key) {
357  object->setOwner(new_owner_id);
358  }
359  }
360 }
361 
363  for (auto it = grantees_.begin(); it != grantees_.end();) {
364  auto current_grantee = *it;
365  ++it;
366  current_grantee->revokeRole(this);
367  }
368  grantees_.clear();
369 }
370 
371 void Role::addGrantee(Grantee* grantee) {
372  if (grantees_.find(grantee) == grantees_.end()) {
373  grantees_.insert(grantee);
374  } else {
375  throw runtime_error("Role " + getName() + " have been granted to " +
376  grantee->getName() + " already.");
377  }
378 }
379 
380 void Role::removeGrantee(Grantee* grantee) {
381  if (grantees_.find(grantee) != grantees_.end()) {
382  grantees_.erase(grantee);
383  } else {
384  throw runtime_error("Role " + getName() + " have not been granted to " +
385  grantee->getName() + " .");
386  }
387 }
388 
389 std::vector<Grantee*> Role::getGrantees() const {
390  std::vector<Grantee*> grantees;
391  for (const auto grantee : grantees_) {
392  grantees.push_back(grantee);
393  }
394  return grantees;
395 }
396 
397 void Role::revokeAllOnDatabase(int32_t dbId) {
399  for (auto grantee : grantees_) {
400  grantee->revokeAllOnDatabase(dbId);
401  }
402 }
403 
404 // Pull privileges from upper roles and push those to grantees
407  for (auto grantee : grantees_) {
408  grantee->updatePrivileges();
409  }
410 }
411 
412 void Role::renameDbObject(const DBObject& object) {
413  Grantee::renameDbObject(object);
414  for (auto grantee : grantees_) {
415  grantee->renameDbObject(object);
416  }
417 }
DBObjectMap effectivePrivileges_
Definition: Grantee.h:70
bool contains(const T &container, const U &element)
Definition: misc.h:204
bool hasAnyPrivilegesOnDb(int32_t dbId, bool only_direct) const
Definition: Grantee.cpp:95
void revokeAllOnDatabase(int32_t dbId) override
Definition: Grantee.cpp:397
DBObjectKey getObjectKey() const
Definition: DBObject.h:221
void renameDbObject(const DBObject &object) override
Definition: Grantee.cpp:412
virtual void updatePrivileges()
Definition: Grantee.cpp:268
void reassignObjectOwner(DBObjectKey &object_key, int32_t new_owner_id)
Definition: Grantee.cpp:348
virtual void grantPrivileges(const DBObject &object)
Definition: Grantee.cpp:105
virtual DBObject * revokePrivileges(const DBObject &object)
Definition: Grantee.cpp:136
virtual void addGrantee(Grantee *grantee)
Definition: Grantee.cpp:371
bool hasAny() const
Definition: DBObject.h:140
int32_t objectId
Definition: DBObject.h:55
static bool hasEnoughPrivs(const DBObject *real, const DBObject *requested)
Definition: Grantee.cpp:187
Definition: Grantee.h:81
static bool hasAnyPrivs(const DBObject *real, const DBObject *)
Definition: Grantee.cpp:199
const std::string & getName() const
Definition: Grantee.h:52
virtual ~Grantee()
Definition: Grantee.cpp:28
DBObject * findDbObject(const DBObjectKey &objectKey, bool only_direct) const
Definition: Grantee.cpp:85
void updatePrivileges() override
Definition: Grantee.cpp:405
virtual bool hasAnyPrivileges(const DBObject &objectRequested, bool only_direct) const
Definition: Grantee.cpp:207
virtual void revokeAllOnDatabase(int32_t dbId)
Definition: Grantee.cpp:296
Grantee(const std::string &name)
Definition: Grantee.cpp:26
virtual void revokeRole(Role *role)
Definition: Grantee.cpp:181
std::vector< Grantee * > getGrantees() const
Definition: Grantee.cpp:389
std::map< DBObjectKey, std::unique_ptr< DBObject >> DBObjectMap
Definition: Grantee.h:33
const DBObjectMap * getDbObjects(bool only_direct) const
Definition: Grantee.h:56
const AccessPrivileges & getPrivileges() const
Definition: DBObject.h:226
virtual void removeGrantee(Grantee *grantee)
Definition: Grantee.cpp:380
std::unordered_set< Role * > roles_
Definition: Grantee.h:68
void checkCycles(Role *newRole)
Definition: Grantee.cpp:310
int32_t dbId
Definition: DBObject.h:54
virtual void grantRole(Role *role)
Definition: Grantee.cpp:163
std::string name_
Definition: Grantee.h:67
bool hasRole(Role *role, bool only_direct) const
Definition: Grantee.cpp:55
void reassignObjectOwners(const std::set< int32_t > &old_owner_ids, int32_t new_owner_id, int32_t db_id)
Definition: Grantee.cpp:330
~Role() override
Definition: Grantee.cpp:362
#define CHECK(condition)
Definition: Logger.h:291
std::unordered_set< Grantee * > grantees_
Definition: Grantee.h:98
DBObjectMap directPrivileges_
Definition: Grantee.h:72
int64_t privileges
Definition: DBObject.h:133
void getPrivileges(DBObject &object, bool only_direct)
Definition: Grantee.cpp:76
std::vector< std::string > getRoles(bool only_direct=true) const
Definition: Grantee.cpp:37
string name
Definition: setup.in.py:72
virtual void renameDbObject(const DBObject &object)
Definition: Grantee.cpp:121
virtual bool checkPrivileges(const DBObject &objectRequested) const
Definition: Grantee.cpp:231