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