odeke-em/drive

Does drive support service accounts, so G Suite users can automate initialisation without user prompts?

cajacko opened this issue · 9 comments

Does this utility support using a separate service account credentials.json file? And how would you go about setting this up?

This would be great as I could automate the whole initialisation process without user prompts. Which would work well in my continuous deployment setup.

I'm imagining something where you could specify a separate credentials file during initialisation:

drive init --credentials credentials.json

Hello there @cajacko, thank you for the question and welcome to drive!

Unfortunately we don't support service accounts since there hasn't been any demand for them.
We currently only support OAuth2.0 credentials since they are revokable.

Therefore I'll take this as the first request for support for Google Service Accounts. I have added
support for Google Service Accounts for proprietary code for Google related services but not here.

Instead of reading credentials from the environment .gd/credentials.json, we could follow the style
of resolution for Google Service account credentials. We can then change up the remote context resolver in here

drive/src/remote.go

Lines 96 to 105 in 5278f2b

func NewRemoteContext(context *config.Context) *Remote {
client := newOAuthClient(context)
service, _ := drive.New(client)
progressChan := make(chan int)
return &Remote{
progressChan: progressChan,
service: service,
client: client,
}
}
to get OAuth2.0 credentials directly from the GSA credentials as is done here https://github.com/golang/oauth2/blob/3c3a985cb79f52a3190fbc056984415ca6763d01/google/example_test.go#L58-L79 and just swap out how we initialize the service.

I'll mark this as a feature-request and if anyone would like to work on it, please feel free or I'll jump in, in about a week when I get a break from school.

@cajacko I've started the work here, initialization for the remote should be complete, what's left is figuring out the initialization process 8eb5d20
but am thinking using GSA accounts with init is a little awkward since the recommended
method of using them is by resolving them from the environment variable but no biggie
we can read from a file itself using https://github.com/golang/oauth2/blob/master/google/jwt.go#L26.

WIP that I'll complete next week when free.

@odeke-em Awesome, thanks for the quick response and progress on this!

@cajacko thanks for the wait, I've added support for Google Service Accounts with PR #882, please get the latest from master by

$ go get -u -v github.com/odeke-em/drive/drive-gen && drive-gen

Please let me know if anything isn't right or if there are any problems.

Hey, Thanks so much for working on this. The connection is working great and I am able to pull/push/list etc.

However I'm not sure what account I am looking at. As there isn't anywhere to specify the user you want to make drive calls on behalf of. I'm not sure whose drive account it is, all that is inside it is a "Getting Started" document.

On the Google docs (https://developers.google.com/identity/protocols/OAuth2ServiceAccount) it mentions the following:


Additional claims

In some enterprise cases, an application can request permission to act on behalf of a particular user in an organization. Permission to perform this type of impersonation must be granted before an application can impersonate a user, and is usually handled by a domain administrator. For more information on domain administration, see Managing API client access.

To obtain an access token that grants an application delegated access to a resource, include the email address of the user in the JWT claim set as the value of the sub field.

Name Description
sub The email address of the user for which the application is requesting delegated access. If an application does not have permission to impersonate a user, the response to an access token request that includes the sub field will be an error.

An example of a JWT claim set that includes the sub field is shown below:

{
  "iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "sub":"some.user@example.com",
  "scope":"https://www.googleapis.com/auth/prediction",
  "aud":"https://www.googleapis.com/oauth2/v4/token",
  "exp":1328554385,
  "iat":1328550785
}

Is this something that would need to be implemented to access a specific drive account, or am I missing something in the Google Drive config side of things?

Thanks

Hello @cajacko, thanks for the question. Unfortunately I don't know how to request for exact user access for a service account, because I use service accounts only for apps and organization. For example you have an app that receives selfies by upload, so you create a console.developers.google.com project and enable Google APIs access to it such as Google Drive.

So in that citation, they say set "sub" as the email of the user you'd like to use it for. Please set "sub" as the email of the user just like you would when doing the OAuth2.0 exchange in the credentials, and let's see what changes. Initializing with the JWT config ie drive init -service-account-file ~/Desktop/gsaFile.json -- assumes that the credentials have already been exported correctly, so you'll need to add that field yourself.

Hi, I added the sub property and desired email into the credentials file to no effect. Although I have been able to access a users folders by sharing them with the service account email address. So now I am able to pull a shared folder by it's ID, which is great. Although I am unable to push to a shared folder, as there does not seem to be an accompanying push by id option. Is there any support for pushing/pulling from shared folders that I am missing?

Here is a bit of context to help understand what I'm trying to do:

An organisation that uses G Suite, has unlimited drive capacity for it's users and wants to use this storage to backup data from various servers. This servers may be setup entirely with continuous deployment so the setup needs to be autonomous.

One of the users creates a backups folder that is shared throughout the organisation. This is the folder that they want the server to be backed up to.

At the moment this drive utility can be setup automatically, can pull the latest backups from the shared folder (by ID) and the last piece of the puzzle is just to be able to push to it.

This shared folder must be shared from a user account, rather than being owned by the service account, as the service account can only have the default storage quota and the organisation is already paying for unlimited storage for it's users.

Thanks

Hmm, @cajacko unfortunately that's out of my knowledge scope, let me ping our Googler coauthor @rakyll for help.
@rakyll do you know to use GSA credentials on behalf of a user? Thanks.

I had this issue recently and realized that drive creates credentials.json (~/gdrive/.gd/credentials.json) file after initiation. You will see that there is a Subject field in this file which is set to an empty string. So I tried my chance and set it to an email address which is delegated under the service account i've specified. And it worked! 🕺

I would like to make a pr related to this but i don't even know the go lang.

You can automate this job with the following:

sed -i -e 's|"Subject":""|"Subject":"'"$GOOGLE_DRIVE_BACKUP_USER"'"|g' ~/gdrive/.gd/credentials.json