• 
      

    Add support for included credentials in webhook targets.

    Review Request #8916 — Created April 27, 2017 and submitted

    Information

    Review Board
    release-2.5.x
    427b75d...

    Reviewers

    Sometimes, a user may need to dispatch a webhook to an authenticated endpoint.
    Django (somewhat sensibly) does not allow inline credentials in URLFields, both
    in forms and models, but in this case we want to allow it.

    This change makes use of a new backport of Django 1.8's URLValidator, which
    supports credentials. The URL is then split and credentials (if included) are
    pulled out and added to a HTTPBasicAuthHandler for the url open.

    • Verified that I was able to save webhook targets that included credentials
      in the URL.
    • Checked that things that definitely weren't URLs were still rejected.
    • Ran unit tests.
    Description From Last Updated

    'django.utils.six.moves.urllib.request.urlopen' imported but unused

    reviewbotreviewbot

    *args

    chipx86chipx86

    **kwargs

    chipx86chipx86

    Shouldn't you be able to just set this on the field itself above using validators=?

    chipx86chipx86

    This file's missing a file docstring. (Should also be in in docs/manual/coderef/index.rst).

    chipx86chipx86

    Hmm, I don't know how else we'd handle this, but I sure wish we didn't have to copy this... This …

    chipx86chipx86

    This will be more readable using the attribute names instead of indexes.

    chipx86chipx86

    F811 redefinition of unused 'URLValidator' from line 7

    reviewbotreviewbot

    E501 line too long (80 > 79 characters)

    reviewbotreviewbot

    E501 line too long (80 > 79 characters)

    reviewbotreviewbot

    you can use url_parts.hostname and urlparts.port instead of splitting this.

    brenniebrennie

    This raises an exception: AttributeError: 'SplitResult' object has no attribute 'params' Instead of url_parts.params there should have been a url_params.fragment: …

    YX yxejamir
    Checks run (1 failed, 1 succeeded, 1 failed with error)
    JSHint passed.
    PEP8 Style Checker internal error.
    Pyflakes failed.

    Pyflakes

    david
    chipx86
    1. 
        
    2. reviewboard/notifications/models.py (Diff revision 2)
       
       
      Show all issues

      *args

    3. reviewboard/notifications/models.py (Diff revision 2)
       
       
      Show all issues

      **kwargs

    4. reviewboard/notifications/models.py (Diff revision 2)
       
       
      Show all issues

      Shouldn't you be able to just set this on the field itself above using validators=?

      1. Django sees a models.URLField and instantiates a forms.URLField. Setting validators on the model field will add it to the form field in addition to the default validators, where what we want to do is replace it.

      2. Maybe what we should do then, since this isn't an isolated problem for this form, is to move the validator into Djblets and have a subclas of URLField that overrides default_validators. Then we can easily just drop this into this form or any other where we need this down the road.

    5. reviewboard/notifications/validators.py (Diff revision 2)
       
       
      Show all issues

      This file's missing a file docstring. (Should also be in in docs/manual/coderef/index.rst).

    6. reviewboard/notifications/validators.py (Diff revision 2)
       
       
       
       
      Show all issues

      Hmm, I don't know how else we'd handle this, but I sure wish we didn't have to copy this... This regex has come up a few times now in Django security updates. Is there any way we can do a pass to parse out credentials and then let the parent validate the rest?

      1. I can't see any way of doing that that wouldn't duplicate the regex in some form.

      2. So I looked into the validation logic in Django 1.6 and in newer versions. They've completely redone the logic in 1.8, which adds support for user/pass validation and just generally fixes a lot of other validation issues (better handling newer TLDs and such). Maybe we could copy the newer one to djblets.util.compat.django.core.validators and do:

        from django.core.validators import URLValidator
        
        
        # Some note about Django 1.8 vs. older versions...
        if not hasattr(URLValidator, 'hostname_re'):  # <-- hostname_re was introduced in the new validator
            class URLValidator(...)
                ...
        

        Then we could import from there, ensuring we're using this validator only on Django 1.6 and using the upstream one on 1.8+.

    7. reviewboard/notifications/webhooks.py (Diff revision 2)
       
       
       
       
       
      Show all issues

      This will be more readable using the attribute names instead of indexes.

    8. 
        
    david
    Review request changed
    Description:
       

    Sometimes, a user may need to dispatch a webhook to an authenticated endpoint.

        Django (somewhat sensibly) does not allow inline credentials in URLFields, both
        in forms and models, but in this case we want to allow it.

       
    ~  

    This change adds a new validator that works like Django's URLValidator but

    ~   includes the credentials within the regex. The URL is then split and
    ~   credentials (if included) are pulled out and added to a HTTPBasicAuthHandler
      ~

    This change makes use of a new backport of Django 1.8's URLValidator, which

      ~ supports credentials. The URL is then split and credentials (if included) are
      ~ pulled out and added to a HTTPBasicAuthHandler for the url open.

    -   for the url open.

    Commit:
    9d987acd1c709167ce61d38855d604b8629abf49
    bac403535da00dc334c5dcd6ba4435efd2fd8b6c

    Checks run (1 failed, 1 succeeded)

    flake8 failed.
    JSHint passed.

    flake8

    david
    brennie
    1. 
        
    2. reviewboard/notifications/webhooks.py (Diff revision 4)
       
       
      Show all issues

      you can use url_parts.hostname and urlparts.port instead of splitting this.

      1. This isn't splitting out the port, it's splitting out the credentials.

    3. 
        
    chipx86
    1. Ship It!
    2. 
        
    david
    Review request changed
    Status:
    Completed
    Change Summary:
    Pushed to release-2.5.x (44f046e)
    YX
    1. 
        
    2. reviewboard/notifications/webhooks.py (Diff revision 4)
       
       
       
       
      Show all issues

      This raises an exception:

      AttributeError: 'SplitResult' object has no attribute 'params'
      

      Instead of url_parts.params there should have been a url_params.fragment:

                      url = urlunsplit(
                          (url_parts.scheme, netloc, url_parts.path,
                           url_parts.query, url_parts.fragment))
      
    3.