Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix credentials usage in BatchHTTPRequest #376

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

Merged
merged 4 commits into from
Jun 20, 2017
Merged

Conversation

theacodes
Copy link
Contributor

@theacodes theacodes commented Mar 30, 2017

Resolves #375 and #350.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Mar 30, 2017
@theacodes
Copy link
Contributor Author

Please don't merge until I verify this will fix #375 and have a chance to write tests.

@sbrieuc
Copy link

sbrieuc commented Mar 31, 2017

@jonparrott Looks like there is a circular import issue

  File "/Users/brieuc/development/source/pip-libs/apiclient/__init__.py", line 19, in <module>
    from googleapiclient import discovery
  File "/Users/brieuc/development/source/pip-libs/googleapiclient/discovery.py", line 56, in <module>
    from googleapiclient import _auth
  File "/Users/brieuc/development/source/pip-libs/googleapiclient/_auth.py", line 32, in <module>
    from googleapiclient.http import build_http
  File "/Users/brieuc/development/source/pip-libs/googleapiclient/http.py", line 65, in <module>
    from googleapiclient import _auth
ImportError: cannot import name _auth

Now going beyond that, the _serialize_request method should also be updated with the _auth.get_credentials_from_http method, which leads to issue #350.

So I think we should change the _serialize_request from:

if request.http is not None and hasattr(request.http.request,
        'credentials'):
    request.http.request.credentials.apply(headers)

to

if request.http is not None:
    creds = _auth.get_credentials_from_http(request.http)
    if creds is not None:
        if _auth.has_access_token(creds):
            creds.apply(headers)

@theacodes
Copy link
Contributor Author

@sbrieuc updated, can you give it another go?
@mgilson it'd be great if you could try it out as well, as this should now resolve #350 as well.

'credentials'):
request.http.request.credentials.apply(headers)
if request.http is not None:
credentials = _auth.get_credentials_from_http(request.http)

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

@sbrieuc
Copy link

sbrieuc commented Apr 1, 2017

@jonparrott Just tried this, everything's good !

@sbrieuc
Copy link

sbrieuc commented Apr 1, 2017

@jonparrott Actually I'm seeing something that might be a bit off from a couple of tests I just performed. In the execute() method, in the case where we have no initial token, we manually refresh the credentials providing the http instance (either the one given to the execute method or the one from the first request in the batch):

# Special case for OAuth2Credentials-style objects which have not yet been
# refreshed with an initial access_token.
creds = _auth.get_credentials_from_http(http)
if creds is not None:
  if not _auth.has_access_token(creds):
    LOGGER.info('Attempting refresh to obtain initial access_token')
    _auth.refresh_credentials(creds, http)

self._execute(http, self._order, self._requests)

Now in _auth.refresh_credentials method, in the case of google-auth credentials we do this:

request = google_auth_httplib2.Request(http)
return credentials.refresh(request)

We're building a Request object using the provided http instance, which in this case will be an AuthorizedHttp object. That means it will use the AuthorizedHttp.request method to perform the request that will get an access token. However, this request method also performs a token refresh if needed. So what I observed is that when we have no initial token for google-auth credentials, the token gets refreshed twice: once because we manually called credentials.refresh and once because the request method used to refresh this token also performs a token refresh.

So my suggestion would be to use a new httplib2.Http() object for the request.

request = google_auth_httplib2.Request(httplib2.Http())
return credentials.refresh(request)

This way the credentials are refreshed only once.

What do you think ?

@theacodes
Copy link
Contributor Author

@sbrieuc I think that's pretty good idea. Updating now.

@theacodes theacodes changed the title [DON'T MERGE] Fix credentials usage in BatchHTTPRequest Fix credentials usage in BatchHTTPRequest Apr 19, 2017
@theacodes
Copy link
Contributor Author

I think this is now in a good state if you want to review, @lukesneeringer.

@sbrieuc I'd love if you can give this another test.

@sbrieuc
Copy link

sbrieuc commented Apr 20, 2017

@jonparrott That seems good to me. All my tests are ok

@theacodes
Copy link
Contributor Author

Great, @lukesneeringer PTAL?

@theacodes
Copy link
Contributor Author

@lukesneeringer another poke here - this should be ready to merge.

@theacodes theacodes mentioned this pull request Jun 20, 2017
@theacodes
Copy link
Contributor Author

I'm going to take @lukesneeringer's silence as tacit approval. (I am happy to address concerns in a follow-up PR)

@@ -1208,8 +1208,7 @@ def _serialize_request(self, request):
if request.http is not None:
credentials = _auth.get_credentials_from_http(request.http)
if credentials is not None:
if _auth.has_access_token(credentials):

This comment was marked as spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants