We spent a lot of time at Corillian (my last job) thinking about Identity, and a few months before I left I started getting into Cardspace and OpenID. This was a little over a year ago. We did a podcast on OpenID as well.
At that time, I tried to take the only .NET implementation at the time of OpenID which was written in in Boo written originally by Grant Monroe and port it to C# causing me to go through the Programmer Phases of Grief. Andrew Arnott and Jason Alexander took the reins and we spend a number of late nights trying to get a good OpenID library working. I gave up, but they soldiered on and created dotnetopenid (downloads), including a client and server as well as Andrew's excellent ASP.NET controls .
Fast-forward to now. My new friend Aaron Hockley decided to a stands and promote OpenID. He said:
Effective immediately, I will no longer comment on tech blogs that don’t support OpenID for comment authentication.
He's just one guy, but his heart is in the right place. He points out that:
Google offers it as a Blogger option. It’s available as a super-easy-to-install WordPress plugin. Movable Type has it as a built-in feature.
OpenID is a good thing and it's Growing. You may already have an OpenID if, for example, you have a Yahoo! account. More on this soon.
How to turn your blog into an OpenID
Simon Willison wrote How to turn your blog into an OpenID and it's very easy.
STEP 1: Get an OpenID. There a lots of servers and services out there you can use. I use http://www.myopenid.com for two reasons. One, I know the CEO (they're in Portland), and two, they support optionally using CardSpace to authenticate yourself (as well as the standard way with password).
STEP 2: Add these two lines to your blog's main template in-between the <HEAD></HEAD> tags at the top of your template. Most all blog engines support editing your template so this should be an easy and very possible thing to do.
Example:
<link rel="openid.server" href="http://www.myopenid.com/server" />
<link rel="openid.delegate" href=http://YOURUSERNAME.myopenid.com/ />
This will let you use your domain/blog as your OpenID. Now, I can log in with "http://www.hanselman.com" when I see an OpenID Login option - and so can you! Go do it now!
Making OpenID Logins Easier
If you have a blog or site with OpenID support, you should go get this little snippet of JavaScript and install an OpenID ID Selector on your blog from http://www.idselector.com/.
One of the things that is slowing OpenID adoption is that many people don't realize that they may already have one. That's what this little Javascript is trying to do by showing folks sites that they recognize. This way my Dad could login using Yahoo and it would make sense to him. It's a little busy, but it's a start. I've added an http://www.idselector.com/ to my blog for comments.
Adding OpenID Support to DasBlog
A year ago, I originally tried to port the Boo code to C# in an attempt to enable OpenID in DasBlog but eventually gave up. However, last night, I re-familiarized myself with the OpenID spec (it's on 2.0 now) and started reading the source for http://code.google.com/p/dotnetopenid/.
In a word, it's a joy. I was able to get OpenID running OK in two hours and working well and up on my blog in two more. I have to give credit to the fantastic work that Andrew Arnott and Jason Alexander and team are doing. It's come far and you should know about it, Dear Reader.
I had two scenarios in DasBlog (again, in case you didn't know, it's the C# and XML-based blog that runs this site and others) to handle.
First, I wanted to support OpenID for Comments which wouldn't actually "log a user in" in the stateful FormsAuthentication sense. I think this isn't a very common scenario, and I'd describe it as One-Time Occasional Authentication. In this case, I used the dotnetopenid classes directly in a moderately complex scenario.
Second, I wanted to support OpenID to login as the Administrator for my site. This would, in fact, log me in via FormsAuthentication. This would be a common scenario that you'd probably care about as it's very typical. In this case, I used the dotnetopenid ASP.NET Controls, which were about as easy as falling off a log. (That's pretty easy.)
Here's the first, harder, scenario.
If you've entered your OpenID and hit Submit Comment then we'll store the current entry and the comment you're submitting. We'll be redirecting away to get authenticated and we'll need them when we get back. If you're running in a WebFarm, you'll want to store these temporary variables in a database or somewhere that doesn't have node-affinity.
Session["pendingComment"] = comment.Text;
Session["pendingEntryId"] = ViewState["entryId"] as string;
OpenIdRelyingParty openid = new OpenIdRelyingParty();
IAuthenticationRequest req = openid.CreateRequest(openid_identifier.Text);
ClaimsRequest fetch = new ClaimsRequest();
fetch.Email = DemandLevel.Require;
fetch.Nickname = DemandLevel.Require;
req.AddExtension(fetch);
SaveCookies();
req.RedirectToProvider();
return;
What I think of as an "OpenID Client" is called a "Relying Party" or "RP" in the parlance of the OpenID folks. In this code we create an AuthenticationRequest and add some additional claims. There's a nice interface-based extension model in this lower-level library that lets you Request or Require information from the user's profile. For comments on the blog, I just need your email for your Gravatar and your Nickname for Display.
I then call RedirectToProvider, and that's if for the request side. Remember I said this was the hard scenario! Not so hard. ;)
Next, we're redirected to an OpenIDProvider, we authenticate (or not) and are redirected BACK with additional information encoded on the GET. On the way back in, in our Page_Load (or an HttpHandler if you like) we check the Response status. If we're Authenticated, we grab the info we requested and add the comment. Bam. Sprinkle in a little error handling and we're all set.
OpenIdRelyingParty openid = new OpenIdRelyingParty();
if (openid.Response != null)
{
// Stage 3: OpenID Provider sending assertion response
switch (openid.Response.Status)
{
case AuthenticationStatus.Authenticated:
ClaimsResponse fetch = openid.Response.GetExtension(typeof(ClaimsResponse)) as ClaimsResponse;
string nick = fetch.Nickname;
string homepage = openid.Response.ClaimedIdentifier;
string email = fetch.Email;
string comment = Session["pendingComment"] as string;
string entryId = Session["pendingEntryId"] as string;
if (String.IsNullOrEmpty(comment) == false && String.IsNullOrEmpty(entryId) == false)
{
AddNewComment(nick, email, homepage, comment, entryId, true);
}
break;
}
}
Here's the second scenario where we'll log in as the Administrator of the blog. I just register the DotNetOpenId assembly in my ASPX page and put an <openidlogin> control on the page. Notice that even the claims I created in the manual scenario above are just properties on this control. There's also events like OnLoggedIn to handle the results.
<%@ Register Assembly="DotNetOpenId" Namespace="DotNetOpenId.RelyingParty" TagPrefix="cc1" %>
<cc1:openidlogin id="OpenIdLogin1"
RequestEmail="Require" RequestNickname="Request" RegisterVisible="false"
RememberMeVisible="True" PolicyUrl="~/PrivacyPolicy.aspx" TabIndex="1"
OnLoggedIn="OpenIdLogin1_LoggedIn"/></cc1:openidlogin>
This controls renders nicely as seen in the screenshot below.
In the OnLoggedIn event, I call my existing security APIs (Thanks to Tony Bunce and Anthony Bouch) and set the AuthCookie from FormsAuthentication.
protected void OpenIdLogin1_LoggedIn(object sender, OpenIdEventArgs e)
{
UserToken token = SiteSecurity.Login(e.Response);
if (token != null)
{
FormsAuthentication.SetAuthCookie(userName, rememberCheckbox.Checked);
Response.Redirect(SiteUtilities.GetAdminPageUrl(), true);
}
}
Poof. I love using well designed libraries and just work. At this point all that was left was adding some CSS and tidying up.
OpenID and ASP.NET WebForms and MVC
The dotnetopenid source includes source for sample sites. It actually includes three samples, two WebForms and one ASP.NET MVC.
The MVC implementation is very clean, even though (or because?) it doesn't use controls. Here's the Authenticate Controller Action:
public void Authenticate() {
var openid = new OpenIdRelyingParty();
if (openid.Response == null) {
// Stage 2: user submitting Identifier
openid.CreateRequest(Request.Form["openid_identifier"]).RedirectToProvider();
} else {
// Stage 3: OpenID Provider sending assertion response
switch (openid.Response.Status) {
case AuthenticationStatus.Authenticated:
FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, false);
break;
case AuthenticationStatus.Canceled:
ViewData["Message"] = "Canceled at provider";
RenderView("Login");
break;
case AuthenticationStatus.Failed:
ViewData["Message"] = openid.Response.Exception.Message;
RenderView("Login");
break;
}
}
}
What about CardSpace?
OpenID is a spec for a protocol that "eliminates the need for multiple usernames across different websites, simplifying your online experience." What's cool is that it's open, so you (the consumer) gets to pick your Provider. It's not owned by anyone, so it's ours to screw up (or succeed with).
CardSpace is built into Vista and installed on XP when you put .NET 3.0 on your system. There are also Identity Selectors for Safari and Firefox in the works. It's different than OpenID in that it's concerned with strong authentication. Therefore, they are very complimentary.
Here's my CardSpace login as I'm getting ready to log into this blog...

...because my chosen OpenID provider at http://www.myopenid.com (it's free) also supports both InfoCards and SSL Certificates for authentication as well as strong passwords.
Notice the "Sign into Information Card" icon below next to the IconCard purple icon.
An OpenID provider can choose to use anything available with which to authenticate you. Here's a video of a Belgian using an eID to authenticate against an OpenID provider at http://openid.trustbearer.com/ that supports biometric devices, USB keys, and smart cards.
So What?
Get involved and give it a try! Here's some things you can do.
- Sign up for a Free OpenID at MyOpenID or one of the many public OpenID providers out there.
- Go use your new OpenID at one of the many sites that supports OpenID.
- Come back to this post and leave your first comment using OpenID!
- Watch Simon Willison talk about the case for OpenID (video)
And, if you're a developer, get an OpenID library like dotnetopenid and consider enabling your app. Consider using the Javascript ID Selector to make for a nicer User Experience.
Hosting By