Ticket #28645: 28645-jc.diff

File 28645-jc.diff, 5.5 KB (added by Tim Graham, 15 months ago)
  • django/contrib/auth/__init__.py

    diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py
    index 590f85442c..73dd3bbfc4 100644
    a b def _get_user_session_key(request): 
    5959    return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY])
    6060
    6161
    62 def authenticate(request=None, **credentials):
     62def authenticate_with_error_code(request=None, **credentials):
    6363    """
    6464    If the given credentials are valid, return a User object.
    6565    """
     66    failed_reasons = []
    6667    for backend, backend_path in _get_backends(return_tuples=True):
    6768        try:
    68             inspect.getcallargs(backend.authenticate, request, **credentials)
     69            inspect.getcallargs(backend.authenticate_with_error_code, request, **credentials)
     70            use_authenticate_with_error_code = True
    6971        except TypeError:
    70             # This backend doesn't accept these credentials as arguments. Try the next one.
    71             continue
     72            try:
     73                inspect.getcallargs(backend.authenticate, request, **credentials)
     74                use_authenticate_with_error_code = False
     75            except TypeError:
     76                # This backend doesn't accept these credentials as arguments. Try the next one.
     77                continue
    7278        try:
    73             user = backend.authenticate(request, **credentials)
     79            if use_authenticate_with_error_code:
     80                user, failed_reason = backend.authenticate_with_error_code(request, **credentials)
     81            else:
     82                user, failed_reason = backend.authenticate(request, **credentials), None
    7483        except PermissionDenied:
    7584            # This backend says to stop in our tracks - this user should not be allowed in at all.
    7685            break
    7786        if user is None:
     87            if failed_reason:
     88                failed_reasons.append(failed_reason)
    7889            continue
    7990        # Annotate the user object with the path of the backend.
    8091        user.backend = backend_path
    def authenticate(request=None, **credentials): 
    8394    # The credentials supplied are invalid to all backends, fire signal
    8495    user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials), request=request)
    8596
     97    return None, failed_reasons[0] if failed_reasons else None
     98
     99def authenticate(*args, **kwargs):
     100    return authenticate_with_error_code(*args, **kwargs)[0]
    86101
    87102def login(request, user, backend=None):
    88103    """
  • django/contrib/auth/backends.py

    diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py
    index 64937753ed..1f1a446d33 100644
    a b class ModelBackend: 
    99    Authenticates against settings.AUTH_USER_MODEL.
    1010    """
    1111
    12     def authenticate(self, request, username=None, password=None, **kwargs):
     12    def authenticate_with_error_code(self, request, username=None, password=None, **kwargs):
    1313        if username is None:
    1414            username = kwargs.get(UserModel.USERNAME_FIELD)
    1515        try:
    class ModelBackend: 
    1919            # difference between an existing and a nonexistent user (#20760).
    2020            UserModel().set_password(password)
    2121        else:
    22             if user.check_password(password) and self.user_can_authenticate(user):
    23                 return user
     22            if user.check_password(password):
     23                if self.user_can_authenticate(user):
     24                    return user, None
     25                else:
     26                    return None, "inactive"
     27        return None, None
     28
     29    def authenticate(self, *args, **kwargs):
     30        return self.authenticate_with_error_code(*args, **kwargs)[0]
    2431
    2532    def user_can_authenticate(self, user):
    2633        """
  • django/contrib/auth/forms.py

    diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
    index dfceccb2ec..9b7b2aa274 100644
    a b import unicodedata 
    22
    33from django import forms
    44from django.contrib.auth import (
    5     authenticate, get_user_model, password_validation,
     5    authenticate_with_error_code, get_user_model, password_validation,
    66)
    77from django.contrib.auth.hashers import (
    88    UNUSABLE_PASSWORD_PREFIX, identify_hasher,
    class AuthenticationForm(forms.Form): 
    189189        password = self.cleaned_data.get('password')
    190190
    191191        if username is not None and password:
    192             self.user_cache = authenticate(self.request, username=username, password=password)
     192            self.user_cache, failed_reason = authenticate_with_error_code(self.request, username=username, password=password)
    193193            if self.user_cache is None:
    194                 # An authentication backend may reject inactive users. Check
    195                 # if the user exists and is inactive, and raise the 'inactive'
    196                 # error if so.
    197                 try:
    198                     self.user_cache = UserModel._default_manager.get_by_natural_key(username)
    199                 except UserModel.DoesNotExist:
    200                     pass
    201                 else:
    202                     self.confirm_login_allowed(self.user_cache)
     194                # An authentication backend may specify a custom rejection reason.
     195                if failed_reason and failed_reason in self.error_messages:
     196                    raise forms.ValidationError(
     197                        self.error_messages[failed_reason],
     198                        code=failed_reason,
     199                    )
    203200                raise self.get_invalid_login_error()
    204201            else:
    205202                self.confirm_login_allowed(self.user_cache)
Back to Top