comparison web/secure.py @ 586:87c20b8c5472 default master

port to python3
author Matt Johnston <matt@ucc.asn.au>
date Mon, 09 Sep 2019 22:24:10 +0800
parents a99631597f65
children
comparison
equal deleted inserted replaced
585:1c484dab4e83 586:87c20b8c5472
1 import re 1 import re
2 import os 2 import os
3 import time 3 import time
4 import fcntl 4 import fcntl
5 import hmac 5 import hmac
6 import binascii
7 import sys 6 import sys
8 import hashlib 7 import hashlib
9 8
10 import bottle 9 import bottle
11 10
25 HASH=hashlib.sha1 24 HASH=hashlib.sha1
26 25
27 CLEAN_RE = re.compile('[^a-z0-9A-Z]') 26 CLEAN_RE = re.compile('[^a-z0-9A-Z]')
28 27
29 def cookie_hash(c): 28 def cookie_hash(c):
30 return hashlib.sha256(c).hexdigest() 29 return hashlib.sha256(c.encode()).hexdigest()
31 30
32 def init_cookie(): 31 def init_cookie():
33 """ Generates a new httponly auth cookie if required. 32 """ Generates a new httponly auth cookie if required.
34 Returns the hash of the cookie (new or existing) 33 Returns the hash of the cookie (new or existing)
35 """ 34 """
36 c = bottle.request.get_cookie(AUTH_COOKIE) 35 c = bottle.request.get_cookie(AUTH_COOKIE)
37 if not c: 36 if not c:
38 c = binascii.hexlify(os.urandom(AUTH_COOKIE_LEN)) 37 c = os.urandom(AUTH_COOKIE_LEN).hex()
39 years = 60*60*24*365 38 years = 60*60*24*365
40 bottle.response.set_cookie(AUTH_COOKIE, c, secure=True, httponly=True, max_age=10*years) 39 bottle.response.set_cookie(AUTH_COOKIE, c, secure=True, httponly=True, max_age=10*years)
41 return cookie_hash(c) 40 return cookie_hash(c)
42 41
43 def check_cookie(allowed_users): 42 def check_cookie(allowed_users):
47 return cookie_hash(c) in allowed_users 46 return cookie_hash(c) in allowed_users
48 47
49 def setup_csrf(): 48 def setup_csrf():
50 NONCE_SIZE=16 49 NONCE_SIZE=16
51 global _csrf_fd, _csrf_key 50 global _csrf_fd, _csrf_key
52 _csrf_fd = os.fdopen(os.open('%s/csrf.dat' % config.DATA_PATH, os.O_RDWR | os.O_CREAT, 0600), 'r+') 51 _csrf_fd = os.fdopen(os.open('%s/csrf.dat' % config.DATA_PATH, os.O_RDWR | os.O_CREAT, 0o600), 'r+')
53 52
54 try: 53 try:
55 fcntl.lockf(_csrf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) 54 fcntl.lockf(_csrf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
56 _csrf_fd.write("%d-%s" % (os.getpid(), binascii.hexlify(os.urandom(NONCE_SIZE)))) 55 _csrf_fd.write("%d-%s" % (os.getpid(), os.urandom(NONCE_SIZE).hex()))
57 _csrf_fd.flush() 56 _csrf_fd.flush()
58 _csrf_fd.seek(0) 57 _csrf_fd.seek(0)
59 except IOError: 58 except IOError:
60 pass 59 pass
61 fcntl.lockf(_csrf_fd, fcntl.LOCK_SH) 60 fcntl.lockf(_csrf_fd, fcntl.LOCK_SH)
64 63
65 64
66 def get_csrf_blob(): 65 def get_csrf_blob():
67 expiry = int(config.CSRF_TIMEOUT + time.time()) 66 expiry = int(config.CSRF_TIMEOUT + time.time())
68 content = '%s-%s' % (init_cookie(), expiry) 67 content = '%s-%s' % (init_cookie(), expiry)
69 mac = hmac.new(_csrf_key, content).hexdigest() 68 mac = hmac.new(_csrf_key.encode(), content.encode()).hexdigest()
70 return "%s-%s" % (content, mac) 69 return "%s-%s" % (content, mac)
71 70
72 def check_csrf_blob(blob): 71 def check_csrf_blob(blob):
73 toks = blob.split('-') 72 toks = blob.split('-')
74 if len(toks) != 3: 73 if len(toks) != 3:
75 print>>sys.stderr, "wrong toks"
76 return False 74 return False
77 75
78 user, expiry, mac = toks 76 user, expiry, mac = toks
79 if user != init_cookie(): 77 if user != init_cookie():
80 print>>sys.stderr, "wrong user"
81 return False 78 return False
82 79
83 try: 80 try:
84 exp = int(expiry) 81 exp = int(expiry)
85 except ValueError: 82 except ValueError:
86 print>>sys.stderr, "failed exp"
87 return False 83 return False
88 84
89 if exp < 1000000000: 85 if exp < 1000000000:
90 return False 86 return False
91 87
92 if exp < time.time(): 88 if exp < time.time():
93 print>>sys.stderr, "expired %d %d" % (exp, time.time())
94 return False 89 return False
95 90
96 check_content = "%s-%s" % (user, expiry) 91 check_content = "%s-%s" % (user, expiry)
97 check_mac = hmac.new(_csrf_key, check_content).hexdigest() 92 check_mac = hmac.new(_csrf_key.encode(), check_content.encode()).hexdigest()
98 if mac == check_mac: 93 if mac == check_mac:
99 print>>sys.stderr, "good hmac"
100 return True 94 return True
101 95
102 print>>sys.stderr, "fail"
103 return False 96 return False
104 97