Using the truststore
library you can inject the context object universally, but in a recent update by the maintainers, it says you shouldn't do this.
How do you use the truststore
with a requests.Session object? I cannot seem to find guidance/doc on how to do this. (it's probably me though)
Can someone please post a sample on using a requests.Session
object with the truststore
SSLContext?
reference: https://truststore.readthedocs.io/en/latest/#user-guide
referenced PR: https://github.com/sethmlarson/truststore/pull/122
You can utilize the transport adapters from requests
that can modify the internals of the library, and override the ssl_context
internally.
import truststore
import requests
import ssl
from requests.adapters import HTTPAdapter
class TruststoreAdapter(HTTPAdapter):
def init_poolmanager(self, connections, maxsize, block=False):
ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
return super().init_poolmanager(connections, maxsize, block, ssl_context=ctx)
s = requests.Session()
s.mount("https://", TruststoreAdapter())
r = s.get("https://localhost:4443/", verify=True)
print(r) # 200 OK
This will match any url starting with https://
and replace the internal ssl context with the one from truststore.SSLContext
instead.
Also, just for clarity, I want to mention this is only neccesary if you are creating a library or a package
inject_into_ssl() must not be used by libraries or packages as it will cause issues on import time when integrated with other libraries
You should be fine using inject_into_ssl()
for any other purpose.
Additionally, if you'd like to verify this works locally (I only tested this on Windows 11), you can follow the steps below. You'll need openssl
localhost
, you can leave everything else blankopenssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.cer -sha256 -days 365
Put the cert.cer
into your computer's trusted certificate store, this will depend on your OS, search online if you're not sure how it's done for your specific OS.
Create and run a simple http server that utilizes the certificate and key generated from step 1, here is a simple one in python (modified from anvileight).
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b'Hello, world!')
httpd = HTTPServer(('localhost', 4443), SimpleHTTPRequestHandler)
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="cert.cer", keyfile="key.pem")
httpd.socket = context.wrap_socket(httpd.socket)
print("Starting...")
httpd.serve_forever()
Use the code from the answer to send a request to the server on https://localhost:4443
, should return 200 OK
Keep the server running, but remove the previously generated certificate from your OS's trusted store, be careful to only remove the certificate we generated
Try to send another request to the server on https://localhost:4443
, now we should see an exception raised requests.exceptions.SSLError
"A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider." Meaning that truststore
is doing it's job correctly.