From 292185bb7dd69538f1fd447918ec1693341258cb Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Thu, 29 May 2025 17:40:21 +0200 Subject: [PATCH] Better unauthorized error page --- hmdooris/BottleHelpers.py | 37 +++++++++++++++++++++-- hmdooris/__main__.py | 4 ++- hmdooris/templates/not_authorized.html.j2 | 2 +- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/hmdooris/BottleHelpers.py b/hmdooris/BottleHelpers.py index 929d4d2..27f1dea 100644 --- a/hmdooris/BottleHelpers.py +++ b/hmdooris/BottleHelpers.py @@ -17,19 +17,51 @@ class BottleHelpers: def require_login(self, func: Callable) -> Callable: if self.group is not None: - return self.auth.require_login(self.auth.require_attribute('groups', self.group)(func)) + return self.auth.require_login(self.require_attribute('groups', self.group)(func)) else: return self.auth.require_login(func) + def require_attribute(self, attr, value): + """ Decorator requires specific attribute value. """ + + def test_attrs(challenge, standard): + """Compare list or val the standard.""" + + stand_list = standard if type(standard) is list else [standard] + chal_list = challenge if type(challenge) is list else [challenge] + + for chal in chal_list: + if chal in stand_list: + return True + return False + + def _outer_wrapper(f): + + def _wrapper(*args, **kwargs): + + if attr in self.auth.my_attrs: + resource = request.session[self.auth.sess_attr][attr] + + if test_attrs(resource, value): + return f(*args, **kwargs) + + abort(401, 'Not Authorized') + + _wrapper.__name__ = f.__name__ + return _wrapper + + return _outer_wrapper + def require_authz(self, func: Callable) -> Callable: if self.group is not None: - return self.auth.require_attribute('groups', self.group)(func) + return self.require_attribute('groups', self.group)(func) else: def _outer_wrapper(f): def _wrapper(*args, **kwargs): if self.auth.my_username is not None: return f(*args, **kwargs) abort(401, 'Not Authorized') + return None _wrapper.__name__ = f.__name__ return _wrapper @@ -47,6 +79,7 @@ class BottleHelpers: if addr.overlaps(allowed): return f(*args, **kwargs) abort(401, 'Not Authorized') + return None _wrapper.__name__ = f.__name__ return _wrapper diff --git a/hmdooris/__main__.py b/hmdooris/__main__.py index d73d625..ad50400 100644 --- a/hmdooris/__main__.py +++ b/hmdooris/__main__.py @@ -84,6 +84,7 @@ def get_api_lock(id): return update_poller.get_lock(id) @app.post('/api/lock/') +@bottle_helpers.require_sourceip @bottle_helpers.require_authz def post_api_lock(id): return ccujack.lock_unlock(id, request.json["locking"]) @@ -92,15 +93,16 @@ def post_api_lock(id): @jinja2_view("not_authorized.html.j2") def not_authorized(error): code, msg = error.args + groups = request.session[auth.sess_attr]['groups'] if 'groups' in request.session[auth.sess_attr] else [] return { 'user': auth.my_username, 'ip': request.remote_addr, 'error': error, 'code': code, 'msg': msg, + 'groups': groups, } -app.error_handler[401] = not_authorized if __name__ == '__main__': app.run(host=config.listen_host, port=config.listen_port, server=GeventWebSocketServer, debug=config.debug, quiet=not config.debug) diff --git a/hmdooris/templates/not_authorized.html.j2 b/hmdooris/templates/not_authorized.html.j2 index f81d318..864a964 100644 --- a/hmdooris/templates/not_authorized.html.j2 +++ b/hmdooris/templates/not_authorized.html.j2 @@ -8,6 +8,6 @@

HM Dooris - {{ msg }}

You are not authorized to lock or unlock.

-

user: {{ user }}, ip: {{ ip }}, error: {{ error }}, code: {{ code }}, msg: {{ msg }}

+

user: {{ user }}, groups: {{ groups }}, ip: {{ ip }}, error: {{ error }}, code: {{ code }}, msg: {{ msg }}

\ No newline at end of file