- Timestamp:
- 30 Nov 2011, 23:13:26 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.sirp/trunk/src/waeup/sirp/applicants/tests/test_authentication.py
r7238 r7240 16 16 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 17 ## 18 import shutil19 import tempfile20 18 import unittest 21 19 from zope.authentication.interfaces import IAuthentication 22 from zope.component import provideAdapter, getUtility, queryUtility 23 from zope.component.hooks import setSite 24 from zope.interface import verify 25 from zope.pluggableauth.interfaces import IAuthenticatedPrincipalFactory 26 from zope.publisher.browser import TestRequest 27 from zope.publisher.interfaces import IRequest 28 from zope.session.interfaces import ISession 29 from zope.testbrowser.testing import Browser 30 from zope.testing import cleanup 31 from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase 32 from waeup.sirp.app import University 33 from waeup.sirp.interfaces import IAuthPluginUtility 34 from waeup.sirp.applicants import ApplicantsContainer, Applicant 20 from zope.component import provideUtility, queryUtility, getGlobalSiteManager 21 from zope.interface.verify import verifyClass, verifyObject 22 from zope.password.password import SSHAPasswordManager 23 from zope.password.interfaces import IPasswordManager 24 from zope.pluggableauth import PluggableAuthentication 25 from zope.security.interfaces import Unauthorized 26 from zope.securitypolicy.role import Role 27 from zope.securitypolicy.interfaces import IRole, Allow 28 from waeup.sirp.authentication import get_principal_role_manager 29 from waeup.sirp.interfaces import IAuthPluginUtility, IUserAccount 35 30 from waeup.sirp.applicants.authentication import ( 36 ApplicantsAuthenticatorPlugin, WAeUPApplicantCredentialsPlugin, 37 ApplicantCredentials, AuthenticatedApplicantPrincipalFactory, 38 ApplicantPrincipalInfo, ApplicantPrincipal, ApplicantsAuthenticatorSetup) 31 ApplicantsAuthenticatorSetup, ApplicantAccount) 32 from waeup.sirp.applicants.tests.test_browser import ApplicantsFullSetup 33 from waeup.sirp.testing import FunctionalLayer 34 35 class ApplicantsAuthenticatorSetupTests(unittest.TestCase): 36 37 def test_iface(self): 38 obj = ApplicantsAuthenticatorSetup() 39 verifyClass(IAuthPluginUtility, ApplicantsAuthenticatorSetup) 40 verifyObject(IAuthPluginUtility, obj) 41 return 42 43 def test_register(self): 44 # Make sure registration works. 45 setup = ApplicantsAuthenticatorSetup() 46 pau = PluggableAuthentication() 47 setup.register(pau) 48 self.assertTrue('applicants' in pau.authenticatorPlugins) 49 return 50 51 def test_unregister(self): 52 # Make sure deregistration works. 53 setup = ApplicantsAuthenticatorSetup() 54 pau = PluggableAuthentication() 55 pau.authenticatorPlugins = ('applicants') 56 setup.unregister(pau) 57 self.assertTrue('applicants' not in pau.authenticatorPlugins) 58 return 39 59 40 60 41 class FakeBatch(dict): 42 def getAccessCode(self, id): 43 return self.get(id) 61 class FakeApplicant(object): 62 applicant_id = 'test_appl' 63 fullname = 'Tilman Gause' 64 password = None 65 email = None 66 phone = None 44 67 45 class FakeAccessCode(object):46 def __init__(self, repr, state = 'initialized'):47 self.representation = repr48 self.state = state49 68 50 class FakeApplication(object):51 def __init__(self, ac=None):52 self.access_code = ac69 class MinimalPAU(PluggableAuthentication): 70 def getPrincipal(self, id): 71 return 'faked principal' 53 72 54 def FakeSite(): 55 return { 56 'applicants': { 57 'APP': { 58 'APP-12345': FakeApplication(u'APP-12345'), 59 'APP-54321': FakeApplication(u'APP-54321'), 60 'APP-22222': FakeApplication(u'APP-OTHER'), 61 'APP-44444': FakeApplication(), 62 'APP-55555': FakeApplication(u'APP-OTHER'), 63 'APP-77777': FakeApplication(u'APP-77777'), 64 }, 65 }, 66 'accesscodes': { 67 'APP': FakeBatch({ 68 'APP-12345': FakeAccessCode('APP-12345'), 69 'APP-54321': FakeAccessCode('APP-54321', 'used'), 70 'APP-11111': FakeAccessCode('APP-11111'), 71 'APP-22222': FakeAccessCode('APP-22222'), 72 'APP-33333': FakeAccessCode('APP-33333', 'used'), 73 'APP-44444': FakeAccessCode('APP-44444', 'used'), 74 'APP-55555': FakeAccessCode('APP-55555', 'used'), 75 'APP-66666': FakeAccessCode('APP-66666', 'disabled'), 76 'APP-77777': FakeAccessCode('APP-77777', 'disabled'), 77 }) 78 } 79 } 80 81 class AuthenticatorPluginTest(FunctionalTestCase): 82 83 layer = FunctionalLayer 84 85 def create_applicant(self, cname, aname, ac=None): 86 # Create an applicant in an applicants container 87 setSite(self.app) 88 if not cname in self.app['applicants'].keys(): 89 container = ApplicantsContainer() 90 self.app['applicants'][cname] = container 91 applicant = Applicant() 92 if ac is not None: 93 applicant.access_code = ac 94 self.app['applicants'][cname][aname] = applicant 95 return 73 class ApplicantAccountTests(unittest.TestCase): 96 74 97 75 def setUp(self): 98 super(AuthenticatorPluginTest, self).setUp() 76 self.fake_stud = FakeApplicant() 77 self.account = ApplicantAccount(self.fake_stud) 99 78 100 # Setup a sample site for each test 101 app = University() 102 self.dc_root = tempfile.mkdtemp() 103 app['datacenter'].setStoragePath(self.dc_root) 79 # We provide a minimal PAU 80 pau = MinimalPAU() 81 provideUtility(pau, IAuthentication) 104 82 105 # Prepopulate the ZODB...106 self.getRootFolder()['app'] = app107 self.app = self.getRootFolder()['app']83 # We register a role 84 test_role = Role('waeup.test.Role', 'Testing Role') 85 provideUtility(test_role, IRole, name='waeup.test.Role') 108 86 109 fake_site = FakeSite() 110 for ckey, fake_container in fake_site['applicants'].items(): 111 for akey, fake_appl in fake_container.items(): 112 self.create_applicant(ckey, akey, fake_appl.access_code) 113 del self.app['accesscodes'] 114 self.app['accesscodes'] = fake_site['accesscodes'] 115 116 self.plugin = ApplicantsAuthenticatorPlugin() 87 # We have to setup a password manager utility manually as we 88 # have no functional test. In functional tests this would 89 # happen automatically, but it would take a lot more time to 90 # run the tests. 91 provideUtility( 92 SSHAPasswordManager(), IPasswordManager, 'SSHA') 117 93 return 118 94 119 95 def tearDown(self): 120 super(AuthenticatorPluginTest, self).tearDown() 121 shutil.rmtree(self.dc_root) 96 self.account.roles = [] # make sure roles are reset 97 gsm = getGlobalSiteManager() 98 to_clean = [] 99 # Clear up utilities registered in setUp 100 to_clean.append( 101 (IPasswordManager, queryUtility( 102 IPasswordManager, name='SSHA', default=None))) 103 to_clean.append( 104 (IAuthentication, queryUtility(IAuthentication, default=None))) 105 to_clean.append( 106 (IRole, queryUtility(IRole, name='test.Role', default=None))) 107 for iface, elem in to_clean: 108 if elem is not None: 109 gsm.unregisterUtility(elem, iface) 122 110 return 123 111 124 def test_invalid_credentials(self): 125 result = self.plugin.authenticateCredentials('not-a-dict') 126 assert result is None 127 128 result = self.plugin.authenticateCredentials( 129 dict(accesscode=None, foo='blah')) 130 assert result is None 131 132 result = self.plugin.authenticateCredentials( 133 dict(accesscode='Nonsense',)) 134 assert result is None 135 136 # Possible cases, where formal correct authentication 137 # data is not valid: 138 result = self.plugin.authenticateCredentials( 139 dict(accesscode='APP-33333')) 140 assert result is None 141 142 result = self.plugin.authenticateCredentials( 143 dict(accesscode='APP-55555')) 144 assert result is None 145 146 result = self.plugin.authenticateCredentials( 147 dict(accesscode='APP-66666')) 148 assert result is None 149 150 result = self.plugin.authenticateCredentials( 151 dict(accesscode='APP-77777')) 152 assert result is None 153 112 def test_iface(self): 113 verifyClass(IUserAccount, ApplicantAccount) 114 verifyObject(IUserAccount, self.account) 154 115 return 155 116 156 def test_valid_credentials(self): 157 """The six different cases where we allow login. 158 159 All other combinations should be forbidden. 160 """ 161 result = self.plugin.authenticateCredentials( 162 dict(accesscode='APP-11111')) 163 assert result is not None 164 165 result = self.plugin.authenticateCredentials( 166 dict(accesscode='APP-12345')) 167 assert result is not None 168 169 result = self.plugin.authenticateCredentials( 170 dict(accesscode='APP-54321')) 171 assert result is not None 172 173 # check the `principalInfo` method of authenticator 174 # plugin. This is only here to satisfy the coverage report. 175 assert self.plugin.principalInfo('not-an-id') is None 117 def test_set_password(self): 118 # make sure we can set a password. 119 self.account.setPassword('secret') 120 self.assertTrue(self.fake_stud.password is not None) 121 # we do not store plaintext passwords 122 self.assertTrue(self.fake_stud.password != 'secret') 123 # passwords are stored as unicode 124 self.assertTrue(isinstance(self.fake_stud.password, unicode)) 176 125 return 177 126 178 session_data = { 179 'zope.pluggableauth.browserplugins': {} 180 } 181 182 class FakeSession(dict): 183 def __init__(self, request): 184 pass 185 186 def get(self, key, default=None): 187 return self.__getitem__(key, default) 188 189 def __getitem__(self, key, default=None): 190 return session_data.get(key, default) 191 192 def __setitem__(self, key, value): 193 session_data[key] = value 127 def test_check_password(self): 128 # make sure we can check a password. 129 self.account.setPassword('secret') 130 result1 = self.account.checkPassword(None) 131 result2 = self.account.checkPassword('nonsense') 132 result3 = self.account.checkPassword('secret') 133 self.assertEqual(result1, False) 134 self.assertEqual(result2, False) 135 self.assertEqual(result3, True) 194 136 return 195 137 196 class CredentialsPluginTest(unittest.TestCase):197 198 def setUp(self):199 self.request = TestRequest()200 provideAdapter(FakeSession, (IRequest,), ISession)201 self.plugin = WAeUPApplicantCredentialsPlugin()202 self. full_request = TestRequest()203 se ssion_data['zope.pluggableauth.browserplugins'] = {}138 def test_check_unset_password(self): 139 # empty and unset passwords do not match anything 140 self.fake_stud.password = None 141 result1 = self.account.checkPassword('') 142 self.fake_stud.password = '' 143 result2 = self.account.checkPassword('') 144 self.assertEqual(result1, False) 145 self.assertEqual(result2, False) 204 146 return 205 147 206 def tearDown(self): 207 cleanup.tearDown() 148 def test_check_password_no_string(self): 149 # if passed in password is not a string, we gain no access 150 self.fake_stud.password = 'secret' 151 result1 = self.account.checkPassword(None) 152 result2 = self.account.checkPassword(object()) 153 self.assertEqual(result1, False) 154 self.assertEqual(result2, False) 208 155 return 209 156 210 def filled_request(self, form_dict): 211 request = TestRequest() 212 for key, value in form_dict.items(): 213 request.form[key] = value 214 return request 215 216 def test_extractCredentials_invalid(self): 217 result = self.plugin.extractCredentials('not-a-request') 218 assert result is None 157 def test_role_set(self): 158 # make sure we can set roles for principals denoted by account 159 prm = get_principal_role_manager() 160 self.assertEqual(prm.getPrincipalsAndRoles(), []) 161 self.account.roles = ['waeup.test.Role'] 162 self.assertEqual( 163 prm.getPrincipalsAndRoles(), 164 [('waeup.test.Role', 'test_appl', Allow)]) 219 165 return 220 166 221 def test_extractCredentials_empty(self): 222 result = self.plugin.extractCredentials(self.request) 223 assert result is None 167 def test_role_get(self): 168 # make sure we can get roles set for an account 169 self.assertEqual(self.account.roles, []) 170 self.account.roles = ['waeup.test.Role',] # set a role 171 self.assertEqual(self.account.roles, ['waeup.test.Role']) 224 172 return 225 173 226 def test_extractCredentials_full_set(self): 227 request = self.filled_request({ 228 'form.ac_prefix': 'APP', 229 'form.ac_series': '1', 230 'form.ac_number': '1234567890', 231 #'form.jamb_reg_no': 'JAMB_NUMBER', 232 }) 233 result = self.plugin.extractCredentials(request) 234 self.assertEqual(result, {'accesscode': 'APP-1-1234567890'}) 235 return 236 237 def test_extractCredentials_accesscode_only(self): 238 request = self.filled_request({ 239 'form.ac_prefix': 'APP', 240 'form.ac_series': '1', 241 'form.ac_number': '1234567890', 242 }) 243 result = self.plugin.extractCredentials(request) 244 self.assertEqual(result, {'accesscode': 'APP-1-1234567890'}) 245 return 246 247 def test_extractCredentials_from_empty_session(self): 248 session_data['zope.pluggableauth.browserplugins']['credentials'] = None 249 result = self.plugin.extractCredentials(self.request) 250 assert result is None 251 return 252 253 def test_extractCredentials_from_nonempty_session(self): 254 credentials = ApplicantCredentials('APP-1-12345') 255 session_data['zope.pluggableauth.browserplugins'][ 256 'credentials'] = credentials 257 result = self.plugin.extractCredentials(self.request) 258 self.assertEqual(result, {'accesscode': 'APP-1-12345'}) 259 return 260 261 262 class ApplicantCredentialsTest(unittest.TestCase): 263 264 def setUp(self): 265 self.credentials = ApplicantCredentials('SOME_ACCESSCODE') 266 return 267 268 def tearDown(self): 269 return 270 271 def test_methods(self): 272 self.assertEqual(self.credentials.getAccessCode(), 'SOME_ACCESSCODE') 273 assert self.credentials.getLogin() is None 274 assert self.credentials.getPassword() is None 275 return 276 277 class FakePluggableAuth(object): 278 prefix = 'foo' 279 280 class PrincipalFactoryTest(unittest.TestCase): 281 282 def setUp(self): 283 self.info = ApplicantPrincipalInfo('APP-1-1234567890') 284 return 285 286 def tearDown(self): 287 pass 288 289 def test_principalFactory_interface(self): 290 verify.verifyClass(IAuthenticatedPrincipalFactory, 291 AuthenticatedApplicantPrincipalFactory 292 ) 293 return 294 295 def test_principalFactory_create(self): 296 factory = AuthenticatedApplicantPrincipalFactory(self.info, None) 297 298 assert factory.info is self.info 299 assert factory.request is None 300 return 301 302 def test_principalFactory_call_w_prefix(self): 303 factory = AuthenticatedApplicantPrincipalFactory(self.info, None) 304 principal = factory(FakePluggableAuth()) 305 306 assert isinstance(principal, ApplicantPrincipal) 307 self.assertEqual(principal.__repr__(), 308 "ApplicantPrincipal('foo.APP-1-1234567890')") 309 self.assertEqual(principal.id, 'foo.APP-1-1234567890') 310 return 311 312 def test_principalFactory_call_wo_prefix(self): 313 factory = AuthenticatedApplicantPrincipalFactory(self.info, None) 314 fake_auth = FakePluggableAuth() 315 fake_auth.prefix = None 316 principal = factory(fake_auth) 317 self.assertEqual(principal.id, 'APP-1-1234567890') 318 return 319 320 class PAUSetupTest(FunctionalTestCase): 321 # Check correct setup of authentication components in the 322 # applicants subpackage. 323 324 # When a university is created, we want by default have our local 325 # authentication components (an authenticator plugin and a 326 # credentials plugin) to be registered with the local PAU. Admins 327 # can remove these components on the fly later-on if they wish. 174 class FunctionalApplicantAuthTests(ApplicantsFullSetup): 328 175 329 176 layer = FunctionalLayer 330 177 331 178 def setUp(self): 332 super(PAUSetupTest, self).setUp() 333 334 # Setup a sample site for each test 335 app = University() 336 self.dc_root = tempfile.mkdtemp() 337 app['datacenter'].setStoragePath(self.dc_root) 338 339 # Prepopulate the ZODB... 340 self.getRootFolder()['app'] = app 341 self.app = self.getRootFolder()['app'] 342 self.browser = Browser() 343 self.browser.handleErrors = False 179 super(FunctionalApplicantAuthTests, self).setUp() 180 return 344 181 345 182 def tearDown(self): 346 super(PAUSetupTest, self).tearDown() 347 shutil.rmtree(self.dc_root) 348 349 def test_extra_auth_plugins_installed(self): 350 # Check whether the auth plugins defined in here are setup 351 # automatically when a university is created 352 353 # Get the PAU responsible for the local site ('app') 354 pau = getUtility(IAuthentication, context=self.app) 355 cred_plugins = pau.getCredentialsPlugins() 356 auth_plugins = pau.getAuthenticatorPlugins() 357 cred_names = [name for name, plugin in cred_plugins] 358 auth_names = [name for name, plugin in auth_plugins] 359 360 # Make sure our local ApplicantsAuthenticatorPlugin is registered... 361 self.assertTrue('applicants' in auth_names) 362 # Make sure our local WAeUPApplicantCredentialsPlugin is registered... 363 self.assertTrue('applicant_credentials' in cred_names) 183 super(FunctionalApplicantAuthTests, self).tearDown() 364 184 return 365 366 class FakePAU(object):367 credentialsPlugins = ()368 authenticatorPlugins = ()369 370 class ApplicantsAuthenticatorSetupTests(FunctionalTestCase):371 372 layer = FunctionalLayer373 374 def test_ifaces(self):375 # make sure we fullfill the interface promises376 obj = ApplicantsAuthenticatorSetup()377 verify.verifyClass(IAuthPluginUtility, ApplicantsAuthenticatorSetup)378 verify.verifyObject(IAuthPluginUtility, obj)379 return380 381 def test_utility_available(self):382 # we can get an applicant auth utility by lookup383 util = queryUtility(IAuthPluginUtility,384 name='applicants_auth_setup')385 self.assertTrue(util is not None)386 return387 388 def test_register(self):389 # make sure we can register additional components390 pau = FakePAU()391 result = ApplicantsAuthenticatorSetup().register(pau)392 self.assertEqual(393 result.credentialsPlugins, ('applicant_credentials',))394 self.assertEqual(395 result.authenticatorPlugins, ('applicants',))396 return397 398 def test_unregister(self):399 # make sure we can unregister applicant auth components400 pau = FakePAU()401 util = ApplicantsAuthenticatorSetup()402 pau = util.register(pau)403 result = util.unregister(pau)404 self.assertEqual(405 result.credentialsPlugins, ())406 self.assertEqual(407 result.authenticatorPlugins, ())408 return
Note: See TracChangeset for help on using the changeset viewer.