Transfer ownership of a file fails - even as Super Administrator (Google Drive API, Java) - google-drive-api

I am trying to transfer ownership of files to Super Administrator. The essential part of the code is shown below. The same code works if I transfer ownership of a document that I own. But in this case the original owner is another user in the same domain. [EDIT] I know there is a "transfer-ownership-of-files-from-1-user-to-another" in admin panel, but this is needed for a case when multiple files/folders, from multiple owners needs to be transferred programmatically. [/EDIT]
So the simple scenario is:
user#domain.com owns a file
the ownership needs to be transferred to the admin#domain.com (Super Administrator). The code is running in AppEngine in Java Servlet. And the Super Administrator is authenticated with OAuth.
However it throws (500 OK) exception always in line update.execute(); (showed in the end).
Is this operation impossible even for a Super Admin?
Thanks for any tips!
try {
Drive service = getDriveService();
Permission newPerm = new Permission();
newPerm.setValue("admin#domain.com");
newPerm.setType("user");
newPerm.setRole("writer");
newPerm = service.permissions().insert(fileId, newPerm).execute();
newPerm.setRole("owner");
Update update = service.permissions().update(fileId, newPerm.getId(), newPerm);
update.setTransferOwnership(true);
update.execute();
} catch (IOException e) {
e.printStackTrace();
log.severe(e.getMessage());
}
The exception thrown looks like:
SEVERE: 500 OK
{
"code" : 500,
"errors" : [ {
"domain" : "global",
"message" : "Internal Error",
"reason" : "internalError"
} ],
"message" : "Internal Error"
}

I finally got this working at least partly. Thanks #ZigMandel for the "impersonation" hint! Now I followed this Domain-wide Delegation of Authority carefully. And used the GoogleCredential created using "Service account"-key. With this credential I can impersonate the Drive API operations like adding permissions and transferring ownership to Admin, for example.
The problem that still remains is that with current Drive API it is impossible to programmatically determine the owner email address, which is needed for impersonated credential creation. Now I need to find a workaround for this. Anyway the fundamental idea works now. Thanks!

You wont be able to do it from apps script.
Can be done from appengine. Ive done it but its beyond of the scope to explain here. Involves using the drive api on behalf of the file owner and adding the oauth permissions at the domain level.

Related

Google Drive API: Where or How to find Shared Drive ID?

I'm trying to use Google's APIs Explorer to run a method (drive.permissions.create) in which I grant a user access to an entire Google Shared Drive (not specifically a file or folder).
After executing the command, I get the following error:
An error occurred. See the response for details.
Request
POST https://www.googleapis.com/drive/v3/files/0AKppN1yZFzBbUk9PVA/permissions?emailMessage=Test&key={YOUR_API_KEY}
{
"role": "organizer",
"type": "user",
"emailAddress": "test#test.com"
}
Response
{
"error":{
"errors":[
{
"domain":"global",
"reason":"notFound",
"message":"File not found: 0AKppN1yZFzBbUk9PVA.",
"locationType":"parameter",
"location":"fileId"
}
],
"code":404,
"message":"File not found: 0AKppN1yZFzBbUk9PVA."
}
}
I acquired value, 0AKppN1yZFzBbUk9PVA, from another command I thought would give me the ID of the Shared Drive I'm trying to share(drive.drives.list). However, this value is incorrect. Where or how can I find the ID of the Shared Drive I'm trying to give access to?
Also, if I'm missing another value to input other than a correct Id for the command to be successful, please let me know. There is still so much I don't know about how Google Drive's API works (or APIs for that matter).
Thanks in advance!
For Shared Drives you need to set supportsAllDrives to true.

VimeoUpload not re-authenticating After Deletion of App Access on Vimeo.com

I was able to connect and upload videos using the library but when I deleted the app connection on Vimeo.com (as a test) the app didn't authorize again.
the upload looks like it's working but nothing is uploaded as the app is no longer connected.
I deleted the app on the phone and restarted but it still won't re-authorize the app.
This comes up in the output:
Vimeo upload state : Executing
Vimeo upload state : Finished
Invalid http status code for download task.
And this is in OldVimeoUpload.swift: ( didn't include the actual access code!)
import Foundation
class OldVimeoUpload: VimeoUpload
{
static var VIMEO_ACCESS_TOKEN :String! // = "there's a string of numbers here"
static let sharedInstance = OldVimeoUpload(backgroundSessionIdentifier: "") { () -> String? in
return VIMEO_ACCESS_TOKEN // See README for details on how to obtain and OAuth token
}
// MARK: - Initialization
override init(backgroundSessionIdentifier: String, authTokenBlock: AuthTokenBlock)
{
super.init(backgroundSessionIdentifier: backgroundSessionIdentifier, authTokenBlock: authTokenBlock)
}
}
It looks like the access token number is commented out. I deleted the 2 forward slashes to see if that would fix it but it didn't.
I spoke too soon.
It sounds like you went to developer.vimeo.com and created an auth token. Used it to upload videos. And then went back to developer.vimeo.com and deleted the auth token.
The app / VimeoUpload will not automatically re-authenticated in this situation. You've killed the token and the app cannot request a new one for you. You'll need to create a new auth token and plug it into the app.
If this is not accurate and you're describing a different issue let us know.
If you inspect the error that's thrown from the failing request I'm guessing you'll see it's a 401 unauthorized related to using an invalid token.
Edit:
Disconnecting your app (as described in your comment below) has the same effect as deleting your auth token from developer.vimeo.com.
Also, VimeoUpload accepts a hardcoded auth token (as you see from the README and your code sample). It will not automatically re-authenticate, probably ever.
If you'd like to handle authentication in your app check out VimeoNetworking or VIMNetworking. Either of those libraries can be used to create a variety of authentication flows / scenarios. Still, if a logged in user disconnects or deletes their token, you will need them to deliberately re-authenticate (i.e. you will need to build that flow yourself). In that case, the user has explicitly stated that they don't want the app to be able to access information on their behalf. It would go against our security contract with them to automatically re-authenticate somehow.
Does that make sense?

FIWARE Object Storage "no tenants available"

When using the Object Storage GE node.js connector implementation from https://github.com/arvidkahl/fiware-object-storage we encounter the problem "no tenants available". We tested with two different community accounts where we first set up an object container within the fiware cloud.
We are able to Receive an Auth Token and get a connection established message, but then we do not get the tenant ID i think. has anyone experienced something like that and can help or give us a better understanding of what is going wrong here?
we installed the fiware-object-storage with npm install fiware-object-storage.
this is our connection code:
var fiwareObjectStorageConfig = {
auth : conf.fiware.auth_url, // IP of the Auth Services, likely "cloud.lab.fi-ware.org"
url : conf.fiware.object_storage_url, // IP of the Object Storage GE -> "cloud.lab.fi-ware.org"
user : conf.fiware.user, // Your FIWARE account email
password : conf.fiware.password, // Your FIWARE account password.. i know.. no comment.
container : conf.fiware.container // Whatever container you want to connect to
};
var fiwareObjectStorage = require('fiware-object-storage');
fios = fiwareObjectStorage(fiwareObjectStorageConfig);
fios.connectToObjectStorage(function() {
console.log(fios.getFileList());
});
This library is a third party library and it is not an official FIWARE implementation.
As you said, there is a problem with this library. I have tested and it needs some fixes. I could not reproduce your error with my account but I have another one while getting file list.
The best option is waiting for their developers to improve that simple library like select Tenant in config file. By now it takes the first tenant on the list.
This is my config file to access Spain2 object store:
fiwareObjectStorageConfig = {
url : '172.32.0.144',
auth : 'cloud.lab.fi-ware.org',
container : 'myContainer',
user : "", // Your FIWARE account email
password : "" // Your FIWARE account password.
};

Strange permission issue with getOwner method in Google Apps Script

When using this line of code in a Google Apps Script
var user = folders[n].getOwner().getEmail()
I get an error saying I am not authorized to perform such an action (your version may vary, I am translating from italian).
What gives? I am just retrieving an information, such as the owner of a folder.
When the script processes a folder I own, the error does not arise, the error arises when it encounters a folder not of mine. The matter is that this line of code is just for spotting folders which are not of mine, to avoid issuing method that would correctly rise an error, like setTrashed. The script looks for empty folders to delete them, but I cannot delete folders I am not the owner of of course. And yes I am into Google apps for business, does it make some difference?
There isn't any specifc warning about file.getOwner().getEmail(), but there is for Class Session.
In limited-privilege executions (such as in response to onOpen or
onEdit), we only return the identity of the active user if both the
user and the script owner are part of the same domain. This is to
protect the privacy of consumer users, who may not want their email
address exposed.
I have no problem with this in a consumer account.
The following function is an excerpt from a gist I posted for a previous question. It wraps the call to .getEmail() (or getUserLoginId() if you prefer) in a try ... catch block, so it avoids errors for users crossing Apps Domains.
function getFileInfo (file,fileType) {
var fileInfo = {
id: file.getId(),
name: file.getName(),
size: file.getSize(),
type: (fileType == "file") ? docTypeToText_(file.getFileType()) : "folder",
created: file.getDateCreated(),
description: file.getDescription(),
owner: file.getOwner()
}
try {
fileInfo.owner = file.getOwner().getEmail()//.getUserLoginId()
} catch(e)
{
// Possible permission problem
fileInfo.owner = "unknown";
}
return fileInfo;
}
UPDATE: Since this was first posted, something has changed. Now my consumer account encounters the aforementioned error when trying to access getOwner() for a file shared from another account. (March 3, 2013)

Google Drive/OAuth - Can't figure out how to get re-usable GoogleCredentials

I've successfully installed and run the Google Drive Quick Start application called DriveCommandLine. I've also adapted it a little to GET file info for one of the files in my Drive account.
What I would like to do now is save the credentials somehow and re-use them without the user having to visit a web page each time to get an authorization code. I have checked out this page with instructions to Retrieve and Use OAuth 2.0 credentials. In order to use the example class (MyClass), I have modified the line in DriveCommandLine where the Credential object is instantiated:
Credential credential = MyClass.getCredentials(code, "");
This results in the following exception being thrown:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:187)
at com.google.api.client.json.jackson.JacksonFactory.createJsonParser(JacksonFactory.java:84)
at com.google.api.client.json.JsonFactory.fromInputStream(JsonFactory.java:247)
at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.load(GoogleClientSecrets.java:168)
at googledrive.MyClass.getFlow(MyClass.java:145)
at googledrive.MyClass.exchangeCode(MyClass.java:166)
at googledrive.MyClass.getCredentials(MyClass.java:239)
at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)
I've been looking at these APIs (Google Drive and OAuth) for 2 days now and have made very little progress. I'd really appreciate some help with the above error and the problem of getting persistent credentials in general.
This whole structure seems unnecessarily complicated to me. Anybody care to explain why I can't just create a simple Credential object by passing in my Google username and password?
Thanks,
Brian O Carroll, Dublin, Ireland
* Update *
Ok, I've just gotten around the above error and now I have a new one.
The way I got around the first problem was by modifying MyClass.getFlow(). Instead of creating a GoogleClientServices object from a json file, I have used a different version of GoogleAuthorizationCodeFlow.Builder that allows you to enter the client ID and client secret directly as Strings:
flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, "<MY CLIENT ID>", "<MY CLIENT SECRET>", SCOPES).setAccessType("offline").setApprovalPrompt("force").build();
The problem I have now is that I get the following error when I try to use flow (GoogleAuthorizationCodeFlow object) to exchange the authorization code for the Credentials object:
An error occurred: com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_scope"
}
googledrive.MyClass$CodeExchangeException
at googledrive.MyClass.exchangeCode(MyClass.java:185)
at googledrive.MyClass.getCredentials(MyClass.java:262)
at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)
Is there some other scope I should be using for this? I am currently using the array of scopes provided with MyClass:
private static final List<String> SCOPES = Arrays.asList(
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile");
Thanks!
I feel your pain. I'm two months in and still getting surprised.
Some of my learnings...
When you request user permissions, specify "offline=true". This will ("sometimes" sic) return a refreshtoken, which is as good as a password with restricted permissions. You can store this and reuse it at any time (until the user revokes it) to fetch an access token.
My feeling is that the Google SDKs are more of a hinderence than a help. One by one, I've stopped using them and now call the REST API directly.
On your last point, you can (just) use the Google clientlogin protocol to access the previous generation of APIs. However this is totally deprecated and will shortly be turned off. OAuth is designed to give fine grained control of authorisation which is intrinsically complex. So although I agree it's complicated, I don't think it's unnecessarily so. We live in a complicated world :-)
Your and mine experiences show that the development community is still in need of a consolidated document and recipes to get this stuff into our rear-view mirrors so we can focus on the task at hand.
Oath2Scopes is imported as follows:
import com.google.api.services.oauth2.Oauth2Scopes;
You need to have the jar file 'google-api-services-oauth2-v2-rev15-1.8.0-beta.jar' in your class path to access that package. It can be downloaded here.
No, I don't know how to get Credentials without having to visit the authorization URL at least once and copy the code. I've modified MyClass to store and retrieve credentials from a database (in my case, it's a simple table that contains userid, accesstoken and refreshtoken). This way I only have to get the authorization code once and once I get the access/refresh tokens, I can reuse them to make a GoogleCredential object. Here's how Imake the GoogleCredential object:
GoogleCredential credential = new GoogleCredential.Builder().setJsonFactory(jsonFactory)
.setTransport(httpTransport).setClientSecrets(clientid, clientsecret).build();
credential.setAccessToken(accessToken);
credential.setRefreshToken(refreshToken);
Just enter your clientid, clientsecret, accessToken and refreshToken above.
I don't really have a whole lot of time to separate and tidy up my entire code to post it up here but if you're still having problems, let me know and I'll see what I can do. Although, you are effectively asking a blind man for directions. My understanding of this whole system is very sketchy!
Cheers,
Brian
Ok, I've finally solved the second problem above and I'm finally getting a working GoogleCredential object with an access token and a refresh token.
I kept trying to solve the scopes problem by modifying the list of scopes in MyClass (the one that manages credentials). In the end I needed to adjust the scopes in my modified version of DriveCommandLine (the one that's originally used to get an authorization code). I added 2 scopes from Oauth2Scopes:
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET,
Arrays.asList(DriveScopes.DRIVE, Oauth2Scopes.USERINFO_EMAIL, Oauth2Scopes.USERINFO_PROFILE))
.setAccessType("offline").setApprovalPrompt("force").build();
Adding the scopes for user information allowed me to get the userid later in MyClass. I can now use the userid to store the credentials in a database for re-use (without having to get the user to go to a URL each time). I also set the access type to "offline" as suggested by pinoyyid.