I've moved TGOpenIDLogin onto Google Code so that the source code repository is accessible and other people can work on it.  I've also created a TGOpenIDLogin discussion group, in case someone actually ends up using it and wants to know some things about it.

(TGOpenIDLogin is a TurboGears module that you can use to add OpenID logins to your TurboGears application without too much fuss.  A previous post has information on how to use it.)

I was innocently trying to add OpenID to an application, following the advice on Damian Cugley's article on using OpenID with Turbogears and on the TurboGears' documentation site's article on OpenID with Identity when I realised that it was way too much like hard work to implement.  Edit this page, put this there, and so forth.  Why couldn't I just import something and have it Just Work?

Well, it seems, that's not hard at all, actually.  Thus, TGOpenIDLogin, which Just Works (well, python-openid Just Works, and I just use that) when you transfer login and so forth to it.  It's a turboGears controller that you can hook up into any TurboGears application and have it take care of logging in of people using OpenID.

It can't be simpler:

from tgopenidlogin.controllers import OpenIDLoginController

class Root(controllers.RootController):
    ...

    openid = OpenIDLoginController(User, VisitIdentity)
    login = openid.login
    logout = openid.logout

It remembers where you were trying to go, and comes with a simple OpenID form to put on any page which will remember what page you were on when you tried to log in - it's tgopenidlogin.widgets.OpenIDLoginForm.

You need to pass in the model for your User and VisitIdentity objects so that it can create users and update user details from their OpenID server, and so that it can log them on. Your User model needs to support usernames of 255 characters long. You can also pass in the web path to the OpenIDLoginController (it defaults to "/openid" relative to your web app base). You can pass in your own OpenID store, or it'll use a SQLite store (well, if you have pysqlite2 installed). You can also set your OpenID trust_root, or it'll default to the base of your web application.

Nothing invalidates logging in with plain username and password if you still want that. Your current login page can have a separate form (using widgets.OpenIDLoginForm, for simplicity) or a link to the TGOpenIDLoginController - just don't put in login = openid.login in your controller...

Still quite a bit to do:

  • It doesn't save original_parameters like the standard TurboGears login does.  This will require storing the parameters somewhere - probably the session.
  • The User/VisitIdentity stuff might only work with SQLAlchemy with assign_mapper and Elixir and maybe SQLObject - non-assign_mapper SQLAlchemy will need a separate handler.  This is probably easiest handled by making it easy to inherit from the controller.
  • The post-authentication action, redirecting to the target page, might not be useful for places that want full registration.  Again, probably best to stub it out with a default implementation, and let people inherit from the controller and override.
  • Oh, I haven't really tested interoperability.  I just used the example server from python-openid, and one that just failed, and few pages without OpenID server links.