From 21f376eaa52c35ef8a56afd97908c250bf5480cf Mon Sep 17 00:00:00 2001 From: Shingo Kitagawa Date: Wed, 15 Jul 2020 02:26:55 +0900 Subject: [PATCH 1/3] add basic and basic_yaml --- src/roswww/roswww_server.py | 68 +++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/roswww/roswww_server.py b/src/roswww/roswww_server.py index b154c1b..15f5b0f 100644 --- a/src/roswww/roswww_server.py +++ b/src/roswww/roswww_server.py @@ -36,15 +36,48 @@ import logging +import base64 +import functools import socket import tornado.ioloop # rosbridge installs tornado import tornado.web +import yaml + from .webrequest_handler import WebRequestHandler from .utils import run_shellcommand, split_words, get_packages + +def basic_auth(auth): + def decore(f): + def _request_auth(handler): + handler.set_header('WWW-Authenticate', 'Basic realm=JSL') + handler.set_status(401) + handler.finish() + return False + + @functools.wraps(f) + def new_f(*args): + handler = args[0] + auth_header = handler.request.headers.get('Authorization') + if auth_header is None: + return _request_auth(handler) + if not auth_header.startswith('Basic '): + return _request_auth(handler) + + auth_decoded = base64.decodestring(auth_header.split(' ', 1)[1]) + username, password = auth_decoded.split(':', 1) + + if auth(username, password): + f(*args) + else: + _request_auth(handler) + return new_f + return decore + + class ROSWWWServer(): - def __init__(self, name, webpath, ports, cached): + def __init__(self, name, webpath, ports, cached, basic=False, basic_yaml=None): ''' :param str name: webserver name :param str webpath: package relative path to web page source. @@ -54,20 +87,51 @@ def __init__(self, name, webpath, ports, cached): self._webpath = webpath self._ports = ports self._cached = cached + self._basic = basic self._logger = self._set_logger() self._packages = get_packages() self._application = self._create_webserver(self._packages) + if self._basic: + if basic_yaml: + with open(basic_yaml) as f: + self._keys = yaml.safe_load(f) + else: + self._keys = {'admin': 'admin'} def _create_webserver(self, packages): ''' @type packages: {str, str} @param packages: name and path of ROS packages. ''' + def _auth(username, password): + if username in self._keys: + return self._keys[username] == password + return False + class NoCacheStaticFileHandler(tornado.web.StaticFileHandler): def set_extra_headers(self, path): self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') - file_handler = tornado.web.StaticFileHandler if self._cached else NoCacheStaticFileHandler + class BasicStaticFileHandler(tornado.web.StaticFileHandler): + @basic_auth(_auth) + def get(self, path, include_body=True): + super(BasicStaticFileHandler, self).get(path, include_body) + + class BasicNoCacheStaticFileHandler(NoCacheStaticFileHandler): + @basic_auth(_auth) + def get(self, path, include_body=True): + super(BasicNoCacheStaticFileHandler, self).get(path, include_body) + + if self._cached: + if self._basic: + file_handler = BasicStaticFileHandler + else: + file_handler = tornado.web.StaticFileHandler + else: + if self._basic: + file_handler = BasicNoCacheStaticFileHandler + else: + file_handler = NoCacheStaticFileHandler handlers = [(r"/", WebRequestHandler, {"packages": packages})] From 6c1845f617d943c506f3012257eeaf137895319b Mon Sep 17 00:00:00 2001 From: Shingo Kitagawa Date: Wed, 15 Jul 2020 02:27:24 +0900 Subject: [PATCH 2/3] add basic and basic_yaml in webserver --- launch/roswww.launch | 4 +++- script/webserver.py | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/launch/roswww.launch b/launch/roswww.launch index 0d28fcd..d84e10b 100644 --- a/launch/roswww.launch +++ b/launch/roswww.launch @@ -2,6 +2,7 @@ + @@ -9,5 +10,6 @@ + --basic $(arg basic) --port $(arg port) + --start_port $(arg start_port) --end_port $(arg end_port)" /> diff --git a/script/webserver.py b/script/webserver.py index 2224eeb..a47f7df 100755 --- a/script/webserver.py +++ b/script/webserver.py @@ -48,17 +48,21 @@ def parse_argument(argv): parser.add_argument('-p', '--port', default=80, type=int, help='Webserver Port number') parser.add_argument('-w', '--webpath', default='www', help='package relative path to web pages') parser.add_argument('--cached', default='true', help='static file is cached') + parser.add_argument('--basic', default='false', help='enable basic authentication') + parser.add_argument('--basic-yaml', default=None, help='basic key yaml file path') parser.add_argument('--start_port', default=8000, type=int, help='setting up port scan range') parser.add_argument('--end_port', default=9000, type=int, help='setting up port scan range') parsed_args = parser.parse_args(argv) cached = False if parsed_args.cached in [0, False, 'false', 'False'] else True - return parsed_args.name, parsed_args.webpath, (parsed_args.port, parsed_args.start_port, parsed_args.end_port), cached + basic = True if parsed_args.basic in [1, True, 'true', 'True'] else False + basic_yaml = parsed_args.basic_yaml + return parsed_args.name, parsed_args.webpath, (parsed_args.port, parsed_args.start_port, parsed_args.end_port), cached, basic, basic_yaml if __name__ == '__main__': rospy.init_node("webserver", disable_signals=True) - name, webpath, port, cached = parse_argument(rospy.myargv()[1:]) - webserver = roswww.ROSWWWServer(name, webpath, port, cached) + name, webpath, port, cached, basic, basic_yaml = parse_argument(rospy.myargv()[1:]) + webserver = roswww.ROSWWWServer(name, webpath, port, cached, basic, basic_yaml) webserver.loginfo("Initialised") webserver.spin() From 71306ad17cab833692151c39bfd4aeedec9a150d Mon Sep 17 00:00:00 2001 From: Shingo Kitagawa Date: Fri, 24 Jul 2020 20:03:00 +0900 Subject: [PATCH 3/3] update basic realm --- src/roswww/roswww_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/roswww/roswww_server.py b/src/roswww/roswww_server.py index 15f5b0f..6342bd3 100644 --- a/src/roswww/roswww_server.py +++ b/src/roswww/roswww_server.py @@ -50,7 +50,7 @@ def basic_auth(auth): def decore(f): def _request_auth(handler): - handler.set_header('WWW-Authenticate', 'Basic realm=JSL') + handler.set_header('WWW-Authenticate', 'Basic realm=roswww') handler.set_status(401) handler.finish() return False