Hi there folks! Haven’t talk to you in a while now, but I’m back to keep the ball rolling.
Today I’m going to talk about Google Accounts, OpenID and my new challenge.
I’m now working as It Consultant specialized in developing solutions that integrates my client (in this case, my company webAula) with big market players like Google, Facebook, Linked In, Twitter and so forth.
When you think of integrating your product to another one, the first thing that comes into play is Identity sharing, Single Sign-on and stuff and there is the job for OpenID Protocol.
In OpenId protocol there are 2 actors: The Identity provider and the Relaying Partner.
The part of Identity Provider (IP) is to hold and protect your information. You have to choose one identity provider (at the most) to hold all your personal information needed online. In this article I’ll be using Google Accounts as IP.
The part of Relaying Partner (RP) is to Rely (dah) on Identity Provider and know how to “talk” to it, and check if the identity is OK.
A great Ryan Boyd talk on Google IO 2011 (it’s 1h long, but it worth it).
Fortunately you don’t have to go through all the trouble of implementing all the protocol in order to set up an RP in your application as there is lot’s of libraries available to you. I my case I’ll use DotNetOpenAuth, free available to you. As a matter of fact you can become a Identity Provider with this library but that is not our case.
First of all you have to include DotNetOpenAuth.dll (downloaded from the above link) as a reference to your project.
Then, in the page that you handle the login process of your application you have to include the library:
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.RelyingParty;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
Then you create a static object for the relaying party and set up the discoveryServices (I’ll assume that your page is called “Default” and your :
//relaying Partner
private static readonly OpenIdRelyingParty relyingParty;static _Default()
{
HostMetaDiscoveryService googleAppsDiscovery =new HostMetaDiscoveryService{
UseGoogleHostedHostMeta = true,
};
relyingParty = new OpenIdRelyingParty();
relyingParty.DiscoveryServices.Insert(0, googleAppsDiscovery);
}
In your Page_Load you add a handler for the AuthResponse:
IAuthenticationResponse authResponse = relyingParty.GetResponse();
And you can create switch to handle the status of the AuthResponse:
if (authResponse != null)
{
switch (authResponse.Status)
{
case AuthenticationStatus.Authenticated:
//SOME LOGIC
//break;
case AuthenticationStatus.Canceled:
And so forth…
If the AuthRespose is null it means that this request to your page is not the return of your identity provider so you have to send them your request for authentication and you can do it like this:
IAuthenticationRequest request = relyingParty.CreateRequest(domain);
sendGoogleRequest(request);private void sendGoogleRequest(IAuthenticationRequest request)
{FetchRequest fetch = new FetchRequest();
fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, true));
fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.First, true));
fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Last, true));
request.AddExtension(fetch)request.RedirectToProvider();
}
It’s important to retrieve the “domain” of the user. In my case it’ll be a parameter of my system.I’ll only allow integration to one Google Apps domain, but you can let the user inform that for you in some form. Just remember to add a validator with some code like this:
protected void openidValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
// This catches common typos that result in an invalid OpenID Identifier.
args.IsValid = Identifier.IsValid(args.Value);
}
This way you can catch elegantly the return of DotNetOpenAuth telling the there was a typo with the domain name, for instance (No endpoint found error).
It’s also a good practice you wrap the process of creating a authRequest in a method so you can grab a protocol exception that might occur:
private void createLoginRequest(string domain)
{
try
{
IAuthenticationRequest request = relyingParty.CreateRequest(domain);
sendGoogleRequest(request);
}
catch (DotNetOpenAuth.Messaging.ProtocolException ex)
{
loginFailedLabel.Text = ex.Message;
}
}
Finally you can grab user details (up there in the beginning of your class) when we were looking on the AuthRequest status:
case AuthenticationStatus.Authenticated:
FetchResponse fetch = authResponse.GetExtension<FetchResponse>();
if (fetch != null)
{
Session["email"] = fetch.GetAttributeValue(WellKnownAttributes.Contact.Email);
Session["firstName"] = fetch.GetAttributeValue(WellKnownAttributes.Name.First);
Session["lastName"] = fetch.GetAttributeValue(WellKnownAttributes.Name.Last);
}FormsAuthentication.SetAuthCookie(fetch.GetAttributeValue(WellKnownAttributes.Name.First), true);
Response.Redirect("/privateSite/",true);
As my friend, Bugs Bunny says: “That’s all folks”.
See you latter.