Skip to content

Commit 3ddff9c

Browse files
betanummericfhamme
andauthored
postgresql_privs: fix schema quoting (#382)
* postgresql_privs: fix schema quoting * add changelog fragment * postgresql_privs: add integration test for schema names with '.' or '"' * postgresql_privs: extend integration test to check if permissions on tables in schemas with names that need to be quoted are set correctly * postgresql_privs: fix integration test syntax * postgresql_privs: fix integration test syntax * postgresql_privs: fix integration test syntax Co-authored-by: Felix Hamme <felix.hamme@ionos.com>
1 parent 70b915a commit 3ddff9c

File tree

4 files changed

+117
-7
lines changed

4 files changed

+117
-7
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bugfixes:
2+
- postgresql_privs - fix quoting of the ``schema`` parameter in SQL statements (https://github.com/ansible-collections/community.postgresql/pull/382).

plugins/modules/postgresql_privs.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,7 @@ def manipulate_privs(self, obj_type, privs, objs, orig_objs, roles, target_roles
817817
if not objs:
818818
return False
819819

820+
quoted_schema_qualifier = '"%s"' % schema_qualifier.replace('"', '""') if schema_qualifier else None
820821
# obj_ids: quoted db object identifiers (sometimes schema-qualified)
821822
if obj_type in ('function', 'procedure'):
822823
obj_ids = []
@@ -825,9 +826,9 @@ def manipulate_privs(self, obj_type, privs, objs, orig_objs, roles, target_roles
825826
f, args = obj.split('(', 1)
826827
except Exception:
827828
raise Error('Illegal function / procedure signature: "%s".' % obj)
828-
obj_ids.append('"%s"."%s"(%s' % (schema_qualifier, f, args))
829+
obj_ids.append('%s."%s"(%s' % (quoted_schema_qualifier, f, args))
829830
elif obj_type in ['table', 'sequence', 'type']:
830-
obj_ids = ['"%s"."%s"' % (schema_qualifier, o) for o in objs]
831+
obj_ids = ['%s."%s"' % (quoted_schema_qualifier, o) for o in objs]
831832
else:
832833
obj_ids = ['"%s"' % o for o in objs]
833834

@@ -846,7 +847,7 @@ def manipulate_privs(self, obj_type, privs, objs, orig_objs, roles, target_roles
846847
# and privs was escaped when it was parsed
847848
# Note: Underscores are replaced with spaces to support multi-word obj_type
848849
if orig_objs is not None:
849-
set_what = '%s ON %s %s' % (','.join(privs), orig_objs, schema_qualifier)
850+
set_what = '%s ON %s %s' % (','.join(privs), orig_objs, quoted_schema_qualifier)
850851
else:
851852
set_what = '%s ON %s %s' % (','.join(privs), obj_type.replace('_', ' '), ','.join(obj_ids))
852853

@@ -875,17 +876,14 @@ def manipulate_privs(self, obj_type, privs, objs, orig_objs, roles, target_roles
875876
if target_roles:
876877
as_who = ','.join('"%s"' % r for r in target_roles)
877878

878-
if schema_qualifier:
879-
schema_qualifier = '"%s"' % schema_qualifier
880-
881879
status_before = get_status(objs)
882880

883881
query = QueryBuilder(state) \
884882
.for_objtype(obj_type) \
885883
.with_grant_option(grant_option) \
886884
.for_whom(for_whom) \
887885
.as_who(as_who) \
888-
.for_schema(schema_qualifier) \
886+
.for_schema(quoted_schema_qualifier) \
889887
.set_what(set_what) \
890888
.for_objs(objs) \
891889
.usage_on_types(usage_on_types) \

tests/integration/targets/postgresql_privs/defaults/main.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ db_user_with_dots2: role.with.dots2
77
db_name_with_hyphens: ansible-db
88
db_user_with_hyphens: ansible-db-user
99
db_schema_with_hyphens: ansible-db-schema
10+
db_schema_with_dot: test.schema
11+
db_schema_with_quote: 'TEST_schema"'
1012
db_session_role1: session_role1
1113
db_session_role2: session_role2
1214
dangerous_name: 'curious.anonymous"; SELECT * FROM information_schema.tables; --'

tests/integration/targets/postgresql_privs/tasks/postgresql_privs_general.yml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,6 +1476,114 @@
14761476
that:
14771477
- result is not changed
14781478

1479+
##############
1480+
# Issue https://github.com/ansible-collections/community.postgresql/issues/381
1481+
- name: create schemas with special names
1482+
become: true
1483+
become_user: "{{ pg_user }}"
1484+
postgresql_schema:
1485+
login_user: "{{ pg_user }}"
1486+
login_password: password
1487+
db: "{{ db_name }}"
1488+
name: '"{{ item }}"'
1489+
state: present
1490+
loop:
1491+
- "{{ db_schema_with_dot|replace('\"', '\"\"') }}"
1492+
- "{{ db_schema_with_quote|replace('\"', '\"\"') }}"
1493+
register: result
1494+
- assert:
1495+
that:
1496+
- result is changed
1497+
- name: create tables in schemas with special names
1498+
become: true
1499+
become_user: "{{ pg_user }}"
1500+
postgresql_table:
1501+
login_user: "{{ pg_user }}"
1502+
login_password: password
1503+
db: "{{ db_name }}"
1504+
name: '"{{ item }}"."test.table.name"'
1505+
columns: []
1506+
loop:
1507+
- "{{ db_schema_with_dot|replace('\"', '\"\"') }}"
1508+
- "{{ db_schema_with_quote|replace('\"', '\"\"') }}"
1509+
register: result
1510+
- assert:
1511+
that:
1512+
- result is changed
1513+
- name: grant privileges on all tables in schemas with special names
1514+
become: yes
1515+
become_user: "{{ pg_user }}"
1516+
postgresql_privs:
1517+
login_user: "{{ pg_user }}"
1518+
login_db: "{{ db_name }}"
1519+
roles: PUBLIC
1520+
objs: ALL_IN_SCHEMA
1521+
type: table
1522+
privs: SELECT
1523+
schema: "{{ item }}"
1524+
loop:
1525+
- "{{ db_schema_with_dot }}"
1526+
- "{{ db_schema_with_quote }}"
1527+
register: result
1528+
- assert:
1529+
that:
1530+
- result is changed
1531+
- name: grant privileges on some table in schemas with special names
1532+
become: yes
1533+
become_user: "{{ pg_user }}"
1534+
postgresql_privs:
1535+
login_user: "{{ pg_user }}"
1536+
login_db: "{{ db_name }}"
1537+
roles: PUBLIC
1538+
objs: 'test.table.name'
1539+
type: table
1540+
privs: SELECT
1541+
schema: "{{ item }}"
1542+
loop:
1543+
- "{{ db_schema_with_dot }}"
1544+
- "{{ db_schema_with_quote }}"
1545+
register: result
1546+
- assert:
1547+
that:
1548+
- result is changed
1549+
- name: check permissions on tables in schemas with special names
1550+
become: true
1551+
become_user: "{{ pg_user }}"
1552+
postgresql_query:
1553+
login_user: "{{ pg_user }}"
1554+
db: "{{ db_name }}"
1555+
query: |
1556+
select true as granted from information_schema.role_table_grants
1557+
where table_schema=%s and table_name='test.table.name' and privilege_type='SELECT' and grantee='PUBLIC'
1558+
positional_args:
1559+
- "{{ item }}"
1560+
loop:
1561+
- "{{ db_schema_with_dot }}"
1562+
- "{{ db_schema_with_quote }}"
1563+
register: result
1564+
- assert:
1565+
that:
1566+
- 'result.results|length == 2'
1567+
- 'result.results[0].rowcount == 1'
1568+
- 'not result.results[0].failed'
1569+
- 'result.results[1].rowcount == 1'
1570+
- 'not result.results[1].failed'
1571+
- name: cleanup test schemas with special names
1572+
become: true
1573+
become_user: "{{ pg_user }}"
1574+
postgresql_schema:
1575+
login_user: "{{ pg_user }}"
1576+
login_password: password
1577+
db: "{{ db_name }}"
1578+
name: '"{{ item }}"'
1579+
state: absent
1580+
cascade_drop: true
1581+
loop:
1582+
- "{{ db_schema_with_dot|replace('\"', '\"\"') }}"
1583+
- "{{ db_schema_with_quote|replace('\"', '\"\"') }}"
1584+
register: result
1585+
1586+
14791587
##############
14801588
# Issue https://github.com/ansible-collections/community.postgresql/issues/332
14811589
- name: Test community.postgresql issue 332 grant usage

0 commit comments

Comments
 (0)