Skip to content
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

Migrating to Google Auth Library #221

Closed
wants to merge 15 commits into from
Closed

Conversation

junpeng-jp
Copy link

Summary of changes

#89

  • Removed all dependencies on oauth2client and transitioned to the use of google-auth

#89

  • Added a thread-safe backend adaptor for saving of authorized credentials to File / Dictionary Backend
  • Only authorized user credentials can be saved to backend
  • Service credential are not saved because of private key duplication risks

#173

  • Deprecate command line auth by raising a DeprecationWarning Exception

Removing manual refresh & authorization header injection code as this is now handle by the Google Auth library

  • Removal of CheckAuth & CheckServiceAuth decorators
  • Deprecation of self.Refresh() & self.Authorize() methods
  • Update self.Get_Http_Object() method to use the AuthorizedHttp object from google's HTTP migration helper library

@junpeng-jp junpeng-jp marked this pull request as ready for review August 7, 2022 14:31
@junpeng-jp
Copy link
Author

@shcheklein I've raise a new PR above. Please do take a look when you have time

@shcheklein
Copy link
Member

@junpeng-jp hey, sure. Please don't hesitate to Request a review via a link at the top. Otherwise it was not clear if it's still in progress or not. Thanks again for the effort. I'll try to find time to review it this week.

@junpeng-jp junpeng-jp marked this pull request as draft August 14, 2022 11:56
@junpeng-jp junpeng-jp marked this pull request as ready for review August 14, 2022 11:56
@junpeng-jp
Copy link
Author

@shcheklein Not sure why but I don't see a button to request a reviewer for this PR. Are you able to help me here?

Screenshot of what I see below
image

@shcheklein shcheklein self-requested a review August 14, 2022 16:26
@shcheklein
Copy link
Member

@junpeng-jp ah, no worries. If it doesn't work- that's fine. Just ping me in the comment.

Sorry for the delay, this PR needs more attention and I need to find time to check it out.

pydrive2/auth.py Outdated
@@ -1,28 +1,31 @@
import json
import webbrowser
import httplib2
import oauth2client.clientsecrets as clientsecrets
import json
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have import json already ^^

pydrive2/auth.py Outdated
"""Decorator to check if the auth is valid and loads auth if not."""
"""
Decorator to check the self.auth & self.http object in a decorated API call.
Loads a new GoogleAuth or Http object if not the needed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if not the needed - needs to be fixed

pydrive2/auth.py Outdated
self._credentials = None

# Lazy loading, read-only properties
# these look like functions but are actually getters for the read only properties
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this explanation, it's quite common pattern

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

almost all of these properties should be private? which ones do we want to expose?



class CredentialBackend(object):
"""Adapter that provides a consistent interface to read and write credential files"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

write credential files -> write credentials

pydrive2/auth.py Outdated

try:
self.credentials = self._default_storage.get()
auth_info = self.default_storage.read_credentials(credentials_file)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think storage should be per file name. Otherwise we have to keep providing credentials_file everywhere + we use the same lock for all credential files potentially

auth_info, scopes=auth_info["scopes"]
)
except ValueError:
warn(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, could you remind me please about the use case? can we drop this?

pydrive2/auth.py Outdated
if self._default_storage is None:
raise InvalidConfigError(
"Backend `file` is not configured, specify "
"credentials file to read in the settings "
"file or pass an explicit value"
)
else:
self._default_storage = Storage(credentials_file)
self._default_storage = FileBackend()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

information is lost at this point that this storage is from the specified credentials_file. I'm not 100% understand the use case why would someone do auth.LoadCredentialsFile("some/custom/path"), but it looks like we are changing the behavior here ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, before it was important since the credentials object was triggering save on refresh, not sure again yet if this is important here ...

self.service = build(
"drive", "v2", http=self.http, cache_discovery=False
raise DeprecationWarning(
"Manual authorization of HTTP will be deprecated as the"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, but we do have AuthorizedHttp(...) call which is similar to the self.credentials.authorize(self.http). In this case again, I'm not sure why it (the public Authorize call) was needed in the first place. Probably for some custom auth flow. Would be great to get more information on this.

Copy link
Member

@shcheklein shcheklein Aug 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Authorize is being used in the Auth above that won't work anymore. And it's needed for custom flow logic like this https://docs.iterative.ai/PyDrive2/oauth/#building-your-own-authentication-flow .

pydrive2/auth.py Outdated
except AccessTokenRefreshError as error:
raise RefreshError("Access token refresh failed: %s" % error)
raise DeprecationWarning(
"Manual refresh will be deprecated as the"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is deprecated ...


@property
def credentials(self):
if not self._credentials:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need / have to support this as a lazy / self-initializing logic for credentials?

btw, have you seen the:

    client_config = ApiAttribute("client_config")
    flow = ApiAttribute("flow")
    credentials = ApiAttribute("credentials")
    http = ApiAttribute("http")
    service = ApiAttribute("service")
    auth_method = ApiAttribute("auth_method")

how those coexist with these properties?

@lappazos
Copy link

@shcheklein @junpeng-jp any update on this PR? I really need the automatic auth using GCP service account credentials.

@shcheklein
Copy link
Member

@lappazos please give it a try https://docs.iterative.ai/PyDrive2/oauth/#authentication-with-a-service-account . You don't need to wait for this PR to be merged.

@lappazos
Copy link

lappazos commented Nov 2, 2022

@shcheklein so i did - i couldn't find where this function is implemented.
i tried to implement it by myself (copy pate), but the GCP environment couldn't find the "client_json_file_path": "service-secrets.json",

@shcheklein
Copy link
Member

@lappazos please, let's move this to a separate issue/discussion. This is not related I think to this PR.

@lappazos
Copy link

@junpeng-jp @shcheklein is this PR stuck?

@shcheklein
Copy link
Member

Closing as stale

@shcheklein shcheklein closed this Apr 9, 2023
@el-abcd
Copy link

el-abcd commented Nov 5, 2023

Just noting that it would be nice if this PR can be "brought back to life/completed" to enable features like "service account impersonation", etc.

Background:
I was working on a small hobby project (and attempting to learn some of the "best practices" for service accounts/authentication, etc.).

IIUC, it seems like using "service account impersonation" is preferred to downloading a "service account key", as the key is long-lived, requires manual rotation, etc. Whereas "impersonation" allows you to just fetch a temporary token for the service account (using your existing user credentials)
service account key

While I'm not 100% certain it is required, I think that using the updated google oauth libraries are probably the best way to enable these features.
And I did have success using the https://github.com/junpeng-jp/PyDrive2 fork for this...

I was able to get it running locally (using mostly default settings for PyDrive2, and creating "impersonated application-default credentials" with:

gcloud auth application-default login --impersonate-service-account SERVICE_ACCT_EMAIL

To make the "application default credentials" be the "impersonated service account" ones.

I was ALSO able to get a test version running on a google cloud run container (where a google managed "service account" is used to run the service, and I was able to get that service account to "impersonate" an existing service account (which already has access to certain drive folders) and get things working that way also. It did require a bit of work (monkey patching the GoogleAuth.ServiceAuth() method to set self._credential to be the impersonated one). I think that would be a "fairly small update" to allow impersonated service accounts cleanly (if this PR is revived).

At any rate, just noting that this PR does appear to be pretty useful, and hoping that this can be brought back to life / completed (as it appears to be pretty far along / functional).

Eric

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants