From 8d114c7e39d8ec8b9b3592e6bb9e259db92af6e3 Mon Sep 17 00:00:00 2001 From: Andrew Klychkov Date: Thu, 12 May 2022 10:36:21 +0300 Subject: [PATCH] mysql_user: fix parsing privs when a user has roles assigned to it (#341) * mysql_user: fix parsing errors when a user has roles assigned * Add a changelog fragment * Fix a typo * Fix CI --- .gitignore | 1 + ...ser_fix_pars_users_with_roles_assigned.yml | 2 + plugins/module_utils/user.py | 11 +++ .../tasks/mysql_role_initial.yml | 21 ++++ .../targets/test_mysql_user/tasks/main.yml | 3 + .../test_user_grants_with_roles_applied.yml | 95 +++++++++++++++++++ 6 files changed, 133 insertions(+) create mode 100644 changelogs/fragments/001-mysql_user_fix_pars_users_with_roles_assigned.yml create mode 100644 tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml diff --git a/.gitignore b/.gitignore index f4407229..6bbe85a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /tests/output/ /changelogs/.plugin-cache.yaml +*.swp # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/changelogs/fragments/001-mysql_user_fix_pars_users_with_roles_assigned.yml b/changelogs/fragments/001-mysql_user_fix_pars_users_with_roles_assigned.yml new file mode 100644 index 00000000..121bc467 --- /dev/null +++ b/changelogs/fragments/001-mysql_user_fix_pars_users_with_roles_assigned.yml @@ -0,0 +1,2 @@ +bugfixes: +- mysql_user - fix parsing privs when a user has roles assigned (https://github.com/ansible-collections/community.mysql/issues/231). diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index 35f701d1..dd0509b2 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -429,8 +429,19 @@ def pick(x): res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3@(['`"]).*\\4( IDENTIFIED BY PASSWORD (['`"]).+\\6)? ?(.*)""", grant[0]) else: res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3""", grant[0]) + if res is None: + # If a user has roles assigned, we'll have one of priv tuples looking like + # GRANT `admin`@`%` TO `user1`@`localhost` + # which will result None as res value. + # As we use the mysql_role module to manipulate roles + # we just ignore such privs below: + res = re.match("""GRANT (.+) TO (['`"]).*""", grant[0]) + if not maria_role and res: + continue + raise InvalidPrivsError('unable to parse the MySQL grant string: %s' % grant[0]) + privileges = res.group(1).split(",") privileges = [pick(x.strip()) for x in privileges] diff --git a/tests/integration/targets/test_mysql_role/tasks/mysql_role_initial.yml b/tests/integration/targets/test_mysql_role/tasks/mysql_role_initial.yml index 1bca3aef..a2167c67 100644 --- a/tests/integration/targets/test_mysql_role/tasks/mysql_role_initial.yml +++ b/tests/integration/targets/test_mysql_role/tasks/mysql_role_initial.yml @@ -1540,3 +1540,24 @@ - '{{ test_db }}' - '{{ test_db1 }}' - '{{ test_db2 }}' + + - name: Drop users + <<: *task_params + mysql_user: + <<: *mysql_params + name: '{{ item }}' + state: absent + loop: + - '{{ user0 }}' + - '{{ user1 }}' + - '{{ user2 }}' + + - name: Drop roles + <<: *task_params + mysql_role: + <<: *mysql_params + name: '{{ item }}' + state: absent + loop: + - '{{ role0 }}' + - test diff --git a/tests/integration/targets/test_mysql_user/tasks/main.yml b/tests/integration/targets/test_mysql_user/tasks/main.yml index 645ea6cc..1d36b402 100644 --- a/tests/integration/targets/test_mysql_user/tasks/main.yml +++ b/tests/integration/targets/test_mysql_user/tasks/main.yml @@ -293,3 +293,6 @@ # Test that mysql_user still works with force_context enabled (database set to "mysql") # (https://github.com/ansible-collections/community.mysql/issues/265) - include: issue-265.yml + + # https://github.com/ansible-collections/community.mysql/issues/231 + - include: test_user_grants_with_roles_applied.yml diff --git a/tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml b/tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml new file mode 100644 index 00000000..8ee738ec --- /dev/null +++ b/tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml @@ -0,0 +1,95 @@ +# https://github.com/ansible-collections/community.mysql/issues/231 +- vars: + mysql_parameters: &mysql_params + login_user: '{{ mysql_user }}' + login_password: '{{ mysql_password }}' + login_host: 127.0.0.1 + login_port: '{{ mysql_primary_port }}' + + block: + - name: Get server version + mysql_info: + <<: *mysql_params + register: srv + + # Skip unsupported versions + - meta: end_play + when: srv['version']['major'] < 8 + + - name: Create test databases + mysql_db: + <<: *mysql_params + name: '{{ item }}' + state: present + loop: + - data1 + - data2 + + - name: Create user with privileges + mysql_user: + <<: *mysql_params + name: '{{ user_name_3 }}' + password: '{{ user_password_3 }}' + priv: + "data1.*": "SELECT" + "data2.*": "SELECT" + state: present + + - name: Run command to show privileges for user (expect privileges in stdout) + command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_3 }}'@'localhost'\"" + register: result + + - name: Assert user has giving privileges + assert: + that: + - "'GRANT SELECT ON `data1`.*' in result.stdout" + - "'GRANT SELECT ON `data2`.*' in result.stdout" + + - name: Create role + mysql_role: + <<: *mysql_params + name: test231 + members: + - '{{ user_name_3 }}@localhost' + + - name: Try to change privs + mysql_user: + <<: *mysql_params + name: '{{ user_name_3 }}' + priv: + "data1.*": "INSERT" + "data2.*": "INSERT" + state: present + + - name: Run command to show privileges for user (expect privileges in stdout) + command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_3 }}'@'localhost'\"" + register: result + + - name: Assert user has giving privileges + assert: + that: + - "'GRANT INSERT ON `data1`.*' in result.stdout" + - "'GRANT INSERT ON `data2`.*' in result.stdout" + + ########## + # Clean up + - name: Drop test databases + mysql_db: + <<: *mysql_params + name: '{{ item }}' + state: present + loop: + - data1 + - data2 + + - name: Drop test user + mysql_user: + <<: *mysql_params + name: '{{ user_name_3 }}' + state: absent + + - name: Drop test role + mysql_role: + <<: *mysql_params + name: test231 + state: absent