The service account of Google Service Account wide delegation defines the service account by using the JSON key file instead of p12

advertisements

I'm able to use a Google Service account with domain wide delegation using the .p12 key file just fine.

I'd like to use the JSON key file instead of the p12 file, but I can't figure out how to set the service account id when using the JSON key.

How do you set the set the user to impersonate using the JSON key file?

Works fine:

File p12File = new File(...);
GoogleCredential.Builder b = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY).setServiceAccountId(properties.getServiceAccountId())
                  .setServiceAccountPrivateKey(SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(),
                      new FileInputStream(p12File), "notasecret",
                      "privatekey", "notasecret"))
                  .setServiceAccountScopes(GOOGLE_SCOPE_LIST);
              if (properties.getServiceAccountEmail() != null) {
                b = b.setServiceAccountUser(properties.getServiceAccountEmail());
              }
              credential = b.build();

Does not work:

String jsonKeyContents = "{\n" +
            "  \"type\": \"service_account\",\n" +
            "  \"project_id\": \"sxxxxxxx0\",\n" +
            "  \"private_key_id\": \"csxxxxxxxxxxxxxxxx\",\n" +
            "  \"private_key\": \"-----BEGIN PRIVATE " +
            "KEY-----\\nMIIxxxxxxxxxxsTbwzsbw" +
            "==\\n-----END PRIVATE KEY-----\\n\",\n" +
            "  \"client_email\": \"[email protected]\",\n" +
            "  \"client_id\": \"1111111111111111111\",\n" +
            "  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n" +
            "  \"token_uri\": \"https://accounts.google.com/o/oauth2/token\",\n" +
            "  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n" +
            "  \"client_x509_cert_url\": \"https://www.googleapis" +
            ".com/robot/v1/metadata/x509/xxxxx%40xxxxxx-xxxxx-123456.iam.gserviceaccount.com\"\n" +
            "}";
try (InputStream privateKeyInputStream = new ByteArrayInputStream(jsonKeyContents
          .getBytes("UTF-8") )) {
        credential = GoogleCredential.fromStream(privateKeyInputStream).createScoped(GOOGLE_SCOPE_LIST);
}

When using the JSON key to use Directory API to list all Enterprise users, I get an error message:

Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 404 Not Found
{
  "code" : 404,
  "errors" : [ {
    "domain" : "global",
    "message" : "Domain not found.",
    "reason" : "notFound"
  } ],
  "message" : "Domain not found."
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
...

All the issues seem to relate to the fact that there is no place to put the service account email.

What am I missing here? Is there someone with a working example they can share some code for?


After all that, I found the answer myself.

See https://github.com/google/google-api-java-client/issues/1007#issuecomment-264157989

To fix it:

  1. Create a GoogleCredential credentialFromJson using the JSON key as specified above. I.e. credential = GoogleCredential.fromStream(privateKeyInputStream).createScoped(GOOGLE_SCOPE_LIST)

  2. Create a builder using the code where we used P12 but instead of creating a Private key from p12 file... use this line: .setServiceAccountPrivateKey(credentialFromJson.getServiceAccountPrivateKey())

Now it works! \m/