test_social_pipeline.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. # -*- coding: utf-8 -*-
  2. from django.contrib.auth import get_user_model
  3. from social_core.backends.github import GithubOAuth2
  4. from misago.core.exceptions import SocialAuthFailed, SocialAuthBanned
  5. from misago.users.models import Ban, BanCache
  6. from misago.users.social.pipeline import (
  7. associate_by_email, create_user, get_username, validate_ip_not_banned, validate_user_not_banned
  8. )
  9. from misago.users.testutils import UserTestCase
  10. UserModel = get_user_model()
  11. class MockRequest(object):
  12. def __init__(self, user_ip='0.0.0.0'):
  13. self.session = {}
  14. self.user_ip = user_ip
  15. class MockStrategy(object):
  16. def __init__(self, user_ip='0.0.0.0'):
  17. self.request = MockRequest(user_ip=user_ip)
  18. class PipelineTestCase(UserTestCase):
  19. def get_initial_user(self):
  20. self.user = self.get_authenticated_user()
  21. class AssociateByEmailTests(PipelineTestCase):
  22. def test_skip_if_user_is_already_set(self):
  23. """pipeline step is skipped if user was found by previous step"""
  24. result = associate_by_email(None, {}, GithubOAuth2, self.user)
  25. self.assertIsNone(result)
  26. def test_skip_if_no_email_passed(self):
  27. """pipeline step is skipped if no email was passed"""
  28. result = associate_by_email(None, {}, GithubOAuth2)
  29. self.assertIsNone(result)
  30. def test_skip_if_user_with_email_not_found(self):
  31. """pipeline step is skipped if no email was passed"""
  32. result = associate_by_email(None, {'email': 'not@found.com'}, GithubOAuth2)
  33. self.assertIsNone(result)
  34. def test_raise_if_user_is_inactive(self):
  35. """pipeline raises if user was inactive"""
  36. self.user.is_active = False
  37. self.user.save()
  38. try:
  39. associate_by_email(None, {'email': self.user.email}, GithubOAuth2)
  40. self.fail("associate_by_email should raise SocialAuthFailed")
  41. except SocialAuthFailed as e:
  42. self.assertEqual(
  43. e.message,
  44. (
  45. "The e-mail address associated with your GitHub account is not available for "
  46. "use on this site."
  47. ),
  48. )
  49. def test_raise_if_user_needs_admin_activation(self):
  50. """pipeline raises if user needs admin activation"""
  51. self.user.requires_activation = UserModel.ACTIVATION_ADMIN
  52. self.user.save()
  53. try:
  54. associate_by_email(None, {'email': self.user.email}, GithubOAuth2)
  55. self.fail("associate_by_email should raise SocialAuthFailed")
  56. except SocialAuthFailed as e:
  57. self.assertEqual(
  58. e.message,
  59. (
  60. "Your account has to be activated by site administrator before you will be "
  61. "able to sign in with GitHub."
  62. ),
  63. )
  64. def test_return_user(self):
  65. """pipeline returns user if email was found"""
  66. result = associate_by_email(None, {'email': self.user.email}, GithubOAuth2)
  67. self.assertEqual(result, {'user': self.user, 'is_new': False})
  68. def test_return_user_email_inactive(self):
  69. """pipeline returns user even if they didn't activate their account manually"""
  70. self.user.requires_activation = UserModel.ACTIVATION_USER
  71. self.user.save()
  72. result = associate_by_email(None, {'email': self.user.email}, GithubOAuth2)
  73. self.assertEqual(result, {'user': self.user, 'is_new': False})
  74. class CreateUser(PipelineTestCase):
  75. def test_skip_if_user_is_set(self):
  76. """pipeline step is skipped if user was passed"""
  77. result = create_user(None, {}, None, user=self.user)
  78. self.assertIsNone(result)
  79. def test_skip_if_no_email_passed(self):
  80. """pipeline step is skipped if no email was passed"""
  81. details = {
  82. 'clean_username': 'TestBob',
  83. }
  84. result = create_user(None, details, None)
  85. self.assertIsNone(result)
  86. def test_skip_if_no_clean_username_passed(self):
  87. """pipeline step is skipped if cleaned username wasnt passed"""
  88. details = {
  89. 'email': 'hello@example.com',
  90. }
  91. result = create_user(None, details, None)
  92. self.assertIsNone(result)
  93. def test_skip_if_email_is_taken(self):
  94. """pipeline step is skipped if email was taken"""
  95. details = {
  96. 'email': self.user.email,
  97. }
  98. result = create_user(None, details, None)
  99. self.assertIsNone(result)
  100. def test_user_is_created(self):
  101. """pipeline step returns user if data is correct"""
  102. details = {
  103. 'email': 'new@example.com'
  104. 'clean_username': 'NewUser',
  105. }
  106. result = create_user(None, details, None)
  107. new_user = UserModel.objects.get(email='new@example.com')
  108. self.assertEqual(result, {
  109. 'user': new_user,
  110. 'is_new': True,
  111. })
  112. self.assertEqual(new_user.username, 'NewUser')
  113. self.assertFalse(new_user.has_useable_password())
  114. class GetUsernameTests(PipelineTestCase):
  115. def test_skip_if_user_is_set(self):
  116. """pipeline step is skipped if user was passed"""
  117. result = get_username(None, {}, None, user=self.user)
  118. self.assertIsNone(result)
  119. def test_skip_if_no_names(self):
  120. """pipeline step is skipped if API returned no names"""
  121. result = get_username(None, {}, None)
  122. self.assertIsNone(result)
  123. def test_resolve_to_username(self):
  124. """pipeline step resolves username"""
  125. result = get_username(None, {'username': 'BobBoberson'}, None)
  126. self.assertEqual(result, {'clean_username': 'BobBoberson'})
  127. def test_normalize_username(self):
  128. """pipeline step normalizes username"""
  129. result = get_username(None, {'username': u'Błop Błoperson'}, None)
  130. self.assertEqual(result, {'clean_username': 'BlopBloperson'})
  131. def test_resolve_to_first_name(self):
  132. """pipeline attempts to use first name because username is taken"""
  133. details = {
  134. 'username': self.user.username,
  135. 'first_name': u'Błob',
  136. }
  137. result = get_username(None, details, None)
  138. self.assertEqual(result, {'clean_username': 'Blob'})
  139. def test_dont_resolve_to_last_name(self):
  140. """pipeline will not fallback to last name because username is taken"""
  141. details = {
  142. 'username': self.user.username,
  143. 'last_name': u'Błob',
  144. }
  145. result = get_username(None, details, None)
  146. self.assertIsNone(result)
  147. def test_resolve_to_first_last_name_first_char(self):
  148. """pipeline will construct username from first name and first char of surname"""
  149. details = {
  150. 'first_name': self.user.username,
  151. 'last_name': u'Błob',
  152. }
  153. result = get_username(None, details, None)
  154. self.assertEqual(result, {'clean_username': self.user.username + 'B'})
  155. def test_dont_resolve_to_banned_name(self):
  156. """pipeline will not resolve to banned name"""
  157. Ban.objects.create(banned_value='*Admin*', check_type=Ban.USERNAME)
  158. details = {
  159. 'username': 'Misago Admin',
  160. 'first_name': u'Błob',
  161. }
  162. result = get_username(None, details, None)
  163. self.assertEqual(result, {'clean_username': 'Blob'})
  164. def test_resolve_full_name(self):
  165. """pipeline will resolve to full name"""
  166. Ban.objects.create(banned_value='*Admin*', check_type=Ban.USERNAME)
  167. details = {
  168. 'username': 'Misago Admin',
  169. 'full_name': u'Błob Błopo',
  170. }
  171. result = get_username(None, details, None)
  172. self.assertEqual(result, {'clean_username': 'BlobBlopo'})
  173. def test_resolve_to_cut_name(self):
  174. """pipeline will resolve cut too long name on second pass"""
  175. details = {
  176. 'username': u'Abrakadabrapokuskonstantynopolitańczykowianeczkatrzy',
  177. }
  178. result = get_username(None, details, None)
  179. self.assertEqual(result, {'clean_username': 'Abrakadabrapok'})
  180. class ValidateIpNotBannedTests(PipelineTestCase):
  181. def test_skip_if_user_not_set(self):
  182. """pipeline step is skipped if no user was passed"""
  183. result = validate_ip_not_banned(None, {}, GithubOAuth2)
  184. self.assertIsNone(result)
  185. def test_raise_if_banned(self):
  186. """pipeline raises if user's IP is banned"""
  187. Ban.objects.create(banned_value='188.*', check_type=Ban.IP)
  188. try:
  189. validate_ip_not_banned(MockStrategy(user_ip='188.1.2.3'), {}, GithubOAuth2, self.user)
  190. self.fail("validate_ip_not_banned should raise SocialAuthBanned")
  191. except SocialAuthBanned as e:
  192. self.assertTrue(isinstance(e.ban, Ban))
  193. def test_exclude_staff(self):
  194. """pipeline excludes staff from bans"""
  195. self.user.is_staff = True
  196. self.user.save()
  197. Ban.objects.create(banned_value='188.*', check_type=Ban.IP)
  198. result = validate_ip_not_banned(
  199. MockStrategy(user_ip='188.1.2.3'), {}, GithubOAuth2, self.user)
  200. self.assertIsNone(result)
  201. class ValidateUserNotBannedTests(PipelineTestCase):
  202. def test_skip_if_user_not_set(self):
  203. """pipeline step is skipped if no user was passed"""
  204. result = validate_user_not_banned(None, {}, GithubOAuth2)
  205. self.assertIsNone(result)
  206. def test_raise_if_banned(self):
  207. """pipeline raises if user's IP is banned"""
  208. Ban.objects.create(banned_value=self.user.username, check_type=Ban.USERNAME)
  209. try:
  210. validate_user_not_banned(MockStrategy(), {}, GithubOAuth2, self.user)
  211. self.fail("validate_ip_not_banned should raise SocialAuthBanned")
  212. except SocialAuthBanned as e:
  213. self.assertEqual(e.ban.user, self.user)
  214. self.assertTrue(isinstance(e.ban, BanCache))
  215. def test_exclude_staff(self):
  216. """pipeline excludes staff from bans"""
  217. self.user.is_staff = True
  218. self.user.save()
  219. Ban.objects.create(banned_value=self.user.username, check_type=Ban.USERNAME)
  220. result = validate_user_not_banned(MockStrategy(), {}, GithubOAuth2, self.user)
  221. self.assertIsNone(result)