From d30d54c26b10f1d1bba604f8190bf8d07ee5ec81 Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Fri, 28 Oct 2016 12:19:05 +1300 Subject: [PATCH 1/6] Optionally load connection arguments from the environment. --- MySQLdb/connections.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MySQLdb/connections.py b/MySQLdb/connections.py index d8406db8..dc847f82 100644 --- a/MySQLdb/connections.py +++ b/MySQLdb/connections.py @@ -11,6 +11,7 @@ NotSupportedError, ProgrammingError import _mysql import re +import os if not PY2: @@ -144,7 +145,12 @@ class object, used to create cursors (keyword only) from MySQLdb.converters import conversions from weakref import proxy - kwargs2 = kwargs.copy() + # Load values from the environment if provided. + # Anything passed locally overrides the environment. + kwargs2 = {key.split("PY_MYSQL_CONNECT_", 1)[1].lower(): value + for key, value in os.environ.items + if key.startswith("PY_MYSQL_CONNECT_")} + kwargs2.update(kwargs) if 'database' in kwargs2: kwargs2['db'] = kwargs2.pop('database') From b86c0d28e9ea6e6a1664d7ebb3d67ae43e8170f9 Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Fri, 28 Oct 2016 12:31:23 +1300 Subject: [PATCH 2/6] Load SSL options from the environment. - Remove the previous generic option loading, which wouldn't work for SSL (because we need a dictionary) and that was all we really cared about. - Load the various SSL options from the environment if they are present and not in the arguments. - Skip this for any localhost connection because TLS doesn't make sense there. --- MySQLdb/connections.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/MySQLdb/connections.py b/MySQLdb/connections.py index dc847f82..6587fbc2 100644 --- a/MySQLdb/connections.py +++ b/MySQLdb/connections.py @@ -145,13 +145,28 @@ class object, used to create cursors (keyword only) from MySQLdb.converters import conversions from weakref import proxy - # Load values from the environment if provided. - # Anything passed locally overrides the environment. - kwargs2 = {key.split("PY_MYSQL_CONNECT_", 1)[1].lower(): value - for key, value in os.environ.items - if key.startswith("PY_MYSQL_CONNECT_")} - kwargs2.update(kwargs) + kwargs2 = kwargs.copy() + # Load SSL arguments from the environment if provided. + # Anything passed locally overrides the environment. + # Skip this if the host is "localhost", as a TLS connection there + # does not make sense, whether it's via a TCP/IP or UNIX socket. + if kwargs2.get("host", "localhost") == "localhost": + ssl_arg = {} + for conf_name in ("key", "cert", "ca", "capath", "cipher"): + try: + value = kwargs2["ssl"][conf_name] + except KeyError: + env_key = "PY_MYSQL_SSL_%s" % conf_name.upper() + try: + value = os.environ[env_key] + except KeyError: + value = None + if value is not None: + ssl_arg[conf_name] = value + if ssl_arg: + kwargs["ssl"] = ssl_arg + if 'database' in kwargs2: kwargs2['db'] = kwargs2.pop('database') if 'password' in kwargs2: From 003418091fae6a2adda37bc1d074212aec545917 Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Fri, 28 Oct 2016 12:33:52 +1300 Subject: [PATCH 3/6] Provide the ability to explicitly say no-ssl. If ssl is not missing but =None, then do not do the environment load. The currently behaviour has ssl=None fail when it tries to make a TLS connection, so this shouldn't break anything, and allows the system to be bypassed when needed. --- MySQLdb/connections.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MySQLdb/connections.py b/MySQLdb/connections.py index 6587fbc2..89fdd08b 100644 --- a/MySQLdb/connections.py +++ b/MySQLdb/connections.py @@ -151,7 +151,8 @@ class object, used to create cursors (keyword only) # Anything passed locally overrides the environment. # Skip this if the host is "localhost", as a TLS connection there # does not make sense, whether it's via a TCP/IP or UNIX socket. - if kwargs2.get("host", "localhost") == "localhost": + if (kwargs2.get("host", "localhost") != "localhost" and + kwargs2.get("ssl", True) is not None): ssl_arg = {} for conf_name in ("key", "cert", "ca", "capath", "cipher"): try: From 88b50c1c6e58f2402889c74ccd5a3cf20bddacda Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Fri, 28 Oct 2016 12:45:38 +1300 Subject: [PATCH 4/6] Always skip SSL if host=localhost. If we are making a connection to localhost, then passing anything for SSL will always mean a failed connection, because a certificate cannot be verified (if TCP/IP) or SSL doesn't make sense (if UNIX). Make it easier to call connect with ssl values by always ignoring them in the localhost case. This means that callers do not need to check if the host is localhost and can simply always provide an SSL value (e.g. if the host is a variable). --- MySQLdb/connections.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/MySQLdb/connections.py b/MySQLdb/connections.py index 89fdd08b..996ce297 100644 --- a/MySQLdb/connections.py +++ b/MySQLdb/connections.py @@ -149,10 +149,8 @@ class object, used to create cursors (keyword only) # Load SSL arguments from the environment if provided. # Anything passed locally overrides the environment. - # Skip this if the host is "localhost", as a TLS connection there - # does not make sense, whether it's via a TCP/IP or UNIX socket. - if (kwargs2.get("host", "localhost") != "localhost" and - kwargs2.get("ssl", True) is not None): + # Skip this if ssl is explicitly passed with a None value. + if kwargs2.get("ssl", True) is not None: ssl_arg = {} for conf_name in ("key", "cert", "ca", "capath", "cipher"): try: @@ -166,8 +164,15 @@ class object, used to create cursors (keyword only) if value is not None: ssl_arg[conf_name] = value if ssl_arg: - kwargs["ssl"] = ssl_arg - + kwargs2["ssl"] = ssl_arg + + # If the host is "localhost", a TLS connection there does not + # make sense, whether it's via a TCP/IP or UNIX socket. Make it + # easier for users by removing the SSL argument in that case. + if ("ssl" in kwargs2 and + kwargs2.get("host", "localhost") == "localhost"): + del kwargs["ssl"] + if 'database' in kwargs2: kwargs2['db'] = kwargs2.pop('database') if 'password' in kwargs2: From fddbc19511a6b7fa7c383eb42c2785542e869282 Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Fri, 28 Oct 2016 12:48:08 +1300 Subject: [PATCH 5/6] Fix whitespace. --- MySQLdb/connections.py | 56 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/MySQLdb/connections.py b/MySQLdb/connections.py index 996ce297..befcd7a7 100644 --- a/MySQLdb/connections.py +++ b/MySQLdb/connections.py @@ -145,34 +145,34 @@ class object, used to create cursors (keyword only) from MySQLdb.converters import conversions from weakref import proxy - kwargs2 = kwargs.copy() - - # Load SSL arguments from the environment if provided. - # Anything passed locally overrides the environment. - # Skip this if ssl is explicitly passed with a None value. - if kwargs2.get("ssl", True) is not None: - ssl_arg = {} - for conf_name in ("key", "cert", "ca", "capath", "cipher"): - try: - value = kwargs2["ssl"][conf_name] - except KeyError: - env_key = "PY_MYSQL_SSL_%s" % conf_name.upper() - try: - value = os.environ[env_key] - except KeyError: - value = None - if value is not None: - ssl_arg[conf_name] = value - if ssl_arg: - kwargs2["ssl"] = ssl_arg - - # If the host is "localhost", a TLS connection there does not - # make sense, whether it's via a TCP/IP or UNIX socket. Make it - # easier for users by removing the SSL argument in that case. - if ("ssl" in kwargs2 and - kwargs2.get("host", "localhost") == "localhost"): - del kwargs["ssl"] - + kwargs2 = kwargs.copy() + + # Load SSL arguments from the environment if provided. + # Anything passed locally overrides the environment. + # Skip this if ssl is explicitly passed with a None value. + if kwargs2.get("ssl", True) is not None: + ssl_arg = {} + for conf_name in ("key", "cert", "ca", "capath", "cipher"): + try: + value = kwargs2["ssl"][conf_name] + except KeyError: + env_key = "PY_MYSQL_SSL_%s" % conf_name.upper() + try: + value = os.environ[env_key] + except KeyError: + value = None + if value is not None: + ssl_arg[conf_name] = value + if ssl_arg: + kwargs2["ssl"] = ssl_arg + + # If the host is "localhost", a TLS connection there does not + # make sense, whether it's via a TCP/IP or UNIX socket. Make it + # easier for users by removing the SSL argument in that case. + if ("ssl" in kwargs2 and + kwargs2.get("host", "localhost") == "localhost"): + del kwargs["ssl"] + if 'database' in kwargs2: kwargs2['db'] = kwargs2.pop('database') if 'password' in kwargs2: From 55a47bb9654126ae1b95e1ea754c73f3621e0829 Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Fri, 28 Oct 2016 22:37:59 +1300 Subject: [PATCH 6/6] Typo --- MySQLdb/connections.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MySQLdb/connections.py b/MySQLdb/connections.py index befcd7a7..4f6566a4 100644 --- a/MySQLdb/connections.py +++ b/MySQLdb/connections.py @@ -171,7 +171,7 @@ class object, used to create cursors (keyword only) # easier for users by removing the SSL argument in that case. if ("ssl" in kwargs2 and kwargs2.get("host", "localhost") == "localhost"): - del kwargs["ssl"] + del kwargs2["ssl"] if 'database' in kwargs2: kwargs2['db'] = kwargs2.pop('database')