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