CodeCommitsIssuesPull requestsActionsInsightsSecurity
cb58b407a983516d3cf03905779f2b8323629dd2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/Access/AccessRights.cpp

1034lines · modecode

1#include <Access/AccessRights.h>
2#include <Common/Exception.h>
3#include <common/logger_useful.h>
4#include <boost/container/small_vector.hpp>
5#include <boost/range/adaptor/map.hpp>
6#include <boost/range/algorithm/sort.hpp>
7#include <unordered_map>
8
9namespace DB
10{
11namespace ErrorCodes
12{
13 extern const int INVALID_GRANT;
14}
15
16
17namespace
18{
19 enum Level
20 {
21 GLOBAL_LEVEL,
22 DATABASE_LEVEL,
23 TABLE_LEVEL,
24 COLUMN_LEVEL,
25 };
26
27 struct Helper
28 {
29 static const Helper & instance()
30 {
31 static const Helper res;
32 return res;
33 }
34
35 const AccessFlags all_flags = AccessFlags::allFlags();
36 const AccessFlags database_flags = AccessFlags::allDatabaseFlags();
37 const AccessFlags table_flags = AccessFlags::allTableFlags();
38 const AccessFlags column_flags = AccessFlags::allColumnFlags();
39 const AccessFlags dictionary_flags = AccessFlags::allDictionaryFlags();
40 const AccessFlags column_level_flags = column_flags;
41 const AccessFlags table_level_flags = table_flags | dictionary_flags | column_level_flags;
42 const AccessFlags database_level_flags = database_flags | table_level_flags;
43
44 const AccessFlags show_databases_flag = AccessType::SHOW_DATABASES;
45 const AccessFlags show_tables_flag = AccessType::SHOW_TABLES;
46 const AccessFlags show_columns_flag = AccessType::SHOW_COLUMNS;
47 const AccessFlags show_dictionaries_flag = AccessType::SHOW_DICTIONARIES;
48 const AccessFlags create_table_flag = AccessType::CREATE_TABLE;
49 const AccessFlags create_view_flag = AccessType::CREATE_VIEW;
50 const AccessFlags create_temporary_table_flag = AccessType::CREATE_TEMPORARY_TABLE;
51 const AccessFlags alter_table_flag = AccessType::ALTER_TABLE;
52 const AccessFlags alter_view_flag = AccessType::ALTER_VIEW;
53 const AccessFlags truncate_flag = AccessType::TRUNCATE;
54 const AccessFlags drop_table_flag = AccessType::DROP_TABLE;
55 const AccessFlags drop_view_flag = AccessType::DROP_VIEW;
56 const AccessFlags alter_ttl_flag = AccessType::ALTER_TTL;
57 const AccessFlags alter_materialize_ttl_flag = AccessType::ALTER_MATERIALIZE_TTL;
58 const AccessFlags system_reload_dictionary = AccessType::SYSTEM_RELOAD_DICTIONARY;
59 const AccessFlags system_reload_embedded_dictionaries = AccessType::SYSTEM_RELOAD_EMBEDDED_DICTIONARIES;
60 };
61
62 using Kind = AccessRightsElementWithOptions::Kind;
63
64 struct ProtoElement
65 {
66 AccessFlags access_flags;
67 boost::container::small_vector<std::string_view, 3> full_name;
68 bool grant_option = false;
69 Kind kind = Kind::GRANT;
70
71 friend bool operator<(const ProtoElement & left, const ProtoElement & right)
72 {
73 static constexpr auto compare_name = [](const boost::container::small_vector<std::string_view, 3> & left_name,
74 const boost::container::small_vector<std::string_view, 3> & right_name,
75 size_t i)
76 {
77 if (i < left_name.size())
78 {
79 if (i < right_name.size())
80 return left_name[i].compare(right_name[i]);
81 else
82 return 1; /// left_name is longer => left_name > right_name
83 }
84 else if (i < right_name.size())
85 return 1; /// right_name is longer => left < right
86 else
87 return 0; /// left_name == right_name
88 };
89
90 if (int cmp = compare_name(left.full_name, right.full_name, 0))
91 return cmp < 0;
92
93 if (int cmp = compare_name(left.full_name, right.full_name, 1))
94 return cmp < 0;
95
96 if (left.kind != right.kind)
97 return (left.kind == Kind::GRANT);
98
99 if (left.grant_option != right.grant_option)
100 return right.grant_option;
101
102 if (int cmp = compare_name(left.full_name, right.full_name, 2))
103 return cmp < 0;
104
105 return (left.access_flags < right.access_flags);
106 }
107
108 AccessRightsElementWithOptions getResult() const
109 {
110 AccessRightsElementWithOptions res;
111 res.access_flags = access_flags;
112 res.grant_option = grant_option;
113 res.kind = kind;
114 switch (full_name.size())
115 {
116 case 0:
117 {
118 res.any_database = true;
119 res.any_table = true;
120 res.any_column = true;
121 break;
122 }
123 case 1:
124 {
125 res.any_database = false;
126 res.database = full_name[0];
127 res.any_table = true;
128 res.any_column = true;
129 break;
130 }
131 case 2:
132 {
133 res.any_database = false;
134 res.database = full_name[0];
135 res.any_table = false;
136 res.table = full_name[1];
137 res.any_column = true;
138 break;
139 }
140 case 3:
141 {
142 res.any_database = false;
143 res.database = full_name[0];
144 res.any_table = false;
145 res.table = full_name[1];
146 res.any_column = false;
147 res.columns.emplace_back(full_name[2]);
148 break;
149 }
150 }
151 return res;
152 }
153 };
154
155 class ProtoElements : public std::vector<ProtoElement>
156 {
157 public:
158 AccessRightsElementsWithOptions getResult() const
159 {
160 ProtoElements sorted = *this;
161 boost::range::sort(sorted);
162 AccessRightsElementsWithOptions res;
163 res.reserve(sorted.size());
164
165 for (size_t i = 0; i != sorted.size();)
166 {
167 size_t count_elements_with_diff_columns = sorted.countElementsWithDifferenceInColumnOnly(i);
168 if (count_elements_with_diff_columns == 1)
169 {
170 /// Easy case: one Element is converted to one AccessRightsElement.
171 const auto & element = sorted[i];
172 if (element.access_flags)
173 res.emplace_back(element.getResult());
174 ++i;
175 }
176 else
177 {
178 /// Difficult case: multiple Elements are converted to one or multiple AccessRightsElements.
179 sorted.appendResultWithElementsWithDifferenceInColumnOnly(i, count_elements_with_diff_columns, res);
180 i += count_elements_with_diff_columns;
181 }
182 }
183 return res;
184 }
185
186 private:
187 size_t countElementsWithDifferenceInColumnOnly(size_t start) const
188 {
189 const auto & start_element = (*this)[start];
190 if ((start_element.full_name.size() != 3) || (start == size() - 1))
191 return 1;
192
193 auto it = std::find_if(begin() + start + 1, end(), [&](const ProtoElement & element)
194 {
195 return (element.full_name.size() != 3) || (element.full_name[0] != start_element.full_name[0])
196 || (element.full_name[1] != start_element.full_name[1]) || (element.grant_option != start_element.grant_option)
197 || (element.kind != start_element.kind);
198 });
199
200 return it - (begin() + start);
201 }
202
203 /// Collects columns together to write multiple columns into one AccessRightsElement.
204 /// That procedure allows to output access rights in more compact way,
205 /// e.g. "SELECT(x, y)" instead of "SELECT(x), SELECT(y)".
206 void appendResultWithElementsWithDifferenceInColumnOnly(size_t start, size_t count, AccessRightsElementsWithOptions & res) const
207 {
208 const auto * pbegin = data() + start;
209 const auto * pend = pbegin + count;
210 AccessFlags handled_flags;
211
212 while (pbegin < pend)
213 {
214 while (pbegin < pend && !(pbegin->access_flags - handled_flags))
215 ++pbegin;
216
217 while (pbegin < pend && !((pend - 1)->access_flags - handled_flags))
218 --pend;
219
220 if (pbegin >= pend)
221 break;
222
223 AccessFlags common_flags = (pbegin->access_flags - handled_flags);
224 for (const auto * element = pbegin + 1; element != pend; ++element)
225 {
226 if (auto new_common_flags = (element->access_flags - handled_flags) & common_flags)
227 common_flags = new_common_flags;
228 }
229
230 res.emplace_back();
231 auto & back = res.back();
232 back.grant_option = pbegin->grant_option;
233 back.kind = pbegin->kind;
234 back.any_database = false;
235 back.database = pbegin->full_name[0];
236 back.any_table = false;
237 back.table = pbegin->full_name[1];
238 back.any_column = false;
239 back.access_flags = common_flags;
240 for (const auto * element = pbegin; element != pend; ++element)
241 {
242 if (((element->access_flags - handled_flags) & common_flags) == common_flags)
243 back.columns.emplace_back(element->full_name[2]);
244 }
245
246 handled_flags |= common_flags;
247 }
248 }
249 };
250}
251
252
253struct AccessRights::Node
254{
255public:
256 std::shared_ptr<const String> node_name;
257 Level level = GLOBAL_LEVEL;
258 AccessFlags access; /// access = (inherited_access - partial_revokes) | explicit_grants
259 AccessFlags final_access; /// final_access = access | implicit_access
260 AccessFlags min_access; /// min_access = final_access & child[0].final_access & ... & child[N-1].final_access
261 AccessFlags max_access; /// max_access = final_access | child[0].final_access | ... | child[N-1].final_access
262 std::unique_ptr<std::unordered_map<std::string_view, Node>> children;
263
264 Node() = default;
265 Node(const Node & src) { *this = src; }
266
267 Node & operator =(const Node & src)
268 {
269 if (this == &src)
270 return *this;
271
272 node_name = src.node_name;
273 level = src.level;
274 access = src.access;
275 final_access = src.final_access;
276 min_access = src.min_access;
277 max_access = src.max_access;
278 if (src.children)
279 children = std::make_unique<std::unordered_map<std::string_view, Node>>(*src.children);
280 else
281 children = nullptr;
282 return *this;
283 }
284
285 void grant(AccessFlags flags, const Helper & helper)
286 {
287 if (!flags)
288 return;
289
290 if (level == GLOBAL_LEVEL)
291 {
292 /// Everything can be granted on the global level.
293 }
294 else if (level == DATABASE_LEVEL)
295 {
296 AccessFlags grantable = flags & helper.database_level_flags;
297 if (!grantable)
298 throw Exception(flags.toString() + " cannot be granted on the database level", ErrorCodes::INVALID_GRANT);
299 flags = grantable;
300 }
301 else if (level == TABLE_LEVEL)
302 {
303 AccessFlags grantable = flags & helper.table_level_flags;
304 if (!grantable)
305 throw Exception(flags.toString() + " cannot be granted on the table level", ErrorCodes::INVALID_GRANT);
306 flags = grantable;
307 }
308 else if (level == COLUMN_LEVEL)
309 {
310 AccessFlags grantable = flags & helper.column_level_flags;
311 if (!grantable)
312 throw Exception(flags.toString() + " cannot be granted on the column level", ErrorCodes::INVALID_GRANT);
313 flags = grantable;
314 }
315
316 addGrantsRec(flags);
317 calculateFinalAccessRec(helper);
318 }
319
320 template <typename ... Args>
321 void grant(const AccessFlags & flags, const Helper & helper, const std::string_view & name, const Args &... subnames)
322 {
323 auto & child = getChild(name);
324 child.grant(flags, helper, subnames...);
325 eraseChildIfPossible(child);
326 calculateFinalAccess(helper);
327 }
328
329 template <typename StringT>
330 void grant(const AccessFlags & flags, const Helper & helper, const std::vector<StringT> & names)
331 {
332 for (const auto & name : names)
333 {
334 auto & child = getChild(name);
335 child.grant(flags, helper);
336 eraseChildIfPossible(child);
337 }
338 calculateFinalAccess(helper);
339 }
340
341 void revoke(const AccessFlags & flags, const Helper & helper)
342 {
343 removeGrantsRec(flags);
344 calculateFinalAccessRec(helper);
345 }
346
347 template <typename... Args>
348 void revoke(const AccessFlags & flags, const Helper & helper, const std::string_view & name, const Args &... subnames)
349 {
350 auto & child = getChild(name);
351
352 child.revoke(flags, helper, subnames...);
353 eraseChildIfPossible(child);
354 calculateFinalAccess(helper);
355 }
356
357 template <typename StringT>
358 void revoke(const AccessFlags & flags, const Helper & helper, const std::vector<StringT> & names)
359 {
360 for (const auto & name : names)
361 {
362 auto & child = getChild(name);
363 child.revoke(flags, helper);
364 eraseChildIfPossible(child);
365 }
366 calculateFinalAccess(helper);
367 }
368
369 bool isGranted(const AccessFlags & flags) const
370 {
371 return min_access.contains(flags);
372 }
373
374 template <typename... Args>
375 bool isGranted(AccessFlags flags, const std::string_view & name, const Args &... subnames) const
376 {
377 if (min_access.contains(flags))
378 return true;
379 if (!max_access.contains(flags))
380 return false;
381
382 const Node * child = tryGetChild(name);
383 if (child)
384 return child->isGranted(flags, subnames...);
385 else
386 return final_access.contains(flags);
387 }
388
389 template <typename StringT>
390 bool isGranted(AccessFlags flags, const std::vector<StringT> & names) const
391 {
392 if (min_access.contains(flags))
393 return true;
394 if (!max_access.contains(flags))
395 return false;
396
397 for (const auto & name : names)
398 {
399 const Node * child = tryGetChild(name);
400 if (child)
401 {
402 if (!child->isGranted(flags, name))
403 return false;
404 }
405 else
406 {
407 if (!final_access.contains(flags))
408 return false;
409 }
410 }
411 return true;
412 }
413
414 friend bool operator ==(const Node & left, const Node & right)
415 {
416 if (left.access != right.access)
417 return false;
418
419 if (!left.children)
420 return !right.children;
421
422 if (!right.children)
423 return false;
424 return *left.children == *right.children;
425 }
426
427 friend bool operator!=(const Node & left, const Node & right) { return !(left == right); }
428
429 void merge(const Node & other, const Helper & helper)
430 {
431 mergeAccessRec(other);
432 calculateFinalAccessRec(helper);
433 }
434
435
436 ProtoElements getElements() const
437 {
438 ProtoElements res;
439 getElementsRec(res, {}, *this, {});
440 return res;
441 }
442
443 static ProtoElements getElements(const Node * node, const Node * node_with_grant_option)
444 {
445 ProtoElements res;
446 getElementsRec(res, {}, node, {}, node_with_grant_option, {});
447 return res;
448 }
449
450 void logTree(Poco::Logger * log, const String & title) const
451 {
452 LOG_TRACE(log, "Tree({}): level={}, name={}, access={}, final_access={}, min_access={}, max_access={}, num_children={}",
453 title, level, node_name ? *node_name : "NULL", access.toString(),
454 final_access.toString(), min_access.toString(), max_access.toString(),
455 (children ? children->size() : 0));
456
457 if (children)
458 {
459 for (auto & child : *children | boost::adaptors::map_values)
460 child.logTree(log, title);
461 }
462 }
463
464private:
465 Node * tryGetChild(const std::string_view & name) const
466 {
467 if (!children)
468 return nullptr;
469 auto it = children->find(name);
470 if (it == children->end())
471 return nullptr;
472 return &it->second;
473 }
474
475 Node & getChild(const std::string_view & name)
476 {
477 auto * child = tryGetChild(name);
478 if (child)
479 return *child;
480 if (!children)
481 children = std::make_unique<std::unordered_map<std::string_view, Node>>();
482 auto new_child_name = std::make_shared<const String>(name);
483 Node & new_child = (*children)[*new_child_name];
484 new_child.node_name = std::move(new_child_name);
485 new_child.level = static_cast<Level>(level + 1);
486 new_child.access = access;
487 return new_child;
488 }
489
490 void eraseChildIfPossible(Node & child)
491 {
492 if (!canEraseChild(child))
493 return;
494 auto it = children->find(*child.node_name);
495 children->erase(it);
496 if (children->empty())
497 children = nullptr;
498 }
499
500 bool canEraseChild(const Node & child) const
501 {
502 return (access == child.access) && !child.children;
503 }
504
505 void addGrantsRec(const AccessFlags & flags)
506 {
507 access |= flags;
508 if (children)
509 {
510 for (auto it = children->begin(); it != children->end();)
511 {
512 auto & child = it->second;
513 child.addGrantsRec(flags);
514 if (canEraseChild(child))
515 it = children->erase(it);
516 else
517 ++it;
518 }
519 if (children->empty())
520 children = nullptr;
521 }
522 }
523
524 void removeGrantsRec(const AccessFlags & flags)
525 {
526 access &= ~flags;
527 if (children)
528 {
529 for (auto it = children->begin(); it != children->end();)
530 {
531 auto & child = it->second;
532 child.removeGrantsRec(flags);
533 if (canEraseChild(child))
534 it = children->erase(it);
535 else
536 ++it;
537 }
538 if (children->empty())
539 children = nullptr;
540 }
541 }
542
543 static void getElementsRec(
544 ProtoElements & res,
545 const boost::container::small_vector<std::string_view, 3> & full_name,
546 const Node & node,
547 const AccessFlags & parent_access)
548 {
549 auto access = node.access;
550 auto revokes = parent_access - access;
551 auto grants = access - parent_access;
552
553 if (revokes)
554 res.push_back(ProtoElement{revokes, full_name, false, Kind::REVOKE});
555
556 if (grants)
557 res.push_back(ProtoElement{grants, full_name, false, Kind::GRANT});
558
559 if (node.children)
560 {
561 for (const auto & [child_name, child] : *node.children)
562 {
563 boost::container::small_vector<std::string_view, 3> child_full_name = full_name;
564 child_full_name.push_back(child_name);
565 getElementsRec(res, child_full_name, child, access);
566 }
567 }
568 }
569
570 static void getElementsRec(
571 ProtoElements & res,
572 const boost::container::small_vector<std::string_view, 3> & full_name,
573 const Node * node,
574 const AccessFlags & parent_access,
575 const Node * node_go,
576 const AccessFlags & parent_access_go)
577 {
578 auto access = node ? node->access : parent_access;
579 auto access_go = node_go ? node_go->access : parent_access_go;
580 auto revokes = parent_access - access;
581 auto revokes_go = parent_access_go - access_go - revokes;
582 auto grants_go = access_go - parent_access_go;
583 auto grants = access - parent_access - grants_go;
584
585 if (revokes)
586 res.push_back(ProtoElement{revokes, full_name, false, Kind::REVOKE});
587
588 if (revokes_go)
589 res.push_back(ProtoElement{revokes_go, full_name, true, Kind::REVOKE});
590
591 if (grants)
592 res.push_back(ProtoElement{grants, full_name, false, Kind::GRANT});
593
594 if (grants_go)
595 res.push_back(ProtoElement{grants_go, full_name, true, Kind::GRANT});
596
597 if (node && node->children)
598 {
599 for (const auto & [child_name, child] : *node->children)
600 {
601 boost::container::small_vector<std::string_view, 3> child_full_name = full_name;
602 child_full_name.push_back(child_name);
603 const Node * child_node = &child;
604 const Node * child_node_go = nullptr;
605 if (node_go && node_go->children)
606 {
607 auto it = node_go->children->find(child_name);
608 if (it != node_go->children->end())
609 child_node_go = &it->second;
610 }
611 getElementsRec(res, child_full_name, child_node, access, child_node_go, access_go);
612 }
613
614 }
615 if (node_go && node_go->children)
616 {
617 for (const auto & [child_name, child] : *node_go->children)
618 {
619 if (node && node->children && node->children->count(child_name))
620 continue; /// already processed
621 boost::container::small_vector<std::string_view, 3> child_full_name = full_name;
622 child_full_name.push_back(child_name);
623 const Node * child_node = nullptr;
624 const Node * child_node_go = &child;
625 getElementsRec(res, child_full_name, child_node, access, child_node_go, access_go);
626 }
627 }
628 }
629
630 void calculateFinalAccessRec(const Helper & helper)
631 {
632 /// Traverse tree.
633 if (children)
634 {
635 for (auto it = children->begin(); it != children->end();)
636 {
637 auto & child = it->second;
638 child.calculateFinalAccessRec(helper);
639 if (canEraseChild(child))
640 it = children->erase(it);
641 else
642 ++it;
643 }
644 if (children->empty())
645 children = nullptr;
646 }
647
648 calculateFinalAccess(helper);
649 }
650
651 void calculateFinalAccess(const Helper & helper)
652 {
653 /// Calculate min and max access among children.
654 AccessFlags min_access_among_children = helper.all_flags;
655 AccessFlags max_access_among_children;
656 if (children)
657 {
658 for (const auto & child : *children | boost::adaptors::map_values)
659 {
660 min_access_among_children &= child.min_access;
661 max_access_among_children |= child.max_access;
662 }
663 }
664
665 /// Calculate implicit access:
666 AccessFlags implicit_access;
667
668 if (level <= DATABASE_LEVEL)
669 {
670 if (access & helper.database_flags)
671 implicit_access |= helper.show_databases_flag;
672 }
673 if (level <= TABLE_LEVEL)
674 {
675 if (access & helper.table_flags)
676 implicit_access |= helper.show_tables_flag;
677 if (access & helper.dictionary_flags)
678 implicit_access |= helper.show_dictionaries_flag;
679 }
680 if (level <= COLUMN_LEVEL)
681 {
682 if (access & helper.column_flags)
683 implicit_access |= helper.show_columns_flag;
684 }
685 if (children && max_access_among_children)
686 {
687 if (level == DATABASE_LEVEL)
688 implicit_access |= helper.show_databases_flag;
689 else if (level == TABLE_LEVEL)
690 implicit_access |= helper.show_tables_flag;
691 }
692
693 if (level == GLOBAL_LEVEL)
694 {
695 if ((access | max_access_among_children) & helper.create_table_flag)
696 implicit_access |= helper.create_temporary_table_flag;
697
698 if (access & helper.system_reload_dictionary)
699 implicit_access |= helper.system_reload_embedded_dictionaries;
700 }
701
702 if (level <= TABLE_LEVEL)
703 {
704 if (access & helper.create_table_flag)
705 implicit_access |= helper.create_view_flag;
706
707 if (access & helper.drop_table_flag)
708 implicit_access |= helper.drop_view_flag;
709
710 if (access & helper.alter_table_flag)
711 implicit_access |= helper.alter_view_flag;
712
713 if (access & helper.alter_ttl_flag)
714 implicit_access |= helper.alter_materialize_ttl_flag;
715 }
716
717 final_access = access | implicit_access;
718
719 /// Calculate min and max access:
720 /// min_access = final_access & child[0].final_access & ... & child[N-1].final_access
721 /// max_access = final_access | child[0].final_access | ... | child[N-1].final_access
722 min_access = final_access & min_access_among_children;
723 max_access = final_access | max_access_among_children;
724 }
725
726 void mergeAccessRec(const Node & rhs)
727 {
728 if (rhs.children)
729 {
730 for (const auto & [rhs_childname, rhs_child] : *rhs.children)
731 getChild(rhs_childname).mergeAccessRec(rhs_child);
732 }
733 access |= rhs.access;
734 if (children)
735 {
736 for (auto & [lhs_childname, lhs_child] : *children)
737 {
738 if (!rhs.tryGetChild(lhs_childname))
739 lhs_child.access |= rhs.access;
740 }
741 }
742 }
743};
744
745
746AccessRights::AccessRights() = default;
747AccessRights::~AccessRights() = default;
748AccessRights::AccessRights(AccessRights && src) = default;
749AccessRights & AccessRights::operator =(AccessRights && src) = default;
750
751
752AccessRights::AccessRights(const AccessRights & src)
753{
754 *this = src;
755}
756
757
758AccessRights & AccessRights::operator =(const AccessRights & src)
759{
760 if (src.root)
761 root = std::make_unique<Node>(*src.root);
762 else
763 root = nullptr;
764 if (src.root_with_grant_option)
765 root_with_grant_option = std::make_unique<Node>(*src.root_with_grant_option);
766 else
767 root_with_grant_option = nullptr;
768 return *this;
769}
770
771
772AccessRights::AccessRights(const AccessFlags & access)
773{
774 grant(access);
775}
776
777
778bool AccessRights::isEmpty() const
779{
780 return !root && !root_with_grant_option;
781}
782
783
784void AccessRights::clear()
785{
786 root = nullptr;
787 root_with_grant_option = nullptr;
788}
789
790
791template <bool with_grant_option, typename... Args>
792void AccessRights::grantImpl(const AccessFlags & flags, const Args &... args)
793{
794 auto helper = [&](std::unique_ptr<Node> & root_node)
795 {
796 if (!root_node)
797 root_node = std::make_unique<Node>();
798 root_node->grant(flags, Helper::instance(), args...);
799 if (!root_node->access && !root_node->children)
800 root_node = nullptr;
801 };
802 helper(root);
803
804 if constexpr (with_grant_option)
805 helper(root_with_grant_option);
806}
807
808template <bool with_grant_option>
809void AccessRights::grantImpl(const AccessRightsElement & element)
810{
811 if (element.any_database)
812 grantImpl<with_grant_option>(element.access_flags);
813 else if (element.any_table)
814 grantImpl<with_grant_option>(element.access_flags, element.database);
815 else if (element.any_column)
816 grantImpl<with_grant_option>(element.access_flags, element.database, element.table);
817 else
818 grantImpl<with_grant_option>(element.access_flags, element.database, element.table, element.columns);
819}
820
821template <bool with_grant_option>
822void AccessRights::grantImpl(const AccessRightsElements & elements)
823{
824 for (const auto & element : elements)
825 grantImpl<with_grant_option>(element);
826}
827
828void AccessRights::grant(const AccessFlags & flags) { grantImpl<false>(flags); }
829void AccessRights::grant(const AccessFlags & flags, const std::string_view & database) { grantImpl<false>(flags, database); }
830void AccessRights::grant(const AccessFlags & flags, const std::string_view & database, const std::string_view & table) { grantImpl<false>(flags, database, table); }
831void AccessRights::grant(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::string_view & column) { grantImpl<false>(flags, database, table, column); }
832void AccessRights::grant(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::vector<std::string_view> & columns) { grantImpl<false>(flags, database, table, columns); }
833void AccessRights::grant(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const Strings & columns) { grantImpl<false>(flags, database, table, columns); }
834void AccessRights::grant(const AccessRightsElement & element) { grantImpl<false>(element); }
835void AccessRights::grant(const AccessRightsElements & elements) { grantImpl<false>(elements); }
836
837void AccessRights::grantWithGrantOption(const AccessFlags & flags) { grantImpl<true>(flags); }
838void AccessRights::grantWithGrantOption(const AccessFlags & flags, const std::string_view & database) { grantImpl<true>(flags, database); }
839void AccessRights::grantWithGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table) { grantImpl<true>(flags, database, table); }
840void AccessRights::grantWithGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::string_view & column) { grantImpl<true>(flags, database, table, column); }
841void AccessRights::grantWithGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::vector<std::string_view> & columns) { grantImpl<true>(flags, database, table, columns); }
842void AccessRights::grantWithGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const Strings & columns) { grantImpl<true>(flags, database, table, columns); }
843void AccessRights::grantWithGrantOption(const AccessRightsElement & element) { grantImpl<true>(element); }
844void AccessRights::grantWithGrantOption(const AccessRightsElements & elements) { grantImpl<true>(elements); }
845
846
847template <bool grant_option, typename... Args>
848void AccessRights::revokeImpl(const AccessFlags & flags, const Args &... args)
849{
850 auto helper = [&](std::unique_ptr<Node> & root_node)
851 {
852 if (!root_node)
853 return;
854 root_node->revoke(flags, Helper::instance(), args...);
855 if (!root_node->access && !root_node->children)
856 root_node = nullptr;
857 };
858 helper(root_with_grant_option);
859
860 if constexpr (!grant_option)
861 helper(root);
862}
863
864template <bool grant_option>
865void AccessRights::revokeImpl(const AccessRightsElement & element)
866{
867 if (element.any_database)
868 revokeImpl<grant_option>(element.access_flags);
869 else if (element.any_table)
870 revokeImpl<grant_option>(element.access_flags, element.database);
871 else if (element.any_column)
872 revokeImpl<grant_option>(element.access_flags, element.database, element.table);
873 else
874 revokeImpl<grant_option>(element.access_flags, element.database, element.table, element.columns);
875}
876
877template <bool grant_option>
878void AccessRights::revokeImpl(const AccessRightsElements & elements)
879{
880 for (const auto & element : elements)
881 revokeImpl<grant_option>(element);
882}
883
884void AccessRights::revoke(const AccessFlags & flags) { revokeImpl<false>(flags); }
885void AccessRights::revoke(const AccessFlags & flags, const std::string_view & database) { revokeImpl<false>(flags, database); }
886void AccessRights::revoke(const AccessFlags & flags, const std::string_view & database, const std::string_view & table) { revokeImpl<false>(flags, database, table); }
887void AccessRights::revoke(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::string_view & column) { revokeImpl<false>(flags, database, table, column); }
888void AccessRights::revoke(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::vector<std::string_view> & columns) { revokeImpl<false>(flags, database, table, columns); }
889void AccessRights::revoke(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const Strings & columns) { revokeImpl<false>(flags, database, table, columns); }
890void AccessRights::revoke(const AccessRightsElement & element) { revokeImpl<false>(element); }
891void AccessRights::revoke(const AccessRightsElements & elements) { revokeImpl<false>(elements); }
892
893void AccessRights::revokeGrantOption(const AccessFlags & flags) { revokeImpl<true>(flags); }
894void AccessRights::revokeGrantOption(const AccessFlags & flags, const std::string_view & database) { revokeImpl<true>(flags, database); }
895void AccessRights::revokeGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table) { revokeImpl<true>(flags, database, table); }
896void AccessRights::revokeGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::string_view & column) { revokeImpl<true>(flags, database, table, column); }
897void AccessRights::revokeGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::vector<std::string_view> & columns) { revokeImpl<true>(flags, database, table, columns); }
898void AccessRights::revokeGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const Strings & columns) { revokeImpl<true>(flags, database, table, columns); }
899void AccessRights::revokeGrantOption(const AccessRightsElement & element) { revokeImpl<true>(element); }
900void AccessRights::revokeGrantOption(const AccessRightsElements & elements) { revokeImpl<true>(elements); }
901
902
903AccessRightsElementsWithOptions AccessRights::getElements() const
904{
905#if 0
906 logTree();
907#endif
908 if (!root)
909 return {};
910 if (!root_with_grant_option)
911 return root->getElements().getResult();
912 return Node::getElements(root.get(), root_with_grant_option.get()).getResult();
913}
914
915
916String AccessRights::toString() const
917{
918 return getElements().toString();
919}
920
921
922template <bool grant_option, typename... Args>
923bool AccessRights::isGrantedImpl(const AccessFlags & flags, const Args &... args) const
924{
925 auto helper = [&](const std::unique_ptr<Node> & root_node) -> bool
926 {
927 if (!root_node)
928 return flags.isEmpty();
929 return root_node->isGranted(flags, args...);
930 };
931 if constexpr (grant_option)
932 return helper(root_with_grant_option);
933 else
934 return helper(root);
935}
936
937template <bool grant_option>
938bool AccessRights::isGrantedImpl(const AccessRightsElement & element) const
939{
940 if (element.any_database)
941 return isGrantedImpl<grant_option>(element.access_flags);
942 else if (element.any_table)
943 return isGrantedImpl<grant_option>(element.access_flags, element.database);
944 else if (element.any_column)
945 return isGrantedImpl<grant_option>(element.access_flags, element.database, element.table);
946 else
947 return isGrantedImpl<grant_option>(element.access_flags, element.database, element.table, element.columns);
948}
949
950template <bool grant_option>
951bool AccessRights::isGrantedImpl(const AccessRightsElements & elements) const
952{
953 for (const auto & element : elements)
954 if (!isGrantedImpl<grant_option>(element))
955 return false;
956 return true;
957}
958
959bool AccessRights::isGranted(const AccessFlags & flags) const { return isGrantedImpl<false>(flags); }
960bool AccessRights::isGranted(const AccessFlags & flags, const std::string_view & database) const { return isGrantedImpl<false>(flags, database); }
961bool AccessRights::isGranted(const AccessFlags & flags, const std::string_view & database, const std::string_view & table) const { return isGrantedImpl<false>(flags, database, table); }
962bool AccessRights::isGranted(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::string_view & column) const { return isGrantedImpl<false>(flags, database, table, column); }
963bool AccessRights::isGranted(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::vector<std::string_view> & columns) const { return isGrantedImpl<false>(flags, database, table, columns); }
964bool AccessRights::isGranted(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const Strings & columns) const { return isGrantedImpl<false>(flags, database, table, columns); }
965bool AccessRights::isGranted(const AccessRightsElement & element) const { return isGrantedImpl<false>(element); }
966bool AccessRights::isGranted(const AccessRightsElements & elements) const { return isGrantedImpl<false>(elements); }
967
968bool AccessRights::hasGrantOption(const AccessFlags & flags) const { return isGrantedImpl<true>(flags); }
969bool AccessRights::hasGrantOption(const AccessFlags & flags, const std::string_view & database) const { return isGrantedImpl<true>(flags, database); }
970bool AccessRights::hasGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table) const { return isGrantedImpl<true>(flags, database, table); }
971bool AccessRights::hasGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::string_view & column) const { return isGrantedImpl<true>(flags, database, table, column); }
972bool AccessRights::hasGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const std::vector<std::string_view> & columns) const { return isGrantedImpl<true>(flags, database, table, columns); }
973bool AccessRights::hasGrantOption(const AccessFlags & flags, const std::string_view & database, const std::string_view & table, const Strings & columns) const { return isGrantedImpl<true>(flags, database, table, columns); }
974bool AccessRights::hasGrantOption(const AccessRightsElement & element) const { return isGrantedImpl<true>(element); }
975bool AccessRights::hasGrantOption(const AccessRightsElements & elements) const { return isGrantedImpl<true>(elements); }
976
977
978bool operator ==(const AccessRights & left, const AccessRights & right)
979{
980 auto helper = [](const std::unique_ptr<AccessRights::Node> & left_node, const std::unique_ptr<AccessRights::Node> & right_node)
981 {
982 if (!left_node)
983 return !right_node;
984 if (!right_node)
985 return false;
986 return *left_node == *right_node;
987 };
988 return helper(left.root, right.root) && helper(left.root_with_grant_option, right.root_with_grant_option);
989}
990
991
992void AccessRights::merge(const AccessRights & other)
993{
994 auto helper = [](std::unique_ptr<Node> & root_node, const std::unique_ptr<Node> & other_root_node)
995 {
996 if (!root_node)
997 {
998 if (other_root_node)
999 root_node = std::make_unique<Node>(*other_root_node);
1000 return;
1001 }
1002 if (other_root_node)
1003 {
1004 root_node->merge(*other_root_node, Helper::instance());
1005 if (!root_node->access && !root_node->children)
1006 root_node = nullptr;
1007 }
1008 };
1009 helper(root, other.root);
1010 helper(root_with_grant_option, other.root_with_grant_option);
1011}
1012
1013
1014AccessRights AccessRights::getFullAccess()
1015{
1016 AccessRights res;
1017 res.grantWithGrantOption(AccessType::ALL);
1018 return res;
1019}
1020
1021
1022void AccessRights::logTree() const
1023{
1024 auto * log = &Poco::Logger::get("AccessRights");
1025 if (root)
1026 {
1027 root->logTree(log, "");
1028 if (root_with_grant_option)
1029 root->logTree(log, "go");
1030 }
1031 else
1032 LOG_TRACE(log, "Tree: NULL");
1033}
1034}