pyjwt icon indicating copy to clipboard operation
pyjwt copied to clipboard

PyJWK doesn't support RSA-OAEP algorithm

Open flyte opened this issue 3 years ago • 13 comments

Using a hosted KeyCloak instance from https://www.cloud-iam.com/ which sets its enc public cert to use RSA-OAEP causes PyJWKClient to throw an exception (raised by PyJWK constructor).

Expected Result

I don't know the ins and outs of it, but either the RSA-OAEP algorithm should be supported or the enc cert ignored (the sig one is RSA256).

Actual Result

Traceback (most recent call last):
  File "/home/flyte/dev/ascender/ascender-api/test.py", line 8, in <module>
    PyJWKSet(certs_from_keycloak["keys"])
  File "/home/flyte/.cache/pypoetry/virtualenvs/ascender-api-35481XGP-py3.10/lib/python3.10/site-packages/jwt/api_jwk.py", line 87, in __init__
    self.keys.append(PyJWK(key))
  File "/home/flyte/.cache/pypoetry/virtualenvs/ascender-api-35481XGP-py3.10/lib/python3.10/site-packages/jwt/api_jwk.py", line 50, in __init__
    raise PyJWKError("Unable to find a algorithm for key: %s" % self._jwk_data)
jwt.exceptions.PyJWKError: Unable to find a algorithm for key: {'kid': 'A2MJgrKnftrPyUXS-FNN4g0spwz1H89gPTAzjb4u91o', 'kty': 'RSA', 'alg': 'RSA-OAEP', 'use': 'enc', 'n': 'xTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO-OiT9dcLqVIlhDckf7yVOfitMG_qZkhIzaOBWNWJZK1_zaeFCv_GQPPEVi_JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu_ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf_EnbSsAibQWXUvVCRRLSNdCrImdR-FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3-w', 'e': 'AQAB', 'x5c': ['MIICnzCCAYcCBgF+Q6te9zANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhhc2NlbmRlcjAeFw0yMjAxMTAxMTA1MTFaFw0zMjAxMTAxMTA2NTFaMBMxETAPBgNVBAMMCGFzY2VuZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO+OiT9dcLqVIlhDckf7yVOfitMG/qZkhIzaOBWNWJZK1/zaeFCv/GQPPEVi/JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu/ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf/EnbSsAibQWXUvVCRRLSNdCrImdR+FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3+wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBXmX39VyMNsmWn6I5myY9YZbHZEaYJ7xZ4eRbkrNN6znx8ar1YdI5zqpp2J91SL7Ni6IVEqHPPkwh/JI6KcEK5mO4bQxLY5YJb4h0z00jFoyn5IxDkFUgbgWQxRanyeSh0iQDHz0J6hbgjzTft25y87KxrdvJDQ8lxoDuQgSogrw/EAl0hMnauS1m87pjkzhhsYDBRwy0G3muDEgmA1E7RAM00ec/SuDAKvwF7HFf6xgSH8YALstz34drKbkWZIiGQIub3Y4swbN3Myb+whiwCLYW1olubFkvH7anSq6d39ZdJhxXmz3rhK0YlJ9O32WHBA1w/U/4wg8YIv6DSHYGF'], 'x5t': 'WAcN3AzixLmWqoKdNhhmxilWhFU', 'x5t#S256': 'M4D1NyJsOrtsjG7tRbDs-zd7hg2tvm9kbYDS4gRO7KI'}

Reproduction Steps

import json

from jwt import PyJWKSet


certs_from_keycloak = json.loads("""{"keys":[{"kid":"JJPd3kTh6QFpJ9P-MSFZbBf43S-LRTAot4DJmwd5EQk","kty":"RSA","alg":"RS256","use":"sig","n":"yluqHNqoRdCqCmhivy_yl4dDDMI5pwg59VMz7dYQREfehxukXPhfchbAHxDhGCZjUYieV4TIRGyEBVR3zQ9ihjStYPz8bXUeWqMBSYaH8R7Xb98GeZplVKnF-OLj0fWJkoNSgPYKuSDm2KXdz2hIZ1jOPKLDqpblnnqxrL_xX-1_kEBWehJmzmS0McCOK2nm7lLWf6zoTBi-bp1x5iNl7qteHdo0UZl1DP4NVE0lYk0uGa-L6ye0pQKS77Ro3R5nURvEO0AcaXYr6wLcxYsPRiYDlOactB6WnRFKAhEgRzdp1a04tH8hquHhrdjTc_ZoZelk6ppd-3ZqGq3jMc7TWw","e":"AQAB","x5c":["MIICnzCCAYcCBgF+Q6teWDANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhhc2NlbmRlcjAeFw0yMjAxMTAxMTA1MTFaFw0zMjAxMTAxMTA2NTFaMBMxETAPBgNVBAMMCGFzY2VuZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyluqHNqoRdCqCmhivy/yl4dDDMI5pwg59VMz7dYQREfehxukXPhfchbAHxDhGCZjUYieV4TIRGyEBVR3zQ9ihjStYPz8bXUeWqMBSYaH8R7Xb98GeZplVKnF+OLj0fWJkoNSgPYKuSDm2KXdz2hIZ1jOPKLDqpblnnqxrL/xX+1/kEBWehJmzmS0McCOK2nm7lLWf6zoTBi+bp1x5iNl7qteHdo0UZl1DP4NVE0lYk0uGa+L6ye0pQKS77Ro3R5nURvEO0AcaXYr6wLcxYsPRiYDlOactB6WnRFKAhEgRzdp1a04tH8hquHhrdjTc/ZoZelk6ppd+3ZqGq3jMc7TWwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQB0EJ2Q8/YKMFr7JRG7IwfMo2Z5bpBluVxtnBTt6EcS+QBQ4LVvh6GmpeNPZhVJHjSb7/yFs1iDGIiJDzbffE+mXRYYfjcl02IlzwOEv+v1wVqbCWfKuZIIDZIWJgmZCJF8xUJgGt+wyv3N2lR1X9GDaCaq9Z4L69vsB+2EQ0YM64ZJf5FXlYQ3Fdaq6kEZaTXpNwR7TlvKFUYaelP0a/c8m/izzfE8dX1WJBUne9Pgnn7emfdTYWmdCAaodv97DJoc3RWQgJhdgxgK85/qDIBfI86FiM3dPWR6/FmLox4f5WIZumWuAgNXBVyvBu+qU7FbwpeS+SlpBCwZuWqoMvEP"],"x5t":"dcy5v0xWv0qvgfX3CzbukvB5TlA","x5t#S256":"tyTUdZfGEopkBZ0BYyC8IxvQL5KFCn9-Po0V4ociZiY"},{"kid":"A2MJgrKnftrPyUXS-FNN4g0spwz1H89gPTAzjb4u91o","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"xTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO-OiT9dcLqVIlhDckf7yVOfitMG_qZkhIzaOBWNWJZK1_zaeFCv_GQPPEVi_JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu_ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf_EnbSsAibQWXUvVCRRLSNdCrImdR-FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3-w","e":"AQAB","x5c":["MIICnzCCAYcCBgF+Q6te9zANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhhc2NlbmRlcjAeFw0yMjAxMTAxMTA1MTFaFw0zMjAxMTAxMTA2NTFaMBMxETAPBgNVBAMMCGFzY2VuZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO+OiT9dcLqVIlhDckf7yVOfitMG/qZkhIzaOBWNWJZK1/zaeFCv/GQPPEVi/JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu/ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf/EnbSsAibQWXUvVCRRLSNdCrImdR+FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3+wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBXmX39VyMNsmWn6I5myY9YZbHZEaYJ7xZ4eRbkrNN6znx8ar1YdI5zqpp2J91SL7Ni6IVEqHPPkwh/JI6KcEK5mO4bQxLY5YJb4h0z00jFoyn5IxDkFUgbgWQxRanyeSh0iQDHz0J6hbgjzTft25y87KxrdvJDQ8lxoDuQgSogrw/EAl0hMnauS1m87pjkzhhsYDBRwy0G3muDEgmA1E7RAM00ec/SuDAKvwF7HFf6xgSH8YALstz34drKbkWZIiGQIub3Y4swbN3Myb+whiwCLYW1olubFkvH7anSq6d39ZdJhxXmz3rhK0YlJ9O32WHBA1w/U/4wg8YIv6DSHYGF"],"x5t":"WAcN3AzixLmWqoKdNhhmxilWhFU","x5t#S256":"M4D1NyJsOrtsjG7tRbDs-zd7hg2tvm9kbYDS4gRO7KI"}]}""")

PyJWKSet(certs_from_keycloak["keys"])

Pretty-printed cert for your pleasure

{
  "kid": "A2MJgrKnftrPyUXS-FNN4g0spwz1H89gPTAzjb4u91o",
  "kty": "RSA",
  "alg": "RSA-OAEP",
  "use": "enc",
  "n": "xTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO-OiT9dcLqVIlhDckf7yVOfitMG_qZkhIzaOBWNWJZK1_zaeFCv_GQPPEVi_JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu_ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf_EnbSsAibQWXUvVCRRLSNdCrImdR-FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3-w",
  "e": "AQAB",
  "x5c": [
  "MIICnzCCAYcCBgF+Q6te9zANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhhc2NlbmRlcjAeFw0yMjAxMTAxMTA1MTFaFw0zMjAxMTAxMTA2NTFaMBMxETAPBgNVBAMMCGFzY2VuZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO+OiT9dcLqVIlhDckf7yVOfitMG/qZkhIzaOBWNWJZK1/zaeFCv/GQPPEVi/JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu/ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf/EnbSsAibQWXUvVCRRLSNdCrImdR+FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3+wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBXmX39VyMNsmWn6I5myY9YZbHZEaYJ7xZ4eRbkrNN6znx8ar1YdI5zqpp2J91SL7Ni6IVEqHPPkwh/JI6KcEK5mO4bQxLY5YJb4h0z00jFoyn5IxDkFUgbgWQxRanyeSh0iQDHz0J6hbgjzTft25y87KxrdvJDQ8lxoDuQgSogrw/EAl0hMnauS1m87pjkzhhsYDBRwy0G3muDEgmA1E7RAM00ec/SuDAKvwF7HFf6xgSH8YALstz34drKbkWZIiGQIub3Y4swbN3Myb+whiwCLYW1olubFkvH7anSq6d39ZdJhxXmz3rhK0YlJ9O32WHBA1w/U/4wg8YIv6DSHYGF"
  ],
  "x5t": "WAcN3AzixLmWqoKdNhhmxilWhFU",
  "x5t#S256": "M4D1NyJsOrtsjG7tRbDs-zd7hg2tvm9kbYDS4gRO7KI"
}

System Information

{
  "cryptography": {
    "version": "36.0.1"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.10.1"
  },
  "platform": {
    "release": "5.4.0-91-generic",
    "system": "Linux"
  },
  "pyjwt": {
    "version": "2.3.0"
  }
}

flyte avatar Jan 11 '22 17:01 flyte

Seems to be affecting token validation from keycloak 16. Downgrading keycloak to version 15.0.1 solves this issue for me. Waiting for this to be fixed before upgrading keycloak.

gchamon avatar Jan 12 '22 15:01 gchamon

I was running into the same problem. Since keys with algorithms I cannot handle are the same to me as non existing keys, I decided to simply ignore them. I derived a slightly adapted PyJWKClient:

class FilteredPyJWKClient(PyJWKClient):
    """
    A PyJWKClient which ignores keys with unknown algorithms instead of throwing an exception.
    """

    @lru_cache(maxsize=1)
    def _default_algorithms(self):
        return get_default_algorithms()

    def fetch_data(self) -> Any:
        data = super().fetch_data()
        return {"keys": [key for key in data.get("keys", []) if key.get("alg", None) in self._default_algorithms()]}

I am not sure if it could be feasible to integrate this kind of behaviour via a flag during the creation of a genuine PyJWKClient or not, but I just wanted to share the solution that worked for me. As soon as this Issue is resolved I will happily switch to the "official" solution.

SamuelYaron avatar Jan 20 '22 21:01 SamuelYaron

As a workaround you can also configure keycloak to disable the RSA-OAEP key or use a different algorithm until it is supported.

Realm->Settings->Keys->rsa-enc-generated->enabled=False

pm-coelho avatar Jan 25 '22 11:01 pm-coelho

That didn't work for me @pm-coelho while using jboss/keycloak latest version

image

Notice that alg is now RS256

image

tiago-peres avatar Jan 26 '22 15:01 tiago-peres

@tiago-peres do you have the crypto optional dependency dependency installed?

pm-coelho avatar Jan 26 '22 15:01 pm-coelho

@tiago-peres do you have the crypto optional dependency dependency installed?

Well spotted... I don't and using RUN pip install pyjwt[crypto] doesn't build the image

image

Then tried RUN pip install cryptography but also

image

tiago-peres avatar Jan 26 '22 15:01 tiago-peres

that looks like a missing OS dependency, make sure you have all that crypto requires installed and on $PATH

pm-coelho avatar Jan 26 '22 15:01 pm-coelho

that looks like a missing OS dependency, make sure you have all that crypto requires installed and on $PATH

you're right again... As per the documentation:

sudo apk add gcc musl-dev python3-dev libffi-dev openssl-dev cargo

it was missing libffi-dev openssl-dev cargo. Currently building the image and will soon test again...

tiago-peres avatar Jan 26 '22 16:01 tiago-peres

As a workaround you can also configure keycloak to disable the RSA-OAEP key or use a different algorithm until it is supported.

Realm->Settings->Keys->rsa-enc-generated->enabled=False

yep, that's working if we ensure the next steps I've done after! Thank you!

tiago-peres avatar Jan 27 '22 09:01 tiago-peres

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days

github-actions[bot] avatar May 16 '22 02:05 github-actions[bot]

We encountered the same error while using pyjwt with keycloak. Is support for RSA-OAEP planned ?

lovasoa avatar May 27 '22 12:05 lovasoa

I think the issue itself may be resolved with #762.

DaGuich avatar Jul 18 '22 07:07 DaGuich

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days

github-actions[bot] avatar Sep 17 '22 02:09 github-actions[bot]