Action not allowed when setowner() ???

1,591 views
Skip to first unread message

David Poulin

unread,
Aug 10, 2021, 10:35:50 AM8/10/21
to Google Apps Script Community
Hi guys,

We want to create a app script that will loop over all foles & files from a root folder id and change owner of folder/file if the owner is not the generic user that we want.

The root folder is a shared folder to our department (not a shared drives) as we wanted to have move flexibility. Employee will upload or move there documentation into that specific folder to share will all the informations and also in case of job leaving, we gonna keep documents.

I use a special generic account to create my script to avoid using my own account and i created the script code. I added some tests function just to confirm the concept, but i receive "Action Not allowed" on line that contain setOwner().

==================================================================
function testChangeOwnerOnOneFile() {
  var new_owner = 'XXXXXXXXXXXXXX';
  var fileId = "XXXXXXXXXXXXXXXXXX";
  var file = DriveApp.getFileById(fileId)
  var currentOwner = file.getOwner();
  
    if(DEBUG){
        console.info("Current file owner is: %s",currentOwner.getEmail());
    }
  
    if(currentOwner.getEmail() != new_owner ){
      if(DEBUG){
        console.info("Changing owner of current file from %s to %s",currentOwner.getEmail(),new_owner);
      }
      file.setOwner(new_owner);
    }
    else{
      if(DEBUG){
        console.info("Current file owner is correct. Nothing to do!!!");
      }
    }
}
==================================================================
i replaced the id and email for security reason....

my appscript.json contain :

{
  "timeZone": "America/New_York",
  "dependencies": {
    "enabledAdvancedServices": [{
      "userSymbol": "Drive",
      "serviceId": "drive",
      "version": "v2"
    }]
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

and also the file that i try to change the owner contain the account that run the script as EDITOR.

I'm assuming that i miss something, but didn't yet.

Any help ?

Clay Smith

unread,
Aug 10, 2021, 10:45:44 AM8/10/21
to google-apps-sc...@googlegroups.com
Hi David, 
I think what you may be encountering is that only a file owner can change ownership. Your users are placing the file into a shared folder. They retain the ownership for the file. You are wanting your code to change the ownership but it's running as your generic user. Only the owner of the file would be able to transfer the ownership. 

This is where Shared Drives come in. If the files are in a shared drive they are owned by the organization. you don't have to worry about the ownership change. 

If you are looking to pursue this regardless you'll need to run the ownership change request as the user who owns the file. Best way is by using a server-server oauth process to get a token and making a REST call to the drive api to change the owner. It's a complex setup but works well once in place. Let me know if you need further assistance. 

Clay

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-apps-script-community/bc42ed4f-9dbb-4e08-aaf2-e66efd1647cbn%40googlegroups.com.


--


David Poulin

unread,
Aug 10, 2021, 10:49:50 AM8/10/21
to Google Apps Script Community
Hi,

thank for the fast answer.

As i'm a begginer with app script...i would appreciate if you have some example or additionnal details about "server-server oauth process to get a token and making a REST call to the drive api to change the owner."

is it related to domain-wide authority ? service account ?.....

Thank

Clay Smith

unread,
Aug 10, 2021, 11:02:10 AM8/10/21
to google-apps-sc...@googlegroups.com
I believe Bruce McPherson has a library which can help with the oAuth token. I've written my own but his work is quite robust with lots of documentation for a beginner. 

But yes, delegated domain-wide authority through a GCP project and Google Admin console setup. You'll get a token for the user on your domain who owns the file then use a UrlFetch.fetch(url, options) to make the call to change ownership. 

Bruce's site:


Clay Smith

unread,
Aug 10, 2021, 11:09:31 AM8/10/21
to google-apps-sc...@googlegroups.com
Throwing in this Stackoverflow which has some other pointers. https://stackoverflow.com/questions/12249232/google-drive-api-change-ownership-of-files

David Poulin

unread,
Aug 10, 2021, 11:43:36 AM8/10/21
to Google Apps Script Community
Hi Clay,

so if i try to summarize step to do :

  1. Create GCP project including enabling api and get credentials (like Bruce tutorial)
  2. In the app script
    1. Do the oneoff script part using service account to deploy the package ??
    2. Refer to the library
  3. Make call using api url
Here my question :

  • Is this really as short as that ?
  • Why the fetch method instead of advanced service like DriveApp ?
  • What about security using that library ?

Thank in advance for all your help and comments

Clay Smith

unread,
Aug 10, 2021, 12:12:52 PM8/10/21
to google-apps-sc...@googlegroups.com
  • Is this really as short as that ? 
It can be. I'll have time in a few hours and can throw together some code for you. 

  • Why the fetch method instead of advanced service like DriveApp ?
The advance service won't allow you to change the authenticated user form the user account you are running from. I assume you want this to be seamless and all your user needs to do is drop it in the folder and it's taken care of. Otherwise you could have a user run a script each time they take the action. 

  • What about security using that library ?
Libraries run on your project. You're basically borrowing the code. I'll throw some raw code together for you to use for transparency. 


Clay

Clay Smith

unread,
Aug 10, 2021, 3:23:27 PM8/10/21
to google-apps-sc...@googlegroups.com

David Poulin

unread,
Aug 10, 2021, 4:01:06 PM8/10/21
to Google Apps Script Community
Hi Clay,

That really make sense, some stuff i need to learn on my own about claim but i understand the whole concept.

Do am i right if i tell :

  • You get token for each owner so you can impersonate the owner to change it ?
  • By usinig 'PATCH' you don't to provide all properties (as other google api call)
  • Not sure to understand this line : "const permission= permissions.items.filter(perm=>perm.emailAddress.toLowerCase()==newOwner.toLowerCase())[0]"
    • to find a permission for the new owner, it need to be already there no ?
    • What if not the case ?

Also, i want to ask you permission to use your example to based our script on if it okay with you ?

Clay Smith

unread,
Aug 10, 2021, 5:12:29 PM8/10/21
to google-apps-sc...@googlegroups.com
Yes, code is available for you and all in this group. 

  • You get token for each owner so you can impersonate the owner to change it ?
Exactly. 

  • By usinig 'PATCH' you don't to provide all properties (as other google api call)
You got it. 
  • Not sure to understand this line : "const permission= permissions.items.filter(perm=>perm.emailAddress.toLowerCase()==newOwner.toLowerCase())[0]"
    • to find a permission for the new owner, it need to be already there no ? 
  • Correct. the new owner must already be associated to the file. So we get the permissions and identify the permission id. Each user actually has their own permission id.
    • What if not the case ?
    If the user is not permissioned for the file they can be added as an editor. In your case the assumption is that the drive file was added to a shared folder which inherently adds the permission to the file. 

    Clay


    David Poulin

    unread,
    Aug 11, 2021, 8:11:29 AM8/11/21
    to Google Apps Script Community
    Hi Clay,

    the scenario will be mainly this 2 :
    • Employee will move their documentation from their drive or other location to the final destination
    • Employee create documentation directly in the destination folder.

    So in that case we will need to check if the new owner already in the permission as editor or other roles, before trying to setowner....

    Also, what about notification ?....
    • For the new owner
    • For the user added as editor prior to set it as owner
    • For user removed from permission 
    I see in the api documentation, that for the create permission operation we can set a properties to false for notification email....but doesn't seem to be avaiable for the update call..

    Thank in advance, all your help is really appreciate

    Message has been deleted

    Clay Smith

    unread,
    Aug 11, 2021, 9:12:39 AM8/11/21
    to google-apps-sc...@googlegroups.com
    The Root My Drive is only accessible in totality by the Google Workspace account logged in. To access a file the user would need to have permission to access assigned. If you are trying to access a file for which you have an ID but no permission you get the exception response. 

    Placing the file in a folder created in the My Drive with permissions already set will transfer the permissions on move of the file into the folder. 

    Hope that clarifies. 

    Clay

    On Wed, Aug 11, 2021 at 9:05 AM David Poulin <david....@groupecanam.com> wrote:
    Also, do am i right if i tell that the app script will have to be run by an account that have already some kind of access ?

    Doing some test this morning and get exception for this line : 

      var file = DriveApp.getFileById(fileId);

    giving this 

    "Exception: No item with the given ID could be found. Possibly because you have not edited this item or you do not have permission to access it."


    The account used to run the script doesn't have any access to the test file...so that sound the problem.

    If the shared root folder have a permission structure with specific groups/account, all file move to the root or subfolder should get the permission structure right ?

    David Poulin

    unread,
    Aug 11, 2021, 9:18:32 AM8/11/21
    to Google Apps Script Community
    Do i assume correctly by telling that if i move one of my file to the shared folder (final destination), it will also inherit from the permission/access from the shared folder ?

    Example
    • My file is shared with me and User A
    • Shared folder is shared with User B, group C and D

    When a move my file to the shared folder, the permission will be merged , no?
    • After the move, the file will be shared with : user A, User B, group C and D

    And all subfolder will work the same way, no ?

    So i need to run my script with a user account that have access to everything in the shared folder or will have using the inheritance....

    Does my understand is correct ?

    Clay Smith

    unread,
    Aug 11, 2021, 10:31:42 AM8/11/21
    to google-apps-sc...@googlegroups.com
    • Do i assume correctly by telling that if i move one of my file to the shared folder (final destination), it will also inherit from the permission/access from the shared folder ?
    This is correct. Your example is correct if you are the one moving the file to the shared folder. 
    And yes, sub folders will also create the same experience. 

    The user moving the file into the folder would have edit access to the folder. 

    User A moves a file into a folder shared with edit rights to User A, B, C, D, and Generic User which runs the code.
    After the move User A B C D and Generic User have edit access to the file owned by User A. 
    Code runs to change the ownership to Generic User. 
    Limitation will be based on how many emails can be sent by the user according the the Mail quota (1500/day) since every ownership change requires an email to be sent and is associated to the quota. 

    Clay


    David Poulin

    unread,
    Aug 11, 2021, 10:42:28 AM8/11/21
    to Google Apps Script Community

    In summary a notification email is sent :
    • For the owner change = Yes to the new owner ( Is there a way to disable the notification email ?)
    • For the user added as editor prior to set it as owner = No with " sendNotificationEmail =false"
    • For user removed from permission  ??? (i assume no notification based on manual operation in google drive gui...but not sure)

    In our case, the new owner will always be a generic account (not an employee account), so email won't be a big deal, but if it possible to disable a much a we can....

    Clay Smith

    unread,
    Aug 11, 2021, 10:51:02 AM8/11/21
    to google-apps-sc...@googlegroups.com
    The ownership email is a mandatory requirement for security reasons. 
    Any other permission change the email notification can be set to false. 


    Clay

    David Poulin

    unread,
    Aug 11, 2021, 4:14:41 PM8/11/21
    to Google Apps Script Community
    Thank for all your help, informations and clarification.

    I really appreciate!!!

    I'm glad to have found this wonderful community!

    David Poulin

    unread,
    Aug 12, 2021, 8:47:51 AM8/12/21
    to Google Apps Script Community
    Hi, me again :(

    i think i miss something to fully understand and be able to advance on my script.

    I did some test this morning and i receive exception like these : 

    "Exception: Request failed for https://www.googleapis.com returned code 401. Truncated server response: { "error": "unauthorized_client", "error_description": "Client is unauthorized to retrieve access tokens using this method, or client not autho... (use muteHttpExceptions option to examine full response)"

    This exception happen in the oAuthToken(user) function that you have provided. The only thing i changed is add try catch... :)

    Here the steps :

    1) I create file in the shared folder (so i'm the owner)
    2) I want to change the owner to the generic account (let's say userB)
    3) When the code run and try to get the token, it use my email address as i'm the owner
    4) Bang!! receive the exception

    From what you telling before, we use the current Owner of the file/folder to get a token and make an api call by impersonation......Am i wrong ?

    Also the generic account, that we want to change owner to, is already editor of the file....so it should not be missing permission...in that scenario...

    What i'm doing wrong ?

    Clay Smith

    unread,
    Aug 12, 2021, 8:54:53 AM8/12/21
    to google-apps-sc...@googlegroups.com
    Hey, the referenced error is related to your GCP project and the setup of the domain wide delegation on the admin console. I suspect you have the domain wide checked off in the GCP project. But have you placed the scopes and the client ID on the admin console under the security APIs? Take a look at this article: https://support.google.com/a/answer/162106?hl=en

    Let me know if this helps. Note that it can take up to 24 hours for this setting to propagate. 

    Clay



    David Poulin

    unread,
    Aug 12, 2021, 9:05:44 AM8/12/21
    to Google Apps Script Community
    Hi,

    just to be sure, because i'm begginer on that

     I suspect you have the domain wide checked off in the GCP project

    Do you refer to the service account that my admin have create for me and that we use in the credentials variable (in your code example) ?

    But have you placed the scopes and the client ID on the admin console under the security APIs? 

    Do you refer to the step in google workspace that the admin need to add the service account client id with the scopes needed, so that bypass the user consent and be able to access all user data with the service account impersonate all users

    I will double check with my google admin to be sure

    Clay Smith

    unread,
    Aug 12, 2021, 9:18:04 AM8/12/21
    to google-apps-sc...@googlegroups.com
    Correct on both counts. Below is a sample of the service account with the Domain-wide Delegation checked off. 

    Screen Shot 2021-08-12 at 9.13.58 AM.png

    David Poulin

    unread,
    Aug 12, 2021, 10:40:14 AM8/12/21
    to Google Apps Script Community
    Hi,

    after double check with my admin, there problem on google workspace side...after he fix it..i was able to go further.

    After some test i found these correction based on your code

    1. Need to add the "      contentType : 'application/json'," to the options otherwise exception pop
    2. Cannot user emailAdress in the payload in the update option...
      
        const oAuth = oAuthToken(currentOwner).access_token
        const head = { Authorization: 'Bearer ' + oAuth }
        const options = {
          method: 'PATCH',
          headers: head,
          contentType : 'application/json',
          payload: JSON.stringify({
            role: 'owner'
          }),
          muteHttpExceptions: true
        };

    i will continue my tests for multiple scenario and will get back if a found other thing

    David Poulin

    unread,
    Aug 13, 2021, 8:43:42 AM8/13/21
    to Google Apps Script Community
    Hi,

    when we use line like " const permissions =Drive.Permissions.list(fileId)" ...

    Am i right to say that if the user running the script is not at least editor, the permission retuned will be undefined ??? (example : user is viewer or commenter)

    So in that case, does the solution will be to make another api call impersonating the owner and get the full list and filter it to get newowner permission.....or if there is some shotcut ??

    thank
    --
    David Poulin
    Administrateur de systèmes / Systems administrator
    Groupe Canam / Canam Group
    T ‪438 940-9339‬

    Clay Smith

    unread,
    Aug 13, 2021, 8:48:20 AM8/13/21
    to google-apps-sc...@googlegroups.com

    >Am i right to say that if the user running the script is not at least editor, the permission retuned will be undefined ??? (example : user is viewer or commenter)

    That is correct. Only users with the Editor role can see the list of permissions. 

    >So in that case, does the solution will be to make another api call impersonating the owner and get the full list and filter it to get newowner permission.....or if there is some shotcut ??

    You can do this. The process you had described required your user to place a file in a folder. This action would require the user to have edit rights to the folder and would transfer the permissions set on the folder to the files placed in it. 


    David Poulin

    unread,
    Aug 13, 2021, 8:57:55 AM8/13/21
    to Google Apps Script Community

    Normally employee that will transfer or wirte their documentation into the shared folder, will have editor access. BUT in my tests scenarios i wanted to do all acess roles possibility....so if in the future their is some change...my code will already take care

    Thank

    David Poulin

    unread,
    Aug 16, 2021, 9:44:05 AM8/16/21
    to Google Apps Script Community
    Hi,

    based on the context for the script i try to complete, use will mainly do 2 things :
    1. Create new documents directly in the shared folder or in one of it subfolder
    2. Move documents/folders from other locations (their drive or other drives)

    From what i understand, both option will have as result that the new documents (moved or created) will inherit from the permission structure. As the generic account used to run the script is the owner of the root folder where user will move/create document....I can assume that everytime i will run the script, the generci account will be editor, except if some user change permission and remove the generic account (that should not happen a 99% of the time). So normally i should not care about what happen if the generic account have no access.......BUT as i want to learn more....i want to do some test...

    Let's try this :
    • User A run the script
    • User A have no access to the file A (with fileid=abcdefg.....)
    • When the script run with authority of User A :
      • Code line like "DriveApp.getFileById(fileId);" will give  exception
      • Code line like "Drive.permissions.list(fileId) " will give exception
      • So we can't get owner.....
    • if we use the api call to get all permission
      • How can we impersonate the owner if we cannot get it ???

    Thank in advance


    Reply all
    Reply to author
    Forward
    0 new messages