mirror of
https://github.com/ansible-collections/community.mysql.git
synced 2025-04-06 10:40:36 -07:00
mysql_user: fixed encrypted option for MySQL 8.0 and test coverage (#79)
* mysql_user: fixed encrypted option for MySQL 8.0 and test coverage The purpose of this change was originally to expand test coverage to unblock #76, but an issue was detected with the encrypted parameter on MySQL 8.0 in the process of writing the tests. Additionally, user_password_update_test.yml had been disabled at some point, so I opted to replace it with two new files that will focus on the password and plugin auth paths. * Updated tests to cover a couple of missing branches * Skip tests that rely on sha256_password if pymysql < 0.9 * Cover the case where pymysql isn't installed for plugin tests * Added better plugin auth checking to tests and other minor changes * Fixed version detection to explicitly handle MariaDB * Removed unneeded import from previous change * Remove whitespace that was introduced by change that was removed * Added unit tests for missing coverage
This commit is contained in:
parent
2de3a57021
commit
06907715d7
12 changed files with 781 additions and 200 deletions
2
changelogs/fragments/79-mysql-user-tests-and-fixes.yml
Normal file
2
changelogs/fragments/79-mysql-user-tests-and-fixes.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
bugfixes:
|
||||
- mysql_user - fixed creating user with encrypted password in MySQL 8.0 (https://github.com/ansible-collections/community.mysql/pull/79).
|
|
@ -133,3 +133,16 @@ def mysql_common_argument_spec():
|
|||
ca_cert=dict(type='path', aliases=['ssl_ca']),
|
||||
check_hostname=dict(type='bool', default=None),
|
||||
)
|
||||
|
||||
|
||||
def get_server_version(cursor):
|
||||
"""Returns a string representation of the server version."""
|
||||
cursor.execute("SELECT VERSION() AS version")
|
||||
result = cursor.fetchone()
|
||||
|
||||
if isinstance(result, dict):
|
||||
version_str = result['version']
|
||||
else:
|
||||
version_str = result[0]
|
||||
|
||||
return version_str
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: mysql_user
|
||||
|
@ -299,10 +298,13 @@ RETURN = '''#'''
|
|||
|
||||
import re
|
||||
import string
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.mysql.plugins.module_utils.database import SQLParseError
|
||||
from ansible_collections.community.mysql.plugins.module_utils.mysql import mysql_connect, mysql_driver, mysql_driver_fail_msg, mysql_common_argument_spec
|
||||
from ansible_collections.community.mysql.plugins.module_utils.mysql import (
|
||||
mysql_connect, mysql_driver, mysql_driver_fail_msg, mysql_common_argument_spec, get_server_version
|
||||
)
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
@ -371,6 +373,19 @@ def use_old_user_mgmt(cursor):
|
|||
return False
|
||||
|
||||
|
||||
def supports_identified_by_password(cursor):
|
||||
"""
|
||||
Determines whether the 'CREATE USER %s@%s IDENTIFIED BY PASSWORD %s' syntax is supported. This was dropped in
|
||||
MySQL 8.0.
|
||||
"""
|
||||
version_str = get_server_version(cursor)
|
||||
|
||||
if 'mariadb' in version_str.lower():
|
||||
return True
|
||||
else:
|
||||
return LooseVersion(version_str) < LooseVersion('8')
|
||||
|
||||
|
||||
def get_mode(cursor):
|
||||
cursor.execute('SELECT @@GLOBAL.sql_mode')
|
||||
result = cursor.fetchone()
|
||||
|
@ -476,7 +491,16 @@ def user_add(cursor, user, host, host_all, password, encrypted,
|
|||
mogrify = do_not_mogrify_requires if old_user_mgmt else mogrify_requires
|
||||
|
||||
if password and encrypted:
|
||||
cursor.execute(*mogrify("CREATE USER %s@%s IDENTIFIED BY PASSWORD %s", (user, host, password), tls_requires))
|
||||
if supports_identified_by_password(cursor):
|
||||
cursor.execute(*mogrify("CREATE USER %s@%s IDENTIFIED BY PASSWORD %s", (user, host, password), tls_requires))
|
||||
else:
|
||||
cursor.execute(
|
||||
*mogrify(
|
||||
"CREATE USER %s@%s IDENTIFIED WITH mysql_native_password AS %s", (user, host, password),
|
||||
tls_requires
|
||||
)
|
||||
)
|
||||
|
||||
elif password and not encrypted:
|
||||
if old_user_mgmt:
|
||||
cursor.execute(*mogrify("CREATE USER %s@%s IDENTIFIED BY %s", (user, host, password), tls_requires))
|
||||
|
|
|
@ -233,10 +233,14 @@
|
|||
- include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
|
||||
|
||||
# ============================================================
|
||||
# Update user password for a user.
|
||||
# Assert the user password is updated and old password can no longer be used.
|
||||
# Test plaintext and encrypted password scenarios.
|
||||
#
|
||||
#- include: user_password_update_test.yml
|
||||
- include: test_user_password.yml
|
||||
|
||||
# ============================================================
|
||||
# Test plugin authentication scenarios.
|
||||
#
|
||||
- include: test_user_plugin_auth.yml
|
||||
|
||||
# ============================================================
|
||||
# Assert create user with SELECT privileges, attempt to create database and update privileges to create database
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
# Tests scenarios for both plaintext and encrypted user passwords.
|
||||
|
||||
- vars:
|
||||
mysql_parameters: &mysql_params
|
||||
login_user: '{{ mysql_user }}'
|
||||
login_password: '{{ mysql_password }}'
|
||||
login_host: 127.0.0.1
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
test_user_name: 'test_user_password'
|
||||
initial_password: 'a5C8SN*DBa0%a75sGz'
|
||||
initial_password_encrypted: '*0A12D4DF68C2A50716111674E565CA3D7D68B048'
|
||||
new_password: 'NkN&qECv33vuQzf3bJg'
|
||||
new_password_encrypted: '*B6559186FAD0953589F54383AD8EE9E9172296DA'
|
||||
test_default_priv_type: 'SELECT'
|
||||
test_default_priv: '*.*:{{ test_default_priv_type }}'
|
||||
|
||||
block:
|
||||
|
||||
# ============================================================
|
||||
# Test setting plaintext password and changing it.
|
||||
#
|
||||
|
||||
- name: Create user with initial password
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
password: '{{ initial_password }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that a change occurred because the user was added
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Get the MySQL version using the newly created used creds
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ initial_password }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
- name: Run mysql_user again without any changes
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
password: '{{ initial_password }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that there weren't any changes because username/password didn't change
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Update the user password
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
password: '{{ new_password }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that a change occurred because the password was updated
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Get the MySQL version data using the original password (should fail)
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ initial_password }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Assert that the mysql_info module failed because we used the old password
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == true"
|
||||
|
||||
- name: Get the MySQL version data using the new password (should work)
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ new_password }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Assert that the mysql_info module succeeded because we used the new password
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password={{ new_password }}
|
||||
|
||||
# ============================================================
|
||||
# Test setting a plaintext password and then the same password encrypted to ensure there isn't a change detected.
|
||||
#
|
||||
|
||||
- name: Create user with initial password
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
password: '{{ initial_password }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that a change occurred because the user was added
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Pass in the same password as before, but in the encrypted form (no change expected)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
password: '{{ initial_password_encrypted }}'
|
||||
encrypted: yes
|
||||
priv: '{{ test_default_priv }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that there weren't any changes because username/password didn't change
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password={{ new_password }}
|
||||
|
||||
# ============================================================
|
||||
# Test setting an encrypted password and then the same password in plaintext to ensure there isn't a change.
|
||||
#
|
||||
|
||||
- name: Create user with initial password
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
password: '{{ initial_password_encrypted }}'
|
||||
encrypted: yes
|
||||
priv: '{{ test_default_priv }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that a change occurred because the user was added
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Get the MySQL version data using the new creds
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ initial_password }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Assert that the mysql_info module succeeded because we used the new password
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
- name: Pass in the same password as before, but in the encrypted form (no change expected)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
password: '{{ initial_password }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that there weren't any changes because username/password didn't change
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password={{ new_password }}
|
||||
|
||||
# ============================================================
|
||||
# Test setting an empty password.
|
||||
#
|
||||
|
||||
- name: Create user with empty password
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that a change occurred because the user was added
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- name: Get the MySQL version using an empty password for the newly created user
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: ''
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
- name: Get the MySQL version using an non-empty password (should fail)
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: 'some_password'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Assert that mysql_info failed
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == true"
|
||||
|
||||
- name: Update the user without changing the password
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that the user wasn't changed because the password is still empty
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password=''
|
|
@ -0,0 +1,386 @@
|
|||
# Test user plugin auth scenarios.
|
||||
|
||||
- vars:
|
||||
mysql_parameters: &mysql_params
|
||||
login_user: '{{ mysql_user }}'
|
||||
login_password: '{{ mysql_password }}'
|
||||
login_host: 127.0.0.1
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
test_user_name: 'test_user_plugin_auth'
|
||||
test_plugin_type: 'mysql_native_password'
|
||||
test_plugin_hash: '*0CB5B86F23FDC24DB19A29B8854EB860CBC47793'
|
||||
test_plugin_auth_string: 'Fdt8fd^34ds'
|
||||
test_plugin_new_hash: '*E74368AC90460FA669F6D41BFB7F2A877DB73745'
|
||||
test_plugin_new_auth_string: 'c$K01LsmK7nJnIR4!h'
|
||||
test_default_priv_type: 'SELECT'
|
||||
test_default_priv: '*.*:{{ test_default_priv_type }}'
|
||||
|
||||
block:
|
||||
|
||||
# ============================================================
|
||||
# Test plugin auth initially setting a hash and then changing to a different hash.
|
||||
#
|
||||
|
||||
- name: Create user with plugin auth (with hash string)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
plugin_hash_string: '{{ test_plugin_hash }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
register: result
|
||||
|
||||
- name: Get user information
|
||||
command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
|
||||
register: show_create_user
|
||||
|
||||
- name: Check that the module made a change and that the expected plugin type is set
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
- "'{{ test_plugin_type }}' in show_create_user.stdout"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Get the MySQL version using the newly created creds
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ test_plugin_auth_string }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
- name: Update the user with a different hash
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
plugin_hash_string: '{{ test_plugin_new_hash }}'
|
||||
register: result
|
||||
|
||||
- name: Check that the module makes the change because the hash changed
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Getting the MySQL info with the new password should work
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ test_plugin_new_auth_string }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_new_auth_string }}
|
||||
|
||||
# ============================================================
|
||||
# Test plugin auth initially setting a hash and then switching to a plaintext auth string.
|
||||
#
|
||||
|
||||
- name: Create user with plugin auth (with hash string)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
plugin_hash_string: '{{ test_plugin_hash }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
register: result
|
||||
|
||||
- name: Get user information
|
||||
command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
|
||||
register: show_create_user
|
||||
|
||||
- name: Check that the module made a change and that the expected plugin type is set
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
- "'{{ test_plugin_type }}' in show_create_user.stdout"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Get the MySQL version using the newly created creds
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ test_plugin_auth_string }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
- name: Update the user with the same hash (no change expected)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
plugin_hash_string: '{{ test_plugin_hash }}'
|
||||
register: result
|
||||
|
||||
- name: Check that the module doesn't make a change when the same hash is passed in
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Change the user using the same plugin, but switch to the same auth string in plaintext form
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
plugin_auth_string: '{{ test_plugin_auth_string }}'
|
||||
register: result
|
||||
|
||||
# Expecting a change is currently by design (see comment in source).
|
||||
- name: Check that the module did not change the password
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- name: Getting the MySQL info should still work
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ test_plugin_auth_string }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_auth_string }}
|
||||
|
||||
# ============================================================
|
||||
# Test plugin auth initially setting a plaintext auth string and then switching to a hash.
|
||||
#
|
||||
|
||||
- name: Create user with plugin auth (with auth string)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
plugin_auth_string: '{{ test_plugin_auth_string }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
register: result
|
||||
|
||||
- name: Get user information
|
||||
command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
|
||||
register: show_create_user
|
||||
|
||||
- name: Check that the module made a change and that the expected plugin type is set
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
- "'{{ test_plugin_type }}' in show_create_user.stdout"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Get the MySQL version using the newly created creds
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ test_plugin_auth_string }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
- name: Update the user with the same auth string
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
plugin_auth_string: '{{ test_plugin_auth_string }}'
|
||||
register: result
|
||||
|
||||
# This is the current expected behavior because there isn't a reliable way to hash the password in the mysql_user
|
||||
# module in order to be able to compare this password with the stored hash. See the source for more info.
|
||||
- name: The module should detect a change even though the password is the same
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Change the user using the same plugin, but switch to the same auth string in hash form
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
plugin_hash_string: '{{ test_plugin_hash }}'
|
||||
register: result
|
||||
|
||||
- name: Check that the module did not change the password
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
- name: Get the MySQL version using the newly created creds
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: '{{ test_plugin_auth_string }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_auth_string }}
|
||||
|
||||
# ============================================================
|
||||
# Test plugin auth with an empty auth string.
|
||||
#
|
||||
|
||||
- name: Create user with plugin auth (empty auth string)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
register: result
|
||||
|
||||
- name: Get user information
|
||||
command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
|
||||
register: show_create_user
|
||||
|
||||
- name: Check that the module made a change and that the expected plugin type is set
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
- "'{{ test_plugin_type }}' in show_create_user.stdout"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Get the MySQL version using an empty password for the newly created user
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: ''
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Assert that mysql_info was successful
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == false"
|
||||
|
||||
- name: Get the MySQL version using an non-empty password (should fail)
|
||||
mysql_info:
|
||||
login_user: '{{ test_user_name }}'
|
||||
login_password: 'some_password'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
filter: version
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Assert that mysql_info failed
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == true"
|
||||
|
||||
- name: Update the user without changing the auth mechanism
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Assert that the user wasn't changed because the auth string is still empty
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_auth_string }}
|
||||
|
||||
# ============================================================
|
||||
# Test plugin auth switching from one type of plugin to another without an auth string or hash. The only other
|
||||
# plugins that are loaded by default are sha2*, but these aren't compatible with pymysql < 0.9, so skip these tests
|
||||
# for those versions.
|
||||
#
|
||||
- name: Get pymysql version
|
||||
shell: pip show pymysql | awk '/Version/ {print $2}'
|
||||
register: pymysql_version
|
||||
|
||||
- name: Test plugin auth switching which doesn't work on pymysql < 0.9
|
||||
when: pymysql_version.stdout == "" or (pymysql_version.stdout != "" and pymysql_version.stdout is version('0.9', '>='))
|
||||
block:
|
||||
|
||||
- name: Create user with plugin auth (empty auth string)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: '{{ test_plugin_type }}'
|
||||
priv: '{{ test_default_priv }}'
|
||||
register: result
|
||||
|
||||
- name: Get user information
|
||||
command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
|
||||
register: show_create_user
|
||||
|
||||
- name: Check that the module made a change and that the expected plugin type is set
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
- "'{{ test_plugin_type }}' in show_create_user.stdout"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
- name: Switch user to sha256_password auth plugin
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ test_user_name }}'
|
||||
plugin: sha256_password
|
||||
priv: '{{ test_default_priv }}'
|
||||
register: result
|
||||
|
||||
- name: Get user information
|
||||
command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
|
||||
register: show_create_user
|
||||
|
||||
- name: Check that the module made a change and that the expected plugin type is set
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
- "'sha256_password' in show_create_user.stdout"
|
||||
|
||||
- include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
|
||||
|
||||
# Cleanup
|
||||
- include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_auth_string }}
|
|
@ -1,178 +0,0 @@
|
|||
# test code update password for the mysql_user module
|
||||
# (c) 2014, Wayne Rosario <wrosario@ansible.com>
|
||||
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 dof the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
- 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:
|
||||
|
||||
# ============================================================
|
||||
# Update user password for a user.
|
||||
# Assert the user password is updated and old password can no longer be used.
|
||||
#
|
||||
- name: create user1 state=present with a password
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_1 }}'
|
||||
password: '{{ user_password_1 }}'
|
||||
priv: '*.*:ALL'
|
||||
state: present
|
||||
|
||||
- name: create user2 state=present with a password
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_2 }}'
|
||||
password: '{{ user_password_2 }}'
|
||||
priv: '*.*:ALL'
|
||||
state: present
|
||||
|
||||
- name: store user2 grants with old password (mysql 5.7.6 and newer)
|
||||
command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ user_name_2 }}'@'localhost'\""
|
||||
register: user_password_old_create
|
||||
ignore_errors: yes
|
||||
|
||||
- name: store user2 grants with old password (mysql 5.7.5 and older)
|
||||
command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_2 }}'@'localhost'\""
|
||||
register: user_password_old
|
||||
when: user_password_old_create is failed
|
||||
|
||||
- name: update user2 state=present with same password (expect changed=false)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_2 }}'
|
||||
password: '{{ user_password_2 }}'
|
||||
priv: '*.*:ALL'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert output user2 was not updated
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
- include: assert_user.yml user_name={{user_name_2}} priv='ALL PRIVILEGES'
|
||||
|
||||
- name: update user2 state=present with a new password (expect changed=true)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_2 }}'
|
||||
password: '{{ user_password_1 }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- include: assert_user.yml user_name={{user_name_2}} priv='ALL PRIVILEGES'
|
||||
|
||||
- name: store user2 grants with old password (mysql 5.7.6 and newer)
|
||||
command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ user_name_2 }}'@'localhost'\""
|
||||
register: user_password_new_create
|
||||
ignore_errors: yes
|
||||
|
||||
- name: store user2 grants with new password
|
||||
command: "{{ mysql_command }} -e SHOW GRANTS FOR '{{ user_name_2 }}'@'localhost'\""
|
||||
register: user_password_new
|
||||
when: user_password_new_create is failed
|
||||
|
||||
- name: assert output message password was update for user2 (mysql 5.7.6 and newer)
|
||||
assert:
|
||||
that:
|
||||
- "user_password_old_create.stdout != user_password_new_create.stdout"
|
||||
when: user_password_new_create is not failed
|
||||
|
||||
- name: assert output message password was update for user2 (mysql 5.7.5 and older)
|
||||
assert:
|
||||
that:
|
||||
- "user_password_old.stdout != user_password_new.stdout"
|
||||
when: user_password_new_create is failed
|
||||
|
||||
- name: create database using user2 and old password
|
||||
mysql_db:
|
||||
login_user: '{{ user_name_2 }}'
|
||||
login_password: '{{ user_password_2 }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
name: '{{ db_name }}'
|
||||
state: present
|
||||
ignore_errors: true
|
||||
register: result
|
||||
|
||||
- debug: var=result.msg
|
||||
- name: assert output message that database not create with old password
|
||||
assert:
|
||||
that:
|
||||
- "result.failed == true"
|
||||
|
||||
- name: create database using user2 and new password
|
||||
mysql_db:
|
||||
login_user: '{{ user_name_2 }}'
|
||||
login_password: '{{ user_password_1 }}'
|
||||
login_host: '{{ mysql_host }}'
|
||||
login_port: '{{ mysql_primary_port }}'
|
||||
name: '{{ db_name }}'
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert output message that database is created with new password
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- name: remove database
|
||||
mysql_db:
|
||||
<<: *mysql_params
|
||||
name: '{{ db_name }}'
|
||||
state: absent
|
||||
login_unix_socket: '{{ mysql_socket }}'
|
||||
|
||||
- include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
|
||||
|
||||
- include: remove_user.yml user_name={{user_name_2}} user_password={{ user_password_1 }}
|
||||
|
||||
- name: Create user with Fdt8fd^34ds using hash. (expect changed=true)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: jmainguy
|
||||
password: '*0cb5b86f23fdc24db19a29b8854eb860cbc47793'
|
||||
encrypted: yes
|
||||
register: encrypt_result
|
||||
|
||||
- name: Check that the module made a change
|
||||
assert:
|
||||
that:
|
||||
- "encrypt_result.changed == True"
|
||||
|
||||
- name: See if the password needs to be updated. (expect changed=false)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: jmainguy
|
||||
password: 'Fdt8fd^34ds'
|
||||
register: plain_result
|
||||
|
||||
- name: Check that the module did not change the password
|
||||
assert:
|
||||
that:
|
||||
- "plain_result.changed == False"
|
||||
|
||||
- name: Remove user (cleanup)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: jmainguy
|
||||
state: absent
|
0
tests/unit/plugins/module_utils/__init__.py
Normal file
0
tests/unit/plugins/module_utils/__init__.py
Normal file
24
tests/unit/plugins/module_utils/test_mysql.py
Normal file
24
tests/unit/plugins/module_utils/test_mysql.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version
|
||||
from ..utils import dummy_cursor_class
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'cursor_return_version,cursor_return_type',
|
||||
[
|
||||
('5.7.0-mysql', 'dict'),
|
||||
('8.0.0-mysql', 'list'),
|
||||
('10.5.0-mariadb', 'dict'),
|
||||
('10.5.1-mariadb', 'list'),
|
||||
]
|
||||
)
|
||||
def test_get_server_version(cursor_return_version, cursor_return_type):
|
||||
"""
|
||||
Test that server versions are handled properly by get_server_version() whether they're returned as a list or dict.
|
||||
"""
|
||||
cursor = dummy_cursor_class(cursor_return_version, cursor_return_type)
|
||||
assert get_server_version(cursor) == cursor_return_version
|
|
@ -7,22 +7,7 @@ __metaclass__ = type
|
|||
import pytest
|
||||
|
||||
from ansible_collections.community.mysql.plugins.modules.mysql_replication import uses_replica_terminology
|
||||
|
||||
|
||||
class dummy_cursor_class():
|
||||
def __init__(self, output, ret_val_type='dict'):
|
||||
self.output = output
|
||||
self.ret_val_type = ret_val_type
|
||||
|
||||
def execute(self, query):
|
||||
pass
|
||||
|
||||
def fetchone(self):
|
||||
if self.ret_val_type == 'dict':
|
||||
return {'version': self.output}
|
||||
|
||||
elif self.ret_val_type == 'list':
|
||||
return [self.output]
|
||||
from ..utils import dummy_cursor_class
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
33
tests/unit/plugins/modules/test_mysql_user.py
Normal file
33
tests/unit/plugins/modules/test_mysql_user.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.mysql.plugins.modules.mysql_user import supports_identified_by_password
|
||||
from ..utils import dummy_cursor_class
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'function_return,cursor_output,cursor_ret_type',
|
||||
[
|
||||
(True, '5.5.1-mysql', 'list'),
|
||||
(True, '5.7.0-mysql', 'dict'),
|
||||
(True, '10.5.0-mariadb', 'dict'),
|
||||
(True, '10.5.1-mariadb', 'dict'),
|
||||
(True, '10.6.0-mariadb', 'dict'),
|
||||
(True, '11.5.1-mariadb', 'dict'),
|
||||
(False, '8.0.22-mysql', 'list'),
|
||||
(False, '8.1.2-mysql', 'dict'),
|
||||
(False, '9.0.0-mysql', 'list'),
|
||||
(False, '8.0.0-mysql', 'list'),
|
||||
(False, '8.0.11-mysql', 'dict'),
|
||||
(False, '8.0.21-mysql', 'list'),
|
||||
]
|
||||
)
|
||||
def test_supports_identified_by_password(function_return, cursor_output, cursor_ret_type):
|
||||
"""
|
||||
Tests whether 'CREATE USER %s@%s IDENTIFIED BY PASSWORD %s' is supported, which is currently supported by everything
|
||||
besides MySQL >= 8.0.
|
||||
"""
|
||||
cursor = dummy_cursor_class(cursor_output, cursor_ret_type)
|
||||
assert supports_identified_by_password(cursor) == function_return
|
19
tests/unit/plugins/utils.py
Normal file
19
tests/unit/plugins/utils.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class dummy_cursor_class():
|
||||
"""Dummy class for returning an answer for SELECT VERSION()."""
|
||||
def __init__(self, output, ret_val_type='dict'):
|
||||
self.output = output
|
||||
self.ret_val_type = ret_val_type
|
||||
|
||||
def execute(self, query):
|
||||
pass
|
||||
|
||||
def fetchone(self):
|
||||
if self.ret_val_type == 'dict':
|
||||
return {'version': self.output}
|
||||
|
||||
elif self.ret_val_type == 'list':
|
||||
return [self.output]
|
Loading…
Add table
Reference in a new issue