Loading django/contrib/auth/backends.py +24 −4 Original line number Diff line number Diff line Loading @@ -15,12 +15,21 @@ class ModelBackend(object): username = kwargs.get(UserModel.USERNAME_FIELD) try: user = UserModel._default_manager.get_by_natural_key(username) if user.check_password(password): return user except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a non-existing user (#20760). UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user def user_can_authenticate(self, user): """ Reject users with is_active=False. Custom user models that don't have that attribute are allowed. """ is_active = getattr(user, 'is_active', None) return is_active or is_active is None def _get_user_permissions(self, user_obj): return user_obj.user_permissions.all() Loading Loading @@ -90,9 +99,15 @@ class ModelBackend(object): def get_user(self, user_id): UserModel = get_user_model() try: return UserModel._default_manager.get(pk=user_id) user = UserModel._default_manager.get(pk=user_id) except UserModel.DoesNotExist: return None return user if self.user_can_authenticate(user) else None class AllowAllUsersModelBackend(ModelBackend): def user_can_authenticate(self, user): return True class RemoteUserBackend(ModelBackend): Loading Loading @@ -140,7 +155,7 @@ class RemoteUserBackend(ModelBackend): user = UserModel._default_manager.get_by_natural_key(username) except UserModel.DoesNotExist: pass return user return user if self.user_can_authenticate(user) else None def clean_username(self, username): """ Loading @@ -158,3 +173,8 @@ class RemoteUserBackend(ModelBackend): By default, returns the user unmodified. """ return user class AllowAllUsersRemoteUserBackend(RemoteUserBackend): def user_can_authenticate(self, user): return True docs/howto/auth-remote-user.txt +14 −3 Original line number Diff line number Diff line Loading @@ -64,10 +64,21 @@ remote users. These interfaces work with users stored in the database regardless of ``AUTHENTICATION_BACKENDS``. .. note:: Since the ``RemoteUserBackend`` inherits from ``ModelBackend``, you will still have all of the same permissions checking that is implemented in ``ModelBackend``. Users with :attr:`is_active=False <django.contrib.auth.models.User.is_active>` won't be allowed to authenticate. Use :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` if you want to allow them to. .. versionchanged:: 1.10 In older versions, inactive users weren't rejected as described above. If your authentication mechanism uses a custom HTTP header and not ``REMOTE_USER``, you can subclass ``RemoteUserMiddleware`` and set the ``header`` attribute to the desired ``request.META`` key. For example:: Loading docs/ref/contrib/auth.txt +63 −8 Original line number Diff line number Diff line Loading @@ -76,15 +76,26 @@ Fields This doesn't necessarily control whether or not the user can log in. Authentication backends aren't required to check for the ``is_active`` flag, and the default backends do not. If you want to reject a login based on ``is_active`` being ``False``, it's up to you to check that in your own login view or a custom authentication backend. However, the flag but the default backend (:class:`~django.contrib.auth.backends.ModelBackend`) and the :class:`~django.contrib.auth.backends.RemoteUserBackend` do. You can use :class:`~django.contrib.auth.backends.AllowAllUsersModelBackend` or :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` if you want to allow inactive users to login. In this case, you'll also want to customize the :class:`~django.contrib.auth.forms.AuthenticationForm` used by the :func:`~django.contrib.auth.views.login` view (which is the default) *does* perform this check, as do the permission-checking methods such as :meth:`~django.contrib.auth.models.User.has_perm` and the authentication in the Django admin. All of those functions/methods will return ``False`` for inactive users. :func:`~django.contrib.auth.views.login` view as it rejects inactive users. Be aware that the permission-checking methods such as :meth:`~django.contrib.auth.models.User.has_perm` and the authentication in the Django admin all return ``False`` for inactive users. .. versionchanged:: 1.10 In older versions, :class:`~django.contrib.auth.backends.ModelBackend` and :class:`~django.contrib.auth.backends.RemoteUserBackend` allowed inactive users to authenticate. .. attribute:: is_superuser Loading Loading @@ -488,6 +499,32 @@ The following backends are available in :mod:`django.contrib.auth.backends`: Returns whether the ``user_obj`` has any permissions on the app ``app_label``. .. method:: ModelBackend.user_can_authenticate() .. versionadded:: 1.10 Returns whether the user is allowed to authenticate. To match the behavior of :class:`~django.contrib.auth.forms.AuthenticationForm` which :meth:`prohibits inactive users from logging in <django.contrib.auth.forms.AuthenticationForm.confirm_login_allowed>`, this method returns ``False`` for users with :attr:`is_active=False <django.contrib.auth.models.User.is_active>`. Custom user models that don't have an :attr:`~django.contrib.auth.models.CustomUser.is_active` field are allowed. .. class:: AllowAllUsersModelBackend .. versionadded:: 1.10 Same as :class:`ModelBackend` except that it doesn't reject inactive users because :meth:`~ModelBackend.user_can_authenticate` always returns ``True``. When using this backend, you'll likely want to customize the :class:`~django.contrib.auth.forms.AuthenticationForm` used by the :func:`~django.contrib.auth.views.login` view by overriding the :meth:`~django.contrib.auth.forms.AuthenticationForm.confirm_login_allowed` method as it rejects inactive users. .. class:: RemoteUserBackend Use this backend to take advantage of external-to-Django-handled Loading Loading @@ -529,3 +566,21 @@ The following backends are available in :mod:`django.contrib.auth.backends`: new user is created, and can be used to perform custom setup actions, such as setting the user's groups based on attributes in an LDAP directory. Returns the user object. .. method:: RemoteUserBackend.user_can_authenticate() .. versionadded:: 1.10 Returns whether the user is allowed to authenticate. This method returns ``False`` for users with :attr:`is_active=False <django.contrib.auth.models.User.is_active>`. Custom user models that don't have an :attr:`~django.contrib.auth.models.CustomUser.is_active` field are allowed. .. class:: AllowAllUsersRemoteUserBackend .. versionadded:: 1.10 Same as :class:`RemoteUserBackend` except that it doesn't reject inactive users because :attr:`~RemoteUserBackend.user_can_authenticate` always returns ``True``. docs/releases/1.10.txt +9 −0 Original line number Diff line number Diff line Loading @@ -669,6 +669,15 @@ Miscellaneous calling ``Command.execute()``, pass the command object as the first argument to ``call_command()``. * :class:`~django.contrib.auth.backends.ModelBackend` and :class:`~django.contrib.auth.backends.RemoteUserBackend` now reject inactive users. This means that inactive users can't login and will be logged out if they are switched from ``is_active=True`` to ``False``. If you need the previous behavior, use the new :class:`~django.contrib.auth.backends.AllowAllUsersModelBackend` or :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` in :setting:`AUTHENTICATION_BACKENDS` instead. .. _deprecated-features-1.10: Features deprecated in 1.10 Loading docs/topics/auth/customizing.txt +15 −4 Original line number Diff line number Diff line Loading @@ -235,10 +235,17 @@ for example, to control anonymous access. Authorization for inactive users ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ An inactive user is a one that is authenticated but has its attribute ``is_active`` set to ``False``. However this does not mean they are not authorized to do anything. For example they are allowed to activate their account. An inactive user is a one that has its :attr:`~django.contrib.auth.models.User.is_active` field set to ``False``. The :class:`~django.contrib.auth.backends.ModelBackend` and :class:`~django.contrib.auth.backends.RemoteUserBackend` authentication backends prohibits these users from authenticating. If a custom user model doesn't have an :attr:`~django.contrib.auth.models.CustomUser.is_active` field, all users will be allowed to authenticate. You can use :class:`~django.contrib.auth.backends.AllowAllUsersModelBackend` or :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` if you want to allow inactive users to authenticate. The support for anonymous users in the permission system allows for a scenario where anonymous users have permissions to do something while inactive Loading @@ -247,6 +254,10 @@ authenticated users do not. Do not forget to test for the ``is_active`` attribute of the user in your own backend permission methods. .. versionchanged:: 1.10 In older versions, the :class:`~django.contrib.auth.backends.ModelBackend` allowed inactive users to authenticate. Handling object permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading Loading
django/contrib/auth/backends.py +24 −4 Original line number Diff line number Diff line Loading @@ -15,12 +15,21 @@ class ModelBackend(object): username = kwargs.get(UserModel.USERNAME_FIELD) try: user = UserModel._default_manager.get_by_natural_key(username) if user.check_password(password): return user except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a non-existing user (#20760). UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user def user_can_authenticate(self, user): """ Reject users with is_active=False. Custom user models that don't have that attribute are allowed. """ is_active = getattr(user, 'is_active', None) return is_active or is_active is None def _get_user_permissions(self, user_obj): return user_obj.user_permissions.all() Loading Loading @@ -90,9 +99,15 @@ class ModelBackend(object): def get_user(self, user_id): UserModel = get_user_model() try: return UserModel._default_manager.get(pk=user_id) user = UserModel._default_manager.get(pk=user_id) except UserModel.DoesNotExist: return None return user if self.user_can_authenticate(user) else None class AllowAllUsersModelBackend(ModelBackend): def user_can_authenticate(self, user): return True class RemoteUserBackend(ModelBackend): Loading Loading @@ -140,7 +155,7 @@ class RemoteUserBackend(ModelBackend): user = UserModel._default_manager.get_by_natural_key(username) except UserModel.DoesNotExist: pass return user return user if self.user_can_authenticate(user) else None def clean_username(self, username): """ Loading @@ -158,3 +173,8 @@ class RemoteUserBackend(ModelBackend): By default, returns the user unmodified. """ return user class AllowAllUsersRemoteUserBackend(RemoteUserBackend): def user_can_authenticate(self, user): return True
docs/howto/auth-remote-user.txt +14 −3 Original line number Diff line number Diff line Loading @@ -64,10 +64,21 @@ remote users. These interfaces work with users stored in the database regardless of ``AUTHENTICATION_BACKENDS``. .. note:: Since the ``RemoteUserBackend`` inherits from ``ModelBackend``, you will still have all of the same permissions checking that is implemented in ``ModelBackend``. Users with :attr:`is_active=False <django.contrib.auth.models.User.is_active>` won't be allowed to authenticate. Use :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` if you want to allow them to. .. versionchanged:: 1.10 In older versions, inactive users weren't rejected as described above. If your authentication mechanism uses a custom HTTP header and not ``REMOTE_USER``, you can subclass ``RemoteUserMiddleware`` and set the ``header`` attribute to the desired ``request.META`` key. For example:: Loading
docs/ref/contrib/auth.txt +63 −8 Original line number Diff line number Diff line Loading @@ -76,15 +76,26 @@ Fields This doesn't necessarily control whether or not the user can log in. Authentication backends aren't required to check for the ``is_active`` flag, and the default backends do not. If you want to reject a login based on ``is_active`` being ``False``, it's up to you to check that in your own login view or a custom authentication backend. However, the flag but the default backend (:class:`~django.contrib.auth.backends.ModelBackend`) and the :class:`~django.contrib.auth.backends.RemoteUserBackend` do. You can use :class:`~django.contrib.auth.backends.AllowAllUsersModelBackend` or :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` if you want to allow inactive users to login. In this case, you'll also want to customize the :class:`~django.contrib.auth.forms.AuthenticationForm` used by the :func:`~django.contrib.auth.views.login` view (which is the default) *does* perform this check, as do the permission-checking methods such as :meth:`~django.contrib.auth.models.User.has_perm` and the authentication in the Django admin. All of those functions/methods will return ``False`` for inactive users. :func:`~django.contrib.auth.views.login` view as it rejects inactive users. Be aware that the permission-checking methods such as :meth:`~django.contrib.auth.models.User.has_perm` and the authentication in the Django admin all return ``False`` for inactive users. .. versionchanged:: 1.10 In older versions, :class:`~django.contrib.auth.backends.ModelBackend` and :class:`~django.contrib.auth.backends.RemoteUserBackend` allowed inactive users to authenticate. .. attribute:: is_superuser Loading Loading @@ -488,6 +499,32 @@ The following backends are available in :mod:`django.contrib.auth.backends`: Returns whether the ``user_obj`` has any permissions on the app ``app_label``. .. method:: ModelBackend.user_can_authenticate() .. versionadded:: 1.10 Returns whether the user is allowed to authenticate. To match the behavior of :class:`~django.contrib.auth.forms.AuthenticationForm` which :meth:`prohibits inactive users from logging in <django.contrib.auth.forms.AuthenticationForm.confirm_login_allowed>`, this method returns ``False`` for users with :attr:`is_active=False <django.contrib.auth.models.User.is_active>`. Custom user models that don't have an :attr:`~django.contrib.auth.models.CustomUser.is_active` field are allowed. .. class:: AllowAllUsersModelBackend .. versionadded:: 1.10 Same as :class:`ModelBackend` except that it doesn't reject inactive users because :meth:`~ModelBackend.user_can_authenticate` always returns ``True``. When using this backend, you'll likely want to customize the :class:`~django.contrib.auth.forms.AuthenticationForm` used by the :func:`~django.contrib.auth.views.login` view by overriding the :meth:`~django.contrib.auth.forms.AuthenticationForm.confirm_login_allowed` method as it rejects inactive users. .. class:: RemoteUserBackend Use this backend to take advantage of external-to-Django-handled Loading Loading @@ -529,3 +566,21 @@ The following backends are available in :mod:`django.contrib.auth.backends`: new user is created, and can be used to perform custom setup actions, such as setting the user's groups based on attributes in an LDAP directory. Returns the user object. .. method:: RemoteUserBackend.user_can_authenticate() .. versionadded:: 1.10 Returns whether the user is allowed to authenticate. This method returns ``False`` for users with :attr:`is_active=False <django.contrib.auth.models.User.is_active>`. Custom user models that don't have an :attr:`~django.contrib.auth.models.CustomUser.is_active` field are allowed. .. class:: AllowAllUsersRemoteUserBackend .. versionadded:: 1.10 Same as :class:`RemoteUserBackend` except that it doesn't reject inactive users because :attr:`~RemoteUserBackend.user_can_authenticate` always returns ``True``.
docs/releases/1.10.txt +9 −0 Original line number Diff line number Diff line Loading @@ -669,6 +669,15 @@ Miscellaneous calling ``Command.execute()``, pass the command object as the first argument to ``call_command()``. * :class:`~django.contrib.auth.backends.ModelBackend` and :class:`~django.contrib.auth.backends.RemoteUserBackend` now reject inactive users. This means that inactive users can't login and will be logged out if they are switched from ``is_active=True`` to ``False``. If you need the previous behavior, use the new :class:`~django.contrib.auth.backends.AllowAllUsersModelBackend` or :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` in :setting:`AUTHENTICATION_BACKENDS` instead. .. _deprecated-features-1.10: Features deprecated in 1.10 Loading
docs/topics/auth/customizing.txt +15 −4 Original line number Diff line number Diff line Loading @@ -235,10 +235,17 @@ for example, to control anonymous access. Authorization for inactive users ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ An inactive user is a one that is authenticated but has its attribute ``is_active`` set to ``False``. However this does not mean they are not authorized to do anything. For example they are allowed to activate their account. An inactive user is a one that has its :attr:`~django.contrib.auth.models.User.is_active` field set to ``False``. The :class:`~django.contrib.auth.backends.ModelBackend` and :class:`~django.contrib.auth.backends.RemoteUserBackend` authentication backends prohibits these users from authenticating. If a custom user model doesn't have an :attr:`~django.contrib.auth.models.CustomUser.is_active` field, all users will be allowed to authenticate. You can use :class:`~django.contrib.auth.backends.AllowAllUsersModelBackend` or :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` if you want to allow inactive users to authenticate. The support for anonymous users in the permission system allows for a scenario where anonymous users have permissions to do something while inactive Loading @@ -247,6 +254,10 @@ authenticated users do not. Do not forget to test for the ``is_active`` attribute of the user in your own backend permission methods. .. versionchanged:: 1.10 In older versions, the :class:`~django.contrib.auth.backends.ModelBackend` allowed inactive users to authenticate. Handling object permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading