diff options
| author | Jean-Michel Vourgère <nirgal@debian.org> | 2015-06-17 15:37:09 +0200 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2015-06-30 18:21:51 -0400 |
| commit | b64c0d4d613b5cabedbc9b847682fe14877537de (patch) | |
| tree | ac3ea4e0c72ccfe41e4c314944d4636791c30da0 /django | |
| parent | eecd42ea7d97bce04bc909c71bed14850060c39c (diff) | |
Fixed #23658 -- Provided the password to PostgreSQL dbshell command
The password from settings.py is written in a temporary .pgpass file
file whose name is given to psql using the PGPASSFILE environment
variable.
Diffstat (limited to 'django')
| -rw-r--r-- | django/db/backends/postgresql_psycopg2/client.py | 67 |
1 files changed, 57 insertions, 10 deletions
diff --git a/django/db/backends/postgresql_psycopg2/client.py b/django/db/backends/postgresql_psycopg2/client.py index aa60e58943..5e3e288301 100644 --- a/django/db/backends/postgresql_psycopg2/client.py +++ b/django/db/backends/postgresql_psycopg2/client.py @@ -1,19 +1,66 @@ +import os import subprocess +from django.core.files.temp import NamedTemporaryFile from django.db.backends.base.client import BaseDatabaseClient +from django.utils.six import print_ + + +def _escape_pgpass(txt): + """ + Escape a fragment of a PostgreSQL .pgpass file. + """ + return txt.replace('\\', '\\\\').replace(':', '\\:') class DatabaseClient(BaseDatabaseClient): executable_name = 'psql' + @classmethod + def runshell_db(cls, settings_dict): + args = [cls.executable_name] + + host = settings_dict.get('HOST', '') + port = settings_dict.get('PORT', '') + name = settings_dict.get('NAME', '') + user = settings_dict.get('USER', '') + passwd = settings_dict.get('PASSWORD', '') + + if user: + args += ['-U', user] + if host: + args += ['-h', host] + if port: + args += ['-p', str(port)] + args += [name] + + temp_pgpass = None + try: + if passwd: + # Create temporary .pgpass file. + temp_pgpass = NamedTemporaryFile(mode='w+') + try: + print_( + _escape_pgpass(host) or '*', + str(port) or '*', + _escape_pgpass(name) or '*', + _escape_pgpass(user) or '*', + _escape_pgpass(passwd), + file=temp_pgpass, + sep=':', + flush=True, + ) + os.environ['PGPASSFILE'] = temp_pgpass.name + except UnicodeEncodeError: + # If the current locale can't encode the data, we let + # the user input the password manually. + pass + subprocess.call(args) + finally: + if temp_pgpass: + temp_pgpass.close() + if 'PGPASSFILE' in os.environ: # unit tests need cleanup + del os.environ['PGPASSFILE'] + def runshell(self): - settings_dict = self.connection.settings_dict - args = [self.executable_name] - if settings_dict['USER']: - args += ["-U", settings_dict['USER']] - if settings_dict['HOST']: - args.extend(["-h", settings_dict['HOST']]) - if settings_dict['PORT']: - args.extend(["-p", str(settings_dict['PORT'])]) - args += [settings_dict['NAME']] - subprocess.call(args) + DatabaseClient.runshell_db(self.connection.settings_dict) |
