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

Last change on this file since 16058 was 15606, checked in by Henrik Bettermann, 5 years ago

Parents access implementation (part 1)

  • Property svn:keywords set to Id
File size: 9.4 KB
Line 
1## $Id: test_authentication.py 15606 2019-09-24 17:21:28Z 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    def getParentsPassword(self):
92        parents_password_dict = getattr(self, 'parents_password', None)
93        if parents_password_dict is not None:
94            delta = timedelta(minutes=self.temp_password_minutes)
95            now = datetime.utcnow()
96            if now < parents_password_dict.get('timestamp') + delta:
97                return parents_password_dict.get('password')
98            else:
99                # Unset temporary password if expired
100                self.parents_password = None
101        return None
102
103
104
105class MinimalPAU(PluggableAuthentication):
106    def getPrincipal(self, id):
107        return 'faked principal'
108
109class StudentAccountTests(unittest.TestCase):
110
111    def setUp(self):
112        self.fake_stud = FakeStudent()
113        self.account = StudentAccount(self.fake_stud)
114
115        # We provide a minimal PAU
116        pau = MinimalPAU()
117        provideUtility(pau, IAuthentication)
118
119        # We register a role
120        test_role = Role('waeup.test.Role', 'Testing Role')
121        provideUtility(test_role, IRole, name='waeup.test.Role')
122
123        # We have to setup a password manager utility manually as we
124        # have no functional test. In functional tests this would
125        # happen automatically, but it would take a lot more time to
126        # run the tests.
127        provideUtility(
128            SSHAPasswordManager(), IPasswordManager, 'SSHA')
129        return
130
131    def tearDown(self):
132        self.account.roles = [] # make sure roles are reset
133        gsm = getGlobalSiteManager()
134        to_clean = []
135        # Clear up utilities registered in setUp
136        to_clean.append(
137            (IPasswordManager, queryUtility(
138                    IPasswordManager, name='SSHA', default=None)))
139        to_clean.append(
140            (IAuthentication, queryUtility(IAuthentication, default=None)))
141        to_clean.append(
142            (IRole, queryUtility(IRole, name='test.Role', default=None)))
143        for iface, elem in to_clean:
144            if elem is not None:
145                gsm.unregisterUtility(elem, iface)
146        return
147
148    def test_iface(self):
149        verifyClass(IUserAccount, StudentAccount)
150        verifyObject(IUserAccount, self.account)
151        return
152
153    def test_set_password(self):
154        # make sure we can set a password.
155        self.account.setPassword('secret')
156        self.assertTrue(self.fake_stud.password is not None)
157        # we do not store plaintext passwords
158        self.assertTrue(self.fake_stud.password != 'secret')
159        # passwords are stored as bytestreams
160        self.assertTrue(isinstance(self.fake_stud.password, basestring))
161        self.assertFalse(isinstance(self.fake_stud.password, unicode))
162        return
163
164    def test_check_password(self):
165        # make sure we can check a password.
166        self.account.setPassword('secret')
167        result1 = self.account.checkPassword(None)
168        result2 = self.account.checkPassword('nonsense')
169        result3 = self.account.checkPassword('secret')
170        self.assertEqual(result1, False)
171        self.assertEqual(result2, False)
172        self.assertEqual(result3, True)
173        return
174
175    def test_check_temp_password(self):
176        # make sure that, if a temp password is set,
177        # this password is used for authentication
178        self.account.setPassword('secret')
179        self.fake_stud.setTempPassword(user='beate', password='temp_secret')
180        result1 = self.account.checkPassword('secret')
181        result2 = self.account.checkPassword(None)
182        result3 = self.account.checkPassword('nonsense')
183        result4 = self.account.checkPassword('temp_secret')
184        self.assertEqual(result1, False)
185        self.assertEqual(result2, False)
186        self.assertEqual(result3, False)
187        self.assertEqual(result4, True)
188        # if the temp password is expired, the original password
189        # is used again
190        delta = timedelta(minutes=11)
191        self.fake_stud.temp_password['timestamp'] = datetime.utcnow() - delta
192        result5 = self.account.checkPassword('temp_secret')
193        result6 = self.account.checkPassword('secret')
194        self.assertEqual(result5, False)
195        self.assertEqual(result6, True)
196        return
197
198    def test_check_unset_password(self):
199        # empty and unset passwords do not match anything
200        self.fake_stud.password = None
201        result1 = self.account.checkPassword('')
202        self.fake_stud.password = ''
203        result2 = self.account.checkPassword('')
204        self.assertEqual(result1, False)
205        self.assertEqual(result2, False)
206        return
207
208    def test_check_password_no_string(self):
209        # if passed in password is not a string, we gain no access
210        self.fake_stud.password = 'secret'
211        result1 = self.account.checkPassword(None)
212        result2 = self.account.checkPassword(object())
213        self.assertEqual(result1, False)
214        self.assertEqual(result2, False)
215        return
216
217    def test_role_set(self):
218        # make sure we can set roles for principals denoted by account
219        prm = get_principal_role_manager()
220        self.assertEqual(prm.getPrincipalsAndRoles(), [])
221        self.account.roles = ['waeup.test.Role']
222        self.assertEqual(
223            prm.getPrincipalsAndRoles(),
224            [('waeup.test.Role', 'test_stud', Allow)])
225        return
226
227    def test_role_get(self):
228        # make sure we can get roles set for an account
229        self.assertEqual(self.account.roles, [])
230        self.account.roles = ['waeup.test.Role',] # set a role
231        self.assertEqual(self.account.roles, ['waeup.test.Role'])
232        return
233
234
235
236class FunctionalStudentAuthTests(StudentsFullSetup):
237
238    layer = FunctionalLayer
239
240    def setUp(self):
241        super(FunctionalStudentAuthTests, self).setUp()
242        return
243
244    def tearDown(self):
245        super(FunctionalStudentAuthTests, self).tearDown()
246        return
247
248    def test_reset_protected_anonymous(self):
249        # anonymous users cannot reset others passwords
250        self.assertRaises(
251            Unauthorized,
252            self.browser.open, self.student_path + '/change_password')
253        return
Note: See TracBrowser for help on using the repository browser.