tokusumi / fastapi-cloudauth

Simple integration between FastAPI and cloud authentication services (AWS Cognito, Auth0, Firebase Authentication).
MIT License
330 stars 35 forks source link

JWKS.firebase() only works if `cryptography` is installed #51

Closed jleclanche closed 2 years ago

jleclanche commented 3 years ago

This took me a while to track down.

Reproduce with: python -c 'from fastapi_cloudauth.verification import *; print(JWKS.firebase("https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"))'

If cryptography is installed, this succeeds.

If it's not installed, it fails with the following traceback:

Traceback (most recent call last):
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 152, in __init__
    self._prepared_key = pyrsa.PublicKey.load_pkcs1(key)
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 124, in load_pkcs1
    return method(keyfile)
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 327, in _load_pkcs1_pem
    der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY')
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in load_pem
    pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in <listcomp>
    pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 75, in _pem_lines
    raise ValueError('No PEM start marker "%r" found' % pem_start)
ValueError: No PEM start marker "b'-----BEGIN RSA PUBLIC KEY-----'" found

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 155, in __init__
    self._prepared_key = pyrsa.PublicKey.load_pkcs1_openssl_pem(key)
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 356, in load_pkcs1_openssl_pem
    der = rsa.pem.load_pem(keyfile, 'PUBLIC KEY')
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in load_pem
    pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in <listcomp>
    pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 75, in _pem_lines
    raise ValueError('No PEM start marker "%r" found' % pem_start)
ValueError: No PEM start marker "b'-----BEGIN PUBLIC KEY-----'" found

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 158, in __init__
    self._prepared_key = pyrsa.PrivateKey.load_pkcs1(key)
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 124, in load_pkcs1
    return method(keyfile)
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 591, in _load_pkcs1_pem
    der = rsa.pem.load_pem(keyfile, b'RSA PRIVATE KEY')
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in load_pem
    pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in <listcomp>
    pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 75, in _pem_lines
    raise ValueError('No PEM start marker "%r" found' % pem_start)
ValueError: No PEM start marker "b'-----BEGIN RSA PRIVATE KEY-----'" found

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 161, in __init__
    der = pyrsa_pem.load_pem(key, b"PRIVATE KEY")
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in load_pem
    pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in <listcomp>
    pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 75, in _pem_lines
    raise ValueError('No PEM start marker "%r" found' % pem_start)
ValueError: No PEM start marker "b'-----BEGIN PRIVATE KEY-----'" found

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/fastapi_cloudauth/verification.py", line 70, in firebase
    keys = {
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/fastapi_cloudauth/verification.py", line 71, in <dictcomp>
    kid: jwk.construct(publickey, algorithm="RS256")
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/jwk.py", line 79, in construct
    return key_class(key_data, algorithm)
  File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 171, in __init__
    raise JWKError(e)
jose.exceptions.JWKError: No PEM start marker "b'-----BEGIN PRIVATE KEY-----'" found

I'm too tired to keep debugging this and figure out why exactly this happens. At first glance it seems that jose has a rsa backend and a cryptography backend and silently falls back to the former if the latter is not installed. They likely don't support the same featureset. Looking at the traceback, I guess the native rsa backend doesn't support certificates… which, to be honest, could use a proper check with a NotImplementedError if that's the case.

I think you should change your dependency from python-jose to python-jose[cryptography].

tokusumi commented 2 years ago

Really appreciate @jleclanche for reproducing error! Decided to add cryptography by default for simplicity from version 0.4.2