Using PyGranta RecordLists as an example implementation.
If I try to connect to Granta MI configured in OIDC mode with a private cert, but with a publicly-hosted IdP with a public cert, authentication fails.
I get the following stack trace:
Traceback (most recent call last):
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connectionpool.py", line 466, in _make_request
self._validate_conn(conn)
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connectionpool.py", line 1095, in _validate_conn
conn.connect()
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connection.py", line 652, in connect
sock_and_verified = _ssl_wrap_socket_and_match_hostname(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connection.py", line 805, in _ssl_wrap_socket_and_match_hostname
ssl_sock = ssl_wrap_socket(
^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\util\ssl_.py", line 465, in ssl_wrap_socket
ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\util\ssl_.py", line 509, in _ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python312\Lib\ssl.py", line 455, in wrap_socket
return self.sslsocket_class._create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python312\Lib\ssl.py", line 1042, in _create
self.do_handshake()
File "C:\Program Files\Python312\Lib\ssl.py", line 1320, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connectionpool.py", line 789, in urlopen
response = self._make_request(
^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connectionpool.py", line 490, in _make_request
raise new_e
urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\adapters.py", line 667, in send
resp = conn.urlopen(
^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connectionpool.py", line 873, in urlopen
return self.urlopen(
^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connectionpool.py", line 873, in urlopen
return self.urlopen(
^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connectionpool.py", line 873, in urlopen
return self.urlopen(
^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\connectionpool.py", line 843, in urlopen
retries = retries.increment(
^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\urllib3\util\retry.py", line 519, in increment
raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='idp.host.com', port=443): Max retries exceeded with url: /oauth/token (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)')))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\code\oidc-investigation\test.py", line 8, in <module>
client = Connection("https://my_mi_server/mi_servicelayer", config).with_oidc().authorize().connect()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\ansys\openapi\common\_session.py", line 484, in authorize
self._session_factory.get_session_with_interactive_authorization(login_timeout)
File "C:\code\oidc-investigation\venv\Lib\site-packages\ansys\openapi\common\_oidc.py", line 195, in get_session_with_interactive_authorization
self._authorized_session.get(self._api_url)
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\sessions.py", line 602, in get
return self.request("GET", url, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\sessions.py", line 575, in request
prep = self.prepare_request(req)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\sessions.py", line 484, in prepare_request
p.prepare(
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\models.py", line 371, in prepare
self.prepare_auth(auth, url)
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\models.py", line 602, in prepare_auth
r = auth(self)
^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests_auth\authentication.py", line 634, in __call__
token = OAuth2.token_cache.get_token(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests_auth\oauth2_tokens.py", line 165, in get_token
new_token = on_missing_token(**on_missing_token_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests_auth\authentication.py", line 652, in request_new_token
token, expires_in, refresh_token = request_new_grant_with_post(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests_auth\authentication.py", line 68, in request_new_grant_with_post
response = session.post(url, data=data, timeout=timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\sessions.py", line 637, in post
return self.request("POST", url, data=data, json=json, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\sessions.py", line 703, in send
r = adapter.send(request, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\ansys\openapi\common\_session.py", line 537, in send
return super().send(request, stream, timeout or self.timeout, verify, cert, proxies)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\oidc-investigation\venv\Lib\site-packages\requests\adapters.py", line 698, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='idp.host.com', port=443): Max retries exceeded with url: /oauth/token (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)')))
It seems to be that the OIDC request to the IdP is being made with the cert required to authenticate to MI. Since when you provide a cert to requests it uses that instead of the certifi scripts, any requests to servers with public certs (or signed by any other CA) will fail.
It is possible to work around this issue either by specifying verify_ssl=False, or install pip-system-certs.
π Steps to reproduce
from ansys.grantami.recordlists import Connection
from ansys.openapi.common import SessionConfiguration
config = SessionConfiguration(
cert_store_path=r"C:\path\to\private\CA\cert.crt"
)
client = Connection("https://my_mi_server/mi_servicelayer", config).with_oidc().authorize().connect()
π Before submitting the issue
π Description of the bug
Using PyGranta RecordLists as an example implementation.
If I try to connect to Granta MI configured in OIDC mode with a private cert, but with a publicly-hosted IdP with a public cert, authentication fails.
I get the following stack trace:
It seems to be that the OIDC request to the IdP is being made with the cert required to authenticate to MI. Since when you provide a cert to requests it uses that instead of the certifi scripts, any requests to servers with public certs (or signed by any other CA) will fail.
It is possible to work around this issue either by specifying
verify_ssl=False
, or installpip-system-certs
.π Steps to reproduce
π» Which operating system are you using?
Windows
π Which ANSYS version are you using?
2024 R2
π Which Python version are you using?
3.12
π¦ Installed packages