Skip to Content

Technology Blog

Technology Blog

Testing As a Different Django User

Recently updated on

All types of Django auth do basically the same thing: They associate a browser session ID with a Django user if the user logs-in successfully.  I found a neat technique to bypass a Django login by modifying with a Django session, which can be useful for testing purposes.

Why is this trick this useful?  Sometimes it's difficult to replicate a login that uses a complicated authentication system (i.e. Facebook auth or OpenID auth) when developing on a local desktop.  I've sometimes found myself wanting to browse a local development copy of a site from the perspective of a particular user.  I obviously can't login to the local development site using that user's Facebook login, so I have to bypass the login step. 

What this isn't:  This trick isn't an exploit or a bug of any sort.  It only works when you have python shell access to a Django application, which means you already have full control over the application's data.  Nonetheless, this should be used for development and testing purposes only. 

This assumes that you are using Django's default model-based session backend (django.contrib.sessions.models.Session), but probably can be adjusted to work with other session backends. 

So to bypass a login, one can do this two step process:

Find the value of the session ID that Django sent to the browser.

Change the Django user ID stored with that session.

To get started, you'll want to browse to your site in a Web browser and find the sessionid cookie that Django provides your browser.  If the session middleware is enabled in the Django site, a sessionid cookie will be sent to your browser automatically, assuming your browser does not already have one. 

Most browsers have a way to view the values of your cookies, though there are a few plugins which make this task easier. Chrome has a nice extension called "Edit This Cookie" and Firefox has an add-on called "Cookies Manager+".  The important thing is that you copy the value of the sessionid cookie, which is a unique hash that corresponds to a Session model instance within Django.  

Once you've copied this sessionid value, you'll want to log in to the Django shell for your site.  At the shell, you'll proceed to modify the following script to log in.  You'll want to paste the session key that you copied into the script below where it makes the "your_session_key" variable assignment.  Also, you should modify the "user" variable assignment below to properly retrieve the user that you want to log in as. 

from django.contrib.auth.models import User
from django.contrib.sessions import models

# Choose a user to log in as
user = User.objects.get(username="myuser")

# session id from your browser
your_session_key='f78ae6b5c0a10b9d0165b77b0a16c824'

# Set the desired authentication backend. 
# For the normal authentication backend, use the following:
authentication_backend = 'django.contrib.auth.backends.ModelBackend'

# OR for the facebook_grap backend, uncomment the following: 
# authentication_backend = "facebook_graph.backends.authentication.AuthenticationBackend"sp; 

def session_user(user, your_session_key, authentication_backend):
    # find the session database object that corresponds to the session key given to the browser
    s = models.Session.objects.get(session_key=your_session_key)

    # Create a dictionary of the data to store in the session: 
    sd = {'_auth_user_backend': authentication_backend,
         '_auth_user_id': user.id,
         'facebook': {'app_is_authenticated': True}}

    # Encode the session data and save it:
    s.session_data = models.Session.objects.encode(sd)
    s.save()

    # If you want to see what data is in the session data, use this: 
    s.get_decoded()

Once you have completed these steps, you should be able to refresh the page in your browser and you will be logged in as the user that you selected.

If you want to do this on a more permanent basis, there is an interesting Django module called django-masquerade.  The downside is that this requires changes to your code.

Hope this is useful to some.  Please comment below with your questions or comments.


Share , ,
If you're getting even a smidge of value from this post, would you please take a sec and share it? It really does help.