Add support for custom authentication forms for hosting services.

Review Request #8149 — Created May 6, 2016 and submitted

Information

Review Board
release-2.0.x

Reviewers

Up until now, we made the assumption that every hosting service just
needed a username and a password (which was sometimes an API key). This
isn't always sufficient, though, and we've worked around this limitation
in the past by taking per-repository fields for additional
credential-related information, which really should have been part of
the account details.

Now, hosting services can define an authentication form. This manages
fields for the hosting URL (if self-hosted), username/password, and
two-factor auth token. Subclasses can override the help text and labels
for these, override the fields completely, or create new fields.

The form is responsible for all validation for authentication
information, the transformation of the fields into a set of credentials
for authorization, and the authorization flow itself. It's also
responsible for state like which of the fields are required or presented
to the user (allowing us to remove some of the hacks in JavaScript).

The main repository configuration form now instantiates one of these
authentication forms for every hosting service. This means that for
every hosting service, the authentication fields are independent,
preventing errors from showing up in an auth form when moving between
hosting services, and preventing other such weird glitches we had with
sharing the auth form.

There's one UI change to how accounts for self-hosted services work.
Previously, the hosting URL field would appear before the accounts
field. You'd type the URL to the service, and the list of accounts
would update to show only those from that service. Now, we show all
accounts across all URLs, each showing the hosting URL its mapped to as
part of the name). The hosting URL is then shown below that (only when
linking an account). This helps make it clear what accounts you have.

The other major change is that re-authenticating now allows you to
change the username and hosting URL, if needed. Previously, this was not
allowed.

All-in-all, this change helps move us to a model where RepositoryForm
doesn't have to do all the work, and we're able to better split up
responsibilities. Similar changes will follow for repository and bug
tracker configuration in the future.

Unit tests pass.

Manually tested the following conditions:

  • Creating a new repository and account with no errors.
  • Creating a new repository and account with auth field errors, and then
    fixing them.
  • Creating a new repository and account with two-factor auth code required,
    and then entering it.
  • Creating a new repository and account with self-hosted service.
  • Creating a new repository with existing account.
  • Creating a new repository with existing account requiring re-auth, and
    providing new credentials (new username, new password, new hosting URL,
    new two-factor auth code).
  • Creating a new repository without a hosting service.
  • Creating a new repository with a hosting service using a custom auth
    form (repeating the above tests).
  • Creating a new repository with bug tracker configurations (both with
    new information and with using the selected hosting service's information).
  • Editing a repository (with all the above tests)
Description From Last Updated

Col: 80 E501 line too long (82 > 79 characters)

reviewbotreviewbot

local variable 'e' is assigned to but never used

reviewbotreviewbot

'forms' imported but unused

reviewbotreviewbot

redefinition of unused 'test_get_file_exists_with_mercurial' from line 1074

reviewbotreviewbot

local variable 'account' is assigned to but never used

reviewbotreviewbot

Typo: password.

brenniebrennie

Can we call it help_text?

brenniebrennie

Probably should have import ugettext_lazy as _ in the code example so people know what _ is.

brenniebrennie

If this is required, we really should have it not default to None. That way, it doesn't appear to be …

brenniebrennie

Col: 80 E501 line too long (82 > 79 characters)

reviewbotreviewbot

The comma here is unnecessary.

brenniebrennie

Can we use something else as id is a builtin?

brenniebrennie

redefinition of unused 'test_get_file_exists_with_mercurial' from line 1073

reviewbotreviewbot

Out of curiousity, why do we override full_clean instead of just clean?

brenniebrennie

Col: 80 E501 line too long (82 > 79 characters)

reviewbotreviewbot

These don't need to be in the try

brenniebrennie

Col: 80 E501 line too long (82 > 79 characters)

reviewbotreviewbot
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/hostingsvcs/models.py
        reviewboard/scmtools/tests.py
        reviewboard/scmtools/admin.py
        reviewboard/scmtools/forms.py
        reviewboard/testing/hosting_services.py
        reviewboard/hostingsvcs/forms.py
        reviewboard/hostingsvcs/service.py
        reviewboard/hostingsvcs/tests.py
    
    Ignored Files:
        reviewboard/static/rb/js/admin/repositoryform.js
        reviewboard/templates/admin/scmtools/repository/change_form.html
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/hostingsvcs/models.py
        reviewboard/scmtools/tests.py
        reviewboard/scmtools/admin.py
        reviewboard/scmtools/forms.py
        reviewboard/testing/hosting_services.py
        reviewboard/hostingsvcs/forms.py
        reviewboard/hostingsvcs/service.py
        reviewboard/hostingsvcs/tests.py
    
    Ignored Files:
        reviewboard/static/rb/js/admin/repositoryform.js
        reviewboard/templates/admin/scmtools/repository/change_form.html
    
    
  2. reviewboard/hostingsvcs/forms.py (Diff revision 1)
     
     
    Show all issues
    Col: 80
     E501 line too long (82 > 79 characters)
    
  3. reviewboard/hostingsvcs/forms.py (Diff revision 1)
     
     
    Show all issues
     local variable 'e' is assigned to but never used
    
  4. reviewboard/hostingsvcs/tests.py (Diff revision 1)
     
     
    Show all issues
     'forms' imported but unused
    
  5. reviewboard/hostingsvcs/tests.py (Diff revision 1)
     
     
    Show all issues
     redefinition of unused 'test_get_file_exists_with_mercurial' from line 1074
    
  6. reviewboard/scmtools/forms.py (Diff revision 1)
     
     
    Show all issues
     local variable 'account' is assigned to but never used
    
  7. 
      
chipx86
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/hostingsvcs/models.py
        reviewboard/scmtools/tests.py
        reviewboard/scmtools/admin.py
        reviewboard/scmtools/forms.py
        reviewboard/testing/hosting_services.py
        reviewboard/hostingsvcs/forms.py
        reviewboard/hostingsvcs/service.py
        reviewboard/hostingsvcs/tests.py
    
    Ignored Files:
        reviewboard/static/rb/js/admin/repositoryform.js
        reviewboard/templates/admin/scmtools/repository/change_form.html
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/hostingsvcs/models.py
        reviewboard/scmtools/tests.py
        reviewboard/scmtools/admin.py
        reviewboard/scmtools/forms.py
        reviewboard/testing/hosting_services.py
        reviewboard/hostingsvcs/forms.py
        reviewboard/hostingsvcs/service.py
        reviewboard/hostingsvcs/tests.py
    
    Ignored Files:
        reviewboard/static/rb/js/admin/repositoryform.js
        reviewboard/templates/admin/scmtools/repository/change_form.html
    
    
  2. reviewboard/hostingsvcs/forms.py (Diff revision 2)
     
     
    Show all issues
    Col: 80
     E501 line too long (82 > 79 characters)
    
  3. reviewboard/hostingsvcs/tests.py (Diff revision 2)
     
     
    Show all issues
     redefinition of unused 'test_get_file_exists_with_mercurial' from line 1073
    
  4. 
      
brennie
  1. 
      
  2. reviewboard/hostingsvcs/forms.py (Diff revision 2)
     
     
    Show all issues

    Typo: password.

  3. reviewboard/hostingsvcs/forms.py (Diff revision 2)
     
     
    Show all issues

    Can we call it help_text?

    1. ModelForm supports help_texts, which is the same thing as this. We're just not using ModelForm here. The naming is for consistency.

  4. reviewboard/hostingsvcs/forms.py (Diff revision 2)
     
     
    Show all issues

    Probably should have import ugettext_lazy as _ in the code example so people know what _ is.

  5. reviewboard/hostingsvcs/forms.py (Diff revision 2)
     
     
     
     
     
     
     
    Show all issues

    If this is required, we really should have it not default to None. That way, it doesn't appear to be optional at first glance.

    1. data must come first as the form parameter, and it's supposed to default to None. That means anything after it must also default to None. It's not great, but it's what we've got :/

  6. reviewboard/hostingsvcs/forms.py (Diff revision 2)
     
     
     

    Does this link correctly in docs?

    1. Yep. Except it should be :meth:.

  7. reviewboard/hostingsvcs/forms.py (Diff revision 2)
     
     
    Show all issues

    The comma here is unnecessary.

    1. "A string containing the hosting URL or None" means the string may contain either one of those, which isn't correct. This is either returning a string containing the hosting URL, or it's returning None.

  8. reviewboard/hostingsvcs/service.py (Diff revision 2)
     
     
    Show all issues

    Can we use something else as id is a builtin?

    1. Yeah. We kind of do a bit of both.. Models have id, for instance. It's just kinda lengthy for hosting service stuff, but I'll switch it over.

  9. reviewboard/scmtools/forms.py (Diff revision 2)
     
     
    Show all issues

    Out of curiousity, why do we override full_clean instead of just clean?

    1. There's things we need to do before Django's full_clean runs, like mess with the required values. If we tried to do that in clean, it'd be too late. Same with manipulation of some of the errors and cleaned_data, the way we're doing it.

  10. 
      
chipx86
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/hostingsvcs/models.py
        reviewboard/scmtools/tests.py
        reviewboard/scmtools/admin.py
        reviewboard/scmtools/forms.py
        reviewboard/testing/hosting_services.py
        reviewboard/hostingsvcs/forms.py
        reviewboard/hostingsvcs/service.py
        reviewboard/hostingsvcs/tests.py
    
    Ignored Files:
        reviewboard/static/rb/js/admin/repositoryform.js
        reviewboard/templates/admin/scmtools/repository/change_form.html
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/hostingsvcs/models.py
        reviewboard/scmtools/tests.py
        reviewboard/scmtools/admin.py
        reviewboard/scmtools/forms.py
        reviewboard/testing/hosting_services.py
        reviewboard/hostingsvcs/forms.py
        reviewboard/hostingsvcs/service.py
        reviewboard/hostingsvcs/tests.py
    
    Ignored Files:
        reviewboard/static/rb/js/admin/repositoryform.js
        reviewboard/templates/admin/scmtools/repository/change_form.html
    
    
  2. reviewboard/hostingsvcs/forms.py (Diff revision 3)
     
     
    Show all issues
    Col: 80
     E501 line too long (82 > 79 characters)
    
  3. 
      
brennie
  1. 
      
  2. reviewboard/hostingsvcs/forms.py (Diff revision 3)
     
     
     
    Show all issues

    These don't need to be in the try

  3. 
      
david
  1. Typo in description: "beforet"

    Aside from what Barret saw, nothing jumps out at me, but it's a big change so it's hard to see how the pieces fit together.

    1. Yeah, there's kind of a lot going on. It's largely because RepositoryForm is such a giant, and I'm hoping to break that down into more manageable pieces with the new repo work.. Are there parts I can try to go over in more detail?

  2. 
      
chipx86
chipx86
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/hostingsvcs/models.py
        reviewboard/scmtools/tests.py
        reviewboard/scmtools/admin.py
        reviewboard/scmtools/forms.py
        reviewboard/testing/hosting_services.py
        reviewboard/hostingsvcs/forms.py
        reviewboard/hostingsvcs/service.py
        reviewboard/hostingsvcs/tests.py
    
    Ignored Files:
        reviewboard/static/rb/js/admin/repositoryform.js
        reviewboard/templates/admin/scmtools/repository/change_form.html
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/hostingsvcs/models.py
        reviewboard/scmtools/tests.py
        reviewboard/scmtools/admin.py
        reviewboard/scmtools/forms.py
        reviewboard/testing/hosting_services.py
        reviewboard/hostingsvcs/forms.py
        reviewboard/hostingsvcs/service.py
        reviewboard/hostingsvcs/tests.py
    
    Ignored Files:
        reviewboard/static/rb/js/admin/repositoryform.js
        reviewboard/templates/admin/scmtools/repository/change_form.html
    
    
  2. reviewboard/hostingsvcs/forms.py (Diff revision 4)
     
     
    Show all issues
    Col: 80
     E501 line too long (82 > 79 characters)
    
  3. 
      
david
  1. Ship It!
  2. 
      
chipx86
Review request changed
Status:
Completed
Change Summary:
Pushed to release-2.0.x (51a14da)