Skip to content

add support for custom SSLContext when using FastHttpUser#2113

Merged
cyberw merged 7 commits into
locustio:masterfrom
renato-farias:feat/fasthttpuser_sslcontext
Jun 17, 2022
Merged

add support for custom SSLContext when using FastHttpUser#2113
cyberw merged 7 commits into
locustio:masterfrom
renato-farias:feat/fasthttpuser_sslcontext

Conversation

@renato-farias

@renato-farias renato-farias commented Jun 13, 2022

Copy link
Copy Markdown
Contributor

As per #2066, currently there's no option for setting up certificates when using FastHttpUser. This PR intends to add a new ssl_context_factory param to enabling this functionality by defining a custom Callable returning a SSLContext when implementing the user.

As the callable will be called within the class context if it is defined outside the ApiLocust class we need to fake an arg there. The two example on how implementing can be found below.

Option 1

import gevent
from locust import task
from locust.contrib.fasthttp import FastHttpUser

def my_custom_context(*args):
    context = gevent.ssl.create_default_context()
    context.check_hostname = True
    context.verify_mode = gevent.ssl.CERT_REQUIRED
    context.load_cert_chain(certfile="yourpempath", keyfile="yourkeypath")
    context.load_verify_locations(cafile="yourcapath")
    return context

class ApiLocust(FastHttpUser):
    ssl_context_factory = my_custom_context
    
    def __init__(self, environment):
        super().__init__(environment=environment)

    @task()
    def submit(self):
        self.client.get('/')

Option 2

import gevent
from locust import task
from locust.contrib.fasthttp import FastHttpUser

class ApiLocust(FastHttpUser):
    
    def __init__(self, environment):
        super().__init__(environment=environment)
   
    def ssl_context_factory(self):
        context = gevent.ssl.create_default_context()
        context.check_hostname = True
        context.verify_mode = gevent.ssl.CERT_REQUIRED
        context.load_cert_chain(certfile="yourpempath", keyfile="yourkeypath")
        context.load_verify_locations(cafile="yourcapath")
        return context

    @task()
    def submit(self):
        self.client.get('/')

Comment thread locust/contrib/fasthttp.py Outdated
# store authentication header (we construct this by using _basic_auth_str() function from requests.auth)
self.auth_header = _construct_basic_auth_str(parsed_url.username, parsed_url.password)

def _check_ssl_context(ssl_context):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this deserves its own method :)

@cyberw

cyberw commented Jun 13, 2022

Copy link
Copy Markdown
Collaborator

Lgtm, apart from the style issues & my comment

@renato-farias

Copy link
Copy Markdown
Contributor Author

Lgtm, apart from the style issues & my comment

Thanks for reviewing it @cyberw . Pushed some fixes.

@renato-farias renato-farias requested a review from cyberw June 13, 2022 23:31
Comment thread locust/contrib/fasthttp.py Outdated
if ssl_context:
if not isinstance(ssl_context, SSLContext):
raise TypeError("You must provide a valid SSLContext.")
ssl_context_factory = lambda: ssl_context

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesnt it make more sense to just pass a function instead of an instantiated SSLContext that we make a fake function for? (I made a comment and then deleted it, but after some more thought I think my initial comment was correct :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surely it does. I was trying to make use of ssl_context as an actual context then the caller could set it accordingly, but making it a factory keeps the way it does in the background. I will rename it to ssl_context_factory and type-hint it as Callable. Thanks for reviewing it.

@cyberw

cyberw commented Jun 16, 2022

Copy link
Copy Markdown
Collaborator

Nice! But the test doesnt really check anything, does it? I guess it could be hard to validate that the context was actually used in the request, but we could at least check that the function was called (perhaps by setting a value there that we assert on)

@renato-farias

Copy link
Copy Markdown
Contributor Author

Nice! But the test doesnt really check anything, does it? I guess it could be hard to validate that the context was actually used in the request, but we could at least check that the function was called (perhaps by setting a value there that we assert on)

Indeed! Now I realised what it was doing. Although it would fail using a wrong context that wasn't the real intention of that test. Added two new tests on the right place (I hope). They are test_custom_ssl_context_fail_with_bad_context and test_custom_ssl_context_passed_correct_to_client_pool.

@cyberw cyberw merged commit a0bcd31 into locustio:master Jun 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants