source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/tests/test_authentication.py @ 6428

Last change on this file since 6428 was 6412, checked in by uli, 14 years ago

Fix test.

File size: 13.3 KB
Line 
1##
2## test_authentication.py
3## Login : <uli@pu.smp.net>
4## Started on  Fri Aug 20 08:18:58 2010 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2010 Uli Fouquet
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
22import grok
23import shutil
24import tempfile
25import unittest
26from zope.app.testing.functional import FunctionalTestCase
27from zope.authentication.interfaces import IAuthentication
28from zope.component import provideAdapter, getUtility
29from zope.component.hooks import setSite, clearSite
30from zope.interface import verify
31from zope.pluggableauth.interfaces import  IAuthenticatedPrincipalFactory
32from zope.publisher.browser import TestRequest
33from zope.publisher.interfaces import IRequest
34from zope.session.interfaces import ISession
35from zope.site import LocalSiteManager
36from zope.testbrowser.testing import Browser
37from zope.testing import cleanup
38from waeup.sirp.testing import FunctionalLayer
39from waeup.sirp.app import University
40from waeup.sirp.applicants import  ApplicantsContainer, Applicant
41from waeup.sirp.applicants.authentication import (
42    ApplicantsAuthenticatorPlugin, WAeUPApplicantCredentialsPlugin,
43    ApplicantCredentials, AuthenticatedApplicantPrincipalFactory,
44    ApplicantPrincipalInfo, ApplicantPrincipal,)
45
46
47class FakeBatch(dict):
48    def getAccessCode(self, id):
49        return self.get(id)
50
51class FakeAccessCode(object):
52    def __init__(self, repr, inv_date=None, disabled=False):
53        self.used = inv_date is not None
54        self.representation = repr
55        self.disabled = disabled
56
57class FakeInvAccessCode(object):
58    invalidation_date = True
59
60class FakeApplication(object):
61    def __init__(self, ac=None):
62        self.access_code = ac
63
64def FakeSite():
65    return {
66        'applicants': {
67            'APP': {
68                'APP-12345': FakeApplication(u'APP-12345'),
69                'APP-54321': FakeApplication(u'APP-54321'),
70                'APP-22222': FakeApplication(u'APP-OTHER'),
71                'APP-44444': FakeApplication(),
72                'APP-55555': FakeApplication(u'APP-OTHER'),
73                },
74            'JAMB': {
75                'JAMB1': FakeApplication(),
76                'JAMB2': FakeApplication(u'APP-12345'),
77                'JAMB3': FakeApplication(u'APP-54321'),
78                'JAMB4': FakeApplication(u'APP-44444'),
79                },
80            },
81        'accesscodes': {
82            'APP': FakeBatch({
83                    'APP-12345': FakeAccessCode('APP-12345'),
84                    'APP-54321': FakeAccessCode('APP-54321', True),
85                    'APP-11111': FakeAccessCode('APP-11111'),
86                    'APP-22222': FakeAccessCode('APP-22222'),
87                    'APP-33333': FakeAccessCode('APP-33333', True),
88                    'APP-44444': FakeAccessCode('APP-44444', True),
89                    'APP-55555': FakeAccessCode('APP-55555', True),
90                    'APP-66666': FakeAccessCode('APP-66666', True, False),
91                    'APP-77777': FakeAccessCode('APP-77777', False, False),
92                    })
93            }
94        }
95
96class AuthenticatorPluginTest(FunctionalTestCase):
97
98    layer = FunctionalLayer
99
100    def create_applicant(self, cname, aname, ac=None):
101        # Create an applicant in an applicants container
102        setSite(self.app)
103        if not cname in self.app['applicants'].keys():
104            container = ApplicantsContainer()
105            self.app['applicants'][cname] = container
106        applicant = Applicant()
107        if ac is not None:
108            applicant.access_code = ac
109        self.app['applicants'][cname][aname] = applicant
110        return
111
112    def setUp(self):
113        super(AuthenticatorPluginTest, self).setUp()
114
115        # Setup a sample site for each test
116        app = University()
117        self.dc_root = tempfile.mkdtemp()
118        app['datacenter'].setStoragePath(self.dc_root)
119
120        # Prepopulate the ZODB...
121        self.getRootFolder()['app'] = app
122        self.app = self.getRootFolder()['app']
123
124        fake_site = FakeSite()
125        for ckey, fake_container in fake_site['applicants'].items():
126            for akey, fake_appl in fake_container.items():
127                self.create_applicant(ckey, akey, fake_appl.access_code)
128        del self.app['accesscodes']
129        self.app['accesscodes'] = fake_site['accesscodes']
130
131        self.plugin = ApplicantsAuthenticatorPlugin()
132        return
133
134    def tearDown(self):
135        super(AuthenticatorPluginTest, self).tearDown()
136        shutil.rmtree(self.dc_root)
137        return
138
139    def test_invalid_credentials(self):
140        result = self.plugin.authenticateCredentials('not-a-dict')
141        assert result is None
142
143        result = self.plugin.authenticateCredentials(
144            dict(accesscode=None, foo='blah'))
145        assert result is None
146
147        result = self.plugin.authenticateCredentials(
148            dict(accesscode='Nonsense',))
149        assert result is None
150
151        # Possible cases, where formal correct authentication
152        # data is not valid:
153        result = self.plugin.authenticateCredentials(
154            dict(accesscode='APP-33333'))
155        assert result is None
156
157        result = self.plugin.authenticateCredentials(
158            dict(accesscode='APP-55555'))
159        assert result is None
160
161        result = self.plugin.authenticateCredentials(
162            dict(accesscode='APP-66666'))
163        assert result is None
164
165        result = self.plugin.authenticateCredentials(
166            dict(accesscode='APP-77777'))
167        assert result is None
168        return
169
170    def test_valid_credentials(self):
171        """The six different cases where we allow login.
172
173        All other combinations should be forbidden.
174        """
175        result = self.plugin.authenticateCredentials(
176            dict(accesscode='APP-11111'))
177        assert result is not None
178
179        result = self.plugin.authenticateCredentials(
180            dict(accesscode='APP-12345'))
181        assert result is not None
182
183        result = self.plugin.authenticateCredentials(
184            dict(accesscode='APP-54321'))
185        assert result is not None
186
187        # check the `principalInfo` method of authenticator
188        # plugin. This is only here to satisfy the coverage report.
189        assert self.plugin.principalInfo('not-an-id') is None
190        return
191
192session_data = {
193    'zope.pluggableauth.browserplugins': {}
194    }
195
196class FakeSession(dict):
197    def __init__(self, request):
198        pass
199
200    def get(self, key, default=None):
201        return self.__getitem__(key, default)
202
203    def __getitem__(self, key, default=None):
204        return session_data.get(key, default)
205
206    def __setitem__(self, key, value):
207        session_data[key] = value
208        return
209
210class CredentialsPluginTest(unittest.TestCase):
211
212    def setUp(self):
213        self.request = TestRequest()
214        provideAdapter(FakeSession, (IRequest,), ISession)
215        self.plugin = WAeUPApplicantCredentialsPlugin()
216        self.full_request = TestRequest()
217        session_data['zope.pluggableauth.browserplugins'] = {}
218        return
219
220    def tearDown(self):
221        cleanup.tearDown()
222        return
223
224    def filled_request(self, form_dict):
225        request = TestRequest()
226        for key, value in form_dict.items():
227            request.form[key] = value
228        return request
229
230    def test_extractCredentials_invalid(self):
231        result = self.plugin.extractCredentials('not-a-request')
232        assert result is None
233        return
234
235    def test_extractCredentials_empty(self):
236        result = self.plugin.extractCredentials(self.request)
237        assert result is None
238        return
239
240    def test_extractCredentials_full_set(self):
241        request = self.filled_request({
242                'form.ac_prefix': 'APP',
243                'form.ac_series': '1',
244                'form.ac_number': '1234567890',
245                #'form.jamb_reg_no': 'JAMB_NUMBER',
246                })
247        result = self.plugin.extractCredentials(request)
248        self.assertEqual(result, {'accesscode': 'APP-1-1234567890'})
249        return
250
251    def test_extractCredentials_accesscode_only(self):
252        request = self.filled_request({
253                'form.ac_prefix': 'APP',
254                'form.ac_series': '1',
255                'form.ac_number': '1234567890',
256                })
257        result = self.plugin.extractCredentials(request)
258        self.assertEqual(result, {'accesscode': 'APP-1-1234567890'})
259        return
260
261    def test_extractCredentials_from_empty_session(self):
262        session_data['zope.pluggableauth.browserplugins']['credentials'] = None
263        result = self.plugin.extractCredentials(self.request)
264        assert result is None
265        return
266
267    def test_extractCredentials_from_nonempty_session(self):
268        credentials = ApplicantCredentials('APP-1-12345')
269        session_data['zope.pluggableauth.browserplugins'][
270            'credentials'] = credentials
271        result = self.plugin.extractCredentials(self.request)
272        self.assertEqual(result, {'accesscode': 'APP-1-12345'})
273        return
274
275
276class ApplicantCredentialsTest(unittest.TestCase):
277
278    def setUp(self):
279        self.credentials = ApplicantCredentials('SOME_ACCESSCODE')
280        return
281
282    def tearDown(self):
283        return
284
285    def test_methods(self):
286        self.assertEqual(self.credentials.getAccessCode(), 'SOME_ACCESSCODE')
287        assert self.credentials.getLogin() is None
288        assert self.credentials.getPassword() is None
289        return
290
291class FakePluggableAuth(object):
292    prefix = 'foo'
293
294class PrincipalFactoryTest(unittest.TestCase):
295
296    def setUp(self):
297        self.info = ApplicantPrincipalInfo('APP-1-1234567890')
298        return
299
300    def tearDown(self):
301        pass
302
303    def test_principalFactory_interface(self):
304        verify.verifyClass(IAuthenticatedPrincipalFactory,
305                           AuthenticatedApplicantPrincipalFactory
306                           )
307        return
308
309    def test_principalFactory_create(self):
310        factory = AuthenticatedApplicantPrincipalFactory(self.info, None)
311
312        assert factory.info is self.info
313        assert factory.request is None
314        return
315
316    def test_principalFactory_call_w_prefix(self):
317        factory = AuthenticatedApplicantPrincipalFactory(self.info, None)
318        principal = factory(FakePluggableAuth())
319
320        assert isinstance(principal, ApplicantPrincipal)
321        self.assertEqual(principal.__repr__(),
322                         "ApplicantPrincipal('foo.APP-1-1234567890')")
323        self.assertEqual(principal.id, 'foo.APP-1-1234567890')
324        return
325
326    def test_principalFactory_call_wo_prefix(self):
327        factory = AuthenticatedApplicantPrincipalFactory(self.info, None)
328        fake_auth = FakePluggableAuth()
329        fake_auth.prefix = None
330        principal = factory(fake_auth)
331        self.assertEqual(principal.id, 'APP-1-1234567890')
332        return
333
334class PAUSetupTest(FunctionalTestCase):
335    # Check correct setup of authentication components in the
336    # applicants subpackage.
337
338    # When a university is created, we want by default have our local
339    # authentication components (an authenticator plugin and a
340    # credentials plugin) to be registered with the local PAU. Admins
341    # can remove these components on the fly later-on if they wish.
342
343    layer = FunctionalLayer
344
345    def setUp(self):
346        super(PAUSetupTest, self).setUp()
347
348        # Setup a sample site for each test
349        app = University()
350        self.dc_root = tempfile.mkdtemp()
351        app['datacenter'].setStoragePath(self.dc_root)
352
353        # Prepopulate the ZODB...
354        self.getRootFolder()['app'] = app
355        self.app = self.getRootFolder()['app']
356        self.browser = Browser()
357        self.browser.handleErrors = False
358
359    def tearDown(self):
360        super(PAUSetupTest, self).tearDown()
361        shutil.rmtree(self.dc_root)
362
363    def test_extra_auth_plugins_installed(self):
364        # Check whether the auth plugins defined in here are setup
365        # automatically when a university is created
366
367        # Get the PAU responsible for the local site ('app')
368        pau = getUtility(IAuthentication, context=self.app)
369        cred_plugins = pau.getCredentialsPlugins()
370        auth_plugins = pau.getAuthenticatorPlugins()
371        cred_names = [name for name, plugin in cred_plugins]
372        auth_names = [name for name, plugin in auth_plugins]
373
374        # Make sure our local ApplicantsAuthenticatorPlugin is registered...
375        self.assertTrue('applicants' in auth_names)
376        # Make sure our local WAeUPApplicantCredentialsPlugin is registered...
377        self.assertTrue('applicant_credentials' in cred_names)
378        return
379
380def test_suite():
381    suite = unittest.TestSuite()
382    for testcase in [
383        AuthenticatorPluginTest, CredentialsPluginTest,
384        ApplicantCredentialsTest, PrincipalFactoryTest,
385        PAUSetupTest,
386        ]:
387        suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
388                testcase
389                )
390        )
391    return suite
Note: See TracBrowser for help on using the repository browser.