|
35 | 35 |
|
36 | 36 | # Increment this PATCH version before using `charmcraft publish-lib` or reset
|
37 | 37 | # to 0 if you are raising the major API version
|
38 |
| -LIBPATCH = 47 |
| 38 | +LIBPATCH = 49 |
39 | 39 |
|
40 | 40 | # Groups to distinguish HBA access
|
41 | 41 | ACCESS_GROUP_IDENTITY = "identity_access"
|
@@ -776,6 +776,42 @@ def is_restart_pending(self) -> bool:
|
776 | 776 | if connection:
|
777 | 777 | connection.close()
|
778 | 778 |
|
| 779 | + @staticmethod |
| 780 | + def build_postgresql_group_map(group_map: Optional[str]) -> List[Tuple]: |
| 781 | + """Build the PostgreSQL authorization group-map. |
| 782 | +
|
| 783 | + Args: |
| 784 | + group_map: serialized group-map with the following format: |
| 785 | + <ldap_group_1>=<psql_group_1>, |
| 786 | + <ldap_group_2>=<psql_group_2>, |
| 787 | + ... |
| 788 | +
|
| 789 | + Returns: |
| 790 | + List of LDAP group to PostgreSQL group tuples. |
| 791 | + """ |
| 792 | + if group_map is None: |
| 793 | + return [] |
| 794 | + |
| 795 | + group_mappings = group_map.split(",") |
| 796 | + group_mappings = (mapping.strip() for mapping in group_mappings) |
| 797 | + group_map_list = [] |
| 798 | + |
| 799 | + for mapping in group_mappings: |
| 800 | + mapping_parts = mapping.split("=") |
| 801 | + if len(mapping_parts) != 2: |
| 802 | + raise ValueError("The group-map must contain value pairs split by commas") |
| 803 | + |
| 804 | + ldap_group = mapping_parts[0] |
| 805 | + psql_group = mapping_parts[1] |
| 806 | + |
| 807 | + if psql_group in [*ACCESS_GROUPS, PERMISSIONS_GROUP_ADMIN]: |
| 808 | + logger.warning(f"Tried to assign LDAP users to forbidden group: {psql_group}") |
| 809 | + continue |
| 810 | + |
| 811 | + group_map_list.append((ldap_group, psql_group)) |
| 812 | + |
| 813 | + return group_map_list |
| 814 | + |
779 | 815 | @staticmethod
|
780 | 816 | def build_postgresql_parameters(
|
781 | 817 | config_options: dict, available_memory: int, limit_memory: Optional[int] = None
|
@@ -855,3 +891,34 @@ def validate_date_style(self, date_style: str) -> bool:
|
855 | 891 | return True
|
856 | 892 | except psycopg2.Error:
|
857 | 893 | return False
|
| 894 | + |
| 895 | + def validate_group_map(self, group_map: Optional[str]) -> bool: |
| 896 | + """Validate the PostgreSQL authorization group-map. |
| 897 | +
|
| 898 | + Args: |
| 899 | + group_map: serialized group-map with the following format: |
| 900 | + <ldap_group_1>=<psql_group_1>, |
| 901 | + <ldap_group_2>=<psql_group_2>, |
| 902 | + ... |
| 903 | +
|
| 904 | + Returns: |
| 905 | + Whether the group-map is valid. |
| 906 | + """ |
| 907 | + if group_map is None: |
| 908 | + return True |
| 909 | + |
| 910 | + try: |
| 911 | + group_map = self.build_postgresql_group_map(group_map) |
| 912 | + except ValueError: |
| 913 | + return False |
| 914 | + |
| 915 | + for _, psql_group in group_map: |
| 916 | + with self._connect_to_database() as connection, connection.cursor() as cursor: |
| 917 | + query = SQL("SELECT TRUE FROM pg_roles WHERE rolname={};") |
| 918 | + query = query.format(Literal(psql_group)) |
| 919 | + cursor.execute(query) |
| 920 | + |
| 921 | + if cursor.fetchone() is None: |
| 922 | + return False |
| 923 | + |
| 924 | + return True |
0 commit comments