mirror of
https://github.com/ansible-collections/community.mysql.git
synced 2025-04-08 19:50:31 -07:00
initial commit for password_expire support
This commit is contained in:
parent
8dfab12bae
commit
314ec02955
4 changed files with 123 additions and 6 deletions
|
@ -23,3 +23,9 @@ def server_supports_alter_user(cursor):
|
||||||
version = get_server_version(cursor)
|
version = get_server_version(cursor)
|
||||||
|
|
||||||
return LooseVersion(version) >= LooseVersion("10.2")
|
return LooseVersion(version) >= LooseVersion("10.2")
|
||||||
|
|
||||||
|
|
||||||
|
def server_supports_password_expire(cursor):
|
||||||
|
version = get_server_version(cursor)
|
||||||
|
|
||||||
|
return LooseVersion(version) >= LooseVersion("10.4.3")
|
||||||
|
|
|
@ -24,3 +24,9 @@ def server_supports_alter_user(cursor):
|
||||||
version = get_server_version(cursor)
|
version = get_server_version(cursor)
|
||||||
|
|
||||||
return LooseVersion(version) >= LooseVersion("5.6")
|
return LooseVersion(version) >= LooseVersion("5.6")
|
||||||
|
|
||||||
|
|
||||||
|
def server_supports_password_expire(cursor):
|
||||||
|
version = get_server_version(cursor)
|
||||||
|
|
||||||
|
return LooseVersion(version) >= LooseVersion("5.7")
|
||||||
|
|
|
@ -151,12 +151,13 @@ def get_existing_authentication(cursor, user, host):
|
||||||
|
|
||||||
def user_add(cursor, user, host, host_all, password, encrypted,
|
def user_add(cursor, user, host, host_all, password, encrypted,
|
||||||
plugin, plugin_hash_string, plugin_auth_string, new_priv,
|
plugin, plugin_hash_string, plugin_auth_string, new_priv,
|
||||||
tls_requires, check_mode, reuse_existing_password):
|
tls_requires, module, reuse_existing_password,
|
||||||
|
password_expire, password_expire_interval):
|
||||||
# we cannot create users without a proper hostname
|
# we cannot create users without a proper hostname
|
||||||
if host_all:
|
if host_all:
|
||||||
return {'changed': False, 'password_changed': False}
|
return {'changed': False, 'password_changed': False}
|
||||||
|
|
||||||
if check_mode:
|
if module.check_mode:
|
||||||
return {'changed': True, 'password_changed': None}
|
return {'changed': True, 'password_changed': None}
|
||||||
|
|
||||||
# Determine what user management method server uses
|
# Determine what user management method server uses
|
||||||
|
@ -200,6 +201,12 @@ def user_add(cursor, user, host, host_all, password, encrypted,
|
||||||
query_with_args_and_tls_requires = query_with_args + (tls_requires,)
|
query_with_args_and_tls_requires = query_with_args + (tls_requires,)
|
||||||
cursor.execute(*mogrify(*query_with_args_and_tls_requires))
|
cursor.execute(*mogrify(*query_with_args_and_tls_requires))
|
||||||
|
|
||||||
|
if password_expire and impl.supports_identified_by_password(cursor):
|
||||||
|
set_password_expire(cursor, user, host, password_expire, password_expire_interval)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="The server version does not match the requirements "
|
||||||
|
"for password_expire parameter. See module's documentation.")
|
||||||
|
|
||||||
if new_priv is not None:
|
if new_priv is not None:
|
||||||
for db_table, priv in iteritems(new_priv):
|
for db_table, priv in iteritems(new_priv):
|
||||||
privileges_grant(cursor, user, host, db_table, priv, tls_requires)
|
privileges_grant(cursor, user, host, db_table, priv, tls_requires)
|
||||||
|
@ -218,7 +225,8 @@ def is_hash(password):
|
||||||
|
|
||||||
def user_mod(cursor, user, host, host_all, password, encrypted,
|
def user_mod(cursor, user, host, host_all, password, encrypted,
|
||||||
plugin, plugin_hash_string, plugin_auth_string, new_priv,
|
plugin, plugin_hash_string, plugin_auth_string, new_priv,
|
||||||
append_privs, subtract_privs, tls_requires, module, role=False, maria_role=False):
|
append_privs, subtract_privs, tls_requires, module,
|
||||||
|
password_expire, password_expire_interval, role=False, maria_role=False):
|
||||||
changed = False
|
changed = False
|
||||||
msg = "User unchanged"
|
msg = "User unchanged"
|
||||||
grant_option = False
|
grant_option = False
|
||||||
|
@ -301,6 +309,27 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
|
||||||
raise e
|
raise e
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
|
# Handle password expiration
|
||||||
|
if bool(password_expire):
|
||||||
|
if impl.server_supports_password_expire(cursor):
|
||||||
|
update = False
|
||||||
|
mariadb_role = True if "mariadb" in str(impl.__name__) else False
|
||||||
|
current_password_policy = get_password_expiration_policy(cursor, user, host, maria_role=mariadb_role)
|
||||||
|
if not (current_password_policy == -1 and password_expire == "default" or
|
||||||
|
current_password_policy == 0 and password_expire == "never" or
|
||||||
|
current_password_policy == password_expire_interval):
|
||||||
|
|
||||||
|
update = True
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return {'changed': True, 'msg': msg, 'password_changed': password_changed}
|
||||||
|
set_password_expire(cursor, user, host, password_expire, password_expire_interval)
|
||||||
|
password_changed = True
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="The server version does not match the requirements "
|
||||||
|
"for password_expire parameter. See module's documentation.")
|
||||||
|
|
||||||
# Handle plugin authentication
|
# Handle plugin authentication
|
||||||
if plugin and not role:
|
if plugin and not role:
|
||||||
cursor.execute("SELECT plugin, authentication_string FROM mysql.user "
|
cursor.execute("SELECT plugin, authentication_string FROM mysql.user "
|
||||||
|
@ -924,6 +953,57 @@ def limit_resources(module, cursor, user, host, resource_limits, check_mode):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def set_password_expire(cursor, user, host, password_expire, password_expire_interval):
|
||||||
|
"""Fuction to set passowrd expiration for user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cursor (cursor): DB driver cursor object.
|
||||||
|
user (str): User name.
|
||||||
|
host (str): User hostname.
|
||||||
|
password_expire (str): Password expiration mode.
|
||||||
|
password_expire_days (int): Invterval of days password expires.
|
||||||
|
"""
|
||||||
|
if password_expire.lower() == "never":
|
||||||
|
statment = "PASSWORD EXPIRE NEVER"
|
||||||
|
elif password_expire.lower() == "default":
|
||||||
|
statment = "PASSWORD EXPIRE DEFAULT"
|
||||||
|
elif password_expire.lower() == "interval":
|
||||||
|
if password_expire_interval > 0:
|
||||||
|
statment = "PASSWORD EXPIRE INTERVAL %d DAY" % (password_expire_interval)
|
||||||
|
else:
|
||||||
|
# expire password now if days <=0
|
||||||
|
if isinstance(password_expire_interval, int):
|
||||||
|
statment = "PASSWORD EXPIRE"
|
||||||
|
query = "ALTER USER %s@%s %s" % (user, host, statment)
|
||||||
|
cursor.execute(query)
|
||||||
|
|
||||||
|
|
||||||
|
def get_password_expiration_policy(cursor, user, host, maria_role=False):
|
||||||
|
"""Function to get password policy for user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cursor (cursor): DB driver cursor object.
|
||||||
|
user (str): User name.
|
||||||
|
host (str): User hostname.
|
||||||
|
maria_role (bool, optional): mariadb or mysql. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
policy (int): Current users password policy.
|
||||||
|
"""
|
||||||
|
if not maria_role:
|
||||||
|
statment = "SELECT password_lifetime FROM mysql.user \
|
||||||
|
WHERE User = %s AND Host = %s", (user, host)
|
||||||
|
else:
|
||||||
|
statment = "SELECT JSON_EXTRACT(Priv, '$.password_lifetime') AS password_lifetime \
|
||||||
|
FROM mysql.global_priv \
|
||||||
|
WHERE User = %s AND Host = %s", (user, host)
|
||||||
|
cursor.execute(*statment)
|
||||||
|
policy = cursor.fetchone()[0]
|
||||||
|
if not policy:
|
||||||
|
policy = -1
|
||||||
|
return int(policy)
|
||||||
|
|
||||||
|
|
||||||
def get_impl(cursor):
|
def get_impl(cursor):
|
||||||
global impl
|
global impl
|
||||||
cursor.execute("SELECT VERSION()")
|
cursor.execute("SELECT VERSION()")
|
||||||
|
|
|
@ -155,6 +155,20 @@ options:
|
||||||
- Cannot be used to set global variables, use the M(community.mysql.mysql_variables) module instead.
|
- Cannot be used to set global variables, use the M(community.mysql.mysql_variables) module instead.
|
||||||
type: dict
|
type: dict
|
||||||
version_added: '3.6.0'
|
version_added: '3.6.0'
|
||||||
|
password_expire:
|
||||||
|
description:
|
||||||
|
- C(never) password will never expire.
|
||||||
|
- C(default) password is defined ussing global system varaiable I(default_password_lifetime) setting.
|
||||||
|
- C(interval) password will expire in days which is defined in I(password_expire_interval)
|
||||||
|
type: str
|
||||||
|
choices: [ never, default, interval ]
|
||||||
|
default: never
|
||||||
|
password_expire_interval:
|
||||||
|
description:
|
||||||
|
- number of days password will expire. Used with I(password_expire)
|
||||||
|
- if C(password_expire_interval <= 0) password will expire immediately.
|
||||||
|
type: int
|
||||||
|
default: None
|
||||||
|
|
||||||
column_case_sensitive:
|
column_case_sensitive:
|
||||||
description:
|
description:
|
||||||
|
@ -415,6 +429,8 @@ def main():
|
||||||
force_context=dict(type='bool', default=False),
|
force_context=dict(type='bool', default=False),
|
||||||
session_vars=dict(type='dict'),
|
session_vars=dict(type='dict'),
|
||||||
column_case_sensitive=dict(type='bool', default=None), # TODO 4.0.0 add default=True
|
column_case_sensitive=dict(type='bool', default=None), # TODO 4.0.0 add default=True
|
||||||
|
password_expire=dict(type='str', choices=['never', 'default', 'interval'], default=None, no_log=True),
|
||||||
|
password_expire_interval=dict(type='int', default=None, no_log=True),
|
||||||
)
|
)
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec=argument_spec,
|
argument_spec=argument_spec,
|
||||||
|
@ -451,6 +467,8 @@ def main():
|
||||||
resource_limits = module.params["resource_limits"]
|
resource_limits = module.params["resource_limits"]
|
||||||
session_vars = module.params["session_vars"]
|
session_vars = module.params["session_vars"]
|
||||||
column_case_sensitive = module.params["column_case_sensitive"]
|
column_case_sensitive = module.params["column_case_sensitive"]
|
||||||
|
password_expire = module.params["password_expire"]
|
||||||
|
password_expire_interval = module.params["password_expire_interval"]
|
||||||
|
|
||||||
if priv and not isinstance(priv, (str, dict)):
|
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))
|
module.fail_json(msg="priv parameter must be str or dict but %s was passed" % type(priv))
|
||||||
|
@ -461,6 +479,10 @@ def main():
|
||||||
if mysql_driver is None:
|
if mysql_driver is None:
|
||||||
module.fail_json(msg=mysql_driver_fail_msg)
|
module.fail_json(msg=mysql_driver_fail_msg)
|
||||||
|
|
||||||
|
if password_expire == "interval" and not password_expire_interval:
|
||||||
|
module.fail_json(msg="password_expire value interval \
|
||||||
|
should be used with password_expire_interval")
|
||||||
|
|
||||||
cursor = None
|
cursor = None
|
||||||
try:
|
try:
|
||||||
if check_implicit_admin:
|
if check_implicit_admin:
|
||||||
|
@ -506,12 +528,14 @@ def main():
|
||||||
if update_password == "always":
|
if update_password == "always":
|
||||||
result = user_mod(cursor, user, host, host_all, password, encrypted,
|
result = user_mod(cursor, user, host, host_all, password, encrypted,
|
||||||
plugin, plugin_hash_string, plugin_auth_string,
|
plugin, plugin_hash_string, plugin_auth_string,
|
||||||
priv, append_privs, subtract_privs, tls_requires, module)
|
priv, append_privs, subtract_privs, tls_requires, module,
|
||||||
|
password_expire, password_expire_interval)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
result = user_mod(cursor, user, host, host_all, None, encrypted,
|
result = user_mod(cursor, user, host, host_all, None, encrypted,
|
||||||
None, None, None,
|
None, None, None,
|
||||||
priv, append_privs, subtract_privs, tls_requires, module)
|
priv, append_privs, subtract_privs, tls_requires, module,
|
||||||
|
password_expire, password_expire_interval)
|
||||||
changed = result['changed']
|
changed = result['changed']
|
||||||
msg = result['msg']
|
msg = result['msg']
|
||||||
password_changed = result['password_changed']
|
password_changed = result['password_changed']
|
||||||
|
@ -527,7 +551,8 @@ def main():
|
||||||
reuse_existing_password = update_password == 'on_new_username'
|
reuse_existing_password = update_password == 'on_new_username'
|
||||||
result = user_add(cursor, user, host, host_all, password, encrypted,
|
result = user_add(cursor, user, host, host_all, password, encrypted,
|
||||||
plugin, plugin_hash_string, plugin_auth_string,
|
plugin, plugin_hash_string, plugin_auth_string,
|
||||||
priv, tls_requires, module.check_mode, reuse_existing_password)
|
priv, tls_requires, module, reuse_existing_password,
|
||||||
|
password_expire, password_expire_interval)
|
||||||
changed = result['changed']
|
changed = result['changed']
|
||||||
password_changed = result['password_changed']
|
password_changed = result['password_changed']
|
||||||
if changed:
|
if changed:
|
||||||
|
|
Loading…
Add table
Reference in a new issue