As you might already know, Google recently opened its Enterprise Marketplace - a centralized place for SaaS applications, integrated with GoogleApps. We at Comindwork integrated our service with GoogleApps long before the announcement, so, logically, we rushed to submit our service to the Marketplace, as it offered a powerful distribution channel.
However, to meet the requirements of Google Market, we should have implemented one more feature: login via Google's OpenID. This task proved to be tougher than we thought, so we decided to share its solution with fellow ASP.Net developers.
The trouble is that Google uses non-standard OpenID implementation. The only .Net OpenID library that supports Google's implementation is DotNetOpenAuth 3.4+
Here's how to make authentication work in a few simple steps:
1. Download DotNetOpenAuth 3.4 or later.
2. Set up a sample application named "OpenIdRelyingPartyWebForms". No need to open it in VS, just add it to IIS as a web site.
3. Modify sample's web.config
4. Run the sample, open loginGoogleApps.aspx, fill in the only form on the page with your Google apps domain and submit (if this doesn't work, try submitting your email instead of your domain, e.g. buru@bla.com instead of bla.com)
5. If the sample worked, copy loginGoogleApps.aspx and loginGoogleApps.aspx.cs to your application, modify it accordingly (for example, modify master page reference). Don't forget to modify your web.config if this page throws security exception. Also, don't forget to add DotNetOpenAuth.dll to your /bin directory.
6. Modify loginGoogleApps.aspx.cs Page_Load to handle the "domain" request param. Simple example:
protected void Page_Load(object sender, EventArgs e) {
if(Request["domain"] != null && Request["domain"] != String.Empty) {
this.OpenIdLoginBoxCtrl.Text = Request["domain"];
this.OpenIdLoginBoxCtrl.ReturnToUrl = Utility.BaseUrl + "loginGoogleApps.aspx";
OpenIdLoginBoxCtrl.LogOn();
}
}
7. Modify your application OpenIDTextBox handler to include your authentication logic. In the simplest case it will look like this:
protected void ProcessLoggedIn(object sender, OpenIdEventArgs e) {
string identity = e.Response.ClaimedIdentifier;
var sreg = e.Response.GetExtension<claimsresponse>();
// the association between your internal account and Google Apps account
IExternalSourceInfo externalSourceInfo = GetExternalSourceInfo("OpenID",identity);
if (!externalSourceInfo.Exists || !InternalAccountExists(externalSourceInfo)) {
ProcessNoExternalSourceInfo(externalSourceInfo,identity,sreg);
}
else {
LogIn(externalSourceInfo);
}
}
8. Test it all. It should work, really :)
9. Add some security double-checks, like checking whether response comes from Google. Something like this:
if(!e.Response.Provider.Uri.AbsoluteUri.StartsWith("https://www.google.com")) {
throw new Exception("hacker detected!");
}
Authentication via Google's OpenID is the first, but not the hardest step on a road to Google Marketplace submission. The integration process is specific to your application, but still, there are a few general rules you should remember:
1. Don't prompt Google Apps user for any new login and password during application installation, or Google will reject your submission (it is opposed to Google Marketplace policy). Just silently create an account in your system, using Google Apps' data. Authenticate this account only via Google Apps.
2. Use your application GoogleAppsConsumerKey and GoogleAppsConsumerKeySecret to retrieve user data. Example:
string appName = "YourAppName";
var requestFactory = new GOAuthRequestFactory(AppsNameTable.GAppsService, appName);
requestFactory.ConsumerKey = "YourGoogleAppsConsumerKey";
requestFactory.ConsumerSecret = "YourGoogleAppsConsumerKeySecret";
UserService userAccountService = new UserService(appName);
userAccountService.RequestFactory = requestFactory;
UserQuery query = new UserQuery(domain);
query.UserName = username;
query.OAuthRequestorId = email;
UserFeed feed = (UserFeed)userAccountService.Query(query);
UserEntry user = feed.Entries[0] as UserEntry;
string firstName = user.Name.GivenName;
string lastName = user.Name.FamilyName;
3. If your application have users from both Google Apps and outer world, implement a clear way to distinguish between those two kinds of users. Apart from obvious difference in functionality for different kinds of users, you'll need to track whether a user came from Google or not later on when payment system will be integrated with Google Marketplace (remember, when it happens, 20% of your revenue from Marketplace users goes to Google).
Well, I guess that's all you need to know to get started.
As for our own experiences with the Marketplace, it is rather promising. Comindwork is
on the Marketplace and is doing pretty well. We're seeing constant registrations stream from the Marketplace, and it is growing over time. Still, it is small in comparison to our main registrations stream, but we expect it to grow faster when Google Marketplace goes out of beta.