You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
5.8 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2016-2017 LasLabs Inc.
  3. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
  4. import mock
  5. from odoo.exceptions import ValidationError
  6. from odoo.tests.common import TransactionCase
  7. @mock.patch(
  8. 'odoo.addons.auth_totp.wizards.res_users_authenticator_create.pyotp'
  9. )
  10. class TestResUsersAuthenticatorCreate(TransactionCase):
  11. def setUp(self):
  12. super(TestResUsersAuthenticatorCreate, self).setUp()
  13. self.test_user = self.env.ref('base.user_root')
  14. def _new_wizard(self, extra_values=None):
  15. base_values = {
  16. 'name': 'Test Authenticator',
  17. 'confirmation_code': 'Test',
  18. 'user_id': self.test_user.id,
  19. }
  20. if extra_values is not None:
  21. base_values.update(extra_values)
  22. return self.env['res.users.authenticator.create'].create(base_values)
  23. def test_secret_key_default(self, pyotp_mock):
  24. '''Should default to random string generated by PyOTP'''
  25. pyotp_mock.random_base32.return_value = test_random = 'Test'
  26. test_wiz = self.env['res.users.authenticator.create']
  27. test_key = test_wiz.default_get(['secret_key'])['secret_key']
  28. self.assertEqual(test_key, test_random)
  29. def test_default_user_id_no_uid_in_context(self, pyotp_mock):
  30. '''Should return empty user recordset when no uid in context'''
  31. test_wiz = self.env['res.users.authenticator.create'].with_context(
  32. uid=None,
  33. )
  34. self.assertFalse(test_wiz._default_user_id())
  35. self.assertEqual(test_wiz._default_user_id()._name, 'res.users')
  36. def test_default_user_id_uid_in_context(self, pyotp_mock):
  37. '''Should return correct user record when there is a uid in context'''
  38. test_wiz = self.env['res.users.authenticator.create'].with_context(
  39. uid=self.test_user.id,
  40. )
  41. self.assertEqual(test_wiz._default_user_id(), self.test_user)
  42. def test_compute_qr_code_tag_no_user_id(self, pyotp_mock):
  43. '''Should not call PyOTP or set field if no user_id present'''
  44. test_wiz = self.env['res.users.authenticator.create'].with_context(
  45. uid=None,
  46. ).new()
  47. pyotp_mock.reset_mock()
  48. self.assertFalse(test_wiz.qr_code_tag)
  49. pyotp_mock.assert_not_called()
  50. def test_compute_qr_code_tag_user_id(self, pyotp_mock):
  51. '''Should set field to image with encoded PyOTP URI if user present'''
  52. pyotp_mock.TOTP().provisioning_uri.return_value = 'test:uri'
  53. test_wiz = self._new_wizard()
  54. self.assertEqual(
  55. test_wiz.qr_code_tag,
  56. '<img src="/report/barcode/?type=QR&amp;value='
  57. '%s&amp;width=300&amp;height=300">' % 'test%3Auri',
  58. )
  59. def test_compute_qr_code_tag_pyotp_use(self, pyotp_mock):
  60. '''Should call PyOTP twice with correct arguments if user_id present'''
  61. test_wiz = self._new_wizard()
  62. pyotp_mock.reset_mock()
  63. test_wiz._compute_qr_code_tag()
  64. pyotp_mock.TOTP.assert_called_once_with(test_wiz.secret_key)
  65. pyotp_mock.TOTP().provisioning_uri.assert_called_once_with(
  66. self.test_user.display_name,
  67. issuer_name=self.test_user.company_id.display_name,
  68. )
  69. def test_perform_validations_wrong_confirmation(self, pyotp_mock):
  70. '''Should raise correct error if PyOTP cannot verify code'''
  71. test_wiz = self._new_wizard()
  72. pyotp_mock.TOTP().verify.return_value = False
  73. with self.assertRaisesRegexp(ValidationError, 'confirmation code'):
  74. test_wiz._perform_validations()
  75. def test_perform_validations_right_confirmation(self, pyotp_mock):
  76. '''Should not raise error if PyOTP can verify code'''
  77. test_wiz = self._new_wizard()
  78. pyotp_mock.TOTP().verify.return_value = True
  79. try:
  80. test_wiz._perform_validations()
  81. except ValidationError:
  82. self.fail('A ValidationError was raised and should not have been.')
  83. def test_perform_validations_pyotp_use(self, pyotp_mock):
  84. '''Should call PyOTP twice with correct arguments'''
  85. test_wiz = self._new_wizard()
  86. pyotp_mock.reset_mock()
  87. test_wiz._perform_validations()
  88. pyotp_mock.TOTP.assert_called_once_with(test_wiz.secret_key)
  89. pyotp_mock.TOTP().verify.assert_called_once_with(
  90. test_wiz.confirmation_code,
  91. )
  92. def test_create_authenticator(self, pyotp_mock):
  93. '''Should create single authenticator record with correct info'''
  94. test_wiz = self._new_wizard()
  95. auth_model = self.env['res.users.authenticator']
  96. auth_model.search([('id', '>', 0)]).unlink()
  97. test_wiz._create_authenticator()
  98. test_auth = auth_model.search([('id', '>', 0)])
  99. self.assertEqual(len(test_auth), 1)
  100. self.assertEqual(
  101. (test_auth.name, test_auth.secret_key, test_auth.user_id),
  102. (test_wiz.name, test_wiz.secret_key, test_wiz.user_id),
  103. )
  104. def test_action_create_return_info(self, pyotp_mock):
  105. '''Should return info of user preferences action with user_id added'''
  106. test_wiz = self._new_wizard()
  107. test_info = self.env.ref('base.action_res_users_my').read()[0]
  108. test_info.update({'res_id': test_wiz.user_id.id})
  109. self.assertEqual(test_wiz.action_create(), test_info)
  110. def test_action_create_helper_use(self, pyotp_mock):
  111. '''Should call correct helper methods with proper arguments'''
  112. test_wiz = self._new_wizard()
  113. with mock.patch.multiple(
  114. test_wiz,
  115. _perform_validations=mock.DEFAULT,
  116. _create_authenticator=mock.DEFAULT,
  117. ):
  118. test_wiz.action_create()
  119. test_wiz._perform_validations.assert_called_once_with()
  120. test_wiz._create_authenticator.assert_called_once_with()