summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/bin/daily_cleanup.py2
-rw-r--r--django/conf/global_settings.py14
-rw-r--r--django/contrib/comments/views/comments.py4
-rw-r--r--django/core/handlers/modpython.py31
-rw-r--r--django/core/handlers/wsgi.py31
-rw-r--r--django/middleware/admin.py13
-rw-r--r--django/middleware/sessions.py69
-rw-r--r--django/models/auth.py61
-rw-r--r--django/models/core.py54
-rw-r--r--django/parts/auth/anonymoususers.py9
-rw-r--r--django/parts/auth/formfields.py4
-rw-r--r--django/views/auth/login.py33
-rw-r--r--docs/faq.txt6
13 files changed, 179 insertions, 152 deletions
diff --git a/django/bin/daily_cleanup.py b/django/bin/daily_cleanup.py
index b7235cd10c..6f2e8da4c0 100644
--- a/django/bin/daily_cleanup.py
+++ b/django/bin/daily_cleanup.py
@@ -7,7 +7,7 @@ DOCUMENTATION_DIRECTORY = '/home/html/documentation/'
def clean_up():
# Clean up old database records
cursor = db.cursor()
- cursor.execute("DELETE FROM auth_sessions WHERE start_time < NOW() - INTERVAL '2 weeks'")
+ cursor.execute("DELETE FROM core_sessions WHERE expire_date < NOW()")
cursor.execute("DELETE FROM registration_challenges WHERE request_date < NOW() - INTERVAL '1 week'")
db.commit()
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 54ec8a377b..54fdcf0770 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -48,9 +48,6 @@ DATABASE_HOST = '' # Set to empty string for localhost
# Host for sending e-mail.
EMAIL_HOST = 'localhost'
-# Name of the session cookie. This can be whatever you want.
-AUTH_SESSION_COOKIE = 'rizzo'
-
# List of locations of the template source files, in search order.
TEMPLATE_DIRS = ()
@@ -113,6 +110,14 @@ MIDDLEWARE_CLASSES = (
"django.middleware.doc.XViewMiddleware",
)
+############
+# SESSIONS #
+############
+
+SESSION_COOKIE_NAME = 'hotclub' # Cookie name. This can be whatever you want.
+SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
+SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
+
#########
# CACHE #
#########
@@ -121,9 +126,6 @@ MIDDLEWARE_CLASSES = (
# possible values.
CACHE_BACKEND = 'simple://'
-# Set to a string like ".lawrence.com", or None for a standard domain cookie.
-REGISTRATION_COOKIE_DOMAIN = None
-
####################
# COMMENTS #
####################
diff --git a/django/contrib/comments/views/comments.py b/django/contrib/comments/views/comments.py
index c14df2cfdd..33972a4c52 100644
--- a/django/contrib/comments/views/comments.py
+++ b/django/contrib/comments/views/comments.py
@@ -2,7 +2,7 @@ from django.core import formfields, template_loader, validators
from django.core.mail import mail_admins, mail_managers
from django.core.exceptions import Http404, ObjectDoesNotExist
from django.core.extensions import DjangoContext as Context
-from django.models.auth import sessions
+from django.models.auth import users
from django.models.comments import comments, freecomments
from django.models.core import contenttypes
from django.parts.auth.formfields import AuthenticationForm
@@ -215,7 +215,7 @@ def post_comment(request):
# If user gave correct username/password and wasn't already logged in, log them in
# so they don't have to enter a username/password again.
if manipulator.get_user() and new_data.has_key('password') and manipulator.get_user().check_password(new_data['password']):
- sessions.start_web_session(manipulator.get_user_id(), request, response)
+ request.session[users.SESSION_KEY] = manipulator.get_user_id()
if errors or request.POST.has_key('preview'):
class CommentFormWrapper(formfields.FormWrapper):
def __init__(self, manipulator, new_data, errors, rating_choices):
diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py
index d7d7c768b1..623db959b2 100644
--- a/django/core/handlers/modpython.py
+++ b/django/core/handlers/modpython.py
@@ -95,29 +95,17 @@ class ModPythonRequest(httpwrappers.HttpRequest):
self._raw_post_data = self._req.read()
return self._raw_post_data
- def _load_session_and_user(self):
- from django.models.auth import sessions
- from django.conf.settings import AUTH_SESSION_COOKIE
- session_cookie = self.COOKIES.get(AUTH_SESSION_COOKIE, '')
- try:
- self._session = sessions.get_session_from_cookie(session_cookie)
- self._user = self._session.get_user()
- except sessions.SessionDoesNotExist:
- from django.parts.auth import anonymoususers
- self._session = None
- self._user = anonymoususers.AnonymousUser()
-
- def _get_session(self):
- if not hasattr(self, '_session'):
- self._load_session_and_user()
- return self._session
-
- def _set_session(self, session):
- self._session = session
-
def _get_user(self):
if not hasattr(self, '_user'):
- self._load_session_and_user()
+ from django.models.auth import users
+ try:
+ user_id = self.session[users.SESSION_KEY]
+ if not user_id:
+ raise ValueError
+ self._user = users.get_object(pk=user_id)
+ except (AttributeError, KeyError, ValueError, users.UserDoesNotExist):
+ from django.parts.auth import anonymoususers
+ self._user = anonymoususers.AnonymousUser()
return self._user
def _set_user(self, user):
@@ -130,7 +118,6 @@ class ModPythonRequest(httpwrappers.HttpRequest):
META = property(_get_meta)
REQUEST = property(_get_request)
raw_post_data = property(_get_raw_post_data)
- session = property(_get_session, _set_session)
user = property(_get_user, _set_user)
class ModPythonHandler(BaseHandler):
diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py
index 5e39dc152a..f7c71f61d9 100644
--- a/django/core/handlers/wsgi.py
+++ b/django/core/handlers/wsgi.py
@@ -76,29 +76,17 @@ class WSGIRequest(httpwrappers.HttpRequest):
self._raw_post_data = self.environ['wsgi.input'].read(int(self.environ["CONTENT_LENGTH"]))
return self._raw_post_data
- def _load_session_and_user(self):
- from django.models.auth import sessions
- from django.conf.settings import AUTH_SESSION_COOKIE
- session_cookie = self.COOKIES.get(AUTH_SESSION_COOKIE, '')
- try:
- self._session = sessions.get_session_from_cookie(session_cookie)
- self._user = self._session.get_user()
- except sessions.SessionDoesNotExist:
- from django.parts.auth import anonymoususers
- self._session = None
- self._user = anonymoususers.AnonymousUser()
-
- def _get_session(self):
- if not hasattr(self, '_session'):
- self._load_session_and_user()
- return self._session
-
- def _set_session(self, session):
- self._session = session
-
def _get_user(self):
if not hasattr(self, '_user'):
- self._load_session_and_user()
+ from django.models.auth import users
+ try:
+ user_id = self.session[users.SESSION_KEY]
+ if not user_id:
+ raise ValueError
+ self._user = users.get_object(pk=user_id)
+ except (AttributeError, KeyError, ValueError, users.UserDoesNotExist):
+ from django.parts.auth import anonymoususers
+ self._user = anonymoususers.AnonymousUser()
return self._user
def _set_user(self, user):
@@ -110,7 +98,6 @@ class WSGIRequest(httpwrappers.HttpRequest):
FILES = property(_get_files)
REQUEST = property(_get_request)
raw_post_data = property(_get_raw_post_data)
- session = property(_get_session, _set_session)
user = property(_get_user, _set_user)
class WSGIHandler(BaseHandler):
diff --git a/django/middleware/admin.py b/django/middleware/admin.py
index a977bacdbf..42d83b5be7 100644
--- a/django/middleware/admin.py
+++ b/django/middleware/admin.py
@@ -1,7 +1,7 @@
from django.utils import httpwrappers
from django.core import template_loader
from django.core.extensions import DjangoContext as Context
-from django.models.auth import sessions, users
+from django.models.auth import users
from django.views.registration import passwords
from django.views.auth.login import logout
import base64, md5
@@ -29,14 +29,17 @@ class AdminUserRequired:
# Otherwise the password reset would need its own entry in the httpd
# conf, which is a little uglier than this. Same goes for the logout
# view.
+
if view_func in (passwords.password_reset, passwords.password_reset_done, logout):
return
+ assert hasattr(request, 'session'), "The admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.middleware.sessions.SessionMiddleware' before %r." % self.__class__.__name__
+
# Check for a logged in, valid user
if self.user_is_valid(request.user):
return
- # If this isn't alreay the login page, display it
+ # If this isn't already the login page, display it
if not request.POST.has_key('this_is_the_login_form'):
if request.POST:
message = "Please log in again, because your session has expired. "\
@@ -64,18 +67,16 @@ class AdminUserRequired:
# The user data is correct; log in the user in and continue
else:
if self.authenticate_user(user, request.POST.get('password', '')):
+ request.session[users.SESSION_KEY] = user.id
if request.POST.has_key('post_data'):
post_data = decode_post_data(request.POST['post_data'])
if post_data and not post_data.has_key('this_is_the_login_form'):
# overwrite request.POST with the saved post_data, and continue
request.POST = post_data
request.user = user
- request.session = sessions.create_session(user.id)
return
else:
- response = httpwrappers.HttpResponseRedirect(request.path)
- sessions.start_web_session(user.id, request, response)
- return response
+ return httpwrappers.HttpResponseRedirect(request.path)
else:
return self.display_login_form(request, ERROR_MESSAGE)
diff --git a/django/middleware/sessions.py b/django/middleware/sessions.py
new file mode 100644
index 0000000000..41cf3daf02
--- /dev/null
+++ b/django/middleware/sessions.py
@@ -0,0 +1,69 @@
+from django.conf.settings import SESSION_COOKIE_NAME, SESSION_COOKIE_AGE, SESSION_COOKIE_DOMAIN
+from django.models.core import sessions
+import datetime
+
+TEST_COOKIE_NAME = 'testcookie'
+TEST_COOKIE_VALUE = 'worked'
+
+class SessionWrapper(object):
+ def __init__(self, session_key):
+ self.session_key = session_key
+ self.modified = False
+
+ def __getitem__(self, key):
+ return self._session[key]
+
+ def __setitem__(self, key, value):
+ self._session[key] = value
+ self.modified = True
+
+ def __delitem__(self, key):
+ del self._session[key]
+ self.modified = True
+
+ def get(self, key, default=None):
+ return self._session.get(key, default)
+
+ def set_test_cookie(self):
+ self[TEST_COOKIE_NAME] = TEST_COOKIE_VALUE
+
+ def test_cookie_worked(self):
+ return self.get(TEST_COOKIE_NAME) == TEST_COOKIE_VALUE
+
+ def _get_session(self):
+ # Lazily loads session from storage.
+ try:
+ return self._session_cache
+ except AttributeError:
+ if self.session_key is None:
+ self._session_cache = {}
+ else:
+ try:
+ s = sessions.get_object(session_key__exact=self.session_key,
+ expire_date__gt=datetime.datetime.now())
+ self._session_cache = s.get_decoded()
+ except sessions.SessionDoesNotExist:
+ self._session_cache = {}
+ return self._session_cache
+
+ _session = property(_get_session)
+
+class SessionMiddleware:
+ def process_view(self, request, view_func, param_dict):
+ request.session = SessionWrapper(request.COOKIES.get(SESSION_COOKIE_NAME, None))
+
+ def process_response(self, request, response):
+ # If request.session was modified, or if response.session was set, save
+ # those changes and set a session cookie.
+ try:
+ modified = request.session.modified
+ except AttributeError:
+ modified = False
+ if modified:
+ session_key = request.session.session_key or sessions.get_new_session_key()
+ new_session = sessions.save(session_key, request.session._session,
+ datetime.datetime.now() + datetime.timedelta(seconds=SESSION_COOKIE_AGE))
+ # TODO: Accept variable session length and domain.
+ response.set_cookie(SESSION_COOKIE_NAME, session_key,
+ max_age=SESSION_COOKIE_AGE, domain=SESSION_COOKIE_DOMAIN)
+ return response
diff --git a/django/models/auth.py b/django/models/auth.py
index 91ed0650ec..9ab403af34 100644
--- a/django/models/auth.py
+++ b/django/models/auth.py
@@ -44,6 +44,9 @@ class User(meta.Model):
help_text="In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."),
meta.ManyToManyField(Permission, name='user_permissions', blank=True, filter_interface=meta.HORIZONTAL),
)
+ module_constants = {
+ 'SESSION_KEY': '_auth_user_id',
+ }
ordering = ('username',)
exceptions = ('SiteProfileNotAvailable',)
admin = meta.Admin(
@@ -172,64 +175,6 @@ class User(meta.Model):
from random import choice
return ''.join([choice(allowed_chars) for i in range(length)])
-class Session(meta.Model):
- fields = (
- meta.ForeignKey(User),
- meta.CharField('session_md5', maxlength=32),
- meta.DateTimeField('start_time', auto_now=True),
- )
- module_constants = {
- 'TEST_COOKIE_NAME': 'testcookie',
- 'TEST_COOKIE_VALUE': 'worked',
- }
-
- def __repr__(self):
- return "session started at %s" % self.start_time
-
- def get_cookie(self):
- "Returns a tuple of the cookie name and value for this session."
- from django.conf.settings import AUTH_SESSION_COOKIE, SECRET_KEY
- import md5
- return AUTH_SESSION_COOKIE, self.session_md5 + md5.new(self.session_md5 + SECRET_KEY + 'auth').hexdigest()
-
- def _module_create_session(user_id):
- "Registers a session and returns the session_md5."
- from django.conf.settings import SECRET_KEY
- import md5, random, sys
- # The random module is seeded when this Apache child is created.
- # Use person_id and SECRET_KEY as added salt.
- session_md5 = md5.new(str(random.randint(user_id, sys.maxint - 1)) + SECRET_KEY).hexdigest()
- s = Session(None, user_id, session_md5, None)
- s.save()
- return s
-
- def _module_get_session_from_cookie(session_cookie_string):
- from django.conf.settings import SECRET_KEY
- import md5
- if not session_cookie_string:
- raise SessionDoesNotExist
- session_md5, tamper_check = session_cookie_string[:32], session_cookie_string[32:]
- if md5.new(session_md5 + SECRET_KEY + 'auth').hexdigest() != tamper_check:
- raise SessionDoesNotExist
- return get_object(session_md5__exact=session_md5, select_related=True)
-
- def _module_destroy_all_sessions(user_id):
- "Destroys all sessions for a user, logging out all computers."
- for session in get_list(user_id__exact=user_id):
- session.delete()
-
- def _module_start_web_session(user_id, request, response):
- "Sets the necessary cookie in the given HttpResponse object, also updates last login time for user."
- from django.models.auth import users
- from django.conf.settings import REGISTRATION_COOKIE_DOMAIN
- user = users.get_object(pk=user_id)
- user.last_login = datetime.datetime.now()
- user.save()
- session = create_session(user_id)
- key, value = session.get_cookie()
- cookie_domain = REGISTRATION_COOKIE_DOMAIN or None
- response.set_cookie(key, value, domain=cookie_domain)
-
class Message(meta.Model):
fields = (
meta.ForeignKey(User),
diff --git a/django/models/core.py b/django/models/core.py
index 985dc38179..e94a35b694 100644
--- a/django/models/core.py
+++ b/django/models/core.py
@@ -103,3 +103,57 @@ class FlatFile(meta.Model):
def get_absolute_url(self):
return self.url
+
+import base64, md5, random, sys
+import cPickle as pickle
+
+class Session(meta.Model):
+ fields = (
+ meta.CharField('session_key', maxlength=40, primary_key=True),
+ meta.TextField('session_data'),
+ meta.DateTimeField('expire_date'),
+ )
+ module_constants = {
+ 'base64': base64,
+ 'md5': md5,
+ 'pickle': pickle,
+ 'random': random,
+ 'sys': sys,
+ }
+
+ def get_decoded(self):
+ from django.conf.settings import SECRET_KEY
+ encoded_data = base64.decodestring(self.session_data)
+ pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
+ if md5.new(pickled + SECRET_KEY).hexdigest() != tamper_check:
+ from django.core.exceptions import SuspiciousOperation
+ raise SuspiciousOperation, "User tampered with session cookie."
+ return pickle.loads(pickled)
+
+ def _module_encode(session_dict):
+ "Returns the given session dictionary pickled and encoded as a string."
+ from django.conf.settings import SECRET_KEY
+ pickled = pickle.dumps(session_dict)
+ pickled_md5 = md5.new(pickled + SECRET_KEY).hexdigest()
+ return base64.encodestring(pickled + pickled_md5)
+
+ def _module_get_new_session_key():
+ "Returns session key that isn't being used."
+ from django.conf.settings import SECRET_KEY
+ # The random module is seeded when this Apache child is created.
+ # Use person_id and SECRET_KEY as added salt.
+ while 1:
+ session_key = md5.new(str(random.randint(0, sys.maxint - 1)) + SECRET_KEY).hexdigest()
+ try:
+ get_object(session_key__exact=session_key)
+ except SessionDoesNotExist:
+ break
+ return session_key
+
+ def _module_save(session_key, session_dict, expire_date):
+ s = Session(session_key, encode(session_dict), expire_date)
+ if session_dict:
+ s.save()
+ else:
+ s.delete() # Clear sessions with no data.
+ return s
diff --git a/django/parts/auth/anonymoususers.py b/django/parts/auth/anonymoususers.py
index 13fa44c434..03f294915c 100644
--- a/django/parts/auth/anonymoususers.py
+++ b/django/parts/auth/anonymoususers.py
@@ -1,9 +1,4 @@
-"""
-Anonymous users
-"""
-
class AnonymousUser:
-
def __init__(self):
pass
@@ -40,9 +35,5 @@ class AnonymousUser:
def get_and_delete_messages(self):
return []
- def add_session(self, session_md5, start_time):
- "Creates Session for this User, saves it, and returns the new object"
- raise NotImplementedError
-
def is_anonymous(self):
return True
diff --git a/django/parts/auth/formfields.py b/django/parts/auth/formfields.py
index 3565331c8f..1ad77dbda5 100644
--- a/django/parts/auth/formfields.py
+++ b/django/parts/auth/formfields.py
@@ -1,4 +1,4 @@
-from django.models.auth import sessions, users
+from django.models.auth import users
from django.core import formfields, validators
class AuthenticationForm(formfields.Manipulator):
@@ -23,7 +23,7 @@ class AuthenticationForm(formfields.Manipulator):
self.user_cache = None
def hasCookiesEnabled(self, field_data, all_data):
- if self.request and (not self.request.COOKIES.has_key(sessions.TEST_COOKIE_NAME) or self.request.COOKIES[sessions.TEST_COOKIE_NAME] != sessions.TEST_COOKIE_VALUE):
+ if self.request and not self.request.test_cookie_worked():
raise validators.ValidationError, "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."
def isValidUser(self, field_data, all_data):
diff --git a/django/views/auth/login.py b/django/views/auth/login.py
index fdb064d0b0..a8d7d143d2 100644
--- a/django/views/auth/login.py
+++ b/django/views/auth/login.py
@@ -1,7 +1,7 @@
from django.parts.auth.formfields import AuthenticationForm
from django.core import formfields, template_loader
from django.core.extensions import DjangoContext as Context
-from django.models.auth import sessions
+from django.models.auth import users
from django.models.core import sites
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
@@ -17,14 +17,12 @@ def login(request):
# Light security check -- make sure redirect_to isn't garbage.
if not redirect_to or '://' in redirect_to or ' ' in redirect_to:
redirect_to = '/accounts/profile/'
- response = HttpResponseRedirect(redirect_to)
- sessions.start_web_session(manipulator.get_user_id(), request, response)
- return response
+ request.session[users.SESSION_KEY] = manipulator.get_user_id()
+ return HttpResponseRedirect(redirect_to)
else:
errors = {}
response = HttpResponse()
- # Set this cookie as a test to see whether the user accepts cookies
- response.set_cookie(sessions.TEST_COOKIE_NAME, sessions.TEST_COOKIE_VALUE)
+ response.session.set_test_cookie()
t = template_loader.get_template('registration/login')
c = Context(request, {
'form': formfields.FormWrapper(manipulator, request.POST, errors),
@@ -34,28 +32,21 @@ def login(request):
response.write(t.render(c))
return response
-def logout(request):
+def logout(request, next_page=None):
"Logs out the user and displays 'You are logged out' message."
- if request.session:
- # Do a redirect to this page until the session has been cleared.
- response = HttpResponseRedirect(request.path)
- # Delete the cookie by setting a cookie with an empty value and max_age=0
- response.set_cookie(request.session.get_cookie()[0], '', max_age=0)
- request.session.delete()
- return response
- else:
+ try:
+ del request.session[users.SESSION_KEY]
+ except KeyError:
t = template_loader.get_template('registration/logged_out')
c = Context(request)
return HttpResponse(t.render(c))
+ else:
+ # Do a redirect to this page until the session has been cleared.
+ return HttpResponseRedirect(next_page or request.path)
def logout_then_login(request):
"Logs out the user if he is logged in. Then redirects to the log-in page."
- response = HttpResponseRedirect('/accounts/login/')
- if request.session:
- # Delete the cookie by setting a cookie with an empty value and max_age=0
- response.set_cookie(request.session.get_cookie()[0], '', max_age=0)
- request.session.delete()
- return response
+ return logout(request, '/accounts/login/')
def redirect_to_login(next):
"Redirects the user to the login page, passing the given 'next' page"
diff --git a/docs/faq.txt b/docs/faq.txt
index e3e8ab4162..d5400dd98c 100644
--- a/docs/faq.txt
+++ b/docs/faq.txt
@@ -310,17 +310,17 @@ The login cookie isn't being set correctly, because the domain of the cookie
sent out by Django doesn't match the domain in your browser. Try these two
things:
- * Set the ``REGISTRATION_COOKIE_DOMAIN`` setting in your admin config file
+ * Set the ``SESSION_COOKIE_DOMAIN`` setting in your admin config file
to match your domain. For example, if you're going to
"http://www.mysite.com/admin/" in your browser, in
- "myproject.settings.admin" you should set ``REGISTRATION_COOKIE_DOMAIN =
+ "myproject.settings.admin" you should set ``SESSION_COOKIE_DOMAIN =
'www.mysite.com'``.
* Some browsers (Firefox?) don't like to accept cookies from domains that
don't have dots in them. If you're running the admin site on "localhost"
or another domain that doesn't have a dot in it, try going to
"localhost.localdomain" or "127.0.0.1". And set
- ``REGISTRATION_COOKIE_DOMAIN`` accordingly.
+ ``SESSION_COOKIE_DOMAIN`` accordingly.
I can't log in. When I enter a valid username and password, it brings up the login page again, with a "Please enter a correct username and password" error.
-----------------------------------------------------------------------------------------------------------------------------------------------------------