annotate 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
rev   line source
bgneal@626 1 """Middleware for wiki integration.
bgneal@626 2
bgneal@626 3 """
bgneal@626 4 import datetime
bgneal@626 5 import hashlib
bgneal@626 6 import logging
bgneal@626 7 import random
bgneal@626 8 import string
bgneal@626 9 import time
bgneal@626 10
bgneal@626 11 from django.conf import settings
bgneal@626 12 import redis
bgneal@626 13
bgneal@626 14 from core.services import get_redis_connection
bgneal@626 15
bgneal@626 16
bgneal@626 17 SESSION_KEY = 'wiki_redis_key'
bgneal@626 18 logger = logging.getLogger(__name__)
bgneal@626 19
bgneal@626 20
bgneal@626 21 def cookie_value(user, now):
bgneal@626 22 """Creates the value for the external wiki cookie."""
bgneal@626 23
bgneal@626 24 # The key part of the cookie is just a string that would make things
bgneal@626 25 # difficult for a spoofer; something that can't be easily made up:
bgneal@626 26
bgneal@626 27 h = hashlib.sha256()
bgneal@626 28 h.update(user.username + user.email)
bgneal@626 29 h.update(now.isoformat())
bgneal@626 30 h.update(''.join(random.sample(string.printable, 64)))
bgneal@626 31 h.update(settings.SECRET_KEY)
bgneal@626 32 key = h.hexdigest()
bgneal@626 33
bgneal@626 34 parts = (user.username, user.email, key)
bgneal@626 35 return '#'.join(parts)
bgneal@626 36
bgneal@626 37
bgneal@626 38 def create_wiki_session(request, response):
bgneal@626 39 """Sets up the session for the external wiki application.
bgneal@626 40
bgneal@626 41 Creates the external cookie for the Wiki.
bgneal@626 42 Updates the Redis set so the Wiki can verify the cookie.
bgneal@626 43
bgneal@626 44 """
bgneal@626 45 now = datetime.datetime.utcnow()
bgneal@626 46 value = cookie_value(request.user, now)
bgneal@626 47 response.set_cookie(settings.WIKI_COOKIE_NAME,
bgneal@626 48 value=value,
bgneal@626 49 max_age=settings.WIKI_COOKIE_AGE,
bgneal@626 50 domain=settings.WIKI_COOKIE_DOMAIN)
bgneal@626 51
bgneal@626 52 # Update a sorted set in Redis with a hash of our cookie and a score
bgneal@626 53 # of the current time as a timestamp. This allows us to delete old
bgneal@626 54 # entries by score periodically. To verify the cookie, the external wiki
bgneal@626 55 # application computes a hash of the cookie value and checks to see if
bgneal@626 56 # it is in our Redis set.
bgneal@626 57
bgneal@626 58 h = hashlib.sha256()
bgneal@626 59 h.update(value)
bgneal@626 60 name = h.hexdigest()
bgneal@626 61 score = time.mktime(now.utctimetuple())
bgneal@626 62 conn = get_redis_connection()
bgneal@626 63
bgneal@626 64 try:
bgneal@626 65 conn.zadd(settings.WIKI_REDIS_SET, score, name)
bgneal@626 66 except redis.RedisError:
bgneal@626 67 logger.error("Error adding wiki cookie key")
bgneal@626 68
bgneal@626 69 # Store the set member name in the session so we can delete it when the
bgneal@626 70 # user logs out:
bgneal@626 71 request.session[SESSION_KEY] = name
bgneal@626 72
bgneal@626 73
bgneal@626 74 def destroy_wiki_session(request, response):
bgneal@626 75 """Destroys the session for the external wiki application.
bgneal@626 76
bgneal@626 77 Delete the external cookie.
bgneal@626 78 Deletes the key from the Redis set as this entry is no longer valid.
bgneal@626 79
bgneal@626 80 """
bgneal@626 81 response.delete_cookie(settings.WIKI_COOKIE_NAME,
bgneal@626 82 domain=settings.WIKI_COOKIE_DOMAIN)
bgneal@626 83
bgneal@626 84 try:
bgneal@626 85 key = request.session[SESSION_KEY]
bgneal@626 86 except KeyError:
bgneal@626 87 # Hmmm, perhaps user logged in before this application was installed.
bgneal@626 88 return
bgneal@626 89
bgneal@626 90 conn = get_redis_connection()
bgneal@626 91 try:
bgneal@626 92 conn.zrem(settings.WIKI_REDIS_SET, key)
bgneal@626 93 except redis.RedisError:
bgneal@626 94 logger.error("Error deleting wiki cookie key")
bgneal@626 95
bgneal@626 96 del request.session[SESSION_KEY]
bgneal@626 97
bgneal@626 98
bgneal@626 99 class WikiMiddleware(object):
bgneal@626 100 """
bgneal@626 101 Check for flags set in the session to determine when to set or delete an
bgneal@626 102 external cookie for the wiki application. When creating a cookie, also
bgneal@626 103 set an entry in Redis that the wiki application can validate to prevent
bgneal@626 104 spoofing.
bgneal@626 105
bgneal@626 106 """
bgneal@626 107
bgneal@626 108 def process_response(self, request, response):
bgneal@626 109
bgneal@626 110 if request.session.get('wiki_set_cookie', False):
bgneal@626 111 del request.session['wiki_set_cookie']
bgneal@626 112
bgneal@626 113 create_wiki_session(request, response)
bgneal@626 114
bgneal@626 115 elif request.session.get('wiki_delete_cookie', False):
bgneal@626 116 del request.session['wiki_delete_cookie']
bgneal@626 117
bgneal@626 118 destroy_wiki_session(request, response)
bgneal@626 119
bgneal@626 120 return response