aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/authentication.py
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@corte.si>2012-12-30 11:27:04 -0800
committerAldo Cortesi <aldo@corte.si>2012-12-30 11:27:04 -0800
commitcfab27232127437cca8ac3699065db653da97dba (patch)
tree60a92d02b45daf421a0329e4d404652b8f6b3baa /libmproxy/authentication.py
parent3c8dcf880860191ef3bd000f95cf7ea980c6bda9 (diff)
parent440a9f6bda8d645945e8c056a5e869c712dd2d69 (diff)
downloadmitmproxy-cfab27232127437cca8ac3699065db653da97dba.tar.gz
mitmproxy-cfab27232127437cca8ac3699065db653da97dba.tar.bz2
mitmproxy-cfab27232127437cca8ac3699065db653da97dba.zip
Merge pull request #83 from rouli/master
Adding some basic proxy authentication code
Diffstat (limited to 'libmproxy/authentication.py')
-rw-r--r--libmproxy/authentication.py95
1 files changed, 95 insertions, 0 deletions
diff --git a/libmproxy/authentication.py b/libmproxy/authentication.py
new file mode 100644
index 00000000..e5383f5a
--- /dev/null
+++ b/libmproxy/authentication.py
@@ -0,0 +1,95 @@
+import binascii
+import contrib.md5crypt as md5crypt
+
+class NullProxyAuth():
+ """ No proxy auth at all (returns empty challange headers) """
+ def __init__(self, password_manager=None):
+ self.password_manager = password_manager
+ self.username = ""
+
+ def authenticate(self, auth_value):
+ """ Tests that the specified user is allowed to use the proxy (stub) """
+ return True
+
+ def auth_challenge_headers(self):
+ """ 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"):
+ NullProxyAuth.__init__(self, password_manager)
+ self.realm = "mitmproxy"
+
+ def authenticate(self, auth_value):
+ if (not auth_value) or (not auth_value[0]):
+ return False;
+ try:
+ scheme, username, password = self.parse_authorization_header(auth_value[0])
+ except:
+ return False
+ 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 {'Proxy-Authenticate':'Basic realm="%s"'%self.realm}
+
+ def parse_authorization_header(self, auth_value):
+ words = auth_value.split()
+ scheme = words[0]
+ user = binascii.a2b_base64(words[1])
+ username, password = user.split(':')
+ return scheme, username, password
+
+class PasswordManager():
+ def __init__(self):
+ pass
+
+ def test(self, username, password_token):
+ return False
+
+class PermissivePasswordManager(PasswordManager):
+
+ def __init__(self):
+ PasswordManager.__init__(self)
+
+ def test(self, username, password_token):
+ if username:
+ return True
+ return False
+
+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
+ full_token = self.usernames[username]
+ dummy, magic, salt, hashed_password = full_token.split('$')
+ expected = md5crypt.md5crypt(password_token, salt, '$'+magic+'$')
+ return expected==full_token
+
+class SingleUserPasswordManager(PasswordManager):
+
+ def __init__(self, username, password):
+ PasswordManager.__init__(self)
+ self.username = username
+ self.password = password
+
+ def test(self, username, password_token):
+ return self.username==username and self.password==password_token