Commit adb88961 by Eric Fischer

Merge pull request #11658 from edx/laq/multiple_login_failures

Avoid MultipleObjectsReturned errors with LoginFailures
parents 3be2737f 8442e4d1
...@@ -265,3 +265,4 @@ Muhammad Ayub Khan <ayub.khan@arbisoft.com> ...@@ -265,3 +265,4 @@ Muhammad Ayub Khan <ayub.khan@arbisoft.com>
Kaloian Doganov <doganov@gmail.com> Kaloian Doganov <doganov@gmail.com>
Sanford Student <sstudent@edx.org> Sanford Student <sstudent@edx.org>
Florian Haas <florian@hastexo.com> Florian Haas <florian@hastexo.com>
Leonardo Quiñonez <leonardo.quinonez@edunext.co>
...@@ -772,6 +772,19 @@ class LoginFailures(models.Model): ...@@ -772,6 +772,19 @@ class LoginFailures(models.Model):
lockout_until = models.DateTimeField(null=True) lockout_until = models.DateTimeField(null=True)
@classmethod @classmethod
def _get_record_for_user(cls, user):
"""
Gets a user's record, and fixes any duplicates that may have arisen due to get_or_create
race conditions. See https://code.djangoproject.com/ticket/13906 for details.
Use this method in place of `LoginFailures.objects.get(user=user)`
"""
records = LoginFailures.objects.filter(user=user).order_by('-lockout_until')
for extra_record in records[1:]:
extra_record.delete()
return records.get()
@classmethod
def is_feature_enabled(cls): def is_feature_enabled(cls):
""" """
Returns whether the feature flag around this functionality has been set Returns whether the feature flag around this functionality has been set
...@@ -784,7 +797,7 @@ class LoginFailures(models.Model): ...@@ -784,7 +797,7 @@ class LoginFailures(models.Model):
Static method to return in a given user has his/her account locked out Static method to return in a given user has his/her account locked out
""" """
try: try:
record = LoginFailures.objects.get(user=user) record = cls._get_record_for_user(user)
if not record.lockout_until: if not record.lockout_until:
return False return False
...@@ -819,7 +832,7 @@ class LoginFailures(models.Model): ...@@ -819,7 +832,7 @@ class LoginFailures(models.Model):
Removes the lockout counters (normally called after a successful login) Removes the lockout counters (normally called after a successful login)
""" """
try: try:
entry = LoginFailures.objects.get(user=user) entry = cls._get_record_for_user(user)
entry.delete() entry.delete()
except ObjectDoesNotExist: except ObjectDoesNotExist:
return return
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment