User locking (#702)

* function to check if a user is locked already

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Add the location and logic of where I think user locking would happen.

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Fix missing parameters for execute()

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Add the locked attribute

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Initial user locking integration tests

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Add attribute documentation

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* More descriptive names in the integration tests

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* - Changes requested/suggested by @Andersson007
- Example usage
- Changelog fragment

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Fix user_is_locked and remove host_all option.

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Fix host of user (was % should have been localhost after deleting `host:` earlier)

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Switch locked to named instead of positional.

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Add check_mode support.

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Add check_mode: true test cases

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Fix names that included `check_mode: true`

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Add idempotence checks

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Switch calls to user_mod with sequences of None positional arguments to full named arguments

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* locked check should not run for roles.

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* check_mode is set at the task level and not the module level

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Add user locking to info module and test.

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Handle DictCursor

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>


* Add check_mode feedback

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>


* Add another builtin account to the exclusion list

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Initial switch to default=None for locked, will need to add a test for it.

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>

* Add check that missing locked argument does not unlock a user

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>
---------

Signed-off-by: E.S. Rosenberg a.k.a. Keeper of the Keys <es.rosenberg+github@gmail.com>
This commit is contained in:
Keeper-of-the-Keys 2025-03-19 15:40:59 +02:00 committed by GitHub
parent dd7e297d50
commit 45a29408ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 285 additions and 14 deletions

View file

@ -189,6 +189,15 @@ options:
fields names in privileges.
type: bool
version_added: '3.8.0'
locked:
description:
- Lock account to prevent connections using it.
- This is primarily used for creating a user that will act as a DEFINER on stored procedures.
- If not specified leaves the lock state as is (for a new user creates unlocked).
type: bool
version_added: '3.13.0'
attributes:
description:
- "Create, update, or delete user attributes (arbitrary 'key: value' comments) for the user."
@ -225,6 +234,7 @@ author:
- Lukasz Tomaszkiewicz (@tomaszkiewicz)
- kmarse (@kmarse)
- Laurent Indermühle (@laurent-indermuehle)
- E.S. Rosenberg (@Keeper-of-the-Keys)
extends_documentation_fragment:
- community.mysql.mysql
@ -400,6 +410,13 @@ EXAMPLES = r'''
priv:
'db1.*': DELETE
- name: Create locked user to act as a definer on procedures
community.mysql.mysql_user:
name: readonly_procedures_locked
locked: true
priv:
db1.*: SELECT
# Example .my.cnf file for setting the root password
# [client]
# user=root
@ -470,6 +487,7 @@ def main():
column_case_sensitive=dict(type='bool', default=None), # TODO 4.0.0 add default=True
password_expire=dict(type='str', choices=['now', 'never', 'default', 'interval'], no_log=True),
password_expire_interval=dict(type='int', required_if=[('password_expire', 'interval', True)], no_log=True),
locked=dict(type='bool'),
)
module = AnsibleModule(
argument_spec=argument_spec,
@ -510,6 +528,7 @@ def main():
column_case_sensitive = module.params["column_case_sensitive"]
password_expire = module.params["password_expire"]
password_expire_interval = module.params["password_expire_interval"]
locked = module.boolean(module.params['locked'])
if priv and not isinstance(priv, (str, dict)):
module.fail_json(msg="priv parameter must be str or dict but %s was passed" % type(priv))
@ -577,13 +596,15 @@ def main():
result = user_mod(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string, salt,
priv, append_privs, subtract_privs, attributes, tls_requires, module,
password_expire, password_expire_interval)
password_expire, password_expire_interval, locked=locked)
else:
result = user_mod(cursor, user, host, host_all, None, encrypted,
None, None, None, None,
priv, append_privs, subtract_privs, attributes, tls_requires, module,
password_expire, password_expire_interval)
result = user_mod(cursor=cursor, user=user, host=host, host_all=host_all, password=None,
encrypted=encrypted, plugin=None, plugin_hash_string=None, plugin_auth_string=None,
salt=None, new_priv=priv, append_privs=append_privs, subtract_privs=subtract_privs,
attributes=attributes, tls_requires=tls_requires, module=module,
password_expire=password_expire, password_expire_interval=password_expire_interval,
locked=locked)
changed = result['changed']
msg = result['msg']
password_changed = result['password_changed']
@ -601,7 +622,7 @@ def main():
result = user_add(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string, salt,
priv, attributes, tls_requires, reuse_existing_password, module,
password_expire, password_expire_interval)
password_expire, password_expire_interval, locked=locked)
changed = result['changed']
password_changed = result['password_changed']
final_attributes = result['attributes']