usernames to be passed in remoteuser for the testknownuser test case users are not created when remote user is not specified numusers user objects count response self client getremoteuser self asserttrueresponse contextuser isanonymous self assertequaluser objects count numusers response self client getremoteuser self header none self asserttrueresponse contextuser isanonymous self assertequaluser objects count numusers response self client getremoteuser self header self asserttrueresponse contextuser isanonymous self assertequaluser objects count numusers def testcsrfvalidationpassesafterprocessrequestloginself csrfclient clientenforcecsrfcheckstrue csrfsecret getnewcsrfstring csrftoken maskciphersecretcsrfsecret csrftokenform maskciphersecretcsrfsecret headers self header fakeuser data csrfmiddlewaretoken csrftokenform verify that csrf is configured for the view csrfclient cookies loadsettings csrfcookiename csrftoken response csrfclient postremoteuser headers self assertequalresponse statuscode 403 self assertinbcsrf verification failed response content this request will call django contrib auth login which will call django middleware csrf rotatetoken thus changing the value of request meta csrfcookie from the user submitted value set by csrfviewmiddleware processrequest to the new csrftoken value set by rotatetoken csrf validation should still pass when the view is later processed by csrfviewmiddleware processview csrfclient cookies loadsettings csrfcookiename csrftoken response csrfclient postremoteuser data headers self assertequalresponse statuscode 200 def testunknownuserself numusers user objects count response self client getremoteuser self header newuser self assertequalresponse contextuser username newuser self assertequaluser objects count numusers 1 user objects getusernamenewuser another request with same user should not create any new users response self client getremoteuser self header newuser self assertequaluser objects count numusers 1 def testknownuserself user objects createusernameknownuser user objects createusernameknownuser2 numusers user objects count response self client getremoteuser self header self knownuser self assertequalresponse contextuser username knownuser self assertequaluser objects count numusers a different user passed in the headers causes the new user to be logged in response self client getremoteuser self header self knownuser2 self assertequalresponse contextuser username knownuser2 self assertequaluser objects count numusers def testlastloginself user user objects createusernameknownuser set lastlogin to something so we can determine if it changes defaultlogin datetime2000 1 1 if settings usetz defaultlogin defaultlogin replacetzinfotimezone utc user lastlogin defaultlogin user save response self client getremoteuser self header self knownuser self assertnotequaldefaultlogin response contextuser lastlogin user user objects getusernameknownuser user lastlogin defaultlogin user save response self client getremoteuser self header self knownuser self assertequaldefaultlogin response contextuser lastlogin def testheaderdisappearsself user objects createusernameknownuser known user authenticates response self client getremoteuser self header self knownuser self assertequalresponse contextuser username knownuser during the session the remoteuser header disappears should trigger logout response self client getremoteuser self asserttrueresponse contextuser isanonymous verify the remoteuser middleware will not remove a user authenticated via another backend user objects createuserusernamemodeluser passwordfoo self client loginusernamemodeluser passwordfoo authenticateusernamemodeluser passwordfoo response self client getremoteuser self assertequalresponse contextuser username modeluser def testuserswitchforcesnewloginself user objects createusernameknownuser known user authenticates response self client getremoteuser self header self knownuser self assertequalresponse contextuser username knownuser during the session the remoteuser changes to a different user response self client getremoteuser self header newnewuser the current user is not the prior remoteuser in backends that create a new user username is newnewuser in backends that do not create new users it is anonymous user self assertnotequalresponse contextuser username knownuser def testinactiveuserself user objects createusernameknownuser isactivefalse response self client getremoteuser self header knownuser self asserttrueresponse contextuser isanonymous class remoteusernocreatebackendremoteuserbackend contains the same tests as remoteusertest but using a custom auth backend class that doesn t create unknown users backend that allows inactive users backend django contrib auth backends allowallusersremoteuserbackend def testinactiveuserself user user objects createusernameknownuser isactivefalse response self client getremoteuser self header self knownuser self assertequalresponse contextuser username user username class customremoteuserbackendremoteuserbackend def cleanusernameself username return username split0 def configureuserself request user createdtrue user email request meta getremoteusertest emailheader if not created user lastname user username user save return user class remoteusercustomtestremoteusertest backend authtests testremoteuser customremoteuserbackend remoteuser strings with email addresses for the custom backend to clean knownuser knownuserexample com knownuser2 knownuser2example com def testknownuserself super testknownuser knownuser user objects getusernameknownuser knownuser2 user objects getusernameknownuser2 self assertequalknownuser email self assertequalknownuser2 email self assertequalknownuser lastname knownuser self assertequalknownuser2 lastname knownuser2 def testunknownuserself numusers user objects count response self client get remoteuser self header newuser self emailheader userexample com self assertequalresponse contextuser username newuser self assertequalresponse contextuser email userexample com self assertequalresponse contextuser lastname self assertequaluser objects count numusers 1 newuser user objects getusernamenewuser self assertequalnewuser email userexample com class customheadermiddlewareremoteusermiddleware header httpauthuser class customheaderremoteusertestremoteusertest middleware authtests testremoteuser customheadermiddleware header httpauthuser class persistentremoteusertestremoteusertest middleware django contrib auth middleware persistentremoteusermiddleware requireheader false def testheaderdisappearsself user objects createusernameknownuser known user authenticates response self client getremoteuser self header self knownuser self assertequalresponse contextuser username knownuser should stay logged in if the remoteuser header disappears response self client getremoteuser self assertfalseresponse contextuser isanonymous self assertequalresponse contextuser username knownuser usernames to be passed in remote_user for the test_known_user test case users are not created when remote user is not specified csrf check must access the csrf token from the session or cookie rather than the request as rotate_token may have been called by an authentication middleware during the process_request phase verify that csrf is configured for the view this request will call django contrib auth login which will call django middleware csrf rotate_token thus changing the value of request meta csrf_cookie from the user submitted value set by csrfviewmiddleware process_request to the new csrftoken value set by rotate_token csrf validation should still pass when the view is later processed by csrfviewmiddleware process_view tests the case where the username passed in the header does not exist as a user another request with same user should not create any new users tests the case where the username passed in the header is a valid user a different user passed in the headers causes the new user to be logged in a user s last_login is set the first time they make a request but not updated in subsequent requests with the same session set last_login to something so we can determine if it changes a logged in user is logged out automatically when the remote_user header disappears during the same browser session known user authenticates during the session the remote_user header disappears should trigger logout verify the remoteuser middleware will not remove a user authenticated via another backend if the username in the header changes between requests that the original user is logged out known user authenticates during the session the remote_user changes to a different user the current user is not the prior remote_user in backends that create a new user username is newnewuser in backends that do not create new users it is anonymous user backend that doesn t create unknown users contains the same tests as remoteusertest but using a custom auth backend class that doesn t create unknown users backend that allows inactive users backend that overrides remoteuserbackend methods grabs username before the character sets user s email address using the email specified in an http header sets user s last name for existing users tests a custom remoteuserbackend subclass that overrides the clean_username and configure_user methods remote_user strings with email addresses for the custom backend to clean the strings passed in remote_user should be cleaned and the known users should not have been configured with an email address the unknown user created should be configured with an email address provided in the request header middleware that overrides custom http auth user header tests a custom remoteusermiddleware subclass with custom http auth user header persistentremoteusermiddleware keeps the user logged in even if the subsequent calls do not contain the header value a logged in user is kept logged in even if the remote_user header disappears during the same browser session known user authenticates should stay logged in if the remote_user header disappears
from datetime import datetime, timezone

from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth.backends import RemoteUserBackend
from django.contrib.auth.middleware import RemoteUserMiddleware
from django.contrib.auth.models import User
from django.middleware.csrf import _get_new_csrf_string, _mask_cipher_secret
from django.test import Client, TestCase, modify_settings, override_settings


@override_settings(ROOT_URLCONF="auth_tests.urls")
class RemoteUserTest(TestCase):
    middleware = "django.contrib.auth.middleware.RemoteUserMiddleware"
    backend = "django.contrib.auth.backends.RemoteUserBackend"
    header = "REMOTE_USER"
    email_header = "REMOTE_EMAIL"

    
    known_user = "knownuser"
    known_user2 = "knownuser2"

    def setUp(self):
        self.patched_settings = modify_settings(
            AUTHENTICATION_BACKENDS={"append": self.backend},
            MIDDLEWARE={"append": self.middleware},
        )
        self.patched_settings.enable()

    def tearDown(self):
        self.patched_settings.disable()

    def test_no_remote_user(self):
        
        num_users = User.objects.count()

        response = self.client.get("/remote_user/")
        self.assertTrue(response.context["user"].is_anonymous)
        self.assertEqual(User.objects.count(), num_users)

        response = self.client.get("/remote_user/", **{self.header: None})
        self.assertTrue(response.context["user"].is_anonymous)
        self.assertEqual(User.objects.count(), num_users)

        response = self.client.get("/remote_user/", **{self.header: ""})
        self.assertTrue(response.context["user"].is_anonymous)
        self.assertEqual(User.objects.count(), num_users)

    def test_csrf_validation_passes_after_process_request_login(self):
        
        csrf_client = Client(enforce_csrf_checks=True)
        csrf_secret = _get_new_csrf_string()
        csrf_token = _mask_cipher_secret(csrf_secret)
        csrf_token_form = _mask_cipher_secret(csrf_secret)
        headers = {self.header: "fakeuser"}
        data = {"csrfmiddlewaretoken": csrf_token_form}

        
        csrf_client.cookies.load({settings.CSRF_COOKIE_NAME: csrf_token})
        response = csrf_client.post("/remote_user/", **headers)
        self.assertEqual(response.status_code, 403)
        self.assertIn(b"CSRF verification failed.", response.content)

        
        
        
        
        
        
        csrf_client.cookies.load({settings.CSRF_COOKIE_NAME: csrf_token})
        response = csrf_client.post("/remote_user/", data, **headers)
        self.assertEqual(response.status_code, 200)

    def test_unknown_user(self):
        
        num_users = User.objects.count()
        response = self.client.get("/remote_user/", **{self.header: "newuser"})
        self.assertEqual(response.context["user"].username, "newuser")
        self.assertEqual(User.objects.count(), num_users + 1)
        User.objects.get(username="newuser")

        
        response = self.client.get("/remote_user/", **{self.header: "newuser"})
        self.assertEqual(User.objects.count(), num_users + 1)

    def test_known_user(self):
        
        User.objects.create(username="knownuser")
        User.objects.create(username="knownuser2")
        num_users = User.objects.count()
        response = self.client.get("/remote_user/", **{self.header: self.known_user})
        self.assertEqual(response.context["user"].username, "knownuser")
        self.assertEqual(User.objects.count(), num_users)
        
        
        response = self.client.get("/remote_user/", **{self.header: self.known_user2})
        self.assertEqual(response.context["user"].username, "knownuser2")
        self.assertEqual(User.objects.count(), num_users)

    def test_last_login(self):
        
        user = User.objects.create(username="knownuser")
        
        default_login = datetime(2000, 1, 1)
        if settings.USE_TZ:
            default_login = default_login.replace(tzinfo=timezone.utc)
        user.last_login = default_login
        user.save()

        response = self.client.get("/remote_user/", **{self.header: self.known_user})
        self.assertNotEqual(default_login, response.context["user"].last_login)

        user = User.objects.get(username="knownuser")
        user.last_login = default_login
        user.save()
        response = self.client.get("/remote_user/", **{self.header: self.known_user})
        self.assertEqual(default_login, response.context["user"].last_login)

    def test_header_disappears(self):
        
        User.objects.create(username="knownuser")
        
        response = self.client.get("/remote_user/", **{self.header: self.known_user})
        self.assertEqual(response.context["user"].username, "knownuser")
        
        response = self.client.get("/remote_user/")
        self.assertTrue(response.context["user"].is_anonymous)
        
        
        User.objects.create_user(username="modeluser", password="foo")
        self.client.login(username="modeluser", password="foo")
        authenticate(username="modeluser", password="foo")
        response = self.client.get("/remote_user/")
        self.assertEqual(response.context["user"].username, "modeluser")

    def test_user_switch_forces_new_login(self):
        
        User.objects.create(username="knownuser")
        
        response = self.client.get("/remote_user/", **{self.header: self.known_user})
        self.assertEqual(response.context["user"].username, "knownuser")
        
        response = self.client.get("/remote_user/", **{self.header: "newnewuser"})
        
        
        
        self.assertNotEqual(response.context["user"].username, "knownuser")

    def test_inactive_user(self):
        User.objects.create(username="knownuser", is_active=False)
        response = self.client.get("/remote_user/", **{self.header: "knownuser"})
        self.assertTrue(response.context["user"].is_anonymous)


class RemoteUserNoCreateBackend(RemoteUserBackend):
    

    create_unknown_user = False


class RemoteUserNoCreateTest(RemoteUserTest):
    

    backend = "auth_tests.test_remote_user.RemoteUserNoCreateBackend"

    def test_unknown_user(self):
        num_users = User.objects.count()
        response = self.client.get("/remote_user/", **{self.header: "newuser"})
        self.assertTrue(response.context["user"].is_anonymous)
        self.assertEqual(User.objects.count(), num_users)


class AllowAllUsersRemoteUserBackendTest(RemoteUserTest):
    

    backend = "django.contrib.auth.backends.AllowAllUsersRemoteUserBackend"

    def test_inactive_user(self):
        user = User.objects.create(username="knownuser", is_active=False)
        response = self.client.get("/remote_user/", **{self.header: self.known_user})
        self.assertEqual(response.context["user"].username, user.username)


class CustomRemoteUserBackend(RemoteUserBackend):
    

    def clean_username(self, username):
        
        return username.split("@")[0]

    def configure_user(self, request, user, created=True):
        
        user.email = request.META.get(RemoteUserTest.email_header, "")
        if not created:
            user.last_name = user.username
        user.save()
        return user


class RemoteUserCustomTest(RemoteUserTest):
    

    backend = "auth_tests.test_remote_user.CustomRemoteUserBackend"
    
    
    known_user = "knownuser@example.com"
    known_user2 = "knownuser2@example.com"

    def test_known_user(self):
        
        super().test_known_user()
        knownuser = User.objects.get(username="knownuser")
        knownuser2 = User.objects.get(username="knownuser2")
        self.assertEqual(knownuser.email, "")
        self.assertEqual(knownuser2.email, "")
        self.assertEqual(knownuser.last_name, "knownuser")
        self.assertEqual(knownuser2.last_name, "knownuser2")

    def test_unknown_user(self):
        
        num_users = User.objects.count()
        response = self.client.get(
            "/remote_user/",
            **{
                self.header: "newuser",
                self.email_header: "user@example.com",
            },
        )
        self.assertEqual(response.context["user"].username, "newuser")
        self.assertEqual(response.context["user"].email, "user@example.com")
        self.assertEqual(response.context["user"].last_name, "")
        self.assertEqual(User.objects.count(), num_users + 1)
        newuser = User.objects.get(username="newuser")
        self.assertEqual(newuser.email, "user@example.com")


class CustomHeaderMiddleware(RemoteUserMiddleware):
    

    header = "HTTP_AUTHUSER"


class CustomHeaderRemoteUserTest(RemoteUserTest):
    

    middleware = "auth_tests.test_remote_user.CustomHeaderMiddleware"
    header = "HTTP_AUTHUSER"


class PersistentRemoteUserTest(RemoteUserTest):
    

    middleware = "django.contrib.auth.middleware.PersistentRemoteUserMiddleware"
    require_header = False

    def test_header_disappears(self):
        
        User.objects.create(username="knownuser")
        
        response = self.client.get("/remote_user/", **{self.header: self.known_user})
        self.assertEqual(response.context["user"].username, "knownuser")
        
        response = self.client.get("/remote_user/")
        self.assertFalse(response.context["user"].is_anonymous)
        self.assertEqual(response.context["user"].username, "knownuser")