Ignore:
Timestamp:
4 Apr 2013, 15:12:43 (12 years ago)
Author:
uli
Message:

Provide infrastructure to remember failed logins.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/tests/test_authentication.py

    r8427 r10055  
    1717##
    1818import grok
     19import logging
     20import time
    1921import unittest
     22from cStringIO import StringIO
     23from zope.component import getGlobalSiteManager
    2024from zope.component.hooks import setSite, clearSite
    2125from zope.interface.verify import verifyClass, verifyObject
     26from zope.password.testing import setUpPasswordManagers
    2227from zope.pluggableauth.interfaces import IAuthenticatorPlugin
    2328from zope.securitypolicy.interfaces import IPrincipalRoleManager
    2429from waeup.kofa.testing import FunctionalTestCase, FunctionalLayer
    2530from waeup.kofa.authentication import (
    26     UserAuthenticatorPlugin, Account, KofaPrincipalInfo,
    27     get_principal_role_manager)
     31    UserAuthenticatorPlugin, Account, KofaPrincipalInfo, FailedLoginInfo,
     32    get_principal_role_manager, UsersPlugin,)
     33from waeup.kofa.interfaces import (
     34    IUserAccount, IFailedLoginInfo, IKofaPrincipalInfo, IKofaPluggable)
    2835
    2936class FakeSite(grok.Site, grok.Container):
     37    #def getSiteManager(self):
     38    #    return None
     39    #    return getGlobalSiteManager()
    3040    pass
    3141
     
    8797        self.assertTrue(hasattr(prm2, '_context') is False)
    8898        return
     99
     100    def make_failed_logins(self, num):
     101        # do `num` failed logins and a valid one afterwards
     102        del self.site['users']
     103        self.site['users'] = {'bob': Account('bob', 'secret')}
     104        plugin = UserAuthenticatorPlugin()
     105        resultlist = []
     106        # reset accounts
     107        for x in range(num):
     108            resultlist.append(plugin.authenticateCredentials(
     109                dict(login='bob', password='wrongsecret')))
     110        resultlist.append(plugin.authenticateCredentials(
     111            dict(login='bob', password='secret')))
     112        return resultlist
     113
     114    def DISABLED_test_failed_logins(self):
     115        # after three failed logins, an account is blocked
     116        # XXX: this tests authenticator with time penalty (currently
     117        # disabled)
     118        results = []
     119        succ_principal = KofaPrincipalInfo(
     120            id='bob',
     121            title='bob',
     122            description=None,
     123            email=None,
     124            phone=None,
     125            public_name=None,
     126            user_type=u'user')
     127        for x in range(4):
     128            results.append(self.make_failed_logins(x))
     129        self.assertEqual(results[2], [None, None, succ_principal])
     130        # last login was blocked although correctly entered due to
     131        # time penalty
     132        self.assertEqual(results[3], [None, None, None, None])
     133        return
     134
     135class KofaPrincipalInfoTests(unittest.TestCase):
     136
     137    def create_info(self):
     138        return KofaPrincipalInfo(
     139            id='bob',
     140            title='bob',
     141            description=None,
     142            email=None,
     143            phone=None,
     144            public_name=None,
     145            user_type=u'user')
     146
     147    def test_iface(self):
     148        # make sure we implement the promised interfaces
     149        info = self.create_info()
     150        verifyClass(IKofaPrincipalInfo, KofaPrincipalInfo)
     151        verifyObject(IKofaPrincipalInfo, info)
     152        return
     153
     154    def test_equality(self):
     155        # we can test two infos for equality
     156        info1 = self.create_info()
     157        info2 = self.create_info()
     158        self.assertEqual(info1, info2)
     159        self.assertTrue(info1 == info2)
     160        info1.id = 'blah'
     161        self.assertTrue(info1 != info2)
     162        self.assertTrue((info1 == info2) is False)
     163        info1.id = 'bob'
     164        info2.id = 'blah'
     165        self.assertTrue(info1 != info2)
     166        self.assertTrue((info1 == info2) is False)
     167        return
     168
     169class FailedLoginInfoTests(unittest.TestCase):
     170
     171    def test_iface(self):
     172        # make sure we fullfill the promised interfaces
     173        info1 = FailedLoginInfo()
     174        info2 = FailedLoginInfo(num=1, last=time.time())
     175        self.assertTrue(
     176            verifyClass(IFailedLoginInfo, FailedLoginInfo))
     177        self.assertTrue(verifyObject(IFailedLoginInfo, info1))
     178        # make sure the stored values have correct type if not None
     179        self.assertTrue(verifyObject(IFailedLoginInfo, info2))
     180        return
     181
     182    def test_default_values(self):
     183        # By default we get 0, None
     184        info = FailedLoginInfo()
     185        self.assertEqual(info.num, 0)
     186        self.assertEqual(info.last, None)
     187        return
     188
     189    def test_set_values_by_attribute(self):
     190        # we can set values by attribute
     191        ts = time.gmtime(0)
     192        info = FailedLoginInfo()
     193        info.num = 5
     194        info.last = ts
     195        self.assertEqual(info.num, 5)
     196        self.assertEqual(info.last, ts)
     197        return
     198
     199    def test_set_values_by_constructor(self):
     200        # we can set values by constructor args
     201        ts = time.gmtime(0)
     202        info = FailedLoginInfo(5, ts)
     203        self.assertEqual(info.num, 5)
     204        self.assertEqual(info.last, ts)
     205        return
     206
     207    def test_set_values_by_keywords(self):
     208        # we can set values by constructor keywords
     209        ts = time.gmtime(0)
     210        info = FailedLoginInfo(last=ts, num=3)
     211        self.assertEqual(info.num, 3)
     212        self.assertEqual(info.last, ts)
     213        return
     214
     215    def test_as_tuple(self):
     216        # we can get the info values as tuple
     217        ts = time.gmtime(0)
     218        info = FailedLoginInfo(last=ts, num=3)
     219        self.assertEqual(info.as_tuple(), (3, ts))
     220        return
     221
     222    def test_set_values(self):
     223        # we can set the values of a an info instance
     224        ts = time.time()
     225        info = FailedLoginInfo()
     226        info.set_values(num=3, last=ts)
     227        self.assertEqual(info.num, 3)
     228        self.assertEqual(info.last, ts)
     229        return
     230
     231    def test_increase(self):
     232        # we can increase the number of failed logins
     233        ts1 = time.time()
     234        info = FailedLoginInfo()
     235        info.increase()
     236        self.assertEqual(info.num, 1)
     237        self.assertTrue(info.last > ts1)
     238        ts2 = info.last
     239        info.increase()
     240        self.assertEqual(info.num, 2)
     241        self.assertTrue(info.last > ts2)
     242        return
     243
     244    def test_reset(self):
     245        # we can reset failed login infos.
     246        info = FailedLoginInfo()
     247        info.increase()
     248        info.reset()
     249        self.assertEqual(info.num, 0)
     250        self.assertEqual(info.last, None)
     251        return
     252
     253class AccountTests(unittest.TestCase):
     254
     255    def setUp(self):
     256        setUpPasswordManagers()
     257        return
     258
     259    def test_iface(self):
     260        acct = Account('bob', 'mypasswd')
     261        self.assertTrue(
     262            verifyClass(IUserAccount, Account))
     263        self.assertTrue(
     264            verifyObject(IUserAccount, acct))
     265        return
     266
     267    def test_failed_logins(self):
     268        # we can retrieve infos about failed logins
     269        ts = time.time()
     270        acct = Account('bob', 'mypasswd')
     271        self.assertTrue(hasattr(acct, 'failed_logins'))
     272        acct.failed_logins.set_values(num=3, last=ts)
     273        self.assertEqual(acct.failed_logins.last, ts)
     274        self.assertEqual(acct.failed_logins.num, 3)
     275        return
     276
     277    def test_failed_logins_per_inst(self):
     278        # we get a different counter for each Account instance
     279        acct1 = Account('bob', 'secret')
     280        acct2 = Account('alice', 'alsosecret')
     281        self.assertTrue(acct1.failed_logins is not acct2.failed_logins)
     282        return
     283
     284class FakeUserAccount(object):
     285    pass
     286
     287class UsersPluginTests(unittest.TestCase):
     288
     289    def setUp(self):
     290        setUpPasswordManagers()
     291        self.site = FakeSite()
     292        self.site['users'] = grok.Container()
     293        return
     294
     295    def get_logger(self):
     296        logger = logging.getLogger('waeup.test')
     297        stream = StringIO()
     298        handler = logging.StreamHandler(stream)
     299        logger.setLevel(logging.DEBUG)
     300        logger.propagate = False
     301        logger.addHandler(handler)
     302        return logger, stream
     303
     304    def test_ifaces(self):
     305        # make sure we implement the promised interfaces
     306        plugin = UsersPlugin()
     307        verifyClass(IKofaPluggable, UsersPlugin)
     308        verifyObject(IKofaPluggable, plugin)
     309        return
     310
     311    def test_update(self):
     312        # make sure user accounts are updated properly.
     313        plugin = UsersPlugin()
     314        logger, stream = self.get_logger()
     315        plugin.update(self.site, 'app', logger)
     316        stream.seek(0)
     317        self.assertEqual(stream.read(), '')
     318        self.site['users']['bob'] = FakeUserAccount()
     319        logger, stream = self.get_logger()
     320        plugin.update(self.site, 'app', logger)
     321        stream.seek(0)
     322        log_content = stream.read()
     323        self.assertTrue(hasattr(self.site['users']['bob'], 'description'))
     324        self.assertTrue(hasattr(self.site['users']['bob'], 'failed_logins'))
     325        self.assertTrue(
     326            isinstance(self.site['users']['bob'].failed_logins,
     327                       FailedLoginInfo))
     328        self.assertTrue('attribute description added' in log_content)
     329        self.assertTrue('attribute failed_logins added' in log_content)
     330        return
Note: See TracChangeset for help on using the changeset viewer.