spec-first / connexion

Connexion is a modern Python web framework that makes spec-first and api-first development easy.
https://connexion.readthedocs.io/en/latest/
Apache License 2.0
4.47k stars 760 forks source link

Test client failing to manage jwt security Unauthorized exceptions #1960

Open carloscbl opened 1 month ago

carloscbl commented 1 month ago

Description

INFO     root:jwt_token_manager.py:273 Invalid token: Not enough segments
ERROR    connexion.middleware.exceptions:exceptions.py:107 <Unauthorized '401: Unauthorized'>
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/jwt/api_jws.py", line 257, in _load
    signing_input, crypto_segment = jwt.rsplit(b".", 1)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: not enough values to unpack (expected 2, got 1)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/app/packages/GWKit/gwkitmodules/jwt_token_manager.py", line 265, in check_token
    data = jwt.decode(utf8token, self.jwt_secret, algorithms=self.algorithms)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jwt/api_jwt.py", line 210, in decode
    decoded = self.decode_complete(
              ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jwt/api_jwt.py", line 151, in decode_complete
    decoded = api_jws.decode_complete(
              ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jwt/api_jws.py", line 198, in decode_complete
    payload, signing_input, header, signature = self._load(jwt)
                                                ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jwt/api_jws.py", line 260, in _load
    raise DecodeError("Not enough segments") from err
jwt.exceptions.DecodeError: Not enough segments

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/usr/local/lib/python3.12/site-packages/connexion/middleware/swagger_ui.py", line 222, in __call__
    await self.router(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 485, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 806, in app
    await self.default(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/connexion/middleware/swagger_ui.py", line 235, in default_fn
    await self.app(original_scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/connexion/middleware/routing.py", line 154, in __call__
    await self.router(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 485, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/connexion/middleware/routing.py", line 48, in __call__
    await self.next_app(original_scope, receive, send)
  File "/usr/local/lib/python3.12/site-packages/connexion/middleware/abstract.py", line 264, in __call__
    return await operation(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/connexion/middleware/security.py", line 110, in __call__
    await self.verification_fn(request)
  File "/usr/local/lib/python3.12/site-packages/connexion/security.py", line 577, in verify_fn
    cls._raise_most_specific(errors)
  File "/usr/local/lib/python3.12/site-packages/connexion/security.py", line 621, in _raise_most_specific
    raise status_to_exc[lowest_status_code]
  File "/usr/local/lib/python3.12/site-packages/connexion/security.py", line 569, in verify_fn
    token_info = await token_info
                 ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/connexion/security.py", line 116, in wrapper
    token_info = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
  File "/app/main/test/integration/../../authapi.py", line 181, in decode_token
    data_from_token = gwkit.jwt_manager_instance.check_token(token)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/packages/GWKit/gwkitmodules/jwt_token_manager.py", line 274, in check_token
    raise Unauthorized(e)
werkzeug.exceptions.Unauthorized: 401 Unauthorized: Not enough segments
INFO     httpx:_client.py:1026 HTTP Request: POST http://testserver/api-isp/v1/identity/logout "HTTP/1.1 500 Internal Server Error"

Expected behaviour

During a test i expect response will be 401 as it raised

    def test_06_logout_invalid_login(self):
        response = self.client.post(self.base_url+f'/identity/logout', headers={"Authorization": "Bearer %s" % self._invalid_access_token, "Content-Type": "application/json"}, data=json.dumps({}))
        #print(str(response))
        print(str(response.json()))
        assert response.status_code == 401

Actual behaviour

INFO     httpx:_client.py:1026 HTTP Request: POST http://testserver/api-isp/v1/identity/logout "HTTP/1.1 500 Internal Server Error"
 assert response.status_code == 401
 E    assert 500 == 401
 E     +  where 500 = <Response [500 Internal Server Error]>.status_code

Steps to reproduce

Additional info:

Output of the commands:

carloscbl commented 1 month ago

After changing exception type to raise connexion.exceptions.OAuthProblem(str(e)) Now seems to be working, but is this intended?