Fixed #29199 -- Fixed crash when database user password contains @ sign on Oracle.

Thanks Shane Allgeier for the report and Tim Graham for the review.
This commit is contained in:
Mariusz Felisiak 2018-03-13 19:06:40 +01:00 committed by GitHub
parent 22bcd3a1d8
commit acfc650f2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 10 deletions

View File

@ -185,18 +185,16 @@ class DatabaseWrapper(BaseDatabaseWrapper):
use_returning_into = self.settings_dict["OPTIONS"].get('use_returning_into', True) use_returning_into = self.settings_dict["OPTIONS"].get('use_returning_into', True)
self.features.can_return_id_from_insert = use_returning_into self.features.can_return_id_from_insert = use_returning_into
def _connect_string(self): def _dsn(self):
settings_dict = self.settings_dict settings_dict = self.settings_dict
if not settings_dict['HOST'].strip(): if not settings_dict['HOST'].strip():
settings_dict['HOST'] = 'localhost' settings_dict['HOST'] = 'localhost'
if settings_dict['PORT']: if settings_dict['PORT']:
dsn = Database.makedsn(settings_dict['HOST'], return Database.makedsn(settings_dict['HOST'], int(settings_dict['PORT']), settings_dict['NAME'])
int(settings_dict['PORT']), return settings_dict['NAME']
settings_dict['NAME'])
else: def _connect_string(self):
dsn = settings_dict['NAME'] return '%s/\\"%s\\"@%s' % (self.settings_dict['USER'], self.settings_dict['PASSWORD'], self._dsn())
return "%s/%s@%s" % (settings_dict['USER'],
settings_dict['PASSWORD'], dsn)
def get_connection_params(self): def get_connection_params(self):
conn_params = self.settings_dict['OPTIONS'].copy() conn_params = self.settings_dict['OPTIONS'].copy()
@ -205,7 +203,12 @@ class DatabaseWrapper(BaseDatabaseWrapper):
return conn_params return conn_params
def get_new_connection(self, conn_params): def get_new_connection(self, conn_params):
return Database.connect(self._connect_string(), **conn_params) return Database.connect(
user=self.settings_dict['USER'],
password=self.settings_dict['PASSWORD'],
dsn=self._dsn(),
**conn_params,
)
def init_connection_state(self): def init_connection_state(self):
cursor = self.create_cursor() cursor = self.create_cursor()

View File

@ -57,7 +57,7 @@ class Tests(unittest.TestCase):
@unittest.skipUnless(connection.vendor == 'oracle', 'Oracle tests') @unittest.skipUnless(connection.vendor == 'oracle', 'Oracle tests')
class HiddenNoDataFoundExceptionTest(TransactionTestCase): class TransactionalTests(TransactionTestCase):
available_apps = ['backends'] available_apps = ['backends']
def test_hidden_no_data_found_exception(self): def test_hidden_no_data_found_exception(self):
@ -83,3 +83,16 @@ class HiddenNoDataFoundExceptionTest(TransactionTestCase):
finally: finally:
with connection.cursor() as cursor: with connection.cursor() as cursor:
cursor.execute('DROP TRIGGER "TRG_NO_DATA_FOUND"') cursor.execute('DROP TRIGGER "TRG_NO_DATA_FOUND"')
def test_password_with_at_sign(self):
old_password = connection.settings_dict['PASSWORD']
connection.settings_dict['PASSWORD'] = 'p@ssword'
try:
self.assertIn('/\\"p@ssword\\"@', connection._connect_string())
with self.assertRaises(DatabaseError) as context:
connection.cursor()
# Database exception: "ORA-01017: invalid username/password" is
# expected.
self.assertIn('ORA-01017', context.exception.args[0].message)
finally:
connection.settings_dict['PASSWORD'] = old_password