3

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

1 Answer 1

3
+50

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

  1. Generate a self-signed certificate and a private key
    1. Make sure the common name is localhost, you can leave everything else blank
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.cer -sha256 -days 365
  1. 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.

  2. 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()
  1. Use the code from the answer to send a request to the server on https://localhost:4443, should return 200 OK

  2. 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

  3. 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.

Sign up to request clarification or add additional context in comments.

Thanks for the answer. I had developed the same solution, but didn't know if there was an alternative to this answer. It would be nice if you could pass the SSLContext right into the Session object. I appreciate the help!
I see, my gut says that it's not possible without some form of black magic ;) since requests abstracts it quite far out of the way, but it would certainly be interesting if someone would do it!
Thanks for this answer which IMHO deserves to be added to truststore's user guide. I invite you @AlexanderFreyr to make a quick PR with your valuable input.
Thanks, I appreciate it @Guts, however I'm quite busy these days so I might not get around to it anytime soon, if you're affiliated with the project you're more than welcome to use any parts of the answer you feel like :)
This solution works for me on Windows and Linux but not on Mac. I opened an issue there. github.com/sethmlarson/truststore/issues/167

Your Answer

Draft saved
Draft discarded

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.