def test_plugin(): plugin = registry.get_plugin('u2f') assert plugin.get_create_form_class() == U2fDeviceCreateForm assert plugin.get_verify_form_class() == U2fVerifyForm user = UserFactory() # When a user logs in the OTP device is added as a property. user.otp_device = U2fDeviceFactory(user=user) assert registry.user_authentication_method(user) == 'u2f'
def test_register_form(rfactory): user = UserFactory() plugin = registry.get_plugin('u2f') request = rfactory.post('/u2f/register/') request.session = {U2F_REGISTRATION_KEY: REG_STATE} request.user = user form = U2fDeviceCreateForm(data=REG_DATA, plugin=plugin, request=request) assert form.is_valid(), form.errors device = form.save() assert device.version == 'webauthn' assert device.aaguid.hex == '00000000000000000000000000000000' assert device.credential == REG_CREDENTIAL assert device.public_key == REG_PUBLIC_KEY assert device.counter == 0
def test_plugin(self): # Plugins are allowed to use the same device/model. totp_plugin = registry.get_plugin('totp') registry.register('TEST', TOTPDevice, update_form_class=DeviceUpdateForm) plugin = registry.get_plugin('test') self.assertEqual(plugin.model, totp_plugin.model) self.assertEqual(str(plugin), 'TEST') self.assertEqual( repr(plugin), "KleidesMfaPlugin(name='TEST', model=<class " "'django_otp.plugins.otp_totp.models.TOTPDevice'>)") self.assertIsNone(plugin.get_create_form_class()) self.assertIsNotNone(plugin.get_update_form_class()) self.assertIsNone(plugin.get_verify_form_class()) # But the name must be unique. with self.assertRaises(AlreadyRegistered): registry.register('tEsT', TOTPDevice) registry.unregister('test') with self.assertRaises(KeyError): registry.unregister('test')
def test_authenticate_form(rfactory, settings): other_device = U2fDeviceFactory() device = U2fDeviceFactory( credential=AUTH_CREDENTIAL, public_key=AUTH_PUBLIC_KEY) user = device.user plugin = registry.get_plugin('u2f') request = rfactory.post('/u2f/authenticate/') request.session = {U2F_AUTHENTICATION_KEY: AUTH_STATE} # Verification requests require the user to have authenticated with # a password but lack the session variables for the session middleware # to load the user. They are effectively anonymous. request.user = AnonymousUser() form = U2fVerifyForm( data=AUTH_DATA, device=other_device, unverified_user=user, plugin=plugin, request=request) assert form.is_valid(), form.errors # webauth presents all known devices to the user and will return the device # that was used to complete authentication (started with other_device). assert form.device == device assert form.device.counter == 4
def test_authenticate_form_failure(rfactory, settings): settings.OTP_U2F_THROTTLE_FACTOR = 0 device = U2fDeviceFactory( credential=AUTH_CREDENTIAL, public_key=AUTH_PUBLIC_KEY, counter=5) user = device.user plugin = registry.get_plugin('u2f') request = rfactory.post('/u2f/authenticate/') request.session = {} # Verification requests require the user to have authenticated with # a password but lack the session variables for the session middleware # to load the user. They are effectively anonymous. request.user = AnonymousUser() # Auth with an expired challenge fails. form = U2fVerifyForm( data={}, device=device, unverified_user=user, plugin=plugin, request=request) assert not form.is_valid() assert 'This field is required.' in form.errors['otp_token'] assert 'The authentication request has expired, try again' in form.errors['__all__'] # noqa request.session = {U2F_AUTHENTICATION_KEY: AUTH_STATE} # Nonsense token data. form = U2fVerifyForm( data={'otp_token': 'XXX'}, device=device, unverified_user=user, plugin=plugin, request=request) assert not form.is_valid() assert 'The authentication request is invalid' in form.errors['__all__'] request.session = {U2F_AUTHENTICATION_KEY: AUTH_STATE} # Test authenticator counter. form = U2fVerifyForm( data=AUTH_DATA, device=device, unverified_user=user, plugin=plugin, request=request) assert not form.is_valid() assert not form.device.confirmed assert f'Device authentication failure (reason: Device appears to be cloned, expected counter > 5 but got 4 instead. The device otp_u2f.u2fdevice/{device.pk} has been disabled.)' in form.errors['__all__'] # noqa
def test_register_form_failure(rfactory): user = UserFactory() plugin = registry.get_plugin('u2f') request = rfactory.post('/u2f/reqister/') request.session = {} request.user = user form = U2fDeviceCreateForm(data={}, plugin=plugin, request=request) assert not form.is_valid() assert 'This field is required.' in form.errors['otp_token'] assert 'The registration request has expired, try again' in form.errors['__all__'] # noqa request.session = {U2F_REGISTRATION_KEY: REG_STATE} form = U2fDeviceCreateForm( data={'otp_token': 'xxx'}, plugin=plugin, request=request) assert not form.is_valid() assert 'The registration request is invalid' in form.errors['__all__'] request = rfactory.get('/u2f/create/', SERVER_NAME='testserver') request.session = {U2F_REGISTRATION_KEY: REG_STATE} request.user = user form = U2fDeviceCreateForm(data=REG_DATA, plugin=plugin, request=request) assert not form.is_valid() assert 'Device registration failure (reason: Invalid origin in ClientData.)' in form.errors['__all__'] # noqa