From 936f70904a3f6b9400181c6ba2fcf450c8fb280a Mon Sep 17 00:00:00 2001 From: Rohan Weeden Date: Mon, 6 Jan 2025 10:57:02 -0900 Subject: [PATCH] Catch errors caused by malformed auth headers --- tests/test_app.py | 16 ++++++++++++++++ thin_egress_app/app.py | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/test_app.py b/tests/test_app.py index afaa3a21..75ccd781 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -166,6 +166,22 @@ def test_request_authorizer_no_headers(current_request, mock_get_urs_url): assert authorizer.get_success_response_headers() == {} +def test_request_authorizer_malformed_header(current_request): + current_request.headers = { + "Authorization": "token", + "x-origin-request-id": "origin_request_id", + } + authorizer = app.RequestAuthorizer() + + assert authorizer.get_profile() is None + response = authorizer.get_error_response() + assert response.status_code == 400 + assert response.body == { + "status_code": 400, + "error_description": "Malformed Authorization header", + } + + @mock.patch(f"{MODULE}.get_profile_with_jwt_bearer", autospec=True) def test_request_authorizer_bearer_header( mock_get_profile_with_jwt_bearer, diff --git a/thin_egress_app/app.py b/thin_egress_app/app.py index 4c32c85e..fa2a035e 100644 --- a/thin_egress_app/app.py +++ b/thin_egress_app/app.py @@ -180,10 +180,14 @@ def get_profile(self) -> Optional[UserProfile]: self._response = do_auth_and_return(app.current_request.context) return None - method, token, *_ = authorization.split() - method = method.lower() + parsed_auth = self._parse_auth_header(authorization) + if parsed_auth is None: + return None + + method, args = parsed_auth if method == "bearer": + token, *_ = args # we will deal with "bearer" auth here. "Basic" auth will be handled by do_auth_and_return() log.debug("we got an Authorization header. %s", authorization) user_profile, self._response = self._get_profile_and_response_from_bearer(token) @@ -203,6 +207,33 @@ def get_profile(self) -> Optional[UserProfile]: self._response = do_auth_and_return(app.current_request.context) return None + def _parse_auth_header(self, authorization: str): + try: + method, token, *args = authorization.split() + method = method.lower() + return method, (token, *args) + except Exception: + status_code = 400 + if check_for_browser(app.current_request.headers): + template_vars = { + "title": "Bad Request", + "status_code": status_code, + "contentstring": "Malformed Authorization header", + "requestid": get_request_id(), + } + + self._response = make_html_response(template_vars, {}, status_code, "error.html") + else: + self._response = Response( + body={ + "status_code": status_code, + "error_description": "Malformed Authorization header", + }, + status_code=status_code, + headers={}, + ) + return None + @with_trace() @cachetools.cached( cachetools.TTLCache(maxsize=32, ttl=1 * 60),