Admin login broken with custom authenticator

I've written a custom authenticator which auths users based on their email address and not their username. This has broken logins at /admin, as it apparently doesn't allow an email to be used in the username field:

Is there a way I could get around this issue?

Answers


Here is the relevant login method from the admin app (unimportant detail elided):

def login(self, request):
    from django.contrib.auth.models import User

    # Check the password.
    username = request.POST.get('username', None)
    password = request.POST.get('password', None)
    user = authenticate(username=username, password=password)
    if user is None:
        message = ERROR_MESSAGE
        if username is not None and u'@' in username:
            # Mistakenly entered e-mail address instead of username? Look it up.
            try:
                user = User.objects.get(email=username)
            except (User.DoesNotExist, User.MultipleObjectsReturned):
                message = _("Usernames cannot contain the '@' character.")
            else:
                if user.check_password(password):
                    message = _("Your e-mail address is not your username."
                                " Try '%s' instead.") % user.username
                else:
                    message = _("Usernames cannot contain the '@' character.")
        return self.display_login_form(request, message)

    # The user data is correct; log in the user in and continue.
    else:
        if user.is_active and user.is_staff:
            login(request, user)
            return http.HttpResponseRedirect(request.get_full_path())
        else:
            return self.display_login_form(request, ERROR_MESSAGE)
login = never_cache(login)

See how it tries to authenticate with the POST data fields of username and password? Notice also, how they don't use a django Form to do authentication? This is purely based on using the built in login and authenticate methods of the auth contrib app. This means there isn't really an opportunity to change the form. Instead, you have to ensure that your custom authenticator is registered as an authentication backend.

AUTHENTICATION_BACKENDS = ('mysite.backends.EmailBackend',)

Since the built in admin login method only checks for the existence of an email address if the AUTH_BACKEND returns no user, it means you should be free to use the email address in the existing form. This should work, but if it doesn't (and you've already set the Auth Backend), below is an alternative method.

So, what you could do, is override the admin login template, and post to your own custom login view which uses your own authenticator.

To override the default login page:

cp [src dir]/django/django/contrib/admin/templates/admin/login.html [project root]/templates/admin/login.html

Next, you'll want to strip out the existing form action, and point it to your own view:

<form action="/custom/login" method="post" id="login-form">{% csrf_token %}

I'm assuming you already have a view that does authentication, so post directly to that, and do a redirect on success to the main admin site.


Need Your Help

Jquery reading input field that was created from JSON loop

javascript jquery json input

I cannot figure out for the life of me why this will not work. I am trying to pull the value of a textfield that was created with a loop from a json file.

typeahead.js replace asp.net dropdownlist key/value

jquery asp.net typeahead.js

My goal is to replace an asp.net dropdownlist using typeahead.js. I have an asp.net web service which returns a list of General Ledger Accounts encoded in json with an example below: