Thomas
Thomas

Reputation: 1354

Update Google Group Subscription with Google App Engine application

I'm building a small app on Google App Engine(PHP) that aim at synchronising an external source with a google group to have an up to date mailing list. (it should run as a GAE cron task)

The Google App Engine project and the google group are inside a GSuite domain.

The sources are here, See firestore2ggroup.php

The issue that I'm having is security related, when I try to call an API, I get a 403 error with no other details.

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "forbidden",
    "message": "Not Authorized to access this resource/api"
   }
  ],
  "code": 403,
  "message": "Not Authorized to access this resource/api"
 }
}

I've followed the steps described here as a start point as it was close to my need:

https://medium.com/@Skaaptjop/access-gsuite-apis-on-your-domain-using-a-service-account-e2a8dbda287c

So I did the following :

update: I've even tried to add more rights, but it still doesn't work:

enter image description here

In my project, I've copied the JSON private key and I've set in app.yaml the variable GOOGLE_APPLICATION_CREDENTIALS with the name of the file.

I used this Google lib to access the Google group:

composer require google/apiclient:^2.0

try
{
  $client = new Google_Client();
  $client->setApplicationName('Pegass2GGroup');
  $client->setScopes(
    [
      Google_Service_Directory::ADMIN_DIRECTORY_GROUP,
      Google_Service_Directory::ADMIN_DIRECTORY_GROUP_MEMBER,
      Google_Service_Directory::ADMIN_DIRECTORY_USER
    ]);
  $client->useApplicationDefaultCredentials(true);
  $access_token = $client->fetchAccessTokenWithAssertion();

  print_r($access_token);

  $service = new Google_Service_Directory($client);

  /** @var $members  Google_Service_Directory_Members */
  $members = $service->members->listMembers($MAILING_LIST);

  /** @var $member  Google_Service_Directory_Member */
  foreach ($members as $member)
  {
    print_r($member->getEmail());
  }
  echo "</pre>";
}
catch(Exception $e)
{
  print_r($e);
  echo "</pre>";
}

I can tell the private key is loaded, because the print_r($e) gives a long exception and the key is listed.

print_r($access_token); gives the following:

Array
(
    [access_token] => dag2qssffdVpRZEr...0BsM_QUgQ
    [expires_in] => 3599
    [token_type] => Bearer
    [created] => 1586787451
)

$MAILING_LIST : is the full email address of the mailing list

Upvotes: 3

Views: 122

Answers (1)

Thomas
Thomas

Reputation: 1354

So the code above was missing the impersonation.

$client->setSubject($EMAIL_TO_IMPERSONATE); //[email protected]

to act as this email when touching data of other members of the domain.

Then I got this error :

(
    [errors:protected] => 
    [message:protected] => {
  "error": "unauthorized_client",
  "error_description": "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested."
}

It was because I was requesting :

  Google_Service_Directory::ADMIN_DIRECTORY_GROUP,
  Google_Service_Directory::ADMIN_DIRECTORY_GROUP_MEMBER,
  Google_Service_Directory::ADMIN_DIRECTORY_USER

but I forgot to add in GSuite API Security Management the following :

  Google_Service_Directory::ADMIN_DIRECTORY_USER

after adding it, it worked. So if you request a set of role, all must be granted. Even If I didn't use Google_Service_Directory::ADMIN_DIRECTORY_USER, the fact that I ask it at connection time and one of it is not granted, block the whole connection.

I think I only need Google_Service_Directory::ADMIN_DIRECTORY_GROUP_MEMBER

So far my working scope to just list the members of a group was :

184920....0484899 (the client id)

https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.group.member,https://www.googleapis.com/auth/apps.groups.settings,https://www.googleapis.com/auth/groups,https://www.googleapis.com/auth/admin.directory.user

Upvotes: 0

Related Questions