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