aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy')
-rw-r--r--libmproxy/cmdline.py15
-rw-r--r--libmproxy/main.py3
-rw-r--r--libmproxy/web/__init__.py24
-rw-r--r--libmproxy/web/app.py29
4 files changed, 67 insertions, 4 deletions
diff --git a/libmproxy/cmdline.py b/libmproxy/cmdline.py
index d8b6000c..b1cbfa3a 100644
--- a/libmproxy/cmdline.py
+++ b/libmproxy/cmdline.py
@@ -760,6 +760,21 @@ def mitmweb():
action="store_true", dest="wdebug",
help="Turn on mitmweb debugging"
)
+ group.add_argument(
+ "--wsingleuser",
+ action="store", dest="wsingleuser", type=str,
+ metavar="USER",
+ help="""
+ Allows access to a a single user, specified in the form
+ username:password.
+ """
+ )
+ group.add_argument(
+ "--whtpasswd",
+ action="store", dest="whtpasswd", type=str,
+ metavar="PATH",
+ help="Allow access to users specified in an Apache htpasswd file."
+ )
common_options(parser)
group = parser.add_argument_group(
diff --git a/libmproxy/main.py b/libmproxy/main.py
index f6664924..ef135754 100644
--- a/libmproxy/main.py
+++ b/libmproxy/main.py
@@ -125,6 +125,9 @@ def mitmweb(args=None): # pragma: no cover
web_options.wdebug = options.wdebug
web_options.wiface = options.wiface
web_options.wport = options.wport
+ web_options.wsingleuser = options.wsingleuser
+ web_options.whtpasswd = options.whtpasswd
+ web_options.process_web_options(parser)
server = get_server(web_options.no_server, proxy_config)
diff --git a/libmproxy/web/__init__.py b/libmproxy/web/__init__.py
index c48b3d09..50c49e8d 100644
--- a/libmproxy/web/__init__.py
+++ b/libmproxy/web/__init__.py
@@ -3,6 +3,8 @@ import collections
import tornado.ioloop
import tornado.httpserver
+from netlib.http import authentication
+
from .. import controller, flow
from . import app
@@ -113,6 +115,9 @@ class Options(object):
"wdebug",
"wport",
"wiface",
+ "wauthenticator",
+ "wsingleuser",
+ "whtpasswd",
]
def __init__(self, **kwargs):
@@ -122,13 +127,30 @@ class Options(object):
if not hasattr(self, i):
setattr(self, i, None)
+ def process_web_options(self, parser):
+ if self.wsingleuser or self.whtpasswd:
+ if self.wsingleuser:
+ if len(self.wsingleuser.split(':')) != 2:
+ return parser.error(
+ "Invalid single-user specification. Please use the format username:password"
+ )
+ username, password = self.wsingleuser.split(':')
+ self.wauthenticator = authentication.PassManSingleUser(username, password)
+ elif self.whtpasswd:
+ try:
+ self.wauthenticator = authentication.PassManHtpasswd(self.whtpasswd)
+ except ValueError as v:
+ return parser.error(v.message)
+ else:
+ self.wauthenticator = None
+
class WebMaster(flow.FlowMaster):
def __init__(self, server, options):
self.options = options
super(WebMaster, self).__init__(server, WebState())
- self.app = app.Application(self, self.options.wdebug)
+ self.app = app.Application(self, self.options.wdebug, self.options.wauthenticator)
if options.rfile:
try:
self.load_flows_file(options.rfile)
diff --git a/libmproxy/web/app.py b/libmproxy/web/app.py
index 958b8669..2c45a1dc 100644
--- a/libmproxy/web/app.py
+++ b/libmproxy/web/app.py
@@ -4,6 +4,7 @@ import tornado.web
import tornado.websocket
import logging
import json
+import base64
from netlib.http import CONTENT_MISSING
from .. import version, filt
@@ -40,7 +41,28 @@ class APIError(tornado.web.HTTPError):
pass
-class RequestHandler(tornado.web.RequestHandler):
+class BasicAuth(object):
+ def set_auth_headers(self):
+ self.set_status(401)
+ self.set_header('WWW-Authenticate', 'Basic realm=MITMWeb')
+ self._transforms = []
+ self.finish()
+
+ def prepare(self):
+ wauthenticator = self.application.settings['wauthenticator']
+ if wauthenticator:
+ auth_header = self.request.headers.get('Authorization')
+ if auth_header is None or not auth_header.startswith('Basic '):
+ self.set_auth_headers()
+ else:
+ self.auth_decoded = base64.decodestring(auth_header[6:])
+ self.username, self.password = self.auth_decoded.split(':', 2)
+ if not wauthenticator.test(self.username, self.password):
+ self.set_auth_headers()
+ raise APIError(401, "Invalid username or password.")
+
+
+class RequestHandler(BasicAuth, tornado.web.RequestHandler):
def set_default_headers(self):
super(RequestHandler, self).set_default_headers()
@@ -100,7 +122,7 @@ class FiltHelp(RequestHandler):
))
-class WebSocketEventBroadcaster(tornado.websocket.WebSocketHandler):
+class WebSocketEventBroadcaster(BasicAuth, tornado.websocket.WebSocketHandler):
# raise an error if inherited class doesn't specify its own instance.
connections = None
@@ -284,7 +306,7 @@ class Settings(RequestHandler):
class Application(tornado.web.Application):
- def __init__(self, master, debug):
+ def __init__(self, master, debug, wauthenticator):
self.master = master
handlers = [
(r"/", IndexHandler),
@@ -308,5 +330,6 @@ class Application(tornado.web.Application):
xsrf_cookies=True,
cookie_secret=os.urandom(256),
debug=debug,
+ wauthenticator=wauthenticator,
)
super(Application, self).__init__(handlers, **settings)