Mercurial > public > sg101
diff wiki/middleware.py @ 626:a6bc1e2efa63
Created wiki app to provide integration with MoinMoin.
This commit has a working middleware & test.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Wed, 07 Nov 2012 20:17:33 -0600 |
parents | |
children | a4300639c6e7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wiki/middleware.py Wed Nov 07 20:17:33 2012 -0600 @@ -0,0 +1,120 @@ +"""Middleware for wiki integration. + +""" +import datetime +import hashlib +import logging +import random +import string +import time + +from django.conf import settings +import redis + +from core.services import get_redis_connection + + +SESSION_KEY = 'wiki_redis_key' +logger = logging.getLogger(__name__) + + +def cookie_value(user, now): + """Creates the value for the external wiki cookie.""" + + # The key part of the cookie is just a string that would make things + # difficult for a spoofer; something that can't be easily made up: + + h = hashlib.sha256() + h.update(user.username + user.email) + h.update(now.isoformat()) + h.update(''.join(random.sample(string.printable, 64))) + h.update(settings.SECRET_KEY) + key = h.hexdigest() + + parts = (user.username, user.email, key) + return '#'.join(parts) + + +def create_wiki_session(request, response): + """Sets up the session for the external wiki application. + + Creates the external cookie for the Wiki. + Updates the Redis set so the Wiki can verify the cookie. + + """ + now = datetime.datetime.utcnow() + value = cookie_value(request.user, now) + response.set_cookie(settings.WIKI_COOKIE_NAME, + value=value, + max_age=settings.WIKI_COOKIE_AGE, + domain=settings.WIKI_COOKIE_DOMAIN) + + # Update a sorted set in Redis with a hash of our cookie and a score + # of the current time as a timestamp. This allows us to delete old + # entries by score periodically. To verify the cookie, the external wiki + # application computes a hash of the cookie value and checks to see if + # it is in our Redis set. + + h = hashlib.sha256() + h.update(value) + name = h.hexdigest() + score = time.mktime(now.utctimetuple()) + conn = get_redis_connection() + + try: + conn.zadd(settings.WIKI_REDIS_SET, score, name) + except redis.RedisError: + logger.error("Error adding wiki cookie key") + + # Store the set member name in the session so we can delete it when the + # user logs out: + request.session[SESSION_KEY] = name + + +def destroy_wiki_session(request, response): + """Destroys the session for the external wiki application. + + Delete the external cookie. + Deletes the key from the Redis set as this entry is no longer valid. + + """ + response.delete_cookie(settings.WIKI_COOKIE_NAME, + domain=settings.WIKI_COOKIE_DOMAIN) + + try: + key = request.session[SESSION_KEY] + except KeyError: + # Hmmm, perhaps user logged in before this application was installed. + return + + conn = get_redis_connection() + try: + conn.zrem(settings.WIKI_REDIS_SET, key) + except redis.RedisError: + logger.error("Error deleting wiki cookie key") + + del request.session[SESSION_KEY] + + +class WikiMiddleware(object): + """ + Check for flags set in the session to determine when to set or delete an + external cookie for the wiki application. When creating a cookie, also + set an entry in Redis that the wiki application can validate to prevent + spoofing. + + """ + + def process_response(self, request, response): + + if request.session.get('wiki_set_cookie', False): + del request.session['wiki_set_cookie'] + + create_wiki_session(request, response) + + elif request.session.get('wiki_delete_cookie', False): + del request.session['wiki_delete_cookie'] + + destroy_wiki_session(request, response) + + return response