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:
|
if username is not None and password:
|
||||||
self.user_cache = authenticate(self.request, username=username, password=password)
|
self.user_cache = authenticate(self.request, username=username, password=password)
|
||||||
if self.user_cache is None:
|
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()
|
raise self.get_invalid_login_error()
|
||||||
else:
|
else:
|
||||||
self.confirm_login_allowed(self.user_cache)
|
self.confirm_login_allowed(self.user_cache)
|
||||||
|
|
|
@ -2,9 +2,28 @@
|
||||||
Django 1.11.10 release notes
|
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
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
|
@ -2,9 +2,28 @@
|
||||||
Django 2.0.2 release notes
|
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
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
from django.contrib.admin.forms import AdminAuthenticationForm
|
from django.contrib.admin.forms import AdminAuthenticationForm
|
||||||
from django.contrib.auth.models import User
|
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):
|
class AdminAuthenticationFormTests(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
|
@ -313,6 +313,9 @@ class UserCreationFormTest(ReloadFormsMixin, TestDataMixin, TestCase):
|
||||||
self.assertTrue(form.is_valid())
|
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):
|
class AuthenticationFormTest(TestDataMixin, TestCase):
|
||||||
|
|
||||||
def test_invalid_username(self):
|
def test_invalid_username(self):
|
||||||
|
@ -342,6 +345,24 @@ class AuthenticationFormTest(TestDataMixin, TestCase):
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form.non_field_errors(), [str(form.error_messages['inactive'])])
|
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):
|
def test_login_failed(self):
|
||||||
signal_calls = []
|
signal_calls = []
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue