Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for custom SSLContext when using FastHttpUser #2113

Merged
merged 7 commits into from
Jun 17, 2022

Conversation

renato-farias
Copy link
Contributor

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

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('/')

@@ -107,6 +110,13 @@ def __init__(
# 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
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
Copy link
Collaborator

cyberw commented Jun 13, 2022

Lgtm, apart from the style issues & my comment

@renato-farias
Copy link
Contributor Author

Lgtm, apart from the style issues & my comment

Thanks for reviewing it @cyberw . Pushed some fixes.

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
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
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
Copy link
Collaborator

cyberw commented Jun 16, 2022

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

None yet

2 participants