diff --git a/ndscheduler/default_settings.py b/ndscheduler/default_settings.py index 00d1626..eb42684 100644 --- a/ndscheduler/default_settings.py +++ b/ndscheduler/default_settings.py @@ -19,6 +19,7 @@ STATIC_DIR_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static') TEMPLATE_DIR_PATH = STATIC_DIR_PATH APP_INDEX_PAGE = 'index.html' +WEBSITE_TITLE = 'Scheduler' # # Server setup @@ -100,3 +101,10 @@ # Packages that contains job classes, e.g., simple_scheduler.jobs JOB_CLASS_PACKAGES = [] + +# Basic Auth +# +# If needs basic auth, modify the dict below +# e.g. BASIC_AUTH_CREDENTIALS = {'username': 'password'} +# +BASIC_AUTH_CREDENTIALS = {} diff --git a/ndscheduler/server/handlers/base.py b/ndscheduler/server/handlers/base.py index 7ca6d2f..b431fb3 100644 --- a/ndscheduler/server/handlers/base.py +++ b/ndscheduler/server/handlers/base.py @@ -5,6 +5,7 @@ """ import json +import base64 from concurrent import futures @@ -17,8 +18,36 @@ class BaseHandler(tornado.web.RequestHandler): executor = futures.ThreadPoolExecutor(max_workers=settings.TORNADO_MAX_WORKERS) + basic_auth_credentials = settings.BASIC_AUTH_CREDENTIALS + basic_auth_realm = 'Scheduler' + + def send_challenge(self): + """Send challenge response.""" + header = 'Basic realm="{}"'.format(self.basic_auth_realm) + self.set_status(401) + self.set_header('WWW-Authenticate', header) + self.finish() + + def get_basic_auth_result(self): + """Get HTTP basic access authentication result.""" + auth_header = self.request.headers.get('Authorization', '') + if not auth_header.startswith('Basic '): + self.send_challenge() + return + + auth_data = auth_header.split(' ')[-1] + auth_data = base64.b64decode(auth_data).decode('utf-8') + username, password = auth_data.split(':') + + challenge = self.basic_auth_credentials.get(username) + if challenge != password: + self.send_challenge() + def prepare(self): """Preprocess requests.""" + if len(self.basic_auth_credentials) > 0: + self.get_basic_auth_result() + try: if self.request.headers['Content-Type'].startswith('application/json'): self.json_args = json.loads(self.request.body.decode()) diff --git a/ndscheduler/server/handlers/index.py b/ndscheduler/server/handlers/index.py index ff0130f..273eb10 100644 --- a/ndscheduler/server/handlers/index.py +++ b/ndscheduler/server/handlers/index.py @@ -13,5 +13,12 @@ class Handler(base.BaseHandler): def get(self): """Serve up the single page app for scheduler dashboard.""" + website_info = { + 'title': settings.WEBSITE_TITLE, + } + meta_info = utils.get_all_available_jobs() - self.render(settings.APP_INDEX_PAGE, jobs_meta_info=json.dumps(meta_info)) + self.render(settings.APP_INDEX_PAGE, + jobs_meta_info=json.dumps(meta_info), + website_info=website_info, + ) diff --git a/ndscheduler/static/index.html b/ndscheduler/static/index.html index dfb97a6..07459fb 100644 --- a/ndscheduler/static/index.html +++ b/ndscheduler/static/index.html @@ -7,7 +7,7 @@ - Scheduler + {{ website_info['title'] }} @@ -33,7 +33,7 @@ - Nextdoor Scheduler + {{ website_info['title'] }}