-
Notifications
You must be signed in to change notification settings - Fork 39
GitHub authentication #25
base: master
Are you sure you want to change the base?
Conversation
|
I think in general this is good. I would say we should kill the if ... == 'google' bit and push that into some class that controls this. While Sentry isn't a great example (as its much more complex), that's what we did there: https://github.com/getsentry/sentry/blob/master/src/sentry/auth/providers/oauth2.py#L130 |
|
Perfect. I'll update my PR :) |
|
👍 This would be awesome |
|
@dcramer do you want it generalized to that extent, or are you okay with provider-specific class implementations of say a |
|
That's fine, it just needs to be done in a way where you don't need to patch the entire code to get a custom provider in if needed. A dictionary with provider names -> setup functions would already be a good start. |
|
Sure. Just wanted to check what level of abstraction you were going for ;) |
|
Alright, abstracted the providers. Let me know, what you think. If we're good, I'll add a bunch of tests to make sure everything works as expected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would make this something like OAuth2Provider.validate().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense
|
My comments are fairly nitpicky, and tbh its probably more work than its worth to make this super flexible. I think in an ideal (read: ideal) world, provider would be something like a Flask app that gets instantiated and attached to the application object (there's some common mechanism of binding state, its a bit gross though). This would happen at runtime (via configure_auth or something), and then call validate on the provider to ensure settings are correct. This would also pass in the app.config values. |
|
That's an interesting idea. So you propose having separate Flask apps for each provider, inheriting from the same base? |
|
Sorry not separate apps, but extensions (which get bound to the app). If you imagine something like app.state['authprovider'] = current provider. The simple version is just: |
|
Just so I'm clear: are you proposing the actual provider be an extension that the |
|
@nickbruun It's a pattern I've seen in various Flask extensions. I don't quite recall which ones off hand, and there might be better ways. That said, you could approach it from my example above, where you have the instance of the extension (the auth provider here), and you simple call init_app like others when the app is created. At that point you could validate configuration thats specific to the given provider, and then in places where you would check "is the provider google" you would simply call out the provider assuming a given API interface. |
|
Alright, I've tried to follow the pattern you set out to the best of my understanding. How does this compare to what you were thinking? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is good, and if we want to extend it in the future we can just have AUTH_BACKEND support a full class path or similar
|
In all files can you ensure the following exists at the top: |
|
In general this looks good. Theres a few pep8 things I can clean up (i.e. import orders) but its nbd. When I have time I'll pull this down and give it a quick QA pass, but the general approach looks good to me. |
|
I've updated the imports in the |
|
We should advance on this subject, we need to check why unittest doesn't pass first. @nickbruun are you still available to finish this PR? |
We rely on GitHub authentication for most developer-related services, so I thought it would be nice if Freight also support it (great job, btw!) This pull request in its current form adds rudimentary support for GitHub authentication, limiting the user to either a specific team ID or organization ID, depending on the granularity desired.
To select the authentication backend used, I've added a configuration variable
AUTH_BACKENDwhich defaults togooglefor Google authentication, and can also begithubfor Github authentication. I've also added some initialization time checks for the validity of the configuration ofAUTH_BACKENDand Github authentication-specific configuration variables. For now, I've defaulted toRuntimeError, but I don't know if you have a preferred exception in this case.I've also subclassed
OAuth2WebServerFlowfor the case of GitHub, as fetching both the user and team after the code/access token exchange has completed, is necessary. Lastly, I've added a check after the exchange to make sure that the user is limited to whatever team or organization is specified.A few notes/questions:
Userfor a hypothetical number of authentication backends.I purposefully haven't done any documentation updates yet, so consider this PR a "for your consideration" at the moment. I'll do proper test coverage and documentation once the details are settled, of course :)
Let me know what you think!