|
11 | 11 | [metabase.lib.test-util :as lib.tu]
|
12 | 12 | [metabase.models.interface :as mi]
|
13 | 13 | [metabase.models.serialization :as serdes]
|
| 14 | + [metabase.permissions.core :as perms] |
| 15 | + [metabase.permissions.models.data-permissions :as data-perms] |
14 | 16 | [metabase.query-processor.store :as qp.store]
|
15 | 17 | [metabase.request.core :as request]
|
16 | 18 | [metabase.secrets.core :as secret]
|
|
627 | 629 | (t2/hydrate :tables)
|
628 | 630 | :tables
|
629 | 631 | (#(map :name %))))))
|
| 632 | + |
| 633 | +(deftest visible-filter-clause-test |
| 634 | + (testing "Database visible-filter-clause generates a HoneySQL clause that filters databases based on user permissions" |
| 635 | + (mt/with-no-data-perms-for-all-users! |
| 636 | + (mt/with-temp [:model/Database {db1-id :id} {:name "Database 1"} |
| 637 | + :model/Database {db2-id :id} {:name "Database 2"} |
| 638 | + :model/Database {db3-id :id} {:name "Database 3"} |
| 639 | + :model/Table _ {:db_id db1-id :name "Table1"} |
| 640 | + :model/Table _ {:db_id db2-id :name "Table2"} |
| 641 | + :model/Table _ {:db_id db3-id :name "Table3"} |
| 642 | + :model/PermissionsGroup pg1 {} |
| 643 | + :model/PermissionsGroup pg2 {}] |
| 644 | + |
| 645 | + ;; Set up permissions: user has access to db1 and db2 via different groups, but not db3 |
| 646 | + (perms/add-user-to-group! (mt/user->id :rasta) pg1) |
| 647 | + (perms/add-user-to-group! (mt/user->id :rasta) pg2) |
| 648 | + |
| 649 | + ;; Clear existing permissions for our test databases only |
| 650 | + (t2/delete! :model/DataPermissions :db_id [:in [db1-id db2-id db3-id]]) |
| 651 | + |
| 652 | + ;; Grant permissions to specific databases |
| 653 | + (data-perms/set-database-permission! pg1 db1-id :perms/view-data :unrestricted) |
| 654 | + (data-perms/set-database-permission! pg1 db1-id :perms/create-queries :query-builder) |
| 655 | + |
| 656 | + (data-perms/set-database-permission! pg2 db2-id :perms/view-data :unrestricted) |
| 657 | + (data-perms/set-database-permission! pg2 db2-id :perms/create-queries :query-builder) |
| 658 | + |
| 659 | + ;; No permissions for db3 |
| 660 | + (data-perms/set-database-permission! pg1 db3-id :perms/view-data :blocked) |
| 661 | + (data-perms/set-database-permission! pg2 db3-id :perms/view-data :blocked) |
| 662 | + |
| 663 | + (let [user-id (mt/user->id :rasta) |
| 664 | + fetch-visible-ids (fn [user-info permission-mapping column-field] |
| 665 | + (let [filter-clause (mi/visible-filter-clause :model/Database column-field user-info permission-mapping)] |
| 666 | + (t2/select-pks-set :model/Database |
| 667 | + {:where [:and |
| 668 | + filter-clause |
| 669 | + [:in :id [db1-id db2-id db3-id]]]})))] ; Only check our test databases |
| 670 | + |
| 671 | + (testing "Superuser should see all databases" |
| 672 | + (let [user-info {:user-id user-id :is-superuser? true} |
| 673 | + permission-mapping {:perms/view-data :unrestricted |
| 674 | + :perms/create-queries :query-builder}] |
| 675 | + (is (= #{db1-id db2-id db3-id} |
| 676 | + (fetch-visible-ids user-info permission-mapping :id)) |
| 677 | + "Superuser should see all databases"))) |
| 678 | + |
| 679 | + (testing "Non-superuser should only see databases they have permissions for" |
| 680 | + (let [user-info {:user-id user-id :is-superuser? false} |
| 681 | + permission-mapping {:perms/view-data :unrestricted |
| 682 | + :perms/create-queries :query-builder}] |
| 683 | + (is (= #{db1-id db2-id} |
| 684 | + (fetch-visible-ids user-info permission-mapping :id)) |
| 685 | + "Non-superuser should only see databases with sufficient permissions"))) |
| 686 | + |
| 687 | + (testing "Using qualified column name" |
| 688 | + (let [user-info {:user-id user-id :is-superuser? false} |
| 689 | + permission-mapping {:perms/view-data :unrestricted |
| 690 | + :perms/create-queries :query-builder}] |
| 691 | + (is (= #{db1-id db2-id} |
| 692 | + (fetch-visible-ids user-info permission-mapping :metabase_database.id)) |
| 693 | + "Should work with qualified column names"))) |
| 694 | + |
| 695 | + (testing "Using column expression" |
| 696 | + (let [user-info {:user-id user-id :is-superuser? false} |
| 697 | + permission-mapping {:perms/view-data :unrestricted |
| 698 | + :perms/create-queries :query-builder}] |
| 699 | + (is (= #{db1-id db2-id} |
| 700 | + (fetch-visible-ids user-info permission-mapping [:coalesce :id :metabase_database.id])) |
| 701 | + "Should work with column expressions"))) |
| 702 | + |
| 703 | + (testing "Different permission levels" |
| 704 | + (testing "Requiring only view-data permissions" |
| 705 | + (let [user-info {:user-id user-id :is-superuser? false} |
| 706 | + permission-mapping {:perms/view-data :unrestricted |
| 707 | + :perms/create-queries :no}] |
| 708 | + (is (= #{db1-id db2-id} |
| 709 | + (fetch-visible-ids user-info permission-mapping :id)) |
| 710 | + "Should include databases where user has view permissions"))) |
| 711 | + |
| 712 | + (testing "Requiring blocked level permissions (most permissive)" |
| 713 | + (let [user-info {:user-id user-id :is-superuser? false} |
| 714 | + permission-mapping {:perms/view-data :blocked |
| 715 | + :perms/create-queries :no}] |
| 716 | + (is (= #{db1-id db2-id db3-id} |
| 717 | + (fetch-visible-ids user-info permission-mapping :id)) |
| 718 | + "Should include all databases when requiring only blocked level")))) |
| 719 | + |
| 720 | + (testing "User with no permissions" |
| 721 | + ;; Remove user from groups we added (avoid touching All Users group) |
| 722 | + (t2/delete! :model/PermissionsGroupMembership |
| 723 | + :user_id user-id |
| 724 | + :group_id [:in [(:id pg1) (:id pg2)]]) |
| 725 | + |
| 726 | + (let [user-info {:user-id user-id :is-superuser? false} |
| 727 | + permission-mapping {:perms/view-data :unrestricted |
| 728 | + :perms/create-queries :query-builder}] |
| 729 | + (is (empty? (fetch-visible-ids user-info permission-mapping :id)) |
| 730 | + "User with no group memberships should see no databases")))))))) |
| 731 | + |
| 732 | +(deftest visible-filter-clause-table-level-permissions-test |
| 733 | + (testing "Database visible-filter-clause with table-level permissions" |
| 734 | + (mt/with-no-data-perms-for-all-users! |
| 735 | + (mt/with-temp [:model/Database {db-id :id} {:name "Test Database"} |
| 736 | + :model/Table {table1-id :id} {:db_id db-id :name "Table1"} |
| 737 | + :model/Table {table2-id :id} {:db_id db-id :name "Table2"} |
| 738 | + :model/Table _ {:db_id db-id :name "Table3"} |
| 739 | + :model/PermissionsGroup pg {}] |
| 740 | + |
| 741 | + (perms/add-user-to-group! (mt/user->id :rasta) pg) |
| 742 | + |
| 743 | + ;; Clear existing permissions for our test database only |
| 744 | + (t2/delete! :model/DataPermissions :db_id db-id) |
| 745 | + |
| 746 | + ;; Block database-level access |
| 747 | + (data-perms/set-database-permission! pg db-id :perms/view-data :blocked) |
| 748 | + (data-perms/set-database-permission! pg db-id :perms/create-queries :no) |
| 749 | + |
| 750 | + ;; Grant table-level permissions to only table1 and table2 |
| 751 | + (data-perms/set-table-permission! pg table1-id :perms/view-data :unrestricted) |
| 752 | + (data-perms/set-table-permission! pg table1-id :perms/create-queries :query-builder) |
| 753 | + |
| 754 | + (data-perms/set-table-permission! pg table2-id :perms/view-data :unrestricted) |
| 755 | + (data-perms/set-table-permission! pg table2-id :perms/create-queries :query-builder) |
| 756 | + |
| 757 | + ;; table3 remains blocked |
| 758 | + |
| 759 | + (let [user-id (mt/user->id :rasta) |
| 760 | + user-info {:user-id user-id :is-superuser? false} |
| 761 | + permission-mapping {:perms/view-data :unrestricted |
| 762 | + :perms/create-queries :query-builder} |
| 763 | + filter-clause (mi/visible-filter-clause :model/Database :id user-info permission-mapping) |
| 764 | + visible-db-ids (t2/select-pks-set :model/Database |
| 765 | + {:where [:and |
| 766 | + filter-clause |
| 767 | + [:= :id db-id]]})] ; Only check our test database |
| 768 | + |
| 769 | + (is (contains? visible-db-ids db-id) |
| 770 | + "Database should be visible when user has access to at least one table")))))) |
0 commit comments