Kaelors
Kaelors

Reputation: 79

Django: custom http header authentification

I want to create an authentication for my Django 1.11 project. A user will be authenticated if the request contains the header : X_USERNAME. I am working with generic views so I use LoginRequiredMixin to control access.

I made this Custom authentication class:

class CustomAuthentication:
    def authenticate(self, request):
        username = request.META.get('X_USERNAME')
        logging.warning(username)
        if not username:
            return None
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            user = User(username=username)
            user.is_staff = False
            user.is_superuser = False
            if request.META.get('X_GROUPNAME') == 'administrator':
                user.is_staff = True
                user.is_superuser = True
            user.save()
        return user, None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

I added it in my settings :

AUTHENTICATION_BACKENDS = ['path.to.file.CustomAuthentication']

But I can't make it work. I am redirected to /accounts/login/?next= which doesn't exist.

Thanks in advance!

EDIT:

I also tried to create a subclass as described here : Django RemoteUser documentation since it looks like what I want to achieve:

class CustomAuthentication(RemoteUserMiddleware):
    header = 'HTTP_X_USERNAME'

It gave me the same result.

Upvotes: 4

Views: 2289

Answers (2)

Kaelors
Kaelors

Reputation: 79

I finally managed to find a solution :

In authentication.py:

from django.contrib.auth.middleware import RemoteUserMiddleware

class CustomMiddleware(RemoteUserMiddleware):
    header = 'HTTP_X_USERNAME'

The second import is compulsory i am not sure why.

In settings.py:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'app.authentication.CustomMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

AUTHENTICATION_BACKENDS = ['app.authentication.RemoteUserBackend']

And finally in the class based views I use LoginRequiredMixin

See: https://docs.djangoproject.com/en/3.2/howto/auth-remote-user/#configuration

Upvotes: 3

Will Keeling
Will Keeling

Reputation: 23054

It seems that the authenticate() method must specify username and password arguments in addition to the request argument. Without these, Django ignores the backend (see django.contrib.auth.__init__._authenticate_with_backend in Django 2.0).

In your case you should be able to default these arguments to None since you're providing the username via a header.

class CustomAuthentication:
    def authenticate(self, request, username=None, password=None):
        username = request.META.get('X_USERNAME')
        ...

Alternatively, use **credentials:

def authenticate(self, request, **credentials):

Upvotes: 0

Related Questions