source: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_authentication.py @ 13316

Last change on this file since 13316 was 9334, checked in by Henrik Bettermann, 12 years ago

Dedicated officers should be able to login as student with a temporary password set by the system. This is the first part of its implementation.

  • Property svn:keywords set to Id
File size: 8.9 KB
Line 
1## $Id: test_authentication.py 9334 2012-10-14 21:02:31Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import unittest
19from datetime import datetime, timedelta
20from zope.authentication.interfaces import IAuthentication
21from zope.component import provideUtility, queryUtility, getGlobalSiteManager
22from zope.interface.verify import verifyClass, verifyObject
23from zope.password.password import SSHAPasswordManager
24from zope.password.interfaces import IPasswordManager
25from zope.pluggableauth import PluggableAuthentication
26from zope.security.interfaces import Unauthorized
27from zope.securitypolicy.role import Role
28from zope.securitypolicy.interfaces import IRole, Allow
29from waeup.kofa.authentication import get_principal_role_manager
30from waeup.kofa.interfaces import IAuthPluginUtility, IUserAccount
31from waeup.kofa.students.authentication import (
32    StudentsAuthenticatorSetup, StudentAccount)
33from waeup.kofa.students.tests.test_browser import StudentsFullSetup
34from waeup.kofa.testing import FunctionalLayer
35
36class StudentsAuthenticatorSetupTests(unittest.TestCase):
37
38    def test_iface(self):
39        obj = StudentsAuthenticatorSetup()
40        verifyClass(IAuthPluginUtility, StudentsAuthenticatorSetup)
41        verifyObject(IAuthPluginUtility, obj)
42        return
43
44    def test_register(self):
45        # Make sure registration works.
46        setup = StudentsAuthenticatorSetup()
47        pau = PluggableAuthentication()
48        setup.register(pau)
49        self.assertTrue('students' in pau.authenticatorPlugins)
50        return
51
52    def test_unregister(self):
53        # Make sure deregistration works.
54        setup = StudentsAuthenticatorSetup()
55        pau = PluggableAuthentication()
56        pau.authenticatorPlugins = ('students')
57        setup.unregister(pau)
58        self.assertTrue('students' not in pau.authenticatorPlugins)
59        return
60
61
62class FakeStudent(object):
63    student_id = 'test_stud'
64    display_fullname = 'Test User'
65    password = None
66    email = None
67    phone = None
68    suspended = False
69    temp_password_minutes = 10
70
71    def setTempPassword(self, user, password):
72        passwordmanager = queryUtility(IPasswordManager, 'SSHA')
73        self.temp_password = {}
74        self.temp_password[
75            'password'] = passwordmanager.encodePassword(password)
76        self.temp_password['user'] = user
77        self.temp_password['timestamp'] = datetime.utcnow()
78
79    def getTempPassword(self):
80        temp_password_dict = getattr(self, 'temp_password', None)
81        if temp_password_dict is not None:
82            delta = timedelta(minutes=self.temp_password_minutes)
83            now = datetime.utcnow()
84            if now < temp_password_dict.get('timestamp') + delta:
85                return temp_password_dict.get('password')
86            else:
87                # Unset temporary password if expired
88                self.temp_password = None
89        return None
90
91
92class MinimalPAU(PluggableAuthentication):
93    def getPrincipal(self, id):
94        return 'faked principal'
95
96class StudentAccountTests(unittest.TestCase):
97
98    def setUp(self):
99        self.fake_stud = FakeStudent()
100        self.account = StudentAccount(self.fake_stud)
101
102        # We provide a minimal PAU
103        pau = MinimalPAU()
104        provideUtility(pau, IAuthentication)
105
106        # We register a role
107        test_role = Role('waeup.test.Role', 'Testing Role')
108        provideUtility(test_role, IRole, name='waeup.test.Role')
109
110        # We have to setup a password manager utility manually as we
111        # have no functional test. In functional tests this would
112        # happen automatically, but it would take a lot more time to
113        # run the tests.
114        provideUtility(
115            SSHAPasswordManager(), IPasswordManager, 'SSHA')
116        return
117
118    def tearDown(self):
119        self.account.roles = [] # make sure roles are reset
120        gsm = getGlobalSiteManager()
121        to_clean = []
122        # Clear up utilities registered in setUp
123        to_clean.append(
124            (IPasswordManager, queryUtility(
125                    IPasswordManager, name='SSHA', default=None)))
126        to_clean.append(
127            (IAuthentication, queryUtility(IAuthentication, default=None)))
128        to_clean.append(
129            (IRole, queryUtility(IRole, name='test.Role', default=None)))
130        for iface, elem in to_clean:
131            if elem is not None:
132                gsm.unregisterUtility(elem, iface)
133        return
134
135    def test_iface(self):
136        verifyClass(IUserAccount, StudentAccount)
137        verifyObject(IUserAccount, self.account)
138        return
139
140    def test_set_password(self):
141        # make sure we can set a password.
142        self.account.setPassword('secret')
143        self.assertTrue(self.fake_stud.password is not None)
144        # we do not store plaintext passwords
145        self.assertTrue(self.fake_stud.password != 'secret')
146        # passwords are stored as bytestreams
147        self.assertTrue(isinstance(self.fake_stud.password, basestring))
148        self.assertFalse(isinstance(self.fake_stud.password, unicode))
149        return
150
151    def test_check_password(self):
152        # make sure we can check a password.
153        self.account.setPassword('secret')
154        result1 = self.account.checkPassword(None)
155        result2 = self.account.checkPassword('nonsense')
156        result3 = self.account.checkPassword('secret')
157        self.assertEqual(result1, False)
158        self.assertEqual(result2, False)
159        self.assertEqual(result3, True)
160        return
161
162    def test_check_temp_password(self):
163        # make sure that, if a temp password is set,
164        # this password is used for authentication
165        self.account.setPassword('secret')
166        self.fake_stud.setTempPassword(user='beate', password='temp_secret')
167        result1 = self.account.checkPassword('secret')
168        result2 = self.account.checkPassword(None)
169        result3 = self.account.checkPassword('nonsense')
170        result4 = self.account.checkPassword('temp_secret')
171        self.assertEqual(result1, False)
172        self.assertEqual(result2, False)
173        self.assertEqual(result3, False)
174        self.assertEqual(result4, True)
175        # if the temp password is expired, the original password
176        # is used again
177        delta = timedelta(minutes=11)
178        self.fake_stud.temp_password['timestamp'] = datetime.utcnow() - delta
179        result5 = self.account.checkPassword('temp_secret')
180        result6 = self.account.checkPassword('secret')
181        self.assertEqual(result5, False)
182        self.assertEqual(result6, True)
183        return
184
185    def test_check_unset_password(self):
186        # empty and unset passwords do not match anything
187        self.fake_stud.password = None
188        result1 = self.account.checkPassword('')
189        self.fake_stud.password = ''
190        result2 = self.account.checkPassword('')
191        self.assertEqual(result1, False)
192        self.assertEqual(result2, False)
193        return
194
195    def test_check_password_no_string(self):
196        # if passed in password is not a string, we gain no access
197        self.fake_stud.password = 'secret'
198        result1 = self.account.checkPassword(None)
199        result2 = self.account.checkPassword(object())
200        self.assertEqual(result1, False)
201        self.assertEqual(result2, False)
202        return
203
204    def test_role_set(self):
205        # make sure we can set roles for principals denoted by account
206        prm = get_principal_role_manager()
207        self.assertEqual(prm.getPrincipalsAndRoles(), [])
208        self.account.roles = ['waeup.test.Role']
209        self.assertEqual(
210            prm.getPrincipalsAndRoles(),
211            [('waeup.test.Role', 'test_stud', Allow)])
212        return
213
214    def test_role_get(self):
215        # make sure we can get roles set for an account
216        self.assertEqual(self.account.roles, [])
217        self.account.roles = ['waeup.test.Role',] # set a role
218        self.assertEqual(self.account.roles, ['waeup.test.Role'])
219        return
220
221
222
223class FunctionalStudentAuthTests(StudentsFullSetup):
224
225    layer = FunctionalLayer
226
227    def setUp(self):
228        super(FunctionalStudentAuthTests, self).setUp()
229        return
230
231    def tearDown(self):
232        super(FunctionalStudentAuthTests, self).tearDown()
233        return
234
235    def test_reset_protected_anonymous(self):
236        # anonymous users cannot reset others passwords
237        self.assertRaises(
238            Unauthorized,
239            self.browser.open, self.student_path + '/change_password')
240        return
Note: See TracBrowser for help on using the repository browser.