8000 Identical IDP keys for sig and enc can fail verification for oauth2 · Issue #771 · authlib/authlib · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Identical IDP keys for sig and enc can fail verification for oauth2 #771
Open
@LevN0

Description

@LevN0

Describe the bug

When an identity provider has multiple keys (for example one for signature and one for encryption), and when the signature key and encryption key are identical, the authorize_access_token call can fail depending on the order in which the identity provider returns the keys.

The issue comes from the create_load_key method, which selects the key via a find_by_kid call. If the server returns keys with identical kid's, which can be the case if the certificates themselves are identical (e.g. keycloak will return identical kid's and this is not configurable), then the find_by_kid will select the first key matching the kid. If this first key's use is set to encryption (because it's the 2nd identical key whose use is set to signature), this causes subsequent validation to raise an exception.

I am linking here to the flask integration for authorize_access_token, but I believe the issue is relevant to other integrations and possibly other use cases as well.

Error Stacks

Traceback (most recent call last):
  File "test-case/.venv/lib64/python3.12/site-packages/flask/app.py", line 1536, in __call__
    return self.wsgi_app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/flask/app.py", line 1514, in wsgi_app
    response = self.handle_exception(e)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/flask_oidc/views.py", line 60, in authorize_view
    token = g._oidc_auth.authorize_access_token()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/authlib/integrations/flask_client/apps.py", line 114, in authorize_access_token
    userinfo = self.parse_id_token(
               ^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/authlib/integrations/base_client/sync_openid.py", line 65, in parse_id_token
    claims = _jwt.decode(
             ^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/authlib/jose/rfc7519/jwt.py", line 104, in decode
    data = self._jws.deserialize_compact(s, load_key, decode_payload)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/authlib/jose/rfc7515/jws.py", line 107, in deserialize_compact
    if algorithm.verify(signing_input, signature, key):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/authlib/jose/rfc7518/jws_algs.py", line 98, in verify
    op_key = key.get_op_key("verify")
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "test-case/.venv/lib64/python3.12/site-packages/authlib/jose/rfc7517/asymmetric_key.py", line 42, in get_op_key
    self.check_key_op(operation)
  File "test-case/.venv/lib64/python3.12/site-packages/authlib/jose/rfc7517/base_key.py", line 87, in check_key_op
    raise InvalidUseError()
authlib.jose.errors.InvalidUseError: invalid_use: Key 'use' is not valid for your usage"""

To Reproduce

Any minimal example that uses flask integration, as long as the identity provider is configured to return 2 or more identical certificates with different uses.

Expected behavior

AuthLib should select the right key (i.e. try to find the signature-use key), no exception should be raised, and authentication should continue.

Environment:

  • OS: Linux
  • Python Version: 3.12
  • Authlib Version: 1.5.2

Additional context

Add any other context about the problem here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0