Mercurial > templog
annotate 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 |
rev | line source |
---|---|
211
59379b2bd056
key fingerprints are case- and whitespace-insensitive.
Matt Johnston <matt@ucc.asn.au>
parents:
194
diff
changeset
|
1 import re |
185 | 2 import os |
3 import time | |
4 import fcntl | |
5 import hmac | |
6 import sys | |
189 | 7 import hashlib |
8 | |
9 import bottle | |
185 | 10 |
11 import config | |
12 | |
291
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
13 __all__ = [ |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
14 "get_csrf_blob", |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
15 "check_csrf_blob", |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
16 "setup_csrf", |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
17 "check_cookie", |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
18 "init_cookie", |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
19 ] |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
20 |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
21 AUTH_COOKIE = 'templogauth' |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
22 AUTH_COOKIE_LEN = 16 |
189 | 23 |
24 HASH=hashlib.sha1 | |
185 | 25 |
211
59379b2bd056
key fingerprints are case- and whitespace-insensitive.
Matt Johnston <matt@ucc.asn.au>
parents:
194
diff
changeset
|
26 CLEAN_RE = re.compile('[^a-z0-9A-Z]') |
59379b2bd056
key fingerprints are case- and whitespace-insensitive.
Matt Johnston <matt@ucc.asn.au>
parents:
194
diff
changeset
|
27 |
291
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
28 def cookie_hash(c): |
586 | 29 return hashlib.sha256(c.encode()).hexdigest() |
211
59379b2bd056
key fingerprints are case- and whitespace-insensitive.
Matt Johnston <matt@ucc.asn.au>
parents:
194
diff
changeset
|
30 |
291
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
31 def init_cookie(): |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
32 """ Generates a new httponly auth cookie if required. |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
33 Returns the hash of the cookie (new or existing) |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
34 """ |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
35 c = bottle.request.get_cookie(AUTH_COOKIE) |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
36 if not c: |
586 | 37 c = os.urandom(AUTH_COOKIE_LEN).hex() |
303 | 38 years = 60*60*24*365 |
39 bottle.response.set_cookie(AUTH_COOKIE, c, secure=True, httponly=True, max_age=10*years) | |
291
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
40 return cookie_hash(c) |
189 | 41 |
291
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
42 def check_cookie(allowed_users): |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
43 c = bottle.request.get_cookie(AUTH_COOKIE) |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
44 if not c: |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
45 return False |
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
46 return cookie_hash(c) in allowed_users |
211
59379b2bd056
key fingerprints are case- and whitespace-insensitive.
Matt Johnston <matt@ucc.asn.au>
parents:
194
diff
changeset
|
47 |
185 | 48 def setup_csrf(): |
49 NONCE_SIZE=16 | |
50 global _csrf_fd, _csrf_key | |
586 | 51 _csrf_fd = os.fdopen(os.open('%s/csrf.dat' % config.DATA_PATH, os.O_RDWR | os.O_CREAT, 0o600), 'r+') |
185 | 52 |
53 try: | |
54 fcntl.lockf(_csrf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) | |
586 | 55 _csrf_fd.write("%d-%s" % (os.getpid(), os.urandom(NONCE_SIZE).hex())) |
185 | 56 _csrf_fd.flush() |
57 _csrf_fd.seek(0) | |
58 except IOError: | |
59 pass | |
60 fcntl.lockf(_csrf_fd, fcntl.LOCK_SH) | |
61 _csrf_key = _csrf_fd.read() | |
62 # keep the lock open until we go away | |
63 | |
64 | |
65 def get_csrf_blob(): | |
66 expiry = int(config.CSRF_TIMEOUT + time.time()) | |
291
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
67 content = '%s-%s' % (init_cookie(), expiry) |
586 | 68 mac = hmac.new(_csrf_key.encode(), content.encode()).hexdigest() |
185 | 69 return "%s-%s" % (content, mac) |
70 | |
71 def check_csrf_blob(blob): | |
72 toks = blob.split('-') | |
73 if len(toks) != 3: | |
74 return False | |
75 | |
76 user, expiry, mac = toks | |
291
f7261dd970da
- replace ssl client certs with cookies
Matt Johnston <matt@ucc.asn.au>
parents:
226
diff
changeset
|
77 if user != init_cookie(): |
185 | 78 return False |
79 | |
80 try: | |
81 exp = int(expiry) | |
82 except ValueError: | |
83 return False | |
84 | |
85 if exp < 1000000000: | |
86 return False | |
87 | |
194 | 88 if exp < time.time(): |
185 | 89 return False |
90 | |
91 check_content = "%s-%s" % (user, expiry) | |
586 | 92 check_mac = hmac.new(_csrf_key.encode(), check_content.encode()).hexdigest() |
185 | 93 if mac == check_mac: |
94 return True | |
95 | |
96 return False | |
97 |