KanbanBoards VI–OpenId Integration

· March 8, 2011

It’s been a while since I did any work on the KanbanBoards project, but now I got around to add some more features. I planning on doing some acceptance tests for creating new boards. The controller functionality was spec’d out in then last installment of the series.

To do that properly I need to touch on two main areas of functionality:

  • Authentication – here I plan to use OpenID and see if I can plug-in some functionality that already exists.
  • Uploading pictures – just for fun I will try to store the pictures in the database and see how that sits. I can already here give away the fact that I didn’t do this today.

And finally show that the whole thing works using an acceptance test that verifies the functionality end-to-end.

Let’s go.

Feedback and updates

I got some great feedback from some people, foremost Darren Cauthon, that I’ve already implemented. That cleaned up my code a lot. Sadly I also messed up a lot when I tried to merge the code into my master. But after some manual hacking I think I’m back on track.

Darren showed two thing that I haven’t thought of earlier:

  • A new feature (upcoming in SpecFlow) is that you can store a factory method inside the ScenarioContext.Current. That method is executed when you Get the value out of the Current dictionary. That cleaned up a lot of stuff
  • A thing that I haven’t really thought of is that you can use attributes, such as BeforeScenario on more than one place. If you organize your steps in different logical block (for the controller, for the different repositories etc.) you can then have the setup for each under the BeforeScenario-step and get a nice clean structure.

Thanks Darren – I learn a lot from you. Hope I can pay you back some day.

OpenID

To the business of the day. I want to log into the site somehow, but thought of storing users and passwords in my database doesn’t sit right nowadays. There’s OpenID for things like that. I simply want to plug that into my application.

So I did what we used to do; I started to browse the net and before long if found http://openidportablearea.codeplex.com which looks great. Right - so it looks like it depends on MvcContrib and something called DotNetAuth. All I need to do now is to find the right versions of that and put them in my lib folder and then find some example code and … BAM! Not anymore, my good friend NuGet will do all that for you with the simple command:

Install-Package OpenIdPortableArea

Haha – it even gives me intellisense support for the name of the package. Ok – I’m officially impressed! NuGet is something every .net developer need to know. Full stop!

And while I wrote that NuGet did this:

Install-Package OpenIdPortableArea ‘MvcContrib’ not installed. Attempting to retrieve dependency from source… Done. ‘MicrosoftWebMvc (≥ 2.0)’ not installed. Attempting to retrieve dependency from source… Done. ‘Mvc2Futures (≥ 2.0.50217.0)’ not installed. Attempting to retrieve dependency from source… Done. ‘DotNetOpenAuth’ not installed. Attempting to retrieve dependency from source… Done. Successfully installed ‘Mvc2Futures 2.0.50217.0’. Successfully installed ‘MicrosoftWebMvc 2.0’. Successfully installed ‘MvcContrib 2.0.95.0’. Successfully installed ‘DotNetOpenAuth 3.4.6.10357’. Successfully installed ‘OpenIdPortableArea 1.0.0.3’. Successfully added ‘Mvc2Futures 2.0.50217.0’ to Web. Successfully added ‘MicrosoftWebMvc 2.0’ to Web. Successfully added ‘MvcContrib 2.0.95.0’ to Web. Successfully added ‘DotNetOpenAuth 3.4.6.10357’ to Web. Successfully added ‘OpenIdPortableArea 1.0.0.3’ to Web.

Lala – now I just need to wire it up. Btw – a portable area is views, controllers and model bundled up into a portable component or .dll.

From the OpenIdPortableArea documentation I get some help to wire it up. Let’s see:

  • Need to AreaRegistration.RegisterAllAreas() in Global.asax. That’s done already in MVC3 applications
  • Use the Authorize-attribute for the controller actions I want the user to be authenticated to run. In my case, so far, it’s the Create-action.
  • And then I need to point the forms authentication in the web.config to the controller action “~/OpenId” which is supplied by the portable area.
  • OpenIdPortableArea uses a message bus supplied by MvcContrib to communicate with OpenID. So I need to use that, which is done with this simple row in Application_Start in Global.asax:    MvcContrib.Bus.AddAllMessageHandlers();

That last part means that I can handle messages that the MvcContrib bus sends out. For example the ClaimsRequestMessage. So I created a PortableAreaHandlers-folder and popped the following (shamelessly stolen) code in there (moved to separate files after you read this):

openid message handlers

In the top part I set up the things I require that the user supplies (name and email) and down below is the code that get called when the user is authenticated.

Finally I changed the implementation of my logon-partial view by (again) steal a partial that OpenIdPortableArea supplies. Like this:

openidportablearea loginwidget

To get this to work you need to add the OpenIdPortableArea into the <namespaces> section of the Web.Config in the Views-folder. That’s just to let your views to know that OpendIdPortableArea is something that they can use.

All of this was stolen from the excellent screencast of Brandon Satrom on MvcContrib.

Problems

But just as I thought this was going to be a breeze I ran into problems. The version of OpenIdPortableArea I used (1.0.0.3) only supported WebForms (aspx) views. And I used Razor.

OSS and social media to the fore

What then happened was a powerful testament to the powers of Twitter and the OSS-community. I am just humbled by this community. The willingness to share and help each other is just amazing. I haven’t once been put down or frowned on by any of the (sometimes very famous) people I’ve asked for help.

Here how it happened;

  • I contacted Brandon Satrom (@brandonsatrom) and asked if he have had the same problem when he did his screencasts
  • He experienced the same thing when he used Razor views.
  • So I contacted John Nelson (@johncoder) who created the OpenID Portable Area in the first place.
  • Aware of the problems he was just about to release a new version of the OpenId Portable Area.
  • Two days later it was on NuGet.org – one version for Razor views and one for WebForms
  • John kindly contacted me back. I downloaded and ran into some small understanding problems. But John “held my hand” and pretty soon I had a working integration (see below)

Retake – wiring up OpenId Portable Area

So here is what you (nowadays) need to do to get OpenId Portable Area into your application and working.

Uninstall any previous version of the OpenId Portable Area (and dependencies)

Get the version of your choice with one of these commands:

  • Install-Package OpenIdPortableArea.RazorViews
  • Install-Package OpenIdPortableArea.WebFormsViews

Add the following little snippet to get a “login widget”; you know the little thing that says “Login” and “You’re logged in as”: Login status widget

And finally add a AuthenticatedMessageHandler. Here is a new version that get the work done. This is the bare minimum you have to write but I have some more comments below Authentication message handler

The rest is configured by the NuGet package. It:

  • Adds the appropriate configuration to your web.config
  • Adds Views and controllers under the Area-folder

The message handlers

The whole idea with the OpenId Portable Area is to minimize your work and that really works great. Although you need to know how to stich it together with your application. Typically that involves the steps I’ve outlined above and one more; ClaimsRequestMessageHandler.

With both the ClaimsHandler and the AuthenticationMessageHandler you hook into events fired by a bus (implemented by MVCContrib if I understood it correctly). So you simply need to tell the messages (requests or responses) what to do.

For the claims request handler we need to specify the claims we have on the OpenId provider. Like this:

Claims Request Message handler

Sadly not all (blogger.com) of the OpenId providers adhere to all your claims so you need to check carefully when the answer returns (AuthenctionMessageHandler).

Screen shot 2011-03-08 at 19.18.57

Also there’s a method being used in my AuthenctionMessageHandler that I didn’t get at first. The method is OpenIdHelpers.Login. That performs the Forms-login, but the values you send it is not username / password. That what’s got me I think. From the documentation we read:

Creates a FormsAuthenticationTicket, and adds a FormsAuthentication Cookie

So rather the method might have been called CreateFormsAuthenticationTicket. I would probably missed that too but the login was really confusing. John Nelson kindly explained it to me so I thought I pay it forward.

With all this in place I can simply login in to my own site using my Google account (for example). Pretty slick with a total of 15 lines of significant code (not counting class declarations etc.).

logged in

Conclusion

The starting point for this series was to explore the new way you do code. For me the TDD and BDD revolution has change that the most during the last years. But lately it’s the NuGet and inclusion of ready-made functionality that super-easy can be integrated and used in your code, that make a big impact on me.

OpenId Portable Area is such a great addition. I wouldn’t dream of writing that myself. But with Johns help and the powered by NuGet I could do it in a matter of minutes. Not counting the OSS / Twitter hallelujah waiting time Smile

A final word; I am on parental leave during the upcoming six months. (Yeah – Sweden is a great country for parents…). As I take care of twins and with a wife working during the nights (sleeps during the days) I suspect that I wont have much time to blog for a while.

I will try to get the site running – but probably not blog about the process, since that slows the creation down a lot, but makes me think a lot also – which is great of course.

You are more than welcome to follow the project on the github location where I will continue to check in the code. Here’s the commit for this post

Thank you for reading this far – I’ve learned a lot.

Twitter, Facebook