Search code examples
djangomonkeypatchingdjango-sessions

Extend number of characters used by Django SessionStore from 32 to 64


Django==1.11.17, Python==3.6.7

I would like to extend the number of characters used for the session key.

Looking in django.contrib.sessions.backends.base.py:

class SessionBase(object):
    ...

    def _get_new_session_key(self):
        "Returns session key that isn't being used."
        while True:
            session_key = get_random_string(32, VALID_KEY_CHARS)
            if not self.exists(session_key):
                break
        return session_key
    ...

I would like to modify 32 -> 64.

I tried monkey-patching, in one of my files:

import django.contrib.sessions.backends.base as sessions_base
import django.contrib.sessions.backends.file as sessions_file
from django.utils.crypto import get_random_string

def _get_new_session_key(self):
    while True:
        session_key = get_random_string(64, sessions_base.VALID_KEY_CHARS)
        print("SESSION KEY: {}".format(session_key))
        if not sessions_file.SessionStore.exists(self, session_key):
            break
    return session_key


sessions_file.SessionStore._get_new_session_key = _get_new_session_key

django.contrib.sessions.backends.file.py implements SessionStore, and exists().
This solution is just ignored by Django, and I get no print statement showing.

Just fyi, this does print the session id (with 64 chars) but errors out:
sessions_file.SessionStore._get_new_session_key = _get_new_session_key(sessions_file.SessionStore)

File "/Users/.../lib/python3.6/site-packages/django/contrib/sessions/backends/file.py", line 51, in _key_to_file
session_key = self._get_or_create_session_key()
AttributeError: 'str' object has no attribute '_get_or_create_session_key'

Questions:

  1. This does not work. Is it due to the fact that the SessionStore object is instantiated due to a middleware, before this file is accessed?

  2. Should my solution be a middleware? (I'd rather monkey-patch)

NOTE:

Also tried:
1. sessions_file.SessionStore.__dict__["_get_new_session_key"] = _get_new_session_key <-- error is raised
2. setattr(sessions_file.SessionStore, '_get_new_session_key', _get_new_session_key)` <-- same issue, ignored


Solution

  • I managed to do override the session key length successfully, using this code:

    import django.contrib.sessions.backends.base as sessions_base
    from django.contrib.sessions.backends.db import SessionStore as OriginalSessionStore
    from django.utils.crypto import get_random_string
    
    def _get_new_session_key(self):
        "Returns session key that isn't being used."
        while True:
            session_key = get_random_string(40, sessions_base.VALID_KEY_CHARS)
            print("*********** SESSION KEY: {}, {}".format(len(session_key), session_key))
            if not OriginalSessionStore.exists(self, session_key=session_key):
                break
        return session_key
    
    OriginalSessionStore._get_new_session_key = _get_new_session_key
    

    What I did find out in the process, is that there is a limit to the session key length, 40 chars.
    Anything above 40 chars would trigger an error:

    django.db.utils.DataError: value too long for type character varying(40)
    

    I will keep looking for a way to modify the type of the session key to hold a value > 40 chars, so any guidance would be welcome.

    Thank you!

    EDIT:

    I found the model AbstractBaseSession in Django.contrib.sessions.base_session.py:

    @python_2_unicode_compatible
    class AbstractBaseSession(models.Model):
        session_key = models.CharField(_('session key'), max_length=40, primary_key=True)
    

    Currently evaluating the implications of overriding it, necessary migration, etc.