Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I impersonate a user of AppEngine java application operating in G-Suite domain?

My standard AppEngine application needs to perform changes in a Google Sheet documents (among others).

To achieve this, I need to obtain a credential for service account, and somehow configure that it should act in behalf of a user.

This method allows gives me default service account credentials:

private static GoogleCredential getDefaultServiceAccountCredential() throws IOException {
    return GoogleCredential.getApplicationDefault()
        .createScoped(MY_SCOPES);
}

but it does not work in behalf of a user.

Following code is similar, uses other (non-default) service account, but still no impersonation happens:

private static GoogleCredential getNonDefaultServiceAccountCredential() throws IOException {
    return GoogleCredential.fromStream(IncomingMailHandlerServlet.class.getResourceAsStream("/tokens/anoher-e6351a8c5b91.json"))
        .createScoped(MY_SCOPES);
}

For impersonation, Google Docs (and many SO advices) mentions how to do it with use of PKCS12 file; however, that file can only be read as PrivateKey on installed application and not on AppEngine.

Is there any way to obtain impersonated credential for java application running in AppEngine? Or, is there a trick to read from a File on AppEngine?

Note that, for all service accounts that I tried, I configured them with role Owner and with DwD (Domain-wide delegation). Is there anything else to configure?

like image 240
Petr Kozelka Avatar asked Mar 17 '18 19:03

Petr Kozelka


1 Answers

The GoogleCredential reference offers a sample to

also use the service account flow to impersonate a user in a domain that you own. This is very similar to the service account flow above, but you additionally call GoogleCredential.Builder.setServiceAccountUser(String)

 public static GoogleCredential createCredentialForServiceAccountImpersonateUser(
      HttpTransport transport,
      JsonFactory jsonFactory,
      String serviceAccountId,
      Collection<String> serviceAccountScopes,
      File p12File,
      String serviceAccountUser) throws GeneralSecurityException, IOException {
    return new GoogleCredential.Builder().setTransport(transport)
        .setJsonFactory(jsonFactory)
        .setServiceAccountId(serviceAccountId)
        .setServiceAccountScopes(serviceAccountScopes)
        .setServiceAccountPrivateKeyFromP12File(p12File)
        .setServiceAccountUser(serviceAccountUser)
        .build();
  }

There are multiple options on how to access a file from App Engine Standard. Below, you have two options explained:


Option 1: the p12File (credentials file) is an App Engine Standard resource file. Check this answer to see how to access such files, code-wise. I strongly recommend this approach because

These files are only available to your code on a read-only basis and not for traffic serving.

File f = new File("path/below/my/project/directory/credentials.json");

and the appengine-web.xml should define the resource files:

<resource-files>
  <include path="path/below/my/project/directory/credentials.json"/>
</resource-files>


Option 2: the credentials file is in Cloud Storage. This document explains how to reach files in Cloud Storage from App Engine Standard. But I believe it's too much of a hassle. I provided this option as well because I have mentioned it.
like image 183
Tudormi Avatar answered Nov 17 '22 21:11

Tudormi