AzureAD / microsoft-authentication-library-for-python

Microsoft Authentication Library (MSAL) for Python makes it easy to authenticate to Microsoft Entra ID. General docs are available here https://learn.microsoft.com/entra/msal/python/ Stable APIs are documented here https://msal-python.readthedocs.io. Questions can be asked on www.stackoverflow.com with tag "msal" + "python".
https://stackoverflow.com/questions/tagged/azure-ad-msal+python
Other
756 stars 191 forks source link

Can I use x.509 certificate ? #599

Closed Theo-Dancoisne closed 9 months ago

Theo-Dancoisne commented 9 months ago

Describe the bug Am I not supposed to use x.509 certificate ?

To Reproduce

Generate a certificate :

Ex 1 in PowerShell
> $cert = New-SelfSignedCertificate -Subject "CN=TheosScheduleAPICronTask" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature -KeyLength 2048 -KeyAlgorithm
 RSA -HashAlgorithm SHA256 -notafter (Get-Date).AddYears(10)
> Export-Certificate -Cert $cert -FilePath "C:\Users\theod\.ssh\Clés divers\TheosScheduleAPICronTask.cer"

And convert the certicate to a x64 one : image

Ex 2 in Bash
$ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out ./TheosScheduleAPICronTask.crt
<give the common name>

Then

Follow the guidline: https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-daemon-acquire-token?tabs=idweb#acquiretokenforclient-api And run the script

Expected behavior acquire_token_for_client and print it

What you see instead Sorry for the mess:

ERROR:msal.oauth2cli.assertion:Some algorithms requires "pip install cryptography". See https://pyjwt.readthedocs.io/en/latest/installation.html#cryptographic-dependencies-optional
Traceback (most recent call last):
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\jwt\algorithms.py", line 350, in prepare_key
    RSAPrivateKey, load_pem_private_key(key_bytes, password=None)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\primitives\serialization\base.py", line 25, in load_pem_private_key
    return ossl.load_pem_private_key(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 747, in load_pem_private_key
    return self._load_key(
           ^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 929, in _load_key
    self._handle_key_loading_error()
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 984, in _handle_key_loading_error
    raise ValueError(
ValueError: ('Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).', [<OpenSSLError(code=503841036, lib=60, reason=524556, reason_text=unsupported)>])

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\oauth2cli\assertion.py", line 114, in create_normal_assertion
    str_or_bytes = jwt.encode(  # PyJWT 1 returns bytes, PyJWT 2 returns str
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\jwt\api_jwt.py", line 73, in encode
    return api_jws.encode(
           ^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\jwt\api_jws.py", line 160, in encode
    key = alg_obj.prepare_key(key)
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\jwt\algorithms.py", line 353, in prepare_key
    return cast(RSAPublicKey, load_pem_public_key(key_bytes))
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\primitives\serialization\base.py", line 35, in load_pem_public_key
    return ossl.load_pem_public_key(data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 794, in load_pem_public_key
    self._handle_key_loading_error()
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 984, in _handle_key_loading_error
    raise ValueError(
ValueError: ('Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).', [<OpenSSLError(code=75497580, lib=9, reason=108, reason_text=no start line)>])
Traceback (most recent call last):
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\jwt\algorithms.py", line 350, in prepare_key
    RSAPrivateKey, load_pem_private_key(key_bytes, password=None)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\primitives\serialization\base.py", line 25, in load_pem_private_key
    return ossl.load_pem_private_key(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 747, in load_pem_private_key
    return self._load_key(
           ^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 929, in _load_key
    self._handle_key_loading_error()
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 984, in _handle_key_loading_error
    raise ValueError(
ValueError: ('Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).', [<OpenSSLError(code=503841036, lib=60, reason=524556, reason_text=unsupported)>])

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:\Users\theod\Projets\Python\MS_Graph_CalendarUpdater\main.py", line 29, in <module>
    result = app.acquire_token_for_client(scopes=config["scope"])
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\application.py", line 2072, in acquire_token_for_client
    return _clean_up(self._acquire_token_silent_with_error(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\application.py", line 1318, in _acquire_token_silent_with_error
    result = self._acquire_token_silent_from_cache_and_possibly_refresh_it(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\application.py", line 1438, in _acquire_token_silent_from_cache_and_possibly_refresh_it
    result = self._acquire_token_for_client(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\application.py", line 2091, in _acquire_token_for_client
    response = client.obtain_token_for_client(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\oauth2cli\oauth2.py", line 752, in obtain_token_for_client
    return self._obtain_token("client_credentials", data=data, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\oauth2cli\oidc.py", line 116, in _obtain_token
    ret = super(Client, self)._obtain_token(grant_type, *args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\oauth2cli\oauth2.py", line 771, in _obtain_token
    resp = super(Client, self)._obtain_token(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\oauth2cli\oauth2.py", line 199, in _obtain_token
    self.client_assertion()  # Do lazy on-the-fly computation
    ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\oauth2cli\assertion.py", line 61, in __call__
    self._buf = {VALUE: self._factory(), EXPIRES_AT: now + self._expires_in}
                        ^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\oauth2cli\assertion.py", line 40, in <lambda>
    self.create_normal_assertion(a, i, s, expires_in=e, **kwargs),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\msal\oauth2cli\assertion.py", line 114, in create_normal_assertion
    str_or_bytes = jwt.encode(  # PyJWT 1 returns bytes, PyJWT 2 returns str
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\jwt\api_jwt.py", line 73, in encode
    return api_jws.encode(
           ^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\jwt\api_jws.py", line 160, in encode
    key = alg_obj.prepare_key(key)
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\jwt\algorithms.py", line 353, in prepare_key
    return cast(RSAPublicKey, load_pem_public_key(key_bytes))
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\primitives\serialization\base.py", line 35, in load_pem_public_key
    return ossl.load_pem_public_key(data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 794, in load_pem_public_key
    self._handle_key_loading_error()
  File "C:\Users\theod\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\hazmat\backends\openssl\backend.py", line 984, in _handle_key_loading_error
    raise ValueError(
ValueError: ('Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).', [<OpenSSLError(code=75497580, lib=9, reason=108, reason_text=no start line)>])

Shouldn't it use x509.load_pem_x509_certificate instead of ossl.load_pem_public_key ?

The MSAL Python version you are using 1.24.0

rayluo commented 9 months ago

The format requirement and suggestions are documented in the parameter client_credential here.

Theo-Dancoisne commented 9 months ago

The format requirement and suggestions are documented in the parameter client_credential here.

Thank you, didn't see this, too used to the doc on learn.microsoft.com and I forgot to check the readme. Sorry for the inconvenience, have a nice day.