-
-
Notifications
You must be signed in to change notification settings - Fork 780
Async security check #869
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
Async security check #869
Conversation
89bfff0 to
3fb9249
Compare
a5876e4 to
8912e28
Compare
|
I rebased the branch on top of master. |
|
Hi guys, when we can expect this to be merged? It would be great to have async security check. At the moment we have some workaround solution with middleware. Thanks 🙂 |
|
Is there any progress on this? |
|
Sorry for the delay. Could you rebase the PR and fix the conflicts? We will take a look afterwards. |
|
|
||
| class OAuthResponseProblem(OAuthProblem): | ||
| def __init__(self, token_response, **kwargs): | ||
| self.token_response = token_response |
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.
what are the implications of removing this?
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
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.
Some history here - every security handler used to raise OAuthResponseProblem in case of an error, so including it (or inheriting from it) was for backwards compatibility.
Hopefully we can drop that requirement at some point.
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.
Oh. Well, I just got rid of it everywhere where it was in use, and added it where it made sense.
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.
If we need to adjust the PR to split that out into another PR then fine. This PR wore me out, so if changes need to occur I'll wait a bit to make them.
| logger = logging.getLogger('connexion.api.security') | ||
|
|
||
|
|
||
| class AioHttpSecurityHandlerFactory(SecurityHandlerFactory): |
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.
are we going to have to write one of these for every framework we support?
Is there a more generic version of this like AsyncSecurityHandlerFactory?
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.
Right now, yes, each framework would need its own SecurityHandlerFactory.
As far as making it more generic - I'm of two minds:
- I think we should assume this is AioHttp-specific until we implement another async framework. At that time, refactoring this into a reusable
AsyncSecurityHandlerthat can be reused by both of them would make sense. - The only thing that uses
aiohttpin this class isget_token_info_remotein how it usesself.client_session. Ifrequestis a ConnexionRequest (vs a framework specific request) then the other functions are very generic, so it should be simple to have anAbstractAsyncSecurityHandlerFactorythat theAioHttpSecurityHandlerFactoryextends to implement theget_token_info_remotemethod.
After I rebase this, I can add the AbstractAsyncSecurityHandlerFactory if you think that's worth it to help adding future frameworks. The risk there is that there actually is something specific to aiohttp here than I'm not seeing by reading, so we'll have to refactor again at that point to only include the generic stuff.
And now that I've typed all that, I think that I will go ahead and do that. I'll leave the rest of my comments here for future reference on the 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.
done
| # Must be created in a coroutine | ||
| self.client_session = aiohttp.ClientSession() | ||
| headers = {'Authorization': 'Bearer {}'.format(token)} | ||
| token_request = yield from self.client_session.get(token_info_url, headers=headers, timeout=5) |
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.
5 is a magic number here - it might make sense to add as a field on the base class in case someone wants to change it.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
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.
done
cognifloyd
left a comment
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.
Wow. good catches. Here are my follow up comments as I try to understand the code :)
| logger = logging.getLogger('connexion.api.security') | ||
|
|
||
|
|
||
| class AioHttpSecurityHandlerFactory(SecurityHandlerFactory): |
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.
Right now, yes, each framework would need its own SecurityHandlerFactory.
As far as making it more generic - I'm of two minds:
- I think we should assume this is AioHttp-specific until we implement another async framework. At that time, refactoring this into a reusable
AsyncSecurityHandlerthat can be reused by both of them would make sense. - The only thing that uses
aiohttpin this class isget_token_info_remotein how it usesself.client_session. Ifrequestis a ConnexionRequest (vs a framework specific request) then the other functions are very generic, so it should be simple to have anAbstractAsyncSecurityHandlerFactorythat theAioHttpSecurityHandlerFactoryextends to implement theget_token_info_remotemethod.
After I rebase this, I can add the AbstractAsyncSecurityHandlerFactory if you think that's worth it to help adding future frameworks. The risk there is that there actually is something specific to aiohttp here than I'm not seeing by reading, so we'll have to refactor again at that point to only include the generic stuff.
And now that I've typed all that, I think that I will go ahead and do that. I'll leave the rest of my comments here for future reference on the thinking.
| # Must be created in a coroutine | ||
| self.client_session = aiohttp.ClientSession() | ||
| headers = {'Authorization': 'Bearer {}'.format(token)} | ||
| token_request = yield from self.client_session.get(token_info_url, headers=headers, timeout=5) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| logger.debug('pass_context_arg_name: %s', pass_context_arg_name) | ||
| self.pass_context_arg_name = pass_context_arg_name | ||
|
|
||
| self.security_handler_factory = self.make_security_handler_factory(pass_context_arg_name) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| :type token: str | ||
| :rtype: dict | ||
| """ | ||
| token_request = session.get(token_info_url, headers={'Authorization': 'Bearer {}'.format(token)}, timeout=5) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
|
|
||
| class OAuthResponseProblem(OAuthProblem): | ||
| def __init__(self, token_response, **kwargs): | ||
| self.token_response = token_response |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| if token_info is self.no_value: | ||
| return self.no_value | ||
| if token_info is None: | ||
| raise OAuthResponseProblem(description=exception_msg) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| if token_info is None: | ||
| raise OAuthResponseProblem(description=exception_msg) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
8912e28 to
bfe0f53
Compare
|
K. I'm not entirely confident about my fixes for generic auth issues. |
25d5448 to
4795d7b
Compare
e1ca702 to
07d20e6
Compare
|
K. I just rebased this on master, removing the Next steps:
|
1b058bc to
0252ff7
Compare
e75b210 to
6bb75db
Compare
6bb75db to
caacc78
Compare
|
@dtkav could you review when you get a chance? |
|
@hjacobs this is ready for review |
|
@jmcs I saw you did some work recently on this project. This PR seems to be ready for quite some time. Any chance to have a look and approve/review? I am in a position where I would need such functionality for performance reasons and I would prefer the changes in the official repo instead of forking my own version of connexion just to get async security handlers. |
|
@chbndrhnns @cognifloyd, I'll review this PR in the next few days. |
|
👍 |
Fixes #868 .
Allow to use coroutines with Aiohttp in security handlers.
Changes proposed in this pull request:
connexion.operations.securityto a class inconnexion.security.SecurityHandlerFactorypass_context_arg_nameoption is supported for security handlers