-
Notifications
You must be signed in to change notification settings - Fork 8
/
basic.py
68 lines (53 loc) · 2.31 KB
/
basic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from functools import wraps
import hashlib
from time import sleep
from typing import Optional
from flask import make_response, request
from werkzeug.datastructures import Authorization
from config import webapp_settings
# TODO
user_password_dict = {
webapp_settings['basic_user']: webapp_settings['basic_password']
}
def need_basic_auth(f):
@wraps(f)
def deco_func(*args, **kwargs):
return basic_authorization() or f(*args, **kwargs)
return deco_func
def basic_authorization():
scheme = 'Basic'
def get_auth() -> Optional[Authorization]:
_auth = request.authorization
if _auth is None and 'Authorization' in request.headers:
# Flask/Werkzeug do not recognize any authentication types
# other than Basic or Digest, so here we parse the header by
# hand
try:
auth_type, token = request.headers['Authorization'].split(None, 1)
_auth = Authorization(auth_type, {'token': token})
except ValueError:
# The Authorization header is either empty or has no token
pass
# if the auth type does not match, we act as if there is no auth
# this is better than failing directly, as it allows the callback
# to handle special cases, like supporting multiple auth types
if _auth is not None and _auth.type.lower() != scheme.lower():
_auth = None
return _auth
auth: Optional[Authorization] = get_auth()
# Flask normally handles OPTIONS requests on its own, but in the
# case it is configured to forward those to the application, we
# need to ignore authentication headers and let the request through
# to avoid unwanted interactions with CORS.
if request.method != 'OPTIONS': # pragma: no cover
if not auth or not auth.password or \
hashlib.sha512(auth.password.encode()).hexdigest() != user_password_dict.get(auth.username):
# defence for brute force
sleep(1)
realm = 'Authentication Required'
res = make_response(realm)
res.status_code = 401
if 'WWW-Authenticate' not in res.headers.keys():
res.headers['WWW-Authenticate'] = '{0} realm="{1}"'.format(scheme, realm)
return res
return None