Fixed CVE-2018-6188 -- Fixed information leakage in AuthenticationForm.
Reverted 359370a8b8
(refs #28645).
This is a security fix.
This commit is contained in:
parent
552abffab1
commit
af33fb250e
|
@ -191,15 +191,6 @@ class AuthenticationForm(forms.Form):
|
|||
if username is not None and password:
|
||||
self.user_cache = authenticate(self.request, username=username, password=password)
|
||||
if self.user_cache is None:
|
||||
# An authentication backend may reject inactive users. Check
|
||||
# if the user exists and is inactive, and raise the 'inactive'
|
||||
# error if so.
|
||||
try:
|
||||
self.user_cache = UserModel._default_manager.get_by_natural_key(username)
|
||||
except UserModel.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
self.confirm_login_allowed(self.user_cache)
|
||||
raise self.get_invalid_login_error()
|
||||
else:
|
||||
self.confirm_login_allowed(self.user_cache)
|
||||
|
|
|
@ -2,9 +2,28 @@
|
|||
Django 1.11.10 release notes
|
||||
============================
|
||||
|
||||
*Expected February 1, 2018*
|
||||
*February 1, 2018*
|
||||
|
||||
Django 1.11.10 fixes several bugs in 1.11.9.
|
||||
Django 1.11.10 fixes a security issue and several bugs in 1.11.9.
|
||||
|
||||
CVE-2018-6188: Information leakage in ``AuthenticationForm``
|
||||
============================================================
|
||||
|
||||
A regression in Django 1.11.8 made
|
||||
:class:`~django.contrib.auth.forms.AuthenticationForm` run its
|
||||
``confirm_login_allowed()`` method even if an incorrect password is entered.
|
||||
This can leak information about a user, depending on what messages
|
||||
``confirm_login_allowed()`` raises. If ``confirm_login_allowed()`` isn't
|
||||
overridden, an attacker enter an arbitrary username and see if that user has
|
||||
been set to ``is_active=False``. If ``confirm_login_allowed()`` is overridden,
|
||||
more sensitive details could be leaked.
|
||||
|
||||
This issue is fixed with the caveat that ``AuthenticationForm`` can no longer
|
||||
raise the "This account is inactive." error if the authentication backend
|
||||
rejects inactive users (the default authentication backend, ``ModelBackend``,
|
||||
has done that since Django 1.10). This issue will be revisited for Django 2.1
|
||||
as a fix to address the caveat will likely be too invasive for inclusion in
|
||||
older versions.
|
||||
|
||||
Bugfixes
|
||||
========
|
||||
|
|
|
@ -2,9 +2,28 @@
|
|||
Django 2.0.2 release notes
|
||||
==========================
|
||||
|
||||
*Expected February 1, 2018*
|
||||
*February 1, 2018*
|
||||
|
||||
Django 2.0.2 fixes several bugs in 2.0.1.
|
||||
Django 2.0.2 fixes a security issue and several bugs in 2.0.1.
|
||||
|
||||
CVE-2018-6188: Information leakage in ``AuthenticationForm``
|
||||
============================================================
|
||||
|
||||
A regression in Django 1.11.8 made
|
||||
:class:`~django.contrib.auth.forms.AuthenticationForm` run its
|
||||
``confirm_login_allowed()`` method even if an incorrect password is entered.
|
||||
This can leak information about a user, depending on what messages
|
||||
``confirm_login_allowed()`` raises. If ``confirm_login_allowed()`` isn't
|
||||
overridden, an attacker enter an arbitrary username and see if that user has
|
||||
been set to ``is_active=False``. If ``confirm_login_allowed()`` is overridden,
|
||||
more sensitive details could be leaked.
|
||||
|
||||
This issue is fixed with the caveat that ``AuthenticationForm`` can no longer
|
||||
raise the "This account is inactive." error if the authentication backend
|
||||
rejects inactive users (the default authentication backend, ``ModelBackend``,
|
||||
has done that since Django 1.10). This issue will be revisited for Django 2.1
|
||||
as a fix to address the caveat will likely be too invasive for inclusion in
|
||||
older versions.
|
||||
|
||||
Bugfixes
|
||||
========
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
from django.contrib.admin.forms import AdminAuthenticationForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
|
||||
# To verify that the login form rejects inactive users, use an authentication
|
||||
# backend that allows them.
|
||||
@override_settings(AUTHENTICATION_BACKENDS=['django.contrib.auth.backends.AllowAllUsersModelBackend'])
|
||||
class AdminAuthenticationFormTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
|
|
@ -313,6 +313,9 @@ class UserCreationFormTest(ReloadFormsMixin, TestDataMixin, TestCase):
|
|||
self.assertTrue(form.is_valid())
|
||||
|
||||
|
||||
# To verify that the login form rejects inactive users, use an authentication
|
||||
# backend that allows them.
|
||||
@override_settings(AUTHENTICATION_BACKENDS=['django.contrib.auth.backends.AllowAllUsersModelBackend'])
|
||||
class AuthenticationFormTest(TestDataMixin, TestCase):
|
||||
|
||||
def test_invalid_username(self):
|
||||
|
@ -342,6 +345,24 @@ class AuthenticationFormTest(TestDataMixin, TestCase):
|
|||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(form.non_field_errors(), [str(form.error_messages['inactive'])])
|
||||
|
||||
# Use an authentication backend that rejects inactive users.
|
||||
@override_settings(AUTHENTICATION_BACKENDS=['django.contrib.auth.backends.ModelBackend'])
|
||||
def test_inactive_user_incorrect_password(self):
|
||||
"""An invalid login doesn't leak the inactive status of a user."""
|
||||
data = {
|
||||
'username': 'inactive',
|
||||
'password': 'incorrect',
|
||||
}
|
||||
form = AuthenticationForm(None, data)
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(
|
||||
form.non_field_errors(), [
|
||||
form.error_messages['invalid_login'] % {
|
||||
'username': User._meta.get_field('username').verbose_name
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
def test_login_failed(self):
|
||||
signal_calls = []
|
||||
|
||||
|
|
Loading…
Reference in New Issue