diff --git a/mysqlsh_plugins_common.py b/mysqlsh_plugins_common.py index 7ca1ac6..3f55ba8 100644 --- a/mysqlsh_plugins_common.py +++ b/mysqlsh_plugins_common.py @@ -59,6 +59,11 @@ def are_instruments_enabled(instrument_name, session, shell): return ok +def get_distro(session): + result = session.run_sql("SELECT @@version_comment") + col = result.fetch_one() + return col[0] + def get_version(session): result = session.run_sql("SELECT @@version") col = result.fetch_one() diff --git a/user/clone.py b/user/clone.py index 5048d93..494f2e6 100644 --- a/user/clone.py +++ b/user/clone.py @@ -1,16 +1,21 @@ from mysqlsh.plugin_manager import plugin, plugin_function from mysqlsh_plugins_common import get_major_version +from mysqlsh_plugins_common import get_distro from user import mds import re def _get_server_info(session): - return session.run_sql("""SELECT CONCAT(@@hostname," (",@@version,")")""").fetch_one()[0] + return session.run_sql( + """SELECT CONCAT(@@hostname," (",@@version,")")""" + ).fetch_one()[0] @plugin_function("user.clone") -def copy_users_grants(userfrom=None, userto=None, dryrun=False, ocimds=False, force=False, session=None): +def copy_users_grants( + userfrom=None, userto=None, dryrun=False, ocimds=False, force=False, session=None +): """ Clone a user to the same server @@ -26,17 +31,22 @@ def copy_users_grants(userfrom=None, userto=None, dryrun=False, ocimds=False, fo """ # Get hold of the global shell object import mysqlsh + shell = mysqlsh.globals.shell old_format = None if session is None: session = shell.get_session() if session is None: - print("No session specified. Either pass a session object to this " - "function or connect the shell to a database") + print( + "No session specified. Either pass a session object to this " + "function or connect the shell to a database" + ) return if not userfrom: - search_string = shell.prompt("Enter the user to search (you can use wildcards '%', leave blank for all): ") + search_string = shell.prompt( + "Enter the user to search (you can use wildcards '%', leave blank for all): " + ) if len(search_string.strip()) > 0: search_string = 'AND user LIKE "{}"'.format(search_string) else: @@ -46,7 +56,11 @@ def copy_users_grants(userfrom=None, userto=None, dryrun=False, ocimds=False, fo print("Info: locked users and users having expired password are not listed.") mysql_version = get_major_version(session) - mysql_major_int = int(mysql_version.split('.')[0]) + mysql_major_int = int(mysql_version.split(".")[0]) + mysql_distro = get_distro(session) + if mysql_distro.lower().startswith("maria"): + print("-- MariaDB Detected and not supported") + return if mysql_major_int >= 8 or mysql_version == "5.7": # Get the list of users stmt = """SELECT DISTINCT User, Host, @@ -54,7 +68,9 @@ def copy_users_grants(userfrom=None, userto=None, dryrun=False, ocimds=False, fo FROM mysql.user WHERE NOT( `account_locked`="Y" AND `password_expired`="Y" AND `authentication_string`="" ) {} ORDER BY User, Host; - """.format(search_string) + """.format( + search_string + ) else: stmt = """SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user' AND COLUMN_NAME='password';""" @@ -65,86 +81,115 @@ def copy_users_grants(userfrom=None, userto=None, dryrun=False, ocimds=False, fo FROM mysql.user WHERE NOT(`password_expired`="Y" AND `authentication_string`="" ) {} ORDER BY User, Host; - """.format(search_string) + """.format( + search_string + ) else: stmt = """SELECT DISTINCT User, Host, IF(authentication_string = "","NO", "YES") HAS_PWD FROM mysql.user WHERE NOT(`password_expired`="Y" AND `authentication_string`="" ) {} ORDER BY User, Host; - """.format(search_string) - users = session.run_sql(stmt).fetch_all() + """.format( + search_string + ) + users = session.run_sql(stmt).fetch_all() final_s = "" - if len(users)>1: + if len(users) > 1: final_s = "s" print("{} user{} found!".format(len(users), final_s)) for user in users: if ocimds and user[2] == "NO": - print("[`{}`@`{}`] is not compatible with OCI MDS as it has not password, ignoring it...".format(user[0], user[1])) + print( + "[`{}`@`{}`] is not compatible with OCI MDS as it has not password, ignoring it...".format( + user[0], user[1] + ) + ) continue if not force: - answer = shell.prompt("Do you want to clone [`{}`@`{}`] ? (y/N) ".format(user[0], user[1]), {'defaultValue': 'n'}) + answer = shell.prompt( + "Do you want to clone [`{}`@`{}`] ? (y/N) ".format(user[0], user[1]), + {"defaultValue": "n"}, + ) else: answer = "y" - if answer.lower() == 'y': + if answer.lower() == "y": if mysql_major_int >= 8: stmt = """SELECT from_user, from_host FROM mysql.role_edges WHERE to_user = ? and to_host = ?""" roles = session.run_sql(stmt, [user[0], user[1]]).fetch_all() - if len(roles)>0: + if len(roles) > 0: for role in roles: - stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(role[0], role[1]) - grants = session.run_sql(stmt).fetch_all() - for grant in grants: - if ocimds: - grant_stmt = grant[0] - on_stmt=re.sub(r"^.*( ON .*\..* TO .*$)",r"\1", grant_stmt) - grant_stmt_tmp = re.sub('^GRANT ','', grant_stmt) - grant_stmt_tmp = re.sub(' ON .*\..* TO .*$','', grant_stmt_tmp) - tab_grants = grant_stmt_tmp.split(', ') - tab_list = [] - for priv in tab_grants: - for allowed_priv in mds.mds_allowed_privileges: - if allowed_priv == priv: - tab_list.append(allowed_priv) - break - if len(tab_list)>0: - grant_stmt="GRANT " + ', '.join(tab_list) + on_stmt - else: - grant_stmt=None - + stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(role[0], role[1]) + grants = session.run_sql(stmt).fetch_all() + for grant in grants: + if ocimds: + grant_stmt = grant[0] + on_stmt = re.sub( + r"^.*( ON .*\..* TO .*$)", r"\1", grant_stmt + ) + grant_stmt_tmp = re.sub("^GRANT ", "", grant_stmt) + grant_stmt_tmp = re.sub( + " ON .*\..* TO .*$", "", grant_stmt_tmp + ) + tab_grants = grant_stmt_tmp.split(", ") + tab_list = [] + for priv in tab_grants: + for allowed_priv in mds.mds_allowed_privileges: + if allowed_priv == priv: + tab_list.append(allowed_priv) + break + if len(tab_list) > 0: + grant_stmt = ( + "GRANT " + ", ".join(tab_list) + on_stmt + ) else: - grant_stmt = grant[0] - if grant_stmt: - grant_stmt = grant_stmt.replace("TO `{}`@`{}`".format(user[0], user[1]), "TO {}".format(userto)) - if dryrun: - print("{};".format(grant_stmt)) - else: - try: - session.run_sql(grant_stmt) - except mysqlsh.DBError as err: - print("Aborting: {}".format(err)) - return + grant_stmt = None + else: + grant_stmt = grant[0] + if grant_stmt: + grant_stmt = grant_stmt.replace( + "TO `{}`@`{}`".format(user[0], user[1]), + "TO {}".format(userto), + ) + if dryrun: + print("{};".format(grant_stmt)) + else: + try: + session.run_sql(grant_stmt) + except mysqlsh.DBError as err: + print("Aborting: {}".format(err)) + return if mysql_major_int < 8 and mysql_version != "5.7": - stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) - create_user = session.run_sql(stmt).fetch_one()[0] + ";" - create_user=create_user.replace(" TO '{}'@'{}'".format(user[0], user[1]),"CREATE USER {}".format(userto)) - create_user = re.sub(r".*CREATE USER ","CREATE USER ", create_user) + stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) + create_user = session.run_sql(stmt).fetch_one()[0] + ";" + create_user = create_user.replace( + " TO '{}'@'{}'".format(user[0], user[1]), + "CREATE USER {}".format(userto), + ) + create_user = re.sub(r".*CREATE USER ", "CREATE USER ", create_user) else: - stmt = """SHOW CREATE USER `{}`@`{}`""".format(user[0], user[1]) - create_user = session.run_sql(stmt).fetch_one()[0] + ";" - #print("-- DEBUG: {}".format(create_user)) - create_user=create_user.replace("CREATE USER `{}`@`{}`".format(user[0], user[1]),"CREATE USER IF NOT EXISTS {}".format(userto)) - #print("-- DEBUG: {}".format(create_user)) - # we need to find the password in binary format - stmt = """SELECT authentication_string, convert(authentication_string using binary) authbin - FROM mysql.user where user='{}' and host='{}'""".format(user[0], user[1]) - auth_user = session.run_sql(stmt).fetch_one() - auth_string = auth_user[0] - auth_string_bin = auth_user[1] - hex_string = auth_string_bin.hex() - create_user = re.sub(r" AS '(.*)' ", r" AS 0x{} ".format(hex_string), create_user) + stmt = """SHOW CREATE USER `{}`@`{}`""".format(user[0], user[1]) + create_user = session.run_sql(stmt).fetch_one()[0] + ";" + # print("-- DEBUG: {}".format(create_user)) + create_user = create_user.replace( + "CREATE USER `{}`@`{}`".format(user[0], user[1]), + "CREATE USER IF NOT EXISTS {}".format(userto), + ) + # print("-- DEBUG: {}".format(create_user)) + # we need to find the password in binary format + stmt = """SELECT authentication_string, convert(authentication_string using binary) authbin + FROM mysql.user where user='{}' and host='{}'""".format( + user[0], user[1] + ) + auth_user = session.run_sql(stmt).fetch_one() + auth_string = auth_user[0] + auth_string_bin = auth_user[1] + hex_string = auth_string_bin.hex() + create_user = re.sub( + r" AS '(.*)' ", r" AS 0x{} ".format(hex_string), create_user + ) if dryrun: print("-- User `{}`@`{}`".format(user[0], user[1])) print(create_user) @@ -159,42 +204,48 @@ def copy_users_grants(userfrom=None, userto=None, dryrun=False, ocimds=False, fo stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) grants = session.run_sql(stmt).fetch_all() - if not dryrun and len(grants)>0: - print("Copying GRANTS.", end='') + if not dryrun and len(grants) > 0: + print("Copying GRANTS.", end="") for grant in grants: if "IDENTIFIED BY PASSWORD" in grant[0]: - grant_stmt = re.sub(r" IDENTIFIED BY PASSWORD.*$","", grant[0]) + grant_stmt = re.sub(r" IDENTIFIED BY PASSWORD.*$", "", grant[0]) else: grant_stmt = grant[0] if ocimds: - on_stmt=re.sub(r"^.*( ON .*\..* TO .*$)",r"\1", grant_stmt) - grant_stmt_tmp = re.sub('^GRANT ','', grant_stmt) - grant_stmt_tmp = re.sub(' ON .*\..* TO .*$','', grant_stmt_tmp) - tab_grants = grant_stmt_tmp.split(', ') + on_stmt = re.sub(r"^.*( ON .*\..* TO .*$)", r"\1", grant_stmt) + grant_stmt_tmp = re.sub("^GRANT ", "", grant_stmt) + grant_stmt_tmp = re.sub(" ON .*\..* TO .*$", "", grant_stmt_tmp) + tab_grants = grant_stmt_tmp.split(", ") tab_list = [] for priv in tab_grants: for allowed_priv in mds.mds_allowed_privileges: if allowed_priv == priv: tab_list.append(allowed_priv) break - if len(tab_list)>0: - grant_stmt="GRANT " + ', '.join(tab_list) + on_stmt + if len(tab_list) > 0: + grant_stmt = "GRANT " + ", ".join(tab_list) + on_stmt else: - grant_stmt=None + grant_stmt = None if grant_stmt: - grant_stmt = grant_stmt.replace("TO `{}`@`{}`".format(user[0], user[1]), "TO {}".format(userto)) - grant_stmt = grant_stmt.replace("TO '{}'@'{}'".format(user[0], user[1]), "TO {}".format(userto)) + grant_stmt = grant_stmt.replace( + "TO `{}`@`{}`".format(user[0], user[1]), "TO {}".format(userto) + ) + grant_stmt = grant_stmt.replace( + "TO '{}'@'{}'".format(user[0], user[1]), "TO {}".format(userto) + ) if dryrun: print("{};".format(grant_stmt)) else: try: session.run_sql(grant_stmt) - print(".", end='') + print(".", end="") except mysqlsh.DBError as err: print("\nAborting: {}".format(err)) - print("You may need to install mysql-client to save the password.") + print( + "You may need to install mysql-client to save the password." + ) return - if not dryrun and len(grants)>0: + if not dryrun and len(grants) > 0: print("\nUser(s) copied successfully!") return diff --git a/user/copy.py b/user/copy.py index 8500ba0..f935db1 100644 --- a/user/copy.py +++ b/user/copy.py @@ -1,5 +1,6 @@ from mysqlsh.plugin_manager import plugin, plugin_function from mysqlsh_plugins_common import get_major_version +from mysqlsh_plugins_common import get_distro from user import mds import re @@ -16,7 +17,9 @@ def _get_server_info(session): - return session.run_sql("""SELECT CONCAT(@@hostname," (",@@version,")")""").fetch_one()[0] + return session.run_sql( + """SELECT CONCAT(@@hostname," (",@@version,")")""" + ).fetch_one()[0] def _connect_to_destination(shell, uri): @@ -47,32 +50,44 @@ def copy_users_grants(dryrun=False, ocimds=False, force=False, session=None): global server_info_origin # Get hold of the global shell object import mysqlsh + shell = mysqlsh.globals.shell old_format = None if session is None: session = shell.get_session() if session is None: - print("No session specified. Either pass a session object to this " - "function or connect the shell to a database") + print( + "No session specified. Either pass a session object to this " + "function or connect the shell to a database" + ) return if session_origin != session: server_info_origin = _get_server_info(session) session_origin = session if session_destination is None: - answer = shell.prompt("You need to specify a destination server (server<:port>): ") + answer = shell.prompt( + "You need to specify a destination server (server<:port>): " + ) if not answer: print("Aborting, no destination server defined.") return else: - session_destination = _connect_to_destination(shell, answer) - if not session_destination: - return - server_info_destination = _get_server_info(session_destination) + session_destination = _connect_to_destination(shell, answer) + if not session_destination: + return + server_info_destination = _get_server_info(session_destination) else: - answer = shell.prompt("The current destination server is [{}] - {}, is that OK ? (y/N) ".format(session_destination.get_uri(), server_info_destination), {'defaultValue': 'n'}) - if answer.lower() == 'n': - answer = shell.prompt("You wanted to change destination server, please specify one (server<:port>): ") + answer = shell.prompt( + "The current destination server is [{}] - {}, is that OK ? (y/N) ".format( + session_destination.get_uri(), server_info_destination + ), + {"defaultValue": "n"}, + ) + if answer.lower() == "n": + answer = shell.prompt( + "You wanted to change destination server, please specify one (server<:port>): " + ) if not answer: print("Aborting, no destination server defined.") return @@ -81,13 +96,20 @@ def copy_users_grants(dryrun=False, ocimds=False, force=False, session=None): if not session_destination: return server_info_destination = _get_server_info(session_destination) - search_string = shell.prompt("Enter the user to search (you can use wildcards '%', leave blank for all): ") + search_string = shell.prompt( + "Enter the user to search (you can use wildcards '%', leave blank for all): " + ) if len(search_string.strip()) > 0: search_string = 'AND user LIKE "{}"'.format(search_string) print("Info: locked users and users having expired password are not listed.") mysql_version = get_major_version(session) - mysql_major_int = int(mysql_version.split('.')[0]) + mysql_major_int = int(mysql_version.split(".")[0]) + mysql_distro = get_distro(session) + if mysql_distro.lower().startswith("maria"): + print("-- MariaDB Detected") + mysql_version = "5.6" + mysql_major_int = 5 if mysql_major_int >= 8 or mysql_version == "5.7": # Get the list of users stmt = """SELECT DISTINCT User, Host, @@ -95,7 +117,9 @@ def copy_users_grants(dryrun=False, ocimds=False, force=False, session=None): FROM mysql.user WHERE NOT( `account_locked`="Y" AND `password_expired`="Y" AND `authentication_string`="" ) {} ORDER BY User, Host; - """.format(search_string) + """.format( + search_string + ) else: stmt = """SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user' AND COLUMN_NAME='password';""" @@ -106,77 +130,114 @@ def copy_users_grants(dryrun=False, ocimds=False, force=False, session=None): FROM mysql.user WHERE NOT(`password_expired`="Y" AND `authentication_string`="" ) {} ORDER BY User, Host; - """.format(search_string) + """.format( + search_string + ) else: stmt = """SELECT DISTINCT User, Host, IF(authentication_string = "","NO", "YES") HAS_PWD FROM mysql.user WHERE NOT(`password_expired`="Y" AND `authentication_string`="" ) {} ORDER BY User, Host; - """.format(search_string) - users = session.run_sql(stmt).fetch_all() + """.format( + search_string + ) + users = session.run_sql(stmt).fetch_all() final_s = "" - if len(users)>1: + if len(users) > 1: final_s = "s" print("{} user{} found!".format(len(users), final_s)) for user in users: if ocimds and user[2] == "NO": - print("[`{}`@`{}`] is not compatible with OCI MDS as it has not password, ignoring it...".format(user[0], user[1])) + print( + "[`{}`@`{}`] is not compatible with OCI MDS as it has not password, ignoring it...".format( + user[0], user[1] + ) + ) continue if not force: - answer = shell.prompt("Do you want to copy [`{}`@`{}`] ? (y/N) ".format(user[0], user[1]), {'defaultValue': 'n'}) + answer = shell.prompt( + "Do you want to copy [`{}`@`{}`] ? (y/N) ".format(user[0], user[1]), + {"defaultValue": "n"}, + ) else: answer = "y" - if answer.lower() == 'y': + if answer.lower() == "y": if mysql_major_int >= 8: stmt = """SELECT from_user, from_host FROM mysql.role_edges WHERE to_user = ? and to_host = ?""" roles = session.run_sql(stmt, [user[0], user[1]]).fetch_all() - if len(roles)>0: + if len(roles) > 0: final_s = " is" question = "Do you want to copy that role ? (y/N) " - if len(roles)>1: + if len(roles) > 1: final_s = "s are" question = "Do you want to copy those roles ? (y/N) " print("The following role{} assigned to the user:".format(final_s)) for role in roles: print("- `{}`@`{}`".format(role[0], role[1])) if not force: - answer = shell.prompt(question, {'defaultValue': 'n'}) - if answer.lower() == 'y': + answer = shell.prompt(question, {"defaultValue": "n"}) + if answer.lower() == "y": for role in roles: - stmt = """SHOW CREATE USER `{}`@`{}`""".format(role[0], role[1]) + stmt = """SHOW CREATE USER `{}`@`{}`""".format( + role[0], role[1] + ) create_user = session.run_sql(stmt).fetch_one()[0] + ";" if dryrun: print("-- Role `{}`@`{}`".format(role[0], role[1])) - print("CREATE ROLE IF NOT EXISTS `{}`@`{}`;".format(role[0], role[1])) - #print(create_user) + print( + "CREATE ROLE IF NOT EXISTS `{}`@`{}`;".format( + role[0], role[1] + ) + ) + # print(create_user) else: - print("Copying ROLE `{}`@`{}`: {} - {}--> {} - {}".format(role[0], role[1], session.get_uri(), server_info_origin, session_destination.get_uri(), server_info_destination)) + print( + "Copying ROLE `{}`@`{}`: {} - {}--> {} - {}".format( + role[0], + role[1], + session.get_uri(), + server_info_origin, + session_destination.get_uri(), + server_info_destination, + ) + ) try: - session_destination.run_sql("CREATE ROLE IF NOT EXISTS ?@?;",[role[0], role[1]]) - #session_destination.run_sql(create_user) + session_destination.run_sql( + "CREATE ROLE IF NOT EXISTS ?@?;", + [role[0], role[1]], + ) + # session_destination.run_sql(create_user) except mysqlsh.DBError as err: print("Aborting: {}".format(err)) return - stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(role[0], role[1]) + stmt = """SHOW GRANTS FOR `{}`@`{}`""".format( + role[0], role[1] + ) grants = session.run_sql(stmt).fetch_all() for grant in grants: if ocimds: grant_stmt = grant[0] - on_stmt=re.sub(r"^.*( ON .*\..* TO .*$)",r"\1", grant_stmt) - grant_stmt_tmp = re.sub('^GRANT ','', grant_stmt) - grant_stmt_tmp = re.sub(' ON .*\..* TO .*$','', grant_stmt_tmp) - tab_grants = grant_stmt_tmp.split(', ') + on_stmt = re.sub( + r"^.*( ON .*\..* TO .*$)", r"\1", grant_stmt + ) + grant_stmt_tmp = re.sub("^GRANT ", "", grant_stmt) + grant_stmt_tmp = re.sub( + " ON .*\..* TO .*$", "", grant_stmt_tmp + ) + tab_grants = grant_stmt_tmp.split(", ") tab_list = [] for priv in tab_grants: for allowed_priv in mds.mds_allowed_privileges: if allowed_priv == priv: tab_list.append(allowed_priv) break - if len(tab_list)>0: - grant_stmt="GRANT " + ', '.join(tab_list) + on_stmt + if len(tab_list) > 0: + grant_stmt = ( + "GRANT " + ", ".join(tab_list) + on_stmt + ) else: - grant_stmt=None + grant_stmt = None else: grant_stmt = grant[0] @@ -191,41 +252,74 @@ def copy_users_grants(dryrun=False, ocimds=False, force=False, session=None): return else: - print("Warning: some grants may fail if the role is not created on the destination server.") + print( + "Warning: some grants may fail if the role is not created on the destination server." + ) back_tick = False if mysql_major_int < 8 and mysql_version != "5.7": - stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) - create_user = session.run_sql(stmt).fetch_one()[0] + ";" - if "`{}`@".format(user[0]) in create_user: - create_user=create_user.replace(" TO `{}`@`".format(user[0]),"CREATE USER IF NOT EXISTS `{}`@`".format(user[0])) - back_tick=True - else: - create_user=create_user.replace(" TO '{}'@'".format(user[0]),"CREATE USER IF NOT EXISTS '{}'@'".format(user[0])) - create_user = re.sub(r".*CREATE USER IF NOT","CREATE USER IF NOT", create_user) + stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) + create_user = session.run_sql(stmt).fetch_one()[0] + ";" + if "`{}`@".format(user[0]) in create_user: + create_user = create_user.replace( + " TO `{}`@`".format(user[0]), + "CREATE USER IF NOT EXISTS `{}`@`".format(user[0]), + ) + back_tick = True + else: + create_user = create_user.replace( + " TO '{}'@'".format(user[0]), + "CREATE USER IF NOT EXISTS '{}'@'".format(user[0]), + ) + create_user = re.sub( + r".*CREATE USER IF NOT", "CREATE USER IF NOT", create_user + ) else: - stmt = """SHOW CREATE USER `{}`@`{}`""".format(user[0], user[1]) - create_user = session.run_sql(stmt).fetch_one()[0] + ";" - create_user=create_user.replace("CREATE USER '{}'@'".format(user[0]),"CREATE USER IF NOT EXISTS '{}'@'".format(user[0])) - # we need to find the password in binary format - stmt = """SELECT authentication_string, convert(authentication_string using binary) authbin - FROM mysql.user where user='{}' and host='{}'""".format(user[0], user[1]) - auth_user = session.run_sql(stmt).fetch_one() - auth_string = auth_user[0] - auth_string_bin = auth_user[1] - hex_string = auth_string_bin.hex() - create_user = re.sub(r" AS '(.*)' ", r" AS 0x{} ".format(hex_string), create_user) + stmt = """SHOW CREATE USER `{}`@`{}`""".format(user[0], user[1]) + create_user = session.run_sql(stmt).fetch_one()[0] + ";" + create_user = create_user.replace( + "CREATE USER '{}'@'".format(user[0]), + "CREATE USER IF NOT EXISTS '{}'@'".format(user[0]), + ) + # we need to find the password in binary format + stmt = """SELECT authentication_string, convert(authentication_string using binary) authbin + FROM mysql.user where user='{}' and host='{}'""".format( + user[0], user[1] + ) + auth_user = session.run_sql(stmt).fetch_one() + auth_string = auth_user[0] + auth_string_bin = auth_user[1] + hex_string = auth_string_bin.hex() + create_user = re.sub( + r" AS '(.*)' ", r" AS 0x{} ".format(hex_string), create_user + ) if mysql_major_int < 8 and mysql_version != "5.7": if len(old_format) > 0 and not back_tick: # we need to find the password - stmt = "SELECT password FROM mysql.user WHERE user='{}' AND host='{}'".format(user[0], user[1]) + stmt = "SELECT password FROM mysql.user WHERE user='{}' AND host='{}'".format( + user[0], user[1] + ) pwd = session.run_sql(stmt).fetch_one()[0] - create_user=create_user.replace("BY PASSWORD","WITH 'mysql_native_password' AS '{}'".format(pwd)) + create_user = create_user.replace( + "BY PASSWORD", + "WITH 'mysql_native_password' AS '{}'".format(pwd), + ) else: - create_user=create_user.replace("BY PASSWORD","WITH 'mysql_native_password' AS") + create_user = create_user.replace( + "BY PASSWORD", "WITH 'mysql_native_password' AS" + ) if dryrun: print("-- User `{}`@`{}`".format(user[0], user[1])) else: - print("Copying USER `{}`@`{}`: {} - {} --> {} - {} ".format(user[0], user[1], session.get_uri(), server_info_origin, session_destination.get_uri(), server_info_destination)) + print( + "Copying USER `{}`@`{}`: {} - {} --> {} - {} ".format( + user[0], + user[1], + session.get_uri(), + server_info_origin, + session_destination.get_uri(), + server_info_destination, + ) + ) try: session_destination.run_sql(create_user) except mysqlsh.DBError as err: @@ -234,40 +328,42 @@ def copy_users_grants(dryrun=False, ocimds=False, force=False, session=None): stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) grants = session.run_sql(stmt).fetch_all() - if not dryrun and len(grants)>0: - print("Copying GRANTS.", end='') + if not dryrun and len(grants) > 0: + print("Copying GRANTS.", end="") for grant in grants: if "IDENTIFIED BY PASSWORD" in grant[0]: - grant_stmt = re.sub(r" IDENTIFIED BY PASSWORD.*$","", grant[0]) + grant_stmt = re.sub(r" IDENTIFIED BY PASSWORD.*$", "", grant[0]) else: grant_stmt = grant[0] if ocimds: - on_stmt=re.sub(r"^.*( ON .*\..* TO .*$)",r"\1", grant_stmt) - grant_stmt_tmp = re.sub('^GRANT ','', grant_stmt) - grant_stmt_tmp = re.sub(' ON .*\..* TO .*$','', grant_stmt_tmp) - tab_grants = grant_stmt_tmp.split(', ') + on_stmt = re.sub(r"^.*( ON .*\..* TO .*$)", r"\1", grant_stmt) + grant_stmt_tmp = re.sub("^GRANT ", "", grant_stmt) + grant_stmt_tmp = re.sub(" ON .*\..* TO .*$", "", grant_stmt_tmp) + tab_grants = grant_stmt_tmp.split(", ") tab_list = [] for priv in tab_grants: for allowed_priv in mds.mds_allowed_privileges: if allowed_priv == priv: tab_list.append(allowed_priv) break - if len(tab_list)>0: - grant_stmt="GRANT " + ', '.join(tab_list) + on_stmt + if len(tab_list) > 0: + grant_stmt = "GRANT " + ", ".join(tab_list) + on_stmt else: - grant_stmt=None + grant_stmt = None if grant_stmt: if dryrun: print("{};".format(grant_stmt)) else: try: session_destination.run_sql(grant_stmt) - print(".", end='') + print(".", end="") except mysqlsh.DBError as err: print("\nAborting: {}".format(err)) - print("You may need to install mysql-client to save the password.") + print( + "You may need to install mysql-client to save the password." + ) return - if not dryrun and len(grants)>0: + if not dryrun and len(grants) > 0: print("\nUser(s) copied successfully!") return diff --git a/user/grants.py b/user/grants.py index 374a29f..7a24822 100644 --- a/user/grants.py +++ b/user/grants.py @@ -1,9 +1,11 @@ from mysqlsh.plugin_manager import plugin, plugin_function from mysqlsh_plugins_common import get_major_version +from mysqlsh_plugins_common import get_distro from user import mds import re + @plugin_function("user.getUsersGrants") def get_users_grants(find=None, exclude=None, ocimds=False, session=None): """ @@ -20,14 +22,17 @@ def get_users_grants(find=None, exclude=None, ocimds=False, session=None): """ # Get hold of the global shell object import mysqlsh + shell = mysqlsh.globals.shell old_format = None if session is None: session = shell.get_session() if session is None: - print("No session specified. Either pass a session object to this " - "function or connect the shell to a database") + print( + "No session specified. Either pass a session object to this " + "function or connect the shell to a database" + ) return search_string = "" exclude_string = "" @@ -38,7 +43,12 @@ def get_users_grants(find=None, exclude=None, ocimds=False, session=None): # Get the version mysql_version = get_major_version(session) - mysql_major_int = int(mysql_version.split('.')[0]) + mysql_major_int = int(mysql_version.split(".")[0]) + mysql_distro = get_distro(session) + if mysql_distro.lower().startswith("maria"): + print("-- MariaDB Detected") + mysql_version = "5.6" + mysql_major_int = 5 if mysql_major_int >= 8: print("-- MySQL Major Version: {}".format(mysql_version)) # Get the list of roles @@ -49,34 +59,39 @@ def get_users_grants(find=None, exclude=None, ocimds=False, session=None): AND `password_expired`='Y' AND `authentication_string`='' {} {} - """.format(search_string, exclude_string) - users = session.run_sql(stmt).fetch_all() + """.format( + search_string, exclude_string + ) + users = session.run_sql(stmt).fetch_all() for user in users: print("-- Role `{}`@`{}`".format(user[0], user[1])) stmt = """SHOW CREATE USER `{}`@`{}`""".format(user[0], user[1]) create_user = session.run_sql(stmt).fetch_one()[0] + ";" - create_user=create_user.replace("CREATE USER '{}'@'".format(user[0]),"CREATE USER IF NOT EXISTS '{}'@'".format(user[0])) - #print("CREATE ROLE IF NOT EXISTS `{}`@`{}`;".format(user[0], user[1])) + create_user = create_user.replace( + "CREATE USER '{}'@'".format(user[0]), + "CREATE USER IF NOT EXISTS '{}'@'".format(user[0]), + ) + # print("CREATE ROLE IF NOT EXISTS `{}`@`{}`;".format(user[0], user[1])) print(create_user) stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) grants = session.run_sql(stmt).fetch_all() for grant in grants: if ocimds: grant_stmt = grant[0] - on_stmt=re.sub(r"^.*( ON .*\..* TO .*$)",r"\1", grant_stmt) - grant_stmt_tmp = re.sub('^GRANT ','', grant_stmt) - grant_stmt_tmp = re.sub(' ON .*\..* TO .*$','', grant_stmt_tmp) - tab_grants = grant_stmt_tmp.split(', ') + on_stmt = re.sub(r"^.*( ON .*\..* TO .*$)", r"\1", grant_stmt) + grant_stmt_tmp = re.sub("^GRANT ", "", grant_stmt) + grant_stmt_tmp = re.sub(" ON .*\..* TO .*$", "", grant_stmt_tmp) + tab_grants = grant_stmt_tmp.split(", ") tab_list = [] for priv in tab_grants: for allowed_priv in mds.mds_allowed_privileges: if allowed_priv == priv: tab_list.append(allowed_priv) break - if len(tab_list)>0: - grant_stmt="GRANT " + ', '.join(tab_list) + on_stmt + if len(tab_list) > 0: + grant_stmt = "GRANT " + ", ".join(tab_list) + on_stmt else: - grant_stmt=None + grant_stmt = None else: grant_stmt = grant[0] if grant_stmt: @@ -86,13 +101,17 @@ def get_users_grants(find=None, exclude=None, ocimds=False, session=None): stmt = """SELECT DISTINCT User, Host FROM mysql.user WHERE NOT( `account_locked`="Y" AND `password_expired`="Y" AND `authentication_string`="" ) {} {} ORDER BY User, Host; - """.format(search_string, exclude_string) + """.format( + search_string, exclude_string + ) else: if mysql_version == "5.7": - stmt = """SELECT DISTINCT User, Host FROM mysql.user + stmt = """SELECT DISTINCT User, Host FROM mysql.user WHERE NOT( `account_locked`="Y" AND `password_expired`="Y" AND `authentication_string`="" ) {} {} ORDER BY User, Host; - """.format(search_string, exclude_string) + """.format( + search_string, exclude_string + ) else: stmt = """SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user' AND COLUMN_NAME='password';""" @@ -103,77 +122,106 @@ def get_users_grants(find=None, exclude=None, ocimds=False, session=None): FROM mysql.user WHERE NOT(`password_expired`="Y" AND `authentication_string`="" ) {} {} ORDER BY User, Host; - """.format(search_string, exclude_string) + """.format( + search_string, exclude_string + ) else: stmt = """SELECT DISTINCT User, Host, IF(authentication_string = "","NO", "YES") HAS_PWD FROM mysql.user WHERE NOT(`password_expired`="Y" AND `authentication_string`="" ) {} {} ORDER BY User, Host; - """.format(search_string, exclude_string) - users = session.run_sql(stmt).fetch_all() + """.format( + search_string, exclude_string + ) + users = session.run_sql(stmt).fetch_all() back_tick = False for user in users: - print("-- User `{}`@`{}`".format(user[0], user[1])) - if mysql_major_int < 8 and mysql_version != "5.7": - stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) - create_user = session.run_sql(stmt).fetch_one()[0] + ";" - if "`{}`@".format(user[0]) in create_user: - create_user=create_user.replace(" TO `{}`@`".format(user[0]),"CREATE USER IF NOT EXISTS `{}`@`".format(user[0])) - back_tick=True - else: - create_user=create_user.replace(" TO '{}'@'".format(user[0]),"CREATE USER IF NOT EXISTS '{}'@'".format(user[0])) - create_user = re.sub(r".*CREATE USER IF NOT","CREATE USER IF NOT", create_user) - else: - stmt = """SHOW CREATE USER `{}`@`{}`""".format(user[0], user[1]) - create_user = session.run_sql(stmt).fetch_one()[0] + ";" - create_user = create_user.replace("CREATE USER `{}`@`".format(user[0]),"CREATE USER IF NOT EXISTS `{}`@`".format(user[0])) - # we need to find the password in binary format - stmt = """SELECT authentication_string, convert(authentication_string using binary) authbin - FROM mysql.user where user='{}' and host='{}'""".format(user[0], user[1]) - auth_user = session.run_sql(stmt).fetch_one() - auth_string = auth_user[0] - auth_string_bin = auth_user[1] - hex_string = auth_string_bin.hex() - create_user = re.sub(r" AS '(.*)' ", r" AS 0x{} ".format(hex_string), create_user) - if mysql_major_int < 8: - if old_format: - if len(old_format) > 0 and not back_tick: - # we need to find the password - stmt = "SELECT password FROM mysql.user WHERE user='{}' AND host='{}'".format(user[0], user[1]) - pwd = session.run_sql(stmt).fetch_one()[0] - create_user=create_user.replace("BY PASSWORD","WITH 'mysql_native_password' AS '{}'".format(pwd)) - else: - create_user=create_user.replace("BY PASSWORD","WITH 'mysql_native_password' AS") - #print("CREATE USER IF NOT EXISTS `{}`@`{}`;".format(user[0], user[1])) - print(create_user) - stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) - grants = session.run_sql(stmt).fetch_all() - for grant in grants: - grant_to_print = grant[0] - if old_format: - if len(old_format) > 0: - if "IDENTIFIED BY PASSWORD" in grant[0]: - grant_to_print = re.sub(r" IDENTIFIED BY PASSWORD.*$","", grant[0]) - if ocimds: - on_stmt=re.sub(r"^.*( ON .*\..* TO .*$)",r"\1", grant_to_print) - grant_stmt_tmp = re.sub('^GRANT ','', grant_to_print) - grant_stmt_tmp = re.sub(' ON .*\..* TO .*$','', grant_stmt_tmp) - tab_grants = grant_stmt_tmp.split(', ') - tab_list = [] - for priv in tab_grants: - for allowed_priv in mds.mds_allowed_privileges: - if allowed_priv == priv: - tab_list.append(allowed_priv) - break - if len(tab_list)>0: - grant_stmt="GRANT " + ', '.join(tab_list) + on_stmt + if len(user[0]) > 0 and len(user[1]) > 0: + print("-- User `{}`@`{}`".format(user[0], user[1])) + if mysql_major_int < 8 and mysql_version != "5.7": + stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) + create_user = session.run_sql(stmt).fetch_one()[0] + ";" + if "`{}`@".format(user[0]) in create_user: + create_user = create_user.replace( + " TO `{}`@`".format(user[0]), + "CREATE USER IF NOT EXISTS `{}`@`".format(user[0]), + ) + back_tick = True else: - grant_stmt=None - if grant_stmt: - print("{};".format(grant_stmt)) + create_user = create_user.replace( + " TO '{}'@'".format(user[0]), + "CREATE USER IF NOT EXISTS '{}'@'".format(user[0]), + ) + create_user = re.sub( + r".*CREATE USER IF NOT", "CREATE USER IF NOT", create_user + ) else: - print("{};".format(grant_to_print)) + stmt = """SHOW CREATE USER `{}`@`{}`""".format(user[0], user[1]) + create_user = session.run_sql(stmt).fetch_one()[0] + ";" + create_user = create_user.replace( + "CREATE USER `{}`@`".format(user[0]), + "CREATE USER IF NOT EXISTS `{}`@`".format(user[0]), + ) + # we need to find the password in binary format + stmt = """SELECT authentication_string, convert(authentication_string using binary) authbin + FROM mysql.user where user='{}' and host='{}'""".format( + user[0], user[1] + ) + auth_user = session.run_sql(stmt).fetch_one() + auth_string = auth_user[0] + auth_string_bin = auth_user[1] + hex_string = auth_string_bin.hex() + create_user = re.sub( + r" AS '(.*)' ", r" AS 0x{} ".format(hex_string), create_user + ) + if mysql_major_int < 8: + if old_format: + if len(old_format) > 0 and not back_tick: + # we need to find the password + stmt = "SELECT password FROM mysql.user WHERE user='{}' AND host='{}'".format( + user[0], user[1] + ) + pwd = session.run_sql(stmt).fetch_one()[0] + create_user = create_user.replace( + "BY PASSWORD", + "WITH 'mysql_native_password' AS '{}'".format(pwd), + ) + else: + create_user = create_user.replace( + "BY PASSWORD", "WITH 'mysql_native_password' AS" + ) + # print("CREATE USER IF NOT EXISTS `{}`@`{}`;".format(user[0], user[1])) + print(create_user) + stmt = """SHOW GRANTS FOR `{}`@`{}`""".format(user[0], user[1]) + grants = session.run_sql(stmt).fetch_all() + for grant in grants: + grant_to_print = grant[0] + if old_format: + if len(old_format) > 0: + if "IDENTIFIED BY PASSWORD" in grant[0]: + grant_to_print = re.sub( + r" IDENTIFIED BY PASSWORD.*$", "", grant[0] + ) + if ocimds: + on_stmt = re.sub(r"^.*( ON .*\..* TO .*$)", r"\1", grant_to_print) + grant_stmt_tmp = re.sub("^GRANT ", "", grant_to_print) + grant_stmt_tmp = re.sub(" ON .*\..* TO .*$", "", grant_stmt_tmp) + tab_grants = grant_stmt_tmp.split(", ") + tab_list = [] + for priv in tab_grants: + for allowed_priv in mds.mds_allowed_privileges: + if allowed_priv == priv: + tab_list.append(allowed_priv) + break + if len(tab_list) > 0: + grant_stmt = "GRANT " + ", ".join(tab_list) + on_stmt + else: + grant_stmt = None + if grant_stmt: + print("{};".format(grant_stmt)) + else: + print("{};".format(grant_to_print)) return