From 9ac2e470a848880aabcffcdfc3251d54c081000b Mon Sep 17 00:00:00 2001 From: Frederic Descamps Date: Wed, 26 Jun 2019 22:56:51 +0200 Subject: [PATCH 1/2] Add password expiration method to the security plugin Signed-off-by: Frederic Descamps --- security/__init__.py | 0 security/expire.py | 39 +++++++++++++++++++++++++++ security/init.py | 63 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 security/__init__.py create mode 100644 security/expire.py diff --git a/security/__init__.py b/security/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/security/expire.py b/security/expire.py new file mode 100644 index 0000000..df4ca5f --- /dev/null +++ b/security/expire.py @@ -0,0 +1,39 @@ +def show_password_expire(show_expired=True, session=None): + import mysqlsh + shell = mysqlsh.globals.shell + + 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") + return + + if show_expired: + stmt = """select concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)), + password_last_changed, IF((cast( + IFNULL(password_lifetime, @@default_password_lifetime) as signed) + + cast(datediff(password_last_changed, now()) as signed) > 0), + concat( + cast( + IFNULL(password_lifetime, @@default_password_lifetime) as signed) + + cast(datediff(password_last_changed, now()) as signed), ' days'), 'expired') expires_in + from mysql.user + where + user not like 'mysql.%'""" + else: + stmt = """select concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)), + password_last_changed, + concat( + cast( + IFNULL(password_lifetime, @@default_password_lifetime) as signed) + + cast(datediff(password_last_changed, now()) as signed), ' days') expires_in + from mysql.user + where + cast( + IFNULL(password_lifetime, @@default_password_lifetime) as signed) + + cast(datediff(password_last_changed, now()) as signed) >= 0 + and user not like 'mysql.%';""" + + result = session.run_sql(stmt) + shell.dump_rows(result) diff --git a/security/init.py b/security/init.py index 5989ced..dab33a3 100644 --- a/security/init.py +++ b/security/init.py @@ -1,2 +1,63 @@ -# init.py +# security/init.py +# -------------- +# Initializes the security plugins. + +# Contents +# -------- +# This plugin will define the following functions + +# Example # ------- + +# MySQL 8.0.16 > > localhost:33060+ > > 2019-06-26 18:48:48 > +# JS> ext.security.showPasswordExpire() +# +-------------------------------------------------------------------+-----------------------+------------+ +# | concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)) | password_last_changed | expires_in | +# +-------------------------------------------------------------------+-----------------------+------------+ +# | `demo`@`%` | 2019-05-21 12:25:58 | expired | +# | `fred`@`%` | 2019-02-07 11:09:01 | expired | +# | `root`@`localhost` | 2019-02-07 11:07:29 | expired | +# +-------------------------------------------------------------------+-----------------------+------------+ +# MySQL 8.0.16 > > localhost:33060+ > > 2019-06-26 18:48:50 > +# JS> ext.security.showPasswordExpire(true) +# +-------------------------------------------------------------------+-----------------------+------------+ +# | concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)) | password_last_changed | expires_in | +# +-------------------------------------------------------------------+-----------------------+------------+ +# | `demo`@`%` | 2019-05-21 12:25:58 | expired | +# | `fred`@`%` | 2019-02-07 11:09:01 | expired | +# | `root`@`localhost` | 2019-02-07 11:07:29 | expired | +# +-------------------------------------------------------------------+-----------------------+------------+ +# MySQL 8.0.16 > > localhost:33060+ > > 2019-06-26 18:48:58 > +# JS> ext.security.showPasswordExpire(false) + + +from ext.mysqlsh_plugins_common import register_plugin +from ext.security import expire as security_expire + +register_plugin("showPasswordExpire", security_expire.show_password_expire, + { + "brief": "Lists all accounta and their expiration date", + "parameters": [ + { + "name": "show_expire", + "brief": "List expired passwords too", + "type": "bool", + "required": False + }, + { + "name": "session", + "brief": "The session to be used on the operation.", + "type": "object", + "classes": ["Session", "ClassicSession"], + "required": False + } + ] + }, + "security", + { + "brief": "Security management and utilities.", + "details": [ + "A collection of security management tools and related " + "utilities" + ] + }) \ No newline at end of file From b45d1feff6ba052a37f82af88c8c44bd69d84fbe Mon Sep 17 00:00:00 2001 From: Frederic Descamps Date: Tue, 9 Jul 2019 21:25:36 +0200 Subject: [PATCH 2/2] add the method requested in the PR Signed-off-by: Frederic Descamps --- security/expire.py | 54 ++++++++++++++++++++++++++++++++++++++++------ security/init.py | 26 ++++++++++++++++++++-- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/security/expire.py b/security/expire.py index df4ca5f..7bd2ff9 100644 --- a/security/expire.py +++ b/security/expire.py @@ -8,21 +8,60 @@ def show_password_expire(show_expired=True, session=None): print("No session specified. Either pass a session object to this " "function or connect the shell to a database") return - + stmt = "select @@default_password_lifetime, @@disconnect_on_expired_password" + result = session.run_sql(stmt) + rows = result.fetch_all() + if rows[0][0] == 0: + print "Default password doesn't expire" + else: + print "Default password expires in %d days" % rows[0][0] + if rows[0][1] == 1: + print "On expired password disconnect" if show_expired: - stmt = """select concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)), + stmt = """select concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)) + AS user, password_last_changed, IF((cast( IFNULL(password_lifetime, @@default_password_lifetime) as signed) + cast(datediff(password_last_changed, now()) as signed) > 0), concat( cast( IFNULL(password_lifetime, @@default_password_lifetime) as signed) - + cast(datediff(password_last_changed, now()) as signed), ' days'), 'expired') expires_in + + cast(datediff(password_last_changed, now()) as signed), ' days'), + IF(@@default_password_lifetime > 0, 'expired', 'do not expire')) expires_in from mysql.user where - user not like 'mysql.%'""" + user not like 'mysql.%' order by user""" else: - stmt = """select concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)), + stmt = """select concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)) + AS user, + password_last_changed, + concat( + cast( + IFNULL(password_lifetime, @@default_password_lifetime) as signed) + + cast(datediff(password_last_changed, now()) as signed), ' days') expires_in + from mysql.user + where + cast( + IFNULL(password_lifetime, @@default_password_lifetime) as signed) + + cast(datediff(password_last_changed, now()) as signed) > 0 + and user not like 'mysql.%' order by user;""" + + result = session.run_sql(stmt) + shell.dump_rows(result) + + +def show_password_expire_soon(expire_in_days=30, session=None): + import mysqlsh + shell = mysqlsh.globals.shell + + 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") + return + stmt = """select concat(sys.quote_identifier(user),'@',sys.quote_identifier(host)) + AS user, password_last_changed, concat( cast( @@ -32,8 +71,9 @@ def show_password_expire(show_expired=True, session=None): where cast( IFNULL(password_lifetime, @@default_password_lifetime) as signed) - + cast(datediff(password_last_changed, now()) as signed) >= 0 - and user not like 'mysql.%';""" + + cast(datediff(password_last_changed, now()) as signed) BETWEEN 1 and {limit} + and user not like 'mysql.%' order by user;""".format(limit=expire_in_days) result = session.run_sql(stmt) shell.dump_rows(result) + diff --git a/security/init.py b/security/init.py index dab33a3..60b4b08 100644 --- a/security/init.py +++ b/security/init.py @@ -36,7 +36,7 @@ register_plugin("showPasswordExpire", security_expire.show_password_expire, { - "brief": "Lists all accounta and their expiration date", + "brief": "Lists all accounts and their expiration date", "parameters": [ { "name": "show_expire", @@ -60,4 +60,26 @@ "A collection of security management tools and related " "utilities" ] - }) \ No newline at end of file + }) + +register_plugin("showPasswordExpireSoon", security_expire.show_password_expire_soon, + { + "brief": "Lists all accounts that will expire in specific days", + "parameters": [ + { + "name": "expire_in_days", + "brief": "List accounts that will expire in that range upper limit, if none provided, the default is 30", + "type": "bool", + "required": False + }, + { + "name": "session", + "brief": "The session to be used on the operation.", + "type": "object", + "classes": ["Session", "ClassicSession"], + "required": False + } + ] + }, + "security" + ) \ No newline at end of file