annotate wiki/middleware.py @ 1182:d7ff63d83973

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