Implement a custom authenticate middleware to correctly handle already-authenticated players in auto-connect webclient mode. Resolves #1037.

This commit is contained in:
Griatch 2016-09-14 22:32:58 +02:00
parent 86f963fa71
commit 07944918f7
3 changed files with 39 additions and 12 deletions

View file

@ -3,16 +3,38 @@ from django.contrib.auth import get_user_model
class CaseInsensitiveModelBackend(ModelBackend):
"""
By default ModelBackend does case _sensitive_ username authentication, which isn't what is
generally expected. This backend supports case insensitive username authentication.
By default ModelBackend does case _sensitive_ username
authentication, which isn't what is generally expected. This
backend supports case insensitive username authentication.
"""
def authenticate(self, username=None, password=None):
User = get_user_model()
try:
user = User.objects.get(username__iexact=username)
if user.check_password(password):
return user
def authenticate(self, username=None, password=None, autologin=None):
"""
Custom authenticate with bypass for auto-logins
Args:
username (str, optional): Name of user to authenticate.
password (str, optional): Password of user
autologin (Player, optional): If given, assume this is
an already authenticated player and bypass authentication.
"""
if autologin:
# Note: Setting .backend on player is critical in order to
# be allowed to call django.auth.login(player) later. This
# is necessary for the auto-login feature of the webclient,
# but it's important to make sure Django doesn't change this
# requirement or the name of the property down the line. /Griatch
autologin.backend = "evennia.web.utils.backends.CaseInsensitiveModelBackend"
return autologin
else:
return None
except User.DoesNotExist:
return None
# In this case .backend will be assigned automatically
# somewhere along the # way.
Player = get_user_model()
try:
player = Player.objects.get(username__iexact=username)
if player.check_password(password):
return player
else:
return None
except Player.DoesNotExist:
return None

View file

@ -6,7 +6,7 @@ page and serve it eventual static content.
"""
from __future__ import print_function
from django.shortcuts import render
from django.contrib.auth import login
from django.contrib.auth import login, authenticate
from evennia.players.models import PlayerDB
from evennia.utils import logger
@ -33,6 +33,8 @@ def _shared_login(request):
# The webclient has previously registered a login to this browser_session
player = PlayerDB.objects.get(id=sesslogin)
try:
# calls our custom authenticate in web/utils/backends.py
player = authenticate(autologin=player)
login(request, player)
except AttributeError:
logger.log_trace()

View file

@ -7,6 +7,7 @@ templates on the fly.
"""
from django.contrib.admin.sites import site
from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.admin.views.decorators import staff_member_required
from django.shortcuts import render
@ -39,6 +40,8 @@ def _shared_login(request):
# The webclient has previously registered a login to this csession
player = PlayerDB.objects.get(id=sesslogin)
try:
# calls our custom authenticate, in web/utils/backend.py
authenticate(autologin=player)
login(request, player)
except AttributeError:
logger.log_trace()