Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Service Account domain wide delegation set service account using JSON key file instead of p12

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 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?

like image 519
Catfish Avatar asked Jan 19 '17 17:01

Catfish


2 Answers

Your JSON file must contain all the required key value pairs as

following key

{
"type": "service_account",
"project_id": "your project Id",
"private_key_id": "private key id",
"private_key": "Private key",
"client_email": "Client email ending with .iam.gserviceaccount.com",
"client_id": "client -id",
"auth_uri": "accounts.google.com/o/oauth2/auth",
"token_uri": "accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "www.googleapis.com/robot/v1/metadata/x509/?????
-170710.iam.gserviceaccount.com"
}

Then use the code below:

private GoogleCredential authorize1() {

    GoogleCredential credential = null;

    HttpTransport = GoogleNetHttpTransport.newTrustedTransport();

    JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

    try {

      InputStream jsonFileStream =
          DriveSample.class.getClassLoader().getResourceAsStream("client_secrets.json");

      GoogleCredential readJsonFile = GoogleCredential
          .fromStream(jsonFileStream, httpTransport, JSON_FACTORY).createScoped(DriveScopes.all());

      credential = new GoogleCredential.Builder().setTransport(readJsonFile.getTransport())
          .setJsonFactory(readJsonFile.getJsonFactory())
          .setServiceAccountId(readJsonFile.getServiceAccountId())
          .setServiceAccountScopes(readJsonFile.getServiceAccountScopes())
          .setServiceAccountPrivateKey(readJsonFile.getServiceAccountPrivateKey()).build();
    } catch (IOException exception) {
      exception.printStackTrace();
    }
    return credential;
}
like image 113
Sumit Kumar Avatar answered Nov 09 '22 00:11

Sumit Kumar


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/

like image 41
Nicholas DiPiazza Avatar answered Nov 08 '22 23:11

Nicholas DiPiazza