1745
1759
'login support to re-enable it',
1746
1760
'code': 'ACCOUNT_SUSPENDED',
1749
condition = "account '%s' is not active" % self.account.displayname
1750
self.mock_logger.debug("PasswordResetTokenHandler.create: email was "
1751
"not sent out because %s" % condition)
1763
self.mock_logger.debug.call_args,
1765
"PasswordResetTokenHandler.create: email was not sent out "
1766
"because account '{}' is Suspended (by admin)".format(
1767
self.account.displayname)
1753
1771
def test_deactivated_account(self):
1754
1772
self.account.status = AccountStatus.DEACTIVATED
1755
1773
self.account.save()
1757
name = 'identityprovider.models.account.Account.can_reset_password'
1758
with patch(name, False):
1759
content = self.do_post(data=self.data, status_code=403)
1761
self.assertEqual(content, {
1762
'message': 'Your account has been deactivated. To reactivate it, '
1763
'please reset your password',
1764
'code': 'ACCOUNT_DEACTIVATED',
1767
condition = "account '%s' is not active" % self.account.displayname
1768
self.mock_logger.debug("PasswordResetTokenHandler.create: email was "
1769
"not sent out because %s" % condition)
1771
def test_can_not_reset_password(self):
1772
name = 'identityprovider.models.account.Account.can_reset_password'
1773
with patch(name, False):
1774
content = self.do_post(data=self.data, status_code=403)
1776
self.assertEqual(content, {
1777
'message': 'Can not reset password. Please contact login support',
1778
'code': 'CAN_NOT_RESET_PASSWORD',
1781
condition = "account '%s' is not active" % self.account.displayname
1782
self.mock_logger.debug("PasswordResetTokenHandler.create: email was "
1783
"not sent out because %s" % condition)
1785
def test_reset_password(self):
1786
email = self.email.email
1787
body = self.do_post({'email': email}, status_code=201)
1789
self.assertEqual(body['email'], email)
1775
result = self.do_post(data=self.data, status_code=201)
1777
self.assert_email_used(result, self.account.preferredemail.email)
1779
def assert_email_used(self, result, expected_email):
1780
# Then the response contains the user's stored email.
1781
self.assertEqual(result['email'], expected_email)
1782
# and the reset email is sent to the user's stored email.
1791
1783
self.assertEqual(len(mail.outbox), 1)
1784
self.assertEqual([expected_email], mail.outbox[0].to)
1785
# and the mail content contains the user's stored email
1792
1786
mail_content = unicode(mail.outbox[0].message())
1787
self.assertIn(expected_email, mail_content)
1788
# and the mail contains a reset password link with a token
1793
1789
links = re.search(
1794
1790
('http://.+?/token/(.+?)/\+resetpassword'), mail_content)
1795
1791
self.assertIsNotNone(links, "Found no +resetpassword links with token")
1796
1792
token = links.group(1)
1797
1793
self.assertIn(token, mail_content)
1798
self.assertIn(email, mail_content)
1800
def test_reset_password_uses_preferred_if_given_not_validated(self):
1801
email = self.factory.make_email_for_account(
1802
self.account, status=EmailStatus.NEW)
1803
self.do_post({'email': email.email}, status_code=201)
1805
tokens = AuthToken.objects.filter(
1806
token_type=AuthTokenType.PASSWORDRECOVERY,
1808
self.assertEqual(tokens.count(), 0)
1810
tokens = AuthToken.objects.filter(
1811
token_type=AuthTokenType.PASSWORDRECOVERY,
1812
email=self.account.preferredemail)
1813
self.assertEqual(tokens.count(), 1)
1815
self.assertEqual(len(mail.outbox), 1)
1816
mail_content = unicode(mail.outbox[0].message())
1817
self.assertNotIn(email.email, mail_content)
1818
self.assertIn(self.account.preferredemail.email, mail_content)
1820
def test_reset_password_uses_given_email_if_validated(self):
1821
email = self.factory.make_email_for_account(
1822
self.account, status=EmailStatus.VALIDATED)
1823
assert self.account.preferredemail.email != email.email
1824
self.do_post({'email': email.email}, status_code=201)
1826
tokens = AuthToken.objects.filter(
1827
token_type=AuthTokenType.PASSWORDRECOVERY,
1828
email=self.account.preferredemail)
1829
self.assertEqual(tokens.count(), 0)
1831
tokens = AuthToken.objects.filter(
1832
token_type=AuthTokenType.PASSWORDRECOVERY,
1834
self.assertEqual(tokens.count(), 1)
1836
self.assertEqual(len(mail.outbox), 1)
1837
mail_content = unicode(mail.outbox[0].message())
1838
self.assertNotIn(self.account.preferredemail.email, mail_content)
1839
self.assertIn(email.email, mail_content)
1794
# and a token was generated for the user's stored email
1795
tokens = AuthToken.objects.filter(
1796
token_type=AuthTokenType.PASSWORDRECOVERY,
1797
email=expected_email)
1798
self.assertEqual(tokens.count(), 1)
1799
# and that's the only token generated
1802
AuthToken.objects.filter(
1803
token_type=AuthTokenType.PASSWORDRECOVERY
1807
def test_reset_password_given_preferred_email(self):
1808
# Given an account with a preferred email address
1809
self.factory.make_account(email="preferred@mail.com")
1811
# When a password reset request matches the preferred email.
1812
# Note the address matches but has distinct case, which for unicode
1813
# may be a distinct email address, so it's important we use the stored
1814
# address, not this one given in the request.
1815
result = self.do_post({'email': "PREFERRED@mail.com"}, status_code=201)
1817
# Then the password reset uses the stored preferred email
1818
self.assert_email_used(result, 'preferred@mail.com')
1820
def test_reset_password_given_new_email_uses_preferred(self):
1821
# Given an account with one preferred email address
1822
account = self.factory.make_account(email="preferred@mail.com")
1823
# and one new email address
1824
self.factory.make_email_for_account(
1825
account, email="new@mail.com", status=EmailStatus.NEW)
1827
# When a password reset gives an email matching the new email
1828
result = self.do_post({'email': "NEW@mail.com"}, status_code=201)
1830
# Then password reset uses the stored preferred email
1831
self.assert_email_used(result, 'preferred@mail.com')
1833
def test_reset_password_given_new_email_uses_validated(self):
1834
# Given an account with one new email address
1835
account = self.factory.make_account(
1836
email="new@mail.com", email_validated=False)
1837
# and one validated email address
1838
self.factory.make_email_for_account(
1839
account, email="validated@mail.com", status=EmailStatus.VALIDATED)
1841
# When a password reset gives an email matching the new email
1842
result = self.do_post({'email': "NEW@mail.com"}, status_code=201)
1844
# Then password reset uses the stored validated email
1845
self.assert_email_used(result, 'validated@mail.com')
1847
def test_reset_password_given_new_email_uses_new(self):
1848
# Given an account with one new email address
1849
self.factory.make_account(
1850
email="new@mail.com", email_validated=False)
1852
# When a password reset request matches the new address
1853
result = self.do_post({'email': "NEW@mail.com"}, status_code=201)
1855
# Then the password reset uses the stored new email
1856
self.assert_email_used(result, 'new@mail.com')
1858
def test_reset_password_given_validated_email_uses_it(self):
1859
# Given an account with one preferred email address
1860
account = self.factory.make_account(email="preferred@mail.com")
1861
# and one validated email address
1862
self.factory.make_email_for_account(
1863
account, email="validated@mail.com", status=EmailStatus.VALIDATED)
1865
# When a password reset request matches the validated address
1866
result = self.do_post({'email': "VALIDATED@mail.com"}, status_code=201)
1868
# Then the password reset uses the stored validated email
1869
self.assert_email_used(result, 'validated@mail.com')
1841
1871
def test_too_many_tokens(self):
1842
1872
with self.settings(MAX_PASSWORD_RESET_TOKENS=0):