I know weird right?  Coding, Google API’s, WTF!?!?  This is a virtualization blog.  Truth is I was a developer before ever moving into the infrastructure space, not much of one, but I was one Smile  Honestly, this is probably the reason why products like vRealize Orchestrator ( More weirdness calling vCO that) that mix both development and infrastructure together appeal to me so much!  More truth – as much as I try I can’t quite get away from development – it’s a part of what I do ( I guess ).

Anyways, cut to the chase – I’ve been recently working on a project revolving around integrating Google Apps with a homegrown .net application I’ve written.  Now, there is such a thing called the provisioning API, which is super easy to use and worked great – but is depreciated and Google could simply stop providing it whenever they want.  Google suggests people move to the Admin SDK – which, of course, is much harder!  Either way, I needed to provide a way for users to reset other users Google Apps passwords from within a .net application, without those users having to provide access or permission to their accounts. My Google-Fu was strong on this one, and by the time I finally got it to work I had about 27 tabs open, therefore I thought it might be nice for the next person to maybe stumble upon one page containing all the info they need to make this happen – therefore – this!

To the developers console

The first step to getting everything to mesh with the Admin SDK involves setting up a project in the Google Developers Console.  Simply log in and select ‘New Project’ and give your project a name and an id.  Easy enough thus far.  Once the project has been created we need to enable the Google Admin SDK.  Select APIs from the APIs & auth section on the navigational menu on the left.  Here, we can simply filter our list of available APIs by inputting ‘Admin SDK’ in the browse box and then enable it by switching its status to On.

EnableAdminSDK

From here we need to create a client ID containing the p12 key and credentials that we need in order to delegate access to.  As mentioned earlier, I’ve decided to go about this via the ‘Service Account’ route as I would like to have an account that I can delegate domain wide admin access to in order to change passwords, create users, etc, and doing this without authorization or permission from the users themselves.  To do click the ‘Create new Client ID’ button inside of the Credentials section of API’s & auth.  When presented with the ‘Application Type’ dialog, select Service account and click ‘Create Client ID’.

CreateServiceAccount

Once the process has completed pay attention to the .p12 key that is automatically downloaded.  We will need this file later when connecting our .net application so go and store it somewhere safe.  Also note the private keys password in the dialog as we will also need this information.

privatekeydownloadpassword

At this point you should see your newly created service account, it’s Client ID, Email Address, and Public Key Fingerprints.  The only piece of information that we need off of this screen is the Client ID – usually a big long string ending in googleusercontent.com.  Go ahead and copy that to your clipboard as we will need it for the next step.

To the Admin Console

From here we need to go to our Google Apps admin console (admin.google.com/your_domain_name and grant this newly created security account access to specific APIs.  Once logged into the admin console, launch the security app (sometimes located in the ‘More Controls’ link near the bottom.

adminconsole-security

Inside of Security we need to go into the Advanced Settings (located by clicking Show more) and then the “Manage API client access” section.

advancedsettings

Now we need to grant our service account access to specific APIs within Google by specifying the individual URLs of the API.  First, paste your Client ID that we created and copied into the Client Name box.  Secondly, copy in all of the API urls (comma separated) that you want to grant access to.  In my case I’m only looking for User and Group Management so I entered https://www.googleapis.com/auth/admin.directory.group, https://www.googleapis.com/auth/admin.directory.user into the API Scope input box.  If you need help figuring out the url for the specific API you are looking for you can find them listed in the Authorize Request section in the developer guide for each Google API.  Once you are ready to go as shown below, click Authorize.

authorizeAPIAccess

And now the code

Thus far we’ve done all the heavy lifting as it pertains to opening up the access for .net to utilize our Admin SDK APIs – time to get into a little code!  Again, I don’t consider myself a hardcore developer, as you can probably tell from my code.  There may be better ways to do this but this is the way I found that worked, and again, not a lot of information out there on how to do this.

First up there are some project references that you need to use.  Honestly, you can get the .net client libraries from Google but the easiest way to bring packages in is by using NuGet as it will pull dependencies down for you.  Go ahead and import the Google APIs Client Library, Google APIs Auth Client Library, Google APIs Core Client Libary, and Google.Apis.Admin.Directory.directory_vi Client Library.  That should be all you need to do the password resets.

So the complete script is listed at the bottom, but for “learning” sake, I’ll break down what I’ve done in the sections to follow.

1
2
String serviceAccountEmail = "350639441533-ss6ssn8r13dg4ahkt20asdfasdf1k0084@developer.gserviceaccount.com";
var certificate = new X509Certificate2(@"c:\p12key\NewProject-3851a658ac16.p12", "notasecret", X509KeyStorageFlags.Exportable);

Here I’m simply declaring some variables; first, the serviceAccountEmail – this is the email (not the ID) of the Service Account we have setup – secondly, our certificate, which is generated by pointing the constructor to the p12 key we generated (remember) and the key password that was displayed (remember).

1
2
3
4
5
6
7
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User="myadminaccount@mwpreston.net",
 
Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser }
}.FromCertificate(certificate));

This line essentially builds the credential object we need in order to instantiate the service we want to perform.    Take special note here I have to pass a user parameter – this is the user that we want our service account to impersonate (they will need to be have correct roles/permissions in Google to perform any of the tasks we attempt).  Also, the Scopes array – this is specifying which exact API scopes we want to authenticate to – these will normally match the end of the API URL, just without decimals.  That said, we have auto-complete in Visual Studio right – use it Smile

1
2
3
4
5
var dirservice = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyNewProject",
});

Each and every API you call from Google inside of .net will need to be stored in a service variable.  This is where we instantiate a new DirectoryService (to access users).  If you were to use the Task Service this would be new TaskService.  No matter what we always use new BaseClientSerivce.Initializer in our constructor.  Note we also pass in our created credential object, as well as the name of our project we created in Google Developer Console.

1
2
3
4
5
User user = dirservice.Users.Get("testuser@mwpreston.net").Execute();
Console.WriteLine(" email: " + user.PrimaryEmail);
Console.WriteLine(" last login: " + user.LastLoginTime);
user.Password = "MyNewPassword";
dirservice.Users.Update(user, "testuser@mwpreston.net").Execute();

And now the magic happens.  Honestly this will be different depending on what API you are using but again we have built-in help and auto-complete in Visual Studio so you should be able to figure out how to do anything you need to.  Above I simply get a user, display a few of their parameters, change their password and then update the user.  Easy enough!

So here’s the code in its’ entirety.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
 
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Admin.Directory.directory_v1;
using Google.Apis.Admin.Directory.directory_v1.Data;
using Google.Apis.Admin.Directory;
 
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Connect to Google API");
Console.WriteLine("=====================");
 
String serviceAccountEmail = "350639441533-ss6ssn8r13dg4ahkt20ubasdf2424@developer.gserviceaccount.com";
var certificate = new X509Certificate2(@"c:\p12key\NewProject-3851a658ac16.p12", "notasecret", X509KeyStorageFlags.Exportable);
 
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User="MyAdminAccount@mwpreston.net",
 
Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser }
}.FromCertificate(certificate));
 
 
var dirservice = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyNewProject",
});
 
User user = dirservice.Users.Get("testuser@mwpreston.net").Execute();
Console.WriteLine(" email: " + user.PrimaryEmail);
Console.WriteLine(" last login: " + user.LastLoginTime);
user.Password = "MyNewPassword";
dirservice.Users.Update(user, "testuser@mwpreston.net").Execute();
 
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}

I know this post may be a little off topic with the rest of this blog but the fact of the matter is I couldn’t find a lot of information out there on how to accomplish changing Google Apps user passwords from .net.  And when I can’t find information I post it!  Hopefully someone will stumble across this and find it useful!  Thanks for reading!