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 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.
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’.
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.
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.
Inside of Security we need to go into the Advanced Settings (located by clicking Show more) and then the “Manage API client access” section.
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.
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
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!
Hey Mike. Thanks for figuring all of this stuff out. I do find this post really helpful so thanks for sharing.
You’re welcome Mr Colleague!
Great write up. It is amazing how little information there is on how to use this stuff. I am trying to modify this to use the ReportsService instead. Do you know of any examples to be had online?
Google needs to hire you! Thanks for helping me finally figure this out after days of running around in circles.
Hi Mike – thanks so much for this post. It’s the only working example that I’ve been able to find for accessing the Directory API. It’s hard to believe that Google released this API with so little support… I have no idea how you managed to figure out how to use the .NET class library without so much as a quickstart sample.
I’m trying to migrate a couple of calls from the old API to the new API, but I’m hitting a problem with figuring out to provide credentials for different domains, without creating a Service Account for every domain. Do you have any suggestions?
I wrote up my problem in detail here: http://stackoverflow.com/questions/28375098/google-admin-sdk-directory-api-getting-groups-from-varying-domains
I owe you a beer… this is a great and concise article, I agree this is the only working example out there, thanks a lot for sharing
i tried it out, but my code can’t update the user information. 🙁
Mike, this was excellent! Google could learn from you. When you are done with Victor’s beer I have one for you too. Thanks.
Thanks Rob…. I’m glad it helped…
Although I mainly blog about virtualization and VMware type technologies I found there was a gaping hole on this topic, and it’s something I needed to get done so I thought why not share….
Let’s get together for those beers soon 🙂
Hi, first off Thanks for this great code. It saves us all a tremendous amount of time!
Unfortunately, I did encounter an error on this line:
User user = dirservice.Users.Get(“email”).Execute();
‘Google.Apis.Auth.OAuth2.Responses.TokenResponseException:
Error:”invalid_grant”, Description:””, Uri:””
Any ideas as to what might be the problem?
Thx!
I’ve never ran into this but a couple of things to check..
Certainly the service account credentials – make sure you have copied and pasted the proper account information – email needs to end in @developer.google…..
Also, path to and correct p12 key…
Hopefully you figure this out….
Seriously amazing post. Thanks for taking the time to write it up!
Hi thanks that’s a great article. We’re adding the ability to provision Google accounts using our automation tool
http://www.centrel-solutions.com/XIAAutomation/features.aspx
What I don’t understand is why it’s so complicated. To create Office 365
accounts you can just use PowerShell to logon using your Admin
credentials none of this extra setup.
Also I don’t understand the point of the developer console, surely if anyone creates an application for resale and the user grants access to that application they have access to all accounts in the Google domain, without needing any domain level credentials?
Thanks!
Dave