diff web/secure.py @ 293:d15dda1b1f76

merge
author Matt Johnston <matt@ucc.asn.au>
date Sat, 06 Jul 2019 18:29:45 +0800
parents f7261dd970da
children a99631597f65
line wrap: on
line diff
--- a/web/secure.py	Thu Mar 19 21:50:52 2015 +0800
+++ b/web/secure.py	Sat Jul 06 18:29:45 2019 +0800
@@ -11,56 +11,47 @@
 
 import config
 
-__all__ = ["get_csrf_blob", "check_csrf_blob", "setup_csrf", "get_user_hash",
-"check_user_hash"]
+__all__ = [
+    "get_csrf_blob", 
+    "check_csrf_blob", 
+    "setup_csrf", 
+    "check_cookie",
+    "init_cookie",
+]
+
+AUTH_COOKIE = 'templogauth'
+AUTH_COOKIE_LEN = 16
 
 HASH=hashlib.sha1
 
 CLEAN_RE = re.compile('[^a-z0-9A-Z]')
 
-def clean_hash(h):
-    return CLEAN_RE.sub('', h.lower())
-
-def get_user_hash():
-    """
-    Uses the following apache config. 
-    Needs a separate port or IP to no-certificate SSL, SNI isn't good enough.
-
-    <location /~matt/templog/set>
-    Require all granted
-    SSLVerifyClient optional_no_ca
-    SSLVerifyDepth 1
-    SSLOptions +StdEnvVars +ExportCertData +OptRenegotiate
-    </location>
-    """
+def cookie_hash(c):
+    return hashlib.sha256(c).hexdigest()
 
-    verify = bottle.request.environ.get('SSL_CLIENT_VERIFY', '')
-    if not (verify == 'GENEROUS' or verify == 'SUCCESS'):
-        return 'FAILVERIFY'
-    blob = bottle.request.environ.get('SSL_CLIENT_CERT')
-    if not blob:
-        return 'NOCERT'
+def init_cookie():
+    """ Generates a new httponly auth cookie if required. 
+    Returns the hash of the cookie (new or existing)
+    """
+    c = bottle.request.get_cookie(AUTH_COOKIE)
+    if not c:
+        c = binascii.hexlify(os.urandom(AUTH_COOKIE_LEN))
+        bottle.response.set_cookie(AUTH_COOKIE, c, secure=True, httponly=True)
+    return cookie_hash(c)
 
-    b64 = ''.join(l for l in blob.split('\n')
-        if not l.startswith('-'))
-
-    return HASH(binascii.a2b_base64(b64)).hexdigest()
-
-def check_user_hash(allowed_users):
-    current_hash = clean_hash(get_user_hash())
-    for a in allowed_users:
-        if current_hash == clean_hash(a):
-            return True
-    return False
+def check_cookie(allowed_users):
+    c = bottle.request.get_cookie(AUTH_COOKIE)
+    if not c:
+        return False
+    return cookie_hash(c) in allowed_users
 
 def setup_csrf():
     NONCE_SIZE=16
     global _csrf_fd, _csrf_key
-    _csrf_fd = open('%s/csrf.dat' % config.DATA_PATH, 'r+')
+    _csrf_fd = os.fdopen(os.open('%s/csrf.dat' % config.DATA_PATH, os.O_RDWR | os.O_CREAT, 0600), 'r+')
 
     try:
         fcntl.lockf(_csrf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
-        os.fchmod(_csrf_fd.fileno(), 0600)
         _csrf_fd.write("%d-%s" % (os.getpid(), binascii.hexlify(os.urandom(NONCE_SIZE))))
         _csrf_fd.flush()
         _csrf_fd.seek(0)
@@ -73,7 +64,7 @@
 
 def get_csrf_blob():
     expiry = int(config.CSRF_TIMEOUT + time.time())
-    content = '%s-%s' % (get_user_hash(), expiry)
+    content = '%s-%s' % (init_cookie(), expiry)
     mac = hmac.new(_csrf_key, content).hexdigest()
     return "%s-%s" % (content, mac)
 
@@ -84,7 +75,7 @@
         return False
 
     user, expiry, mac = toks
-    if user != get_user_hash():
+    if user != init_cookie():
         print>>sys.stderr, "wrong user"
         return False