-
Notifications
You must be signed in to change notification settings - Fork 69
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
feat: support self-signed JWT flow for service accounts #774
Conversation
Codecov Report
@@ Coverage Diff @@
## master #774 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 26 27 +1
Lines 1608 1653 +45
Branches 328 337 +9
=========================================
+ Hits 1608 1653 +45
Continue to review full report at Codecov.
|
d696ce3
to
f154176
Compare
if host != self.DEFAULT_HOST and not scopes: | ||
scopes = self.AUTH_SCOPES |
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 port is provided (say pubsub.googleapis.com:443
instead of pubsub.googleapis.com
) the library will think the OAuth2 flow is necessary.
I initially tried splitting on :
but that broke the showcase tests where default host is localhost. Is there a better way to parse the provided host reliably?
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.
Silly questions: which is the OAuth2 flow, and why do we not want it all the time? Is it the "old style"? What are we trying to parse out? We can always fall back to regexes, something like
host_re = re.compile("(?P<host>[^:]+)(:(?P<port>\d+))?")
Or is that not the part of parsing out the host that's problematic?
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.
Ah sorry for being vague.
The OAuth2 flow (currently always used for service accounts) requires a call out to oauth2.googleapis.com
. With a service account, it's sometimes possible to "self-sign" the token, which avoids a network round trip.
The self-signed JWT option can be used when:
- A service account is being used
- A scope has not been set by the user
- A target_audience has not been set by the user (irrelevant as we don't have an client option for this)
- An api_endpoint has not been set by the user
Number 4 is what's relevant here. If the user is using the non-default endpoint we want to make sure the auth library uses OAuth2. The suggested way to do this in the doc is to pass user scopes to the auth library.
I think that regex will work! I'll experiment and push a new commit.
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, this is quite the endeavor. Thanks for doing it!
if host != self.DEFAULT_HOST and not scopes: | ||
scopes = self.AUTH_SCOPES |
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.
Silly questions: which is the OAuth2 flow, and why do we not want it all the time? Is it the "old style"? What are we trying to parse out? We can always fall back to regexes, something like
host_re = re.compile("(?P<host>[^:]+)(:(?P<port>\d+))?")
Or is that not the part of parsing out the host that's problematic?
gapic/templates/%namespace/%name_%version/%sub/services/%service/transports/rest.py.j2
Outdated
Show resolved
Hide resolved
gapic/templates/%namespace/%name_%version/%sub/services/%service/transports/rest.py.j2
Outdated
Show resolved
Hide resolved
FYI, cl/357773081 is submitted, so I guess custom endpoint will no longer be an issue for self signed JWT going forward. @bshaffer |
@bshaffer Would you be able to take a look? |
gapic/templates/%namespace/%name_%version/%sub/services/%service/transports/base.py.j2
Outdated
Show resolved
Hide resolved
gapic/templates/%namespace/%name_%version/%sub/services/%service/transports/grpc_asyncio.py.j2
Outdated
Show resolved
Hide resolved
This is true but it still will be some time before it rolls out. It's up to the owners of this repo if that's acceptable to wait for the rollout or go ahead with the fix we have here. I'd prefer the latter. |
Yep, agreed, it is just a FYI. It still takes one or two weeks for the roll out. |
gapic/templates/%namespace/%name_%version/%sub/services/%service/transports/grpc.py.j2
Outdated
Show resolved
Hide resolved
gapic/templates/%namespace/%name_%version/%sub/services/%service/transports/base.py.j2
Outdated
Show resolved
Hide resolved
gapic/templates/%namespace/%name_%version/%sub/services/%service/transports/grpc.py.j2
Outdated
Show resolved
Hide resolved
75472e0
to
38c3b18
Compare
@bshaffer PTAL. :) |
Does @bshaffer need to take a look, or is this good to merge? |
@bshaffer or @arithmetic1728 would you mind taking another look? |
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.
@bshaffer I removed the scope override with custom endpoints to match guidance in https://docs.google.com/document/d/1FoJPYQu8ZHdGBFY9TBRZCDrWJJnxw3fAz5CG5mdZR9E/edit. Could you take a look?
gapic/templates/%namespace/%name_%version/%sub/services/%service/transports/base.py.j2
Show resolved
Hide resolved
@software-dov Could you take one more look? Thank you for your help getting this over the line. :) |
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.
One question I still have is, unfortunately, for the case of the regional endpoint us-documentai.googleapis.com
, we need a check to make sure the DEFAULT_HOST
doesn't contain a regional endpoint.
If this is something we should do here, or somewhere else, I am not sure, I just want to verify it's being considered!
@@ -99,13 +99,13 @@ class {{ service.name }}Transport(abc.ABC): | |||
scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) | |||
|
|||
# Save the scopes. | |||
self._scopes = scopes_kwargs["scopes"] | |||
self._scopes = scopes or self.AUTH_SCOPES |
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 I'm understanding this correctly, scopes_kwargs["scopes"]
was essentially scopes
but with a check for if the endpoint
was supplied. And I am interpreting scopes or self.AUTH_SCOPES
to mean "user supplied scopes or the default scopes"
Is that accurate?
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.
Yep! Since the endpoint
restriction has been lifted I went back to "user supplied scopes or the default scopes"
@@ -120,19 +120,7 @@ class {{ service.name }}Transport(abc.ABC): | |||
self._credentials = credentials | |||
|
|||
|
|||
@classmethod | |||
def _get_user_scopes(cls, host: str, scopes: Optional[Sequence[str]]) -> Optional[Sequence[str]]: |
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.
👍
@bshaffer From reading the doc it seems like documentai is the exception, so I am planning on handling that with a synthtool/owlbot replace. If we anticipate more APIs using the regional endpoints as the default host I can build logic into the generator. |
That sounds great! |
🤖 I have created a release \*beep\* \*boop\* --- ## [0.44.0](https://www.github.com/googleapis/gapic-generator-python/compare/v0.43.3...v0.44.0) (2021-04-23) ### Features * support self-signed JWT flow for service accounts ([#774](https://www.github.com/googleapis/gapic-generator-python/issues/774)) ([89d6f35](https://www.github.com/googleapis/gapic-generator-python/commit/89d6f35c54b0a9b81c9b5f580d2e9eb87352ed93)) ### Bug Fixes * enable GAPIC metadata generation ([#843](https://www.github.com/googleapis/gapic-generator-python/issues/843)) ([697816c](https://www.github.com/googleapis/gapic-generator-python/commit/697816ce7d5b201d6ced85fadd89f9140da67b37)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
See RFC (internal only) and https://aip.dev/auth/4111.
Support the self-signed JWT flow for service accounts by passing
default_scopes
anddefault_host
in calls to the auth library andcreate_channel
. This depends on features exposed in the following PRs: googleapis/python-api-core#134, googleapis/google-auth-library-python#665.It may be easier to look at https://github.com/googleapis/python-translate/pull/107/files for a diff on a real library.
This change is written so that the library is (temporarily) compatible with older
google-api-core
andgoogle-auth
versions. Because of this it not possible to reach 100% coverage on a single unit test run.pytest
runs twice in two of thenox
sessions.Miscellaneous changes:
__init__.py
files in subdirs of thetest/
directory, as otherwise pytest-cov seems to fail to collect coverage properly in some instances.packaging
for Version comparison https://pypi.org/project/packaging/