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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
import binascii
import contrib.md5crypt as md5crypt
import http
class NullProxyAuth():
"""
No proxy auth at all (returns empty challange headers)
"""
def __init__(self, password_manager):
self.password_manager = password_manager
def clean(self, headers):
"""
Clean up authentication headers, so they're not passed upstream.
"""
pass
def authenticate(self, headers):
"""
Tests that the user is allowed to use the proxy
"""
return True
def auth_challenge_headers(self):
"""
Returns a dictionary containing the headers require to challenge the user
"""
return {}
class BasicProxyAuth(NullProxyAuth):
CHALLENGE_HEADER = 'Proxy-Authenticate'
AUTH_HEADER = 'Proxy-Authorization'
def __init__(self, password_manager, realm):
NullProxyAuth.__init__(self, password_manager)
self.realm = realm
def clean(self, headers):
del headers[self.AUTH_HEADER]
def authenticate(self, headers):
auth_value = headers.get(self.AUTH_HEADER, [])
if not auth_value:
return False
parts = http.parse_http_basic_auth(auth_value[0])
if not parts:
return False
scheme, username, password = parts
if scheme.lower()!='basic':
return False
if not self.password_manager.test(username, password):
return False
self.username = username
return True
def auth_challenge_headers(self):
return {self.CHALLENGE_HEADER:'Basic realm="%s"'%self.realm}
class PassMan():
def test(self, username, password_token):
return False
class PassManNonAnon:
"""
Ensure the user specifies a username, accept any password.
"""
def test(self, username, password_token):
if username:
return True
return False
class PassManHtpasswd:
"""
Read usernames and passwords from an htpasswd file
"""
def __init__(self, fp):
"""
Raises ValueError if htpasswd file is invalid.
"""
self.usernames = {}
for l in fp:
l = l.strip().split(':')
if len(l) != 2:
raise ValueError("Invalid htpasswd file.")
parts = l[1].split('$')
if len(parts) != 4:
raise ValueError("Invalid htpasswd file.")
self.usernames[l[0]] = dict(
token = l[1],
dummy = parts[0],
magic = parts[1],
salt = parts[2],
hashed_password = parts[3]
)
def test(self, username, password_token):
ui = self.usernames.get(username)
if not ui:
return False
expected = md5crypt.md5crypt(password_token, ui["salt"], '$'+ui["magic"]+'$')
return expected==ui["token"]
class PassManSingleUser:
def __init__(self, username, password):
self.username, self.password = username, password
def test(self, username, password_token):
return self.username==username and self.password==password_token
|