diff options
Diffstat (limited to 'libmproxy/authentication.py')
-rw-r--r-- | libmproxy/authentication.py | 79 |
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 |