Merge pull request #929 from ganguera/ganguera/basic_auth

Added Basic Auth support for MITMWeb interface
This commit is contained in:
Maximilian Hils 2016-02-12 23:35:16 +01:00
commit bd68b4f678
4 changed files with 67 additions and 4 deletions

View File

@ -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(

View File

@ -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)

View File

@ -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)

View File

@ -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)