diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/mysql_user | 39 |
1 files changed, 32 insertions, 7 deletions
diff --git a/lib/mysql_user b/lib/mysql_user index 9758939..602235a 100644 --- a/lib/mysql_user +++ b/lib/mysql_user @@ -134,51 +134,74 @@ password=n<_665{vS43y import ConfigParser import getpass import tempfile try: import MySQLdb except ImportError: mysqldb_found = False else: mysqldb_found = True # =========================================== # MySQL module specific support methods. # def user_exists(cursor, user, host): cursor.execute("SELECT count(*) FROM user WHERE user = %s AND host = %s", (user,host)) count = cursor.fetchone() return count[0] > 0 -def user_add(cursor, user, host, password, new_priv): - cursor.execute("CREATE USER %s@%s IDENTIFIED BY %s", (user,host,password)) +def load_plugin(cursor, plugin): + cursor.execute("SELECT count(*) FROM plugin WHERE name = %s", plugin) + count = cursor.fetchone() + if count[0] == 0: + so = "%s.so" % plugin + cursor.execute("INSTALL PLUGIN %s SONAME %s", (plugin, so)) + +def user_add(cursor, user, host, password, new_priv, auth_plugin): + if password is None: + # Automatically loaded on first first use. + load_plugin(cursor, auth_plugin) + cursor.execute("CREATE USER %s@%s IDENTIFIED WITH %s", (user,host,auth_plugin)) + else: + cursor.execute("CREATE USER %s@%s IDENTIFIED BY %s", (user,host,password)) if new_priv is not None: for db_table, priv in new_priv.iteritems(): privileges_grant(cursor, user,host,db_table,priv) return True -def user_mod(cursor, user, host, password, new_priv, append_privs): +def user_mod(cursor, user, host, password, new_priv, append_privs, auth_plugin): changed = False grant_option = False + # Handle plugin. + if auth_plugin is not None: + cursor.execute("SELECT plugin FROM user WHERE user = %s AND host = %s", (user,host)) + if cursor.fetchone()[0] != auth_plugin: + # Sadly there is no proper way to updade the authentication plugin: + # http://bugs.mysql.com/bug.php?id=67449 + cursor.execute( "UPDATE user SET plugin = %s, password = '' WHERE user = %s AND host = %s" + , (auth_plugin,user,host)) + cursor.execute("FLUSH PRIVILEGES") + changed = True + # Handle passwords. if password is not None: cursor.execute("SELECT password FROM user WHERE user = %s AND host = %s", (user,host)) current_pass_hash = cursor.fetchone() cursor.execute("SELECT PASSWORD(%s)", (password,)) new_pass_hash = cursor.fetchone() if current_pass_hash[0] != new_pass_hash[0]: cursor.execute("SET PASSWORD FOR %s@%s = PASSWORD(%s)", (user,host,password)) changed = True # Handle privileges. if new_priv is not None: curr_priv = privileges_get(cursor, user,host) # If the user has privileges on a db.table that doesn't appear at all in # the new specification, then revoke all privileges on it. for db_table, priv in curr_priv.iteritems(): # If the user has the GRANT OPTION on a db.table, revoke it first. if "GRANT" in priv: grant_option = True @@ -382,49 +405,51 @@ def connect(module, login_user, login_password): # =========================================== # Module execution. # def main(): module = AnsibleModule( argument_spec = dict( login_user=dict(default=None), login_password=dict(default=None), login_host=dict(default="localhost"), login_port=dict(default="3306"), login_unix_socket=dict(default=None), user=dict(required=True, aliases=['name']), password=dict(default=None), host=dict(default="localhost"), state=dict(default="present", choices=["absent", "present"]), priv=dict(default=None), append_privs=dict(type="bool", default="no"), check_implicit_admin=dict(default=False), + auth_plugin=dict(default=None) ) ) user = module.params["user"] password = module.params["password"] host = module.params["host"] state = module.params["state"] priv = module.params["priv"] check_implicit_admin = module.params['check_implicit_admin'] append_privs = module.boolean(module.params["append_privs"]) + auth_plugin = module.params['auth_plugin'] if not mysqldb_found: module.fail_json(msg="the python mysqldb module is required") if priv is not None: try: priv = privileges_unpack(priv) except: module.fail_json(msg="invalid privileges string") # Either the caller passes both a username and password with which to connect to # mysql, or they pass neither and allow this module to read the credentials from # ~/.my.cnf. login_password = module.params["login_password"] login_user = module.params["login_user"] if login_user is None and login_password is None: mycnf_creds = load_mycnf() if mycnf_creds is False: login_user = "root" login_password = "" @@ -432,35 +457,35 @@ def main(): login_user = mycnf_creds["user"] login_password = mycnf_creds["passwd"] elif login_password is None or login_user is None: module.fail_json(msg="when supplying login arguments, both login_user and login_password must be provided") cursor = None try: if check_implicit_admin: try: cursor = connect(module, 'root', '') except: pass if not cursor: cursor = connect(module, login_user, login_password) except Exception, e: module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials") if state == "present": if user_exists(cursor, user, host): - changed = user_mod(cursor, user, host, password, priv, append_privs) + changed = user_mod(cursor, user, host, password, priv, append_privs, auth_plugin) else: - if password is None: - module.fail_json(msg="password parameter required when adding a user") - changed = user_add(cursor, user, host, password, priv) + if (password is None and auth_plugin is None) or (password is not None and auth_plugin is not None): + module.fail_json(msg="password xor auth_plugin is required when adding a user") + changed = user_add(cursor, user, host, password, priv, auth_plugin) elif state == "absent": if user_exists(cursor, user, host): changed = user_delete(cursor, user, host) else: changed = False module.exit_json(changed=changed, user=user) # this is magic, see lib/ansible/module_common.py #<<INCLUDE_ANSIBLE_MODULE_COMMON>> main() |