0

I'm attempting to migrate our code for using the (soon to be deprecated) Google Provisioning API to the Admin SDK Directory API, via the .NET client libraries provided by Google.

In the old Provisioning API (via the .NET client library) a call to get the groups for a domain was very simple:

Google.GData.Apps.AppsService apps = new Google.GData.Apps.AppsService(AppDomain, DomainAdminEmail, AdminPassword);
Google.GData.Apps.Groups.GroupsService service = apps.Groups;
AppsExtendedFeed appsFeed = service.RetrieveAllGroups();

Not exactly rocket science, and the only credentials required were the domain, the domain's admin email, and the admin password. As long as you can supply those three parameters, you can get the groups for any domain.

I've been trying for two days to create an equivalent call using the new Admin SDK Directory API (via the new .NET client library), and it's giving me a very hard time. The only way that I've been able to get it to work at all is to create a Service Account for the project associated with the domain's admin email, including generation of a private key file, based on a useful post by mwpreston):

//Create security certificate using private key file and password.
var certificate = new X509Certificate2(pathToPrivateKeyFile, privateKeyPassword, X509KeyStorageFlags.Exportable);

//Create a service credential using the certificate, admin email and API scopes.
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
    User = adminUserEmail,
    Scopes = scopes
}.FromCertificate(certificate));

//Create Directory Service using the service credential and the application name.
var dirservice = new DirectoryService(new BaseClientService.Initializer()
{
    HttpClientInitializer = credential,
    ApplicationName = applicationName
 });

 var groupsListRequest = dirservice.Groups.List();
 groupsListRequest.Domain = domain;
 domainGroups = groupsListRequest.Execute();

However, because the Service Account is associated with a specific domain (as specified in the admin email account for the Service Account) it can only be used to request groups from that specific domain.

We have clients with thousands of different domains. It's impractical to create a new Service Account for every client's domain (as well as a private key file).

I've searched and searched for a way to call the DirectoryService in a way that uses the same parameters (domain, admin email and password) but I can't find anything. The documentation for the Admin API .NET client library is extremely sparse and is of no help.

The Provisioning API will be deprecated on April 20th 2015, so someone else there must have been faced with this issue. Can anyone help?

2 Answers2

0

You should use "impersonate" (via .setServiceAccountUser("user@example.com")) while constructing credential. Look for examples here.

user3686724
  • 603
  • 1
  • 5
  • 15
  • Unfortunately that won't solve my problem. I need to be able to request groups (and members of groups) from many _different_ domains. The original API allowed me to make the call using a domain, admin email, and password; the new API seems to insist that I use a specific Service Account for each domain. That's impractical because our clients have thousands of domains. – Lost on the Net Feb 08 '15 at 16:45
  • Maybe I just don't understand your problem, but in my applications I also access directory information for different domains with one service account by constructing just credential object (which is still same except for serviceAccountUser - target domain admin) which is then passed to directory api constructor/builder as you can see in following code... – user3686724 Feb 08 '15 at 22:49
  • GoogleCredential.Builder bgc = new GoogleCredential.Builder() .setTransport(t) .setJsonFactory(jsonFactory) .setServiceAccountScopes(scopes) .setServiceAccountPrivateKey(serviceAccountPrivateKey) .setServiceAccountId(Config.SERVICE_ACCOUNT_ID) .setServiceAccountUser(serviceAccountUser); Directory dir = new Directory.Builder(gc.getTransport(), gc.getJsonFactory(), null).setHttpRequestInitializer(gc).build(); – user3686724 Feb 08 '15 at 22:49
  • Thanks for the feedback - it looks like you're using the Java client library, while I have to use the .NET client library. However, you have given me some very useful leads on what to try to replicate using .NET. I'll dig into the code tomorrow and see if I can do with .NET what you're doing in Java. I'll report back tomorrow. – Lost on the Net Feb 09 '15 at 00:39
  • Hi @user3686724 - I can't find any way to request data when the user's domain does not match the domain of the Service Account administrator. I see that it's possible on the Google Admin Console to associate more than one domain with an account (Google Admin Console -> Domains -> Add a domain or a domain alias). Is that how your account is set up? Perhaps that's why you are able to request data from more than one domain via your Service Account? – Lost on the Net Feb 09 '15 at 16:32
  • Domain of service account administrator? In google developers project console I only see clientId, email address which are both something + gserviceaccount.com (and cert fingerprint) so there is no target domain and no need of google admin console. You just build credential based on scopes, private key associated with that service account, account id (=service account email address) and impersonated service account user, which is target domain administrator. – user3686724 Feb 09 '15 at 16:46
  • Hi @user3686724 - When I try to set the impersonated service account user to the email address of an administrator account on the target domain, I get an error message: Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:"" Am I mean to use the email address of an admin user on the target domain, or the Email Address of the target domain Service Account (which looks like gibberish69gibberish69gibberish69@developer.gserviceaccount.com)? – Lost on the Net Feb 09 '15 at 19:29
  • Administrator of target domain (should be the one who authorized requested scopes). – user3686724 Feb 09 '15 at 22:19
0

You can create a project on Google Developer Console and generate a refresh/access token instead. Here's the link - https://developers.google.com/accounts/docs/OAuth2WebServer

I haven't used the client library hence can't help you with the code. You can use the 'list' API which will give you all the groups for all domains of a customer (if you provide the customerId) - https://developers.google.com/admin-sdk/directory/v1/reference/groups/list

Sayali
  • 356
  • 1
  • 2
  • 13