aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/authentication.py
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy/authentication.py')
-rw-r--r--libmproxy/authentication.py79
1 files changed, 53 insertions, 26 deletions
diff --git a/libmproxy/authentication.py b/libmproxy/authentication.py
index e5383f5a..500ead6b 100644
--- a/libmproxy/authentication.py
+++ b/libmproxy/authentication.py
@@ -2,35 +2,49 @@ import binascii
import contrib.md5crypt as md5crypt
class NullProxyAuth():
- """ No proxy auth at all (returns empty challange headers) """
- def __init__(self, password_manager=None):
+ """
+ No proxy auth at all (returns empty challange headers)
+ """
+ def __init__(self, password_manager):
self.password_manager = password_manager
self.username = ""
- def authenticate(self, auth_value):
- """ Tests that the specified user is allowed to use the proxy (stub) """
+ 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 """
+ """
+ Returns a dictionary containing the headers require to challenge the user
+ """
return {}
- def get_username(self):
- return self.username
-
class BasicProxyAuth(NullProxyAuth):
-
- def __init__(self, password_manager, realm="mitmproxy"):
+ CHALLENGE_HEADER = 'Proxy-Authenticate'
+ AUTH_HEADER = 'Proxy-Authorization'
+ def __init__(self, password_manager, realm):
NullProxyAuth.__init__(self, password_manager)
- self.realm = "mitmproxy"
+ self.realm = realm
- def authenticate(self, auth_value):
- if (not auth_value) or (not auth_value[0]):
- return False;
+ 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
try:
- scheme, username, password = self.parse_authorization_header(auth_value[0])
- except:
+ scheme, username, password = self.parse_auth_value(auth_value[0])
+ except ValueError:
return False
if scheme.lower()!='basic':
return False
@@ -40,14 +54,26 @@ class BasicProxyAuth(NullProxyAuth):
return True
def auth_challenge_headers(self):
- return {'Proxy-Authenticate':'Basic realm="%s"'%self.realm}
+ return {self.CHALLENGE_HEADER:'Basic realm="%s"'%self.realm}
- def parse_authorization_header(self, auth_value):
+ def unparse_auth_value(self, scheme, username, password):
+ v = binascii.b2a_base64(username + ":" + password)
+ return scheme + " " + v
+
+ def parse_auth_value(self, auth_value):
words = auth_value.split()
+ if len(words) != 2:
+ raise ValueError("Invalid basic auth credential.")
scheme = words[0]
- user = binascii.a2b_base64(words[1])
- username, password = user.split(':')
- return scheme, username, password
+ try:
+ user = binascii.a2b_base64(words[1])
+ except binascii.Error:
+ raise ValueError("Invalid basic auth credential: user:password pair not valid base64: %s"%words[1])
+ parts = user.split(':')
+ if len(parts) != 2:
+ raise ValueError("Invalid basic auth credential: decoded user:password pair not valid: %s"%user)
+ return scheme, parts[0], parts[1]
+
class PasswordManager():
def __init__(self):
@@ -56,8 +82,8 @@ class PasswordManager():
def test(self, username, password_token):
return False
-class PermissivePasswordManager(PasswordManager):
+class PermissivePasswordManager(PasswordManager):
def __init__(self):
PasswordManager.__init__(self)
@@ -66,16 +92,17 @@ class PermissivePasswordManager(PasswordManager):
return True
return False
-class HtpasswdPasswordManager(PasswordManager):
- """ Read usernames and passwords from a file created by Apache htpasswd"""
+class HtpasswdPasswordManager(PasswordManager):
+ """
+ Read usernames and passwords from a file created by Apache htpasswd
+ """
def __init__(self, filehandle):
PasswordManager.__init__(self)
entries = (line.strip().split(':') for line in filehandle)
valid_entries = (entry for entry in entries if len(entry)==2)
self.usernames = {username:token for username,token in valid_entries}
-
def test(self, username, password_token):
if username not in self.usernames:
return False
@@ -84,8 +111,8 @@ class HtpasswdPasswordManager(PasswordManager):
expected = md5crypt.md5crypt(password_token, salt, '$'+magic+'$')
return expected==full_token
-class SingleUserPasswordManager(PasswordManager):
+class SingleUserPasswordManager(PasswordManager):
def __init__(self, username, password):
PasswordManager.__init__(self)
self.username = username