diff options
author | Alois Mahdal <amahdal@redhat.com> | 2014-03-17 21:02:38 +0100 |
---|---|---|
committer | Alois Mahdal <amahdal@redhat.com> | 2014-03-25 10:22:15 +0100 |
commit | 4982dd72dbb5c0441c2fe0e3e213cd25c0424ea7 (patch) | |
tree | e9d6abce6b3b9efcd94df21f448c954d287c2e3d /src/account | |
parent | 1dcddcb94f89be4f06c762ee982c1a4e477abad4 (diff) | |
download | openlmi-providers-4982dd72dbb5c0441c2fe0e3e213cd25c0424ea7.tar.gz openlmi-providers-4982dd72dbb5c0441c2fe0e3e213cd25c0424ea7.tar.xz openlmi-providers-4982dd72dbb5c0441c2fe0e3e213cd25c0424ea7.zip |
account: Add tests for invalid system files
Each test creates an instance it LMI_Account, then intentionally
cripples one of system files related to users/groups, and performs
a simple sanity test that checks if instance properties are readable.
Diffstat (limited to 'src/account')
-rw-r--r-- | src/account/test/TestAccountInvalidEtc.py | 452 | ||||
-rw-r--r-- | src/account/test/common.py | 119 |
2 files changed, 570 insertions, 1 deletions
diff --git a/src/account/test/TestAccountInvalidEtc.py b/src/account/test/TestAccountInvalidEtc.py new file mode 100644 index 0000000..7ed77c3 --- /dev/null +++ b/src/account/test/TestAccountInvalidEtc.py @@ -0,0 +1,452 @@ +# -*- encoding: utf-8 -*- +# Copyright(C) 2012-2013 Red Hat, Inc. All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or(at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Authors: Alois Mahdal <amahdal@redhat.com> + +import sys + +from common import AccountBase, BackupStorage, BaseCrippler +from lmi.shell import LMIInstance + + +## ......................................................................... ## +## Helper functions +## ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ## + +def gen_cripple(*args): + """ + Generator of test methods. Each call to this function adds + one test method to TestAccountInvalidEtc. + + All arguments are passed to PasswdCrippler.cripple. + """ + + def _new_cripple_test(self): + self.crippler.cripple(*args) + self.assertSane() + + meth_name = "test%s_%s_%s" % (path.replace("/", "_"), op, case) + _new_cripple_test.__name__ = meth_name + setattr(TestAccountInvalidEtc, meth_name, _new_cripple_test) + + +## ......................................................................... ## +## Test data (later "converted" to test methods) +## ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ## + +class PasswdCrippler(BaseCrippler): + """ + Cripple files related to user management + """ + + def _define_cases(self): + + data = { + 'ep': '$6$S2M8XGNtfRj/7mnX$Sn8XPyzOFYKSqSYLRlII4wYQc2A' + '.R6gQxh19Oz9e6KHLcCsvLK7ePJWLbZInWktI8/ZaiT/fFA' + 'Tjx6c3Q1A.Y1', + 'o15': 32769, # over 15-bit uint + 'o32': 4294967297, # over 32-bit uint + 'mi': sys.maxint, + 'omi': sys.maxint + 1, + } + + cases = {} + cases['/etc/passwd'] = { + + # syntax traps + 'empty_fields': "::::::", + 'one_field': "user1\n", + 'less_fields': "user1:x:2000:2000:U1:/home/user1", + 'more_fields': "user1:x:2000:2000:U1:/home/user1:/bin/bash:hm", + + # funny + 'pegasus': "pegasus:x:66:65" + ":tog-pegasus OpenPegasus WBEM/CIM services" + ":/var/lib/Pegasus:/sbin/nologin", + 'root': "root:x:0:0:root:/root:/bin/bash", + + # field: name + 'name_empty': ":x:2000:2000:U1:/home/user1:/bin/bash", + 'name_null': "\x00:x:2000:2000:U1:/home/user1:/bin/bash", + 'name_tab': "\x09:x:2000:2000:U1:/home/user1:/bin/bash", + 'name_space': " :x:2000:2000:U1:/home/user1:/bin/bash", + 'name_semicol': ";:x:2000:2000:U1:/home/user1:/bin/bash", + 'name_comma': ",:x:2000:2000:U1:/home/user1:/bin/bash", + 'name_duplicate': "user1:x:2000:2000:U1:/home/user1:/bin/bash\n" + "user1:x:2001:2001:User 2:/home/user2:/bin/bash", + + # field: password + 'password_empty': "user1::2000:2000:U1:/home/user1:/bin/bash", + 'password_null': "user1:\x00:2000:2000:U1:/home/user1:/bin/bash", + 'password_tab': "user1:\x09:2000:2000:U1:/home/user1:/bin/bash", + 'password_space': "user1: :2000:2000:U1:/home/user1:/bin/bash", + 'password_semicol': "user1:;:2000:2000:U1:/home/user1:/bin/bash", + 'password_comma': "user1:,:2000:2000:U1:/home/user1:/bin/bash", + 'password_2aster': "user1:**:2000:2000:U1:/home/user1:/bin/bash", + 'password_2x': "user1:xx:2000:2000:U1:/home/user1:/bin/bash", + 'password_asterx': "user1:*x:2000:2000:U1:/home/user1:/bin/bash", + 'password_xaster': "user1:x*:2000:2000:U1:/home/user1:/bin/bash", + + # field: uid + 'uid_empty': "user1:x::2000:U1:/home/user1:/bin/bash", + 'uid_null': "user1:x:\x00:2000:U1:/home/user1:/bin/bash", + 'uid_tab': "user1:x:\x09:2000:U1:/home/user1:/bin/bash", + 'uid_space': "user1:x: :2000:U1:/home/user1:/bin/bash", + 'uid_semicol': "user1:x:;:2000:U1:/home/user1:/bin/bash", + 'uid_comma': "user1:x:,:2000:U1:/home/user1:/bin/bash", + 'uid_string': "user1:x:hey:2000:U1:/home/user1:/bin/bash", + 'uid_negative': "user1:x:-2000:2000:U1:/home/user1:/bin/bash", + 'uid_over15': "user1:x:%(o15)d:2000:U1:/home/user1:/bin/bash", + 'uid_over32': "user1:x:%(o32)d:2000:U1:/home/user1:/bin/bash", + 'uid_over_maxint': "user1:x:%(omi)d:2000:U1:/home/user1:/bin/sh", + 'uid_maxint': "user1:x:%(mi)d:2000:U1:/home/user1:/bin/bash", + 'uid_duplicate': "user1:x:2000:2000:U1:/home/user1:/bin/bash\n" + "user2:x:2000:2001:User 2:/home/user2:/bin/bash", + + # field: gid + 'gid_empty': "user1:x:2000::U1:/home/user1:/bin/bash", + 'gid_null': "user1:x:2000:\x00:U1:/home/user1:/bin/bash", + 'gid_tab': "user1:x:2000:\x09:U1:/home/user1:/bin/bash", + 'gid_space': "user1:x:2000: :U1:/home/user1:/bin/bash", + 'gid_semicol': "user1:x:2000:;:U1:/home/user1:/bin/bash", + 'gid_comma': "user1:x:2000:,:U1:/home/user1:/bin/bash", + 'gid_string': "user1:x:2000:hey:U1:/home/user1:/bin/bash", + 'gid_negative': "user1:x:2000:-2000:U1:/home/user1:/bin/bash", + 'gid_over15': "user1:x:2000:%(o15)d:U1:/home/user1:/bin/bash", + 'gid_over32': "user1:x:2000:%(o32)d:U1:/home/user1:/bin/bash", + 'gid_over_maxint': "user1:x:2000:%(omi)d:U1:/home/user1:/bin/sh", + 'gid_maxint': "user1:x:2000:%(mi)d:U1:/home/user1:/bin/bash", + 'gid_duplicate': "user1:x:2000:2000:U1:/home/user1:/bin/bash\n" + "user2:x:2001:2000:User 2:/home/user2:/bin/bash", + + # field: directory + 'directory_empty': "user1:x:2000:2000:U1::/bin/bash", + 'directory_null': "user1:x:2000:2000:U1:\x00:/bin/bash", + 'directory_tab': "user1:x:2000:2000:U1:\x09:/bin/bash", + + } + + cases['/etc/group'] = { + + # a valid line as a template + 'valid': "group1:x:2000:user1,user2,user3", + + # syntax traps + 'empty_fields': ":::", + 'one_field': "group1\n", + 'less_fields': "group1:x:user1,user2,user3", + 'more_fields': "group1:x:2000:user1,user2,user3:hey", + + # funny + 'pegasus': "pegasus:x:65:", + 'root': "root:x:0:", + + # field: name + 'name_empty': ":x:2000:user1,user2,user3", + 'name_null': "\x00:x:2000:user1,user2,user3", + 'name_tab': "\x09:x:2000:user1,user2,user3", + 'name_space': " :x:2000:user1,user2,user3", + 'name_semicol': ";:x:2000:user1,user2,user3", + 'name_comma': ",:x:2000:user1,user2,user3", + 'name_duplicate': "group1:x:2000:user1,user2,user3\n" + "group1:x:2001:user1,user2,user3", + + # field: password + 'password_empty': "group1::2000:user1,user2,user3", + 'password_null': "group1:\x00:2000:user1,user2,user3", + 'password_tab': "group1:\x09:2000:user1,user2,user3", + 'password_space': "group1: :2000:user1,user2,user3", + 'password_semicol': "group1:;:2000:user1,user2,user3", + 'password_comma': "group1:,:2000:user1,user2,user3", + 'password_2aster': "group1:**:2000:user1,user2,user3", + 'password_2x': "group1:xx:2000:user1,user2,user3", + 'password_asterx': "group1:*x:2000:user1,user2,user3", + 'password_xaster': "group1:x*:2000:user1,user2,user3", + + # field: gid + 'gid_empty': "group1:x::user1,user2,user3", + 'gid_null': "group1:x:\x00:user1,user2,user3", + 'gid_tab': "group1:x:\x09:user1,user2,user3", + 'gid_space': "group1:x: :user1,user2,user3", + 'gid_semicol': "group1:x:;:user1,user2,user3", + 'gid_comma': "group1:x:,:user1,user2,user3", + 'gid_string': "group1:x:hey:user1,user2,user3", + 'gid_negative': "group1:x:-2000:user1,user2,user3", + 'gid_over15': "group1:x:%(o15)d:user1,user2,user3", + 'gid_over32': "group1:x:%(o32)d:user1,user2,user3", + 'gid_over_maxint': "group1:x:%(omi)d:user1.user2,user3", + 'gid_maxint': "group1:x:%(mi)d:user1,user2,user3", + 'gid_duplicate': "group1:x:2000:user1,user2,user3" + "user2:x:2000:user1,user2,user3", + + # field: ulist + 'ulist_null': "group1:x:2000:\x00", + 'ulist_tab': "group1:x:2000:\x09", + 'ulist_space': "group1:x:2000: ", + 'ulist_semicol': "group1:x:2000:;", + 'ulist_nulls': "group1:x:2000:\x00,\x00", + 'ulist_tabs': "group1:x:2000:\x09,\x09", + 'ulist_spaces': "group1:x:2000: , ", + 'ulist_semicols': "group1:x:2000:;,;", + 'ulist_comma': "group1:x:2000:,", + + } + + cases['/etc/shadow'] = { + + # a valid line as a template + 'valid': "user1:%(ep)s:16118:0:99999:7:::", + + # syntax traps + 'empty_fields': "::::::::", + 'one_field': "user1\n", + 'less_fields': "user1:%(ep)s:16118:0:99999:7::", + 'more_fields': "user1:%(ep)s:16118:0:99999:7::::hey", + + # funny + 'pegasus': "pegasus:$6$1.d1PKQWTeS.8eXI$qM5NXh0a9RRv7ajn" + "Sigd1wBqZp9l2.cVlJfPtybJUxbilM7HScfv.kW6EWcU" + "YKd3mU2bszTiQab0tKgmehzz5.:16146::::::", + 'root': "root:$6$s//AqmEc2gzQyFuL$9rUPnSPE6uYpDTBCiel" + "tHK5.5I0iJiiJva4bPnD5QH6/6iFKzJ32Lcrxxszz9In" + "BuorKT3ypIHeHeGvPkaPfO/:16118:0:99999:7:::", + + # field: name + 'name_empty': ":%(ep)s:16118:0:99999:7:::", + 'name_null': "\x00:%(ep)s:16118:0:99999:7:::", + 'name_tab': "\x09:%(ep)s:16118:0:99999:7:::", + 'name_space': " :%(ep)s:16118:0:99999:7:::", + 'name_semicol': ";:%(ep)s:16118:0:99999:7:::", + 'name_comma': ",:%(ep)s:16118:0:99999:7:::", + 'name_duplicate': "user1:%(ep)s:16118:0:99999:7:::\n" + "user1:%(ep)s:16118:0:99999:7:::", + + # field: password + 'password_empty': "user1:%(ep)s:16118:0:99999:7:::", + 'password_null': "user1:%(ep)s:16118:0:99999:7:::", + 'password_tab': "user1:%(ep)s:16118:0:99999:7:::", + 'password_space': "user1:%(ep)s:16118:0:99999:7:::", + 'password_semicol': "user1:%(ep)s:16118:0:99999:7:::", + 'password_comma': "user1:%(ep)s:16118:0:99999:7:::", + 'password_2aster': "user1:%(ep)s:16118:0:99999:7:::", + 'password_2x': "user1:%(ep)s:16118:0:99999:7:::", + 'password_asterx': "user1:%(ep)s:16118:0:99999:7:::", + 'password_xaster': "user1:%(ep)s:16118:0:99999:7:::", + + # field: last change + 'lastch_empty': "user1:%(ep)s::0:99999:7:::", + 'lastch_null': "user1:%(ep)s:\x00:0:99999:7:::", + 'lastch_tab': "user1:%(ep)s:\x09:0:99999:7:::", + 'lastch_space': "user1:%(ep)s: :0:99999:7:::", + 'lastch_semicol': "user1:%(ep)s:;:0:99999:7:::", + 'lastch_comma': "user1:%(ep)s:,:0:99999:7:::", + 'lastch_string': "user1:%(ep)s:hey:0:99999:7:::", + 'lastch_negative': "user1:%(ep)s:-42:0:99999:7:::", + 'lastch_over15': "user1:%(ep)s:%(o15)d:0:99999:7:::", + 'lastch_over32': "user1:%(ep)s:%(o32)d:0:99999:7:::", + 'lastch_over_maxint': "user1:%(ep)s:%(omi)d:0:99999:7:::", + 'lastch_maxint': "user1:%(ep)s:%(mi)d:0:99999:7:::", + + # field: minimum age + 'minage_empty': "user1:%(ep)s:16118::99999:7:::", + 'minage_null': "user1:%(ep)s:16118:\x00:99999:7:::", + 'minage_tab': "user1:%(ep)s:16118:\x09:99999:7:::", + 'minage_space': "user1:%(ep)s:16118: :99999:7:::", + 'minage_semicol': "user1:%(ep)s:16118:;:99999:7:::", + 'minage_comma': "user1:%(ep)s:16118:,:99999:7:::", + 'minage_string': "user1:%(ep)s:16118:hey:99999:7:::", + 'minage_negative': "user1:%(ep)s:16118:-42:99999:7:::", + 'minage_over15': "user1:%(ep)s:16118:%(o15)d:99999:7:::", + 'minage_over32': "user1:%(ep)s:16118:%(o32)d:99999:7:::", + 'minage_over_maxint': "user1:%(ep)s:16118:%(omi)d:99999:7:::", + 'minage_maxint': "user1:%(ep)s:16118:%(mi)d:99999:7:::", + + # field: maximum age + 'maxage_empty': "user1:%(ep)s:16118:0::7:::", + 'maxage_null': "user1:%(ep)s:16118:0:\x00:7:::", + 'maxage_tab': "user1:%(ep)s:16118:0:\x09:7:::", + 'maxage_space': "user1:%(ep)s:16118:0: :7:::", + 'maxage_semicol': "user1:%(ep)s:16118:0:;:7:::", + 'maxage_comma': "user1:%(ep)s:16118:0:,:7:::", + 'maxage_string': "user1:%(ep)s:16118:0:hey:7:::", + 'maxage_negative': "user1:%(ep)s:16118:0:-42:7:::", + 'maxage_over15': "user1:%(ep)s:16118:0:%(o15)d:7:::", + 'maxage_over32': "user1:%(ep)s:16118:0:%(o32)d:7:::", + 'maxage_over_maxint': "user1:%(ep)s:16118:0:%(omi)d:7:::", + 'maxage_maxint': "user1:%(ep)s:16118:0:%(mi)d:7:::", + + # field: warning period + 'wperiod_empty': "user1:%(ep)s:16118:0:99999::::", + 'wperiod_null': "user1:%(ep)s:16118:0:99999:\x00:::", + 'wperiod_tab': "user1:%(ep)s:16118:0:99999:\x09:::", + 'wperiod_space': "user1:%(ep)s:16118:0:99999: :::", + 'wperiod_semicol': "user1:%(ep)s:16118:0:99999:;:::", + 'wperiod_comma': "user1:%(ep)s:16118:0:99999:,:::", + 'wperiod_string': "user1:%(ep)s:16118:0:99999:hey:::", + 'wperiod_negative': "user1:%(ep)s:16118:0:99999:-42:::", + 'wperiod_over15': "user1:%(ep)s:16118:0:99999:%(o15)d:::", + 'wperiod_over32': "user1:%(ep)s:16118:0:99999:%(o32)d:::", + 'wperiod_over_maxint': "user1:%(ep)s:16118:0:99999:%(omi)d:::", + 'wperiod_maxint': "user1:%(ep)s:16118:0:99999:%(mi)d:::", + + # field: inactivity period + 'iperiod_empty': "user1:%(ep)s:16118:0:99999:7:::", + 'iperiod_null': "user1:%(ep)s:16118:0:99999:7:\x00::", + 'iperiod_tab': "user1:%(ep)s:16118:0:99999:7:\x09::", + 'iperiod_space': "user1:%(ep)s:16118:0:99999:7: ::", + 'iperiod_semicol': "user1:%(ep)s:16118:0:99999:7:;::", + 'iperiod_comma': "user1:%(ep)s:16118:0:99999:7:,::", + 'iperiod_string': "user1:%(ep)s:16118:0:99999:7:hey::", + 'iperiod_negative': "user1:%(ep)s:16118:0:99999:7:-42::", + 'iperiod_over15': "user1:%(ep)s:16118:0:99999:7:%(o15)d::", + 'iperiod_over32': "user1:%(ep)s:16118:0:99999:7:%(o32)d::", + 'iperiod_over_maxint': "user1:%(ep)s:16118:0:99999:7:%(omi)d::", + 'iperiod_maxint': "user1:%(ep)s:16118:0:99999:7:%(mi)d::", + + # field: account expiration date + 'expdate_empty': "user1:%(ep)s:16118:0:99999:7:::", + 'expdate_null': "user1:%(ep)s:16118:0:99999:7::\x00:", + 'expdate_tab': "user1:%(ep)s:16118:0:99999:7::\x09:", + 'expdate_space': "user1:%(ep)s:16118:0:99999:7:: :", + 'expdate_semicol': "user1:%(ep)s:16118:0:99999:7::;:", + 'expdate_comma': "user1:%(ep)s:16118:0:99999:7::,:", + 'expdate_string': "user1:%(ep)s:16118:0:99999:7::hey:", + 'expdate_negative': "user1:%(ep)s:16118:0:99999:7::-42:", + 'expdate_over15': "user1:%(ep)s:16118:0:99999:7::%(o15)d:", + 'expdate_over32': "user1:%(ep)s:16118:0:99999:7::%(o32)d:", + 'expdate_over_maxint': "user1:%(ep)s:16118:0:99999:7::%(omi)d:", + 'expdate_maxint': "user1:%(ep)s:16118:0:99999:7::%(mi)d:", + + } + + cases['/etc/gshadow'] = { + + # a valid line as a template + 'valid': "group1:%(ep)s:user1,user2:user3,user4", + + # syntax traps + 'empty_fields': ":::", + 'one_field': "user1\n", + 'less_fields': "group1:%(ep)s:user1,user2", + 'more_fields': "group1:%(ep)s:user1,user2:user3,user4:hey", + + # funny + 'pegasus': "pegasus:!::", + 'root': "root:::", + + # field: name + 'name_empty': ":%(ep)s:user1,user2:user3,user4", + 'name_null': "\x00:%(ep)s:user1,user2:user3,user4", + 'name_tab': "group1:%(ep)s:user1,user2:user3,user4", + 'name_space': "group1:%(ep)s:user1,user2:user3,user4", + 'name_semicol': "group1:%(ep)s:user1,user2:user3,user4", + 'name_comma': "group1:%(ep)s:user1,user2:user3,user4", + 'name_duplicate': "group1:%(ep)s:user1,user2:user3,user4\n" + "group1:%(ep)s:user1,user2:user3,user4", + + # field: password + 'password_empty': "group1::user1,user2:user3,user4", + 'password_null': "group1:\x00:user1,user2:user3,user4", + 'password_tab': "group1:\x09:user1,user2:user3,user4", + 'password_space': "group1: :user1,user2:user3,user4", + 'password_semicol': "group1:;:user1,user2:user3,user4", + 'password_comma': "group1:,:user1,user2:user3,user4", + 'password_2aster': "group1:**:user1,user2:user3,user4", + 'password_2x': "group1:xx:user1,user2:user3,user4", + 'password_asterx': "group1:*x:user1,user2:user3,user4", + 'password_xaster': "group1:x*:user1,user2:user3,user4", + + # field: alist + 'alist_null': "group1:%(ep)s:\x00:user3,user4", + 'alist_tab': "group1:%(ep)s:\x00:user3,user4", + 'alist_space': "group1:%(ep)s: :user3,user4", + 'alist_semicol': "group1:%(ep)s:;:user3,user4", + 'alist_nulls': "group1:%(ep)s:\x00,\x00:user3,user4", + 'alist_tabs': "group1:%(ep)s:\x09,\x09:user3,user4", + 'alist_spaces': "group1:%(ep)s: , :user3,user4", + 'alist_semicols': "group1:%(ep)s:;,;:user3,user4", + 'alist_comma': "group1:%(ep)s:,:user3,user4", + + # field: ulist + 'ulist_null': "group1:%(ep)s:user1,user2:\x00", + 'ulist_tab': "group1:%(ep)s:user1,user2:\x00", + 'ulist_space': "group1:%(ep)s:user1,user2: ", + 'ulist_semicol': "group1:%(ep)s:user1,user2:;", + 'ulist_nulls': "group1:%(ep)s:user1,user2:\x00,\x00", + 'ulist_tabs': "group1:%(ep)s:user1,user2:\x09,\x09", + 'ulist_spaces': "group1:%(ep)s:user1,user2: , ", + 'ulist_semicols': "group1:%(ep)s:user1,user2:;,;", + 'ulist_comma': "group1:%(ep)s:user1,user2:,", + + } + + # add common cases + # + for key in cases: + cases[key]['many_fields'] = ":".join(["field"] * 5000) + + # expand data + for path in cases: + for case in cases[path]: + cases[path][case] = cases[path][case] % data + + return cases + + +## ......................................................................... ## +## Actual test +## ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ## + +class TestAccountInvalidEtc(AccountBase): + + CLASS_NAME = "LMI_Account" + + def setUp(self): + self.bs = BackupStorage() + self.bs.add_file("/etc/passwd") + self.bs.add_file("/etc/shadow") + self.bs.add_file("/etc/group") + self.bs.add_file("/etc/gshadow") + self.inst = self.cim_class.first_instance() + self.addCleanup(self.bs.restore_all) + self.crippler = PasswdCrippler() + + def assertSane(self): + """ + Assert that main properties can be read + """ + self.assertIsInstance(self.inst, LMIInstance) + # check if it provides key properties + for attr in ['CreationClassName', 'Name', 'SystemCreationClassName', + 'SystemName']: + self.assertIsNotNone(self.inst.properties_dict()[attr]) + + # check if it provides other properties, which should be set + for attr in ['host', 'UserID', 'UserPassword', 'UserPasswordEncoding']: + self.assertIsNotNone(self.inst.properties_dict()[attr]) + +## +## Here test methods are generated from data in PasswdCrippler instance, +# + +crippler = PasswdCrippler() + +for path in crippler.all_paths(): + for case in crippler.all_cases_for(path): + for op in ['append', 'replace']: + gen_cripple(path, case, op) diff --git a/src/account/test/common.py b/src/account/test/common.py index 2b3b423..862d1d4 100644 --- a/src/account/test/common.py +++ b/src/account/test/common.py @@ -13,7 +13,7 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Authors: Roman Rakus <rrakus@redhat.com> # @@ -24,6 +24,7 @@ Base class and utilities for all OpenLMI Account tests. import hashlib import os import tempfile +import string import subprocess from collections import Counter from collections import OrderedDict @@ -202,3 +203,119 @@ class BackupStorage(): Destroy the temporary backup """ subprocess.call(["rm", "-rf", self.root]) + + +class BaseCrippler: + """ + Helper class for crippling system files. + + To use the class, you need to sub-class it and implement + _define_cases method. + """ + + LINE_LENGTH = 500 + LINE_COUNT = 50 + BINARY_LENGTH = 10 * 1024 * 1024 + + ## virtual + # + + def _define_cases(self): + """ + Define cases per file supported + + This function must return a dict with one set of cases per + file: key is path and value is another dict defining cases + as pairs of name ([a-zA-Z_]) and content. + + Quick example: + + { + '/etc/file1': { + 'case1': "some triggering content", + 'case2': "some other triggering content", + 'case3': "some funny triggering content", + }, + '/etc/file2': { + 'case1': "some triggering content", + 'case2': "some other triggering content", + 'case3': "some funny triggering content", + }, + } + + Note that trailing newline is added automatically to each content + string. Also, whether content will be appended or replaced is decided + by caller of the BaseCrippler.cripple method. + """ + pass + + ## internal + # + + def __init__(self): + self.autocases = { + 'empty': lambda: '', + 'random_line': self._random_line, + 'random_lines': self._random_lines, + 'random_binary': self._random_binary, + } + self.cases = self._define_cases() + + def _append_to(self, path, content): + with open(path, 'a+') as fh: + fh.write(content) + + def _clobber(self, path, content): + with open(path, 'w+') as fh: + fh.write(content) + + def _random_binary(self, size=BINARY_LENGTH): + chars = ''.join([chr(i) for i in xrange(256)]) + return methods.random_string(size, chars) + + def _random_line(self, size=LINE_LENGTH): + chars = string.letters + string.punctuation + " \t" + return methods.random_string(size, chars) + "\n" + + def _random_lines(self, size=LINE_LENGTH, count=LINE_COUNT): + return "".join([self._random_line(size) for i in xrange(count)]) + + def _get_content(self, path, case): + + try: + content = self.autocases[case]() + except KeyError: + try: + content = self.cases[path][case] + "\n" + except KeyError: + raise ValueError("unknown case: %s for: %s" % (case, path)) + return content + + ## public + # + + def all_cases_for(self, path): + """ + Return list of cases available for path + """ + return self.cases[path].keys() + self.autocases.keys() + + def all_paths(self): + """ + Return list of paths served by this implementation + """ + return self.cases.keys() + + def cripple(self, path, case, op="replace"): + """ + Cripple file according to selected case. + + op is either "append" or "replace" and means that the content will + be appended to the file, otherwise it will replace it. + """ + if op == 'replace': + self._clobber(path, self._get_content(path, case)) + elif op == 'append': + self._append_to(path, self._get_content(path, case)) + else: + raise ValueError("unknown op: %s" % op) |