From 604ecf9985164f4bde63dcd1589536fd108cf725 Mon Sep 17 00:00:00 2001 From: William Rocha Date: Tue, 18 Mar 2014 03:27:16 +0000 Subject: [PATCH] TACACSRC multiline bug fix and unittests update Change-Id: Ia5e5c4c11049184ce127cca7e5f7eea2b3686b16 --- tests/data/brokenpw_tacacsrc | 7 +++++ tests/data/emptypw_tacacsrc | 4 +++ tests/data/longpw_tacacsrc | 4 +++ tests/data/medium_tacacsrc | 4 +++ tests/data/settings.py | 6 ++++ tests/data/tacacsrc | 6 +++- tests/test_tacacsrc.py | 56 ++++++++++++++++++++++++++++++------ trigger/tacacsrc.py | 2 +- 8 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 tests/data/brokenpw_tacacsrc create mode 100644 tests/data/emptypw_tacacsrc create mode 100644 tests/data/longpw_tacacsrc create mode 100644 tests/data/medium_tacacsrc diff --git a/tests/data/brokenpw_tacacsrc b/tests/data/brokenpw_tacacsrc new file mode 100644 index 0000000..192c599 --- /dev/null +++ b/tests/data/brokenpw_tacacsrc @@ -0,0 +1,7 @@ +# Saved by test_tacacsrc at 2014-03-20 15:35:23 GMT + +LONGPWCREDS_uname_ = hpRBGORH+9y7OLTVV2fZcA== +LONGPWCREDS_pwd_ = DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncO +AQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4B +ARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEB +ETXDEncOAQERNcMSdw== diff --git a/tests/data/emptypw_tacacsrc b/tests/data/emptypw_tacacsrc new file mode 100644 index 0000000..3a665ab --- /dev/null +++ b/tests/data/emptypw_tacacsrc @@ -0,0 +1,4 @@ +# Saved by trigger.tacacsrc at 2014-03-27 16:10:33 GMT + +EMPTYPWCREDS_uname_ = vjG6C84fD8fLdkVMuX+8Dw== +EMPTYPWCREDS_pwd_ = diff --git a/tests/data/longpw_tacacsrc b/tests/data/longpw_tacacsrc new file mode 100644 index 0000000..ead4de9 --- /dev/null +++ b/tests/data/longpw_tacacsrc @@ -0,0 +1,4 @@ +# Saved by test_tacacsrc at 2014-03-20 15:35:23 GMT + +LONGPWCREDS_uname_ = hpRBGORH+9y7OLTVV2fZcA== +LONGPWCREDS_pwd_ = DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw== diff --git a/tests/data/medium_tacacsrc b/tests/data/medium_tacacsrc new file mode 100644 index 0000000..2efbf07 --- /dev/null +++ b/tests/data/medium_tacacsrc @@ -0,0 +1,4 @@ +# Saved by test_tacacsrc at 2014-03-20 15:35:23 GMT +# +MEDIUMPWCREDS_uname_ = lCyjasq21Yp+ZvqgftGOWw== +MEDIUMPWCREDS_pwd_ = zDZLFvLK8dlXO2tgTeIC3H+2NVzGxQt1zDZLFvLK8dlXO2tgTeIC3H+2NVzGxQt1zDZLFvLK8dlXO2tgTeIC3H+2NVzGxQt1 diff --git a/tests/data/settings.py b/tests/data/settings.py index 584fbf8..026e325 100644 --- a/tests/data/settings.py +++ b/tests/data/settings.py @@ -13,6 +13,12 @@ DEFAULT_REALM = 'aol' TACACSRC_KEYFILE = os.getenv('TACACSRC_KEYFILE', os.path.join(PREFIX, 'tackf')) TACACSRC = os.getenv('TACACSRC', os.path.join(PREFIX, 'tacacsrc')) +RIGHT_TACACSRC = os.getenv('TACACSRC', os.path.join(PREFIX, 'right_tacacsrc')) +MEDIUMPW_TACACSRC = os.getenv('TACACSRC', os.path.join(PREFIX, 'mediumpw_tacacsrc')) +LONGPW_TACACSRC = os.getenv('TACACSRC', os.path.join(PREFIX, 'longpw_tacacsrc')) +BROKENPW_TACACSRC = os.getenv('TACACSRC', os.path.join(PREFIX, 'brokenpw_tacacsrc')) +EMPTYPW_TACACSRC = os.getenv('TACACSRC', os.path.join(PREFIX, 'emptypw_tacacsrc')) + # Configs NETDEVICES_SOURCE = os.environ.get('NETDEVICES_SOURCE', diff --git a/tests/data/tacacsrc b/tests/data/tacacsrc index e0fb33f..83be401 100644 --- a/tests/data/tacacsrc +++ b/tests/data/tacacsrc @@ -1,4 +1,8 @@ -# Dummy .tacacsrc file. Decrypts to user "jschmoe", password "abc123". +# tacacsrc file for test_tacacsrc.py +MEDIUMPWCREDS_uname_ = lCyjasq21Yp+ZvqgftGOWw== +MEDIUMPWCREDS_pwd_ = zDZLFvLK8dlXO2tgTeIC3H+2NVzGxQt1zDZLFvLK8dlXO2tgTeIC3H+2NVzGxQt1zDZLFvLK8dlXO2tgTeIC3H+2NVzGxQt1 +LONGPWCREDS_uname_ = hpRBGORH+9y7OLTVV2fZcA== +LONGPWCREDS_pwd_ = DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw4BARE1wxJ3DgEBETXDEncOAQERNcMSdw== aol_uname_ = xc732xCvl5M= aol_pwd_ = uJ6J2YMUhao= diff --git a/tests/test_tacacsrc.py b/tests/test_tacacsrc.py index bc8c77a..3756102 100644 --- a/tests/test_tacacsrc.py +++ b/tests/test_tacacsrc.py @@ -11,18 +11,42 @@ import os import unittest import tempfile +from mock import patch from trigger.conf import settings from trigger.tacacsrc import Tacacsrc, Credentials # Constants -RIGHT_CREDS = Credentials('jschmoe', 'abc123', 'aol') -RIGHT_TACACSRC = { +aol = Credentials('jschmoe', 'abc123', 'aol') +AOL_TACACSRC = { 'aol_uname_': 'jschmoe', 'aol_pwd_': 'abc123', } RIGHT_PERMS = '0600' +MEDIUMPWCREDS = Credentials('MEDIUMPWCREDS', 'MEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUM', 'MEDIUMPWCREDS') +MEDIUMPW_TACACSRC = { + 'MEDIUMPWCREDS_uname_': 'MEDIUMPWCREDS', + 'MEDIUMPWCREDS_pwd_': 'MEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUMMEDIUM', +} + +LONGPWCREDS = Credentials('LONGPWCREDS', 'LONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONG', 'LONGPWCREDS') +LONGPW_TACACSRC = { + 'LONGPWCREDS_uname_': 'LONGPWCREDS', + 'LONGPWCREDS_pwd_': 'LONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONG', +} + +EMPTYPWCREDS = Credentials('EMPTYPWCREDS', '', 'EMPTYPWCREDS') +EMPTYPW_TACACSRC = { + 'EMPTYPWCREDS_uname_': 'EMPTYPWCREDS', + 'EMPTYPWCREDS_pwd_': '', +} + +LIST_OF_CREDS = ['aol', 'MEDIUMPWCREDS', 'LONGPWCREDS', ] +LIST_OF_TACACSRC = [ AOL_TACACSRC, MEDIUMPW_TACACSRC, LONGPW_TACACSRC ] +ALL_CREDS = [ (name,eval(name)) for name in LIST_OF_CREDS] +ALL_TACACSRC = dict() +[ALL_TACACSRC.update(x) for x in LIST_OF_TACACSRC] def miniparser(data, tcrc): """Manually parse .tacacsrc lines into a dict""" @@ -43,8 +67,9 @@ class TacacsrcTest(unittest.TestCase): def testRead(self): """Test reading .tacacsrc.""" t = Testing_Tacacsrc() - self.assertEqual(t.version, '2.0') - self.assertEqual(t.creds['aol'], RIGHT_CREDS) + for name,value in ALL_CREDS: + self.assertEqual(t.version, '2.0') + self.assertEqual(t.creds['%s' % name], value) def _get_perms(self, filename): """Get octal permissions for a filename""" @@ -55,15 +80,19 @@ def testWrite(self): """Test writing .tacacsrc.""" _, file_name = tempfile.mkstemp('_tacacsrc') t = Testing_Tacacsrc(generate_new=False) - t.creds['aol'] = RIGHT_CREDS - # Overload the default file_name w/ our temp file - t.file_name = file_name - t.write() + + for name,value in ALL_CREDS: + t.creds['%s' % name] = value + # Overload the default file_name w/ our temp file or + # create a new tacacsrc by setting file_name to 'tests/data/tacacsrc' + t.file_name = file_name + t.write() # Read the file we wrote back in and check it against what we think it # should look like. + self.maxDiff = None output = miniparser(t._read_file_old(), t) - self.assertEqual(output, RIGHT_TACACSRC) + self.assertEqual(output, ALL_TACACSRC) # And then compare it against the manually parsed value using # miniparser() @@ -72,6 +101,15 @@ def testWrite(self): self.assertEqual(output, miniparser(lines, t)) os.remove(file_name) + def test_brokenpw(self): + self.assertRaises(ValueError, Testing_Tacacsrc, tacacsrc_file='tests/data/brokenpw_tacacsrc') + + def test_emptypw(self): + devnull = open(os.devnull, 'w') + with patch('trigger.tacacsrc.prompt_credentials', side_effect=KeyError): + with patch('sys.stdout', devnull): + self.assertRaises(KeyError, Testing_Tacacsrc, tacacsrc_file='tests/data/emptypw_tacacsrc') + def test_perms(self): """Test that permissions are being enforced.""" t = Testing_Tacacsrc() diff --git a/trigger/tacacsrc.py b/trigger/tacacsrc.py index 9f31456..14b4aa8 100644 --- a/trigger/tacacsrc.py +++ b/trigger/tacacsrc.py @@ -384,7 +384,7 @@ def _encrypt_old(self, s): # We need to return a newline if a field is empty so as not to break # .tacacsrc parsing (trust me, this is easier) - return encodestring(cryptobj.encrypt(s + padding)) or '\n' + return (encodestring(cryptobj.encrypt(s + padding)).replace('\n', '') or '' ) + '\n' def _decrypt_old(self, s): """Decodes using the old method. Strips newline for you."""