annotate wiki/middleware.py @ 1145:a469445d8be3

Convert fixed pages to V3 design.
author Brian Neal <bgneal@gmail.com>
date Mon, 14 Nov 2016 19:40:36 -0600
parents 47521d9e94bd
children ba3230aba90c
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@629 15 from wiki.constants import SESSION_SET_MEMBER
bgneal@626 16
bgneal@626 17
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@841 28 h.update(user.username.encode('utf-8'))
bgneal@841 29 h.update(user.email.encode('utf-8'))
bgneal@626 30 h.update(now.isoformat())
bgneal@626 31 h.update(''.join(random.sample(string.printable, 64)))
bgneal@626 32 h.update(settings.SECRET_KEY)
bgneal@626 33 key = h.hexdigest()
bgneal@626 34
bgneal@626 35 parts = (user.username, user.email, key)
bgneal@626 36 return '#'.join(parts)
bgneal@626 37
bgneal@626 38
bgneal@626 39 def create_wiki_session(request, response):
bgneal@626 40 """Sets up the session for the external wiki application.
bgneal@626 41
bgneal@626 42 Creates the external cookie for the Wiki.
bgneal@626 43 Updates the Redis set so the Wiki can verify the cookie.
bgneal@626 44
bgneal@626 45 """
bgneal@626 46 now = datetime.datetime.utcnow()
bgneal@626 47 value = cookie_value(request.user, now)
bgneal@626 48 response.set_cookie(settings.WIKI_COOKIE_NAME,
bgneal@626 49 value=value,
bgneal@626 50 max_age=settings.WIKI_COOKIE_AGE,
bgneal@626 51 domain=settings.WIKI_COOKIE_DOMAIN)
bgneal@626 52
bgneal@626 53 # Update a sorted set in Redis with a hash of our cookie and a score
bgneal@626 54 # of the current time as a timestamp. This allows us to delete old
bgneal@626 55 # entries by score periodically. To verify the cookie, the external wiki
bgneal@626 56 # application computes a hash of the cookie value and checks to see if
bgneal@626 57 # it is in our Redis set.
bgneal@626 58
bgneal@626 59 h = hashlib.sha256()
bgneal@626 60 h.update(value)
bgneal@626 61 name = h.hexdigest()
bgneal@626 62 score = time.mktime(now.utctimetuple())
bgneal@626 63 conn = get_redis_connection()
bgneal@626 64
bgneal@626 65 try:
bgneal@626 66 conn.zadd(settings.WIKI_REDIS_SET, score, name)
bgneal@626 67 except redis.RedisError:
bgneal@626 68 logger.error("Error adding wiki cookie key")
bgneal@626 69
bgneal@626 70 # Store the set member name in the session so we can delete it when the
bgneal@626 71 # user logs out:
bgneal@627 72 request.session[SESSION_SET_MEMBER] = name
bgneal@626 73
bgneal@626 74
bgneal@627 75 def destroy_wiki_session(set_member, response):
bgneal@626 76 """Destroys the session for the external wiki application.
bgneal@626 77
bgneal@626 78 Delete the external cookie.
bgneal@627 79 Deletes the member from the Redis set as this entry is no longer valid.
bgneal@626 80
bgneal@626 81 """
bgneal@626 82 response.delete_cookie(settings.WIKI_COOKIE_NAME,
bgneal@626 83 domain=settings.WIKI_COOKIE_DOMAIN)
bgneal@626 84
bgneal@627 85 if set_member:
bgneal@627 86 conn = get_redis_connection()
bgneal@627 87 try:
bgneal@627 88 conn.zrem(settings.WIKI_REDIS_SET, set_member)
bgneal@627 89 except redis.RedisError:
bgneal@627 90 logger.error("Error deleting wiki cookie set member")
bgneal@626 91
bgneal@626 92
bgneal@626 93 class WikiMiddleware(object):
bgneal@626 94 """
bgneal@633 95 Check for flags on the request object to determine when to set or delete an
bgneal@626 96 external cookie for the wiki application. When creating a cookie, also
bgneal@626 97 set an entry in Redis that the wiki application can validate to prevent
bgneal@626 98 spoofing.
bgneal@626 99
bgneal@626 100 """
bgneal@626 101
bgneal@626 102 def process_response(self, request, response):
bgneal@626 103
bgneal@629 104 if hasattr(request, 'wiki_set_cookie'):
bgneal@626 105 create_wiki_session(request, response)
bgneal@627 106 elif hasattr(request, 'wiki_delete_cookie'):
bgneal@627 107 destroy_wiki_session(request.wiki_delete_cookie, response)
bgneal@626 108
bgneal@626 109 return response