OpenIDAuthentication tutorial

DHH’s OpenIDAuthentication plugin for Rails is evolving and progressing quickly. Over the weekend, David updated the plugin to no longer assume an overloaded login form.

Removed open_id? as the idea of using the same input box for both OpenID and username has died — use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH - Revision 6631]

This morning, Ben Curtis put up an excellent, short tutorial on using this plugin on an existing site.

It’s wonderful having the creator of Rails working on OpenID. :) The design of DHH’s plugin is small, simple and clean — it doesn’t rely on a lot of generated code like openid_login_generator and has a much cleaner abstraction on top of ruby-openid, as compared to Eastmedia’s OpenID+Consumer plugin/generator.

The barriers to implementing OpenID for a Rails site are falling quickly.

Overloading username and openid_url

DHH, who is promisingly writing a Rails plugin for OpenID with Rick and others, has made a case for applications to store a user’s openid_url in place of their username, and present a unified login form which hides or reveals the different processing of openid & password logins, based on the presence of the http prefix.

When users start typing an OpenID identifier URL into the username field, the web app transparently turns it into an OpenID login action.

The common implementation today is to add an openid_url field alongside the existing user data, provide a login screen that offers regular and OpenID login, and often internally maps OpenID’s nickname (from the Simple Registration Extention) to the username/login.

What are some pros/cons to the proposed overloading approach?

Pros

  • For users, the the login or signup screens aren’t complicated further with another visible alternative
  • As a developer, you don’t have to use an additional field in the database
  • As a developer, you don’t have to deal with potential uniqueness conflicts between one person’s OpenID nickname, and another person’s username (which may require an additional username/email form to be presented during account creation in the case of a conflict)

Cons

  • According to Spec (s 3.2.1), the user shouldn’t be required to prefix their identifier with http (basically, a usability issue)
  • The gentleman’s standard (also in the spec) of naming the form field “openid_url” to allow it to be auto-populated across sites is lost.
  • Both OpenID users and traditional users may be confused by the overloaded form. If the OpenID logo is displayed, it doesn’t have a natural home which won’t confuse one party or the other
  • The application no longer has a place to store a friendly name for the user. So views display a URL, which will typically be much longer than a username, and require some additional view logic to turn into a link
  • OpenID accounts are at a privacy disadvantage vs. username/password accounts, because their visible username tracks directly back to them
  • For the developer, the code for the two authentication methods (password, openid) becomes even more coupled

Wrong on anything? And other major pro/cons missed?

On the whole, what’s common with current implementations (separate openid form on the login page for the user, separate openid field in the database for the application) is both in line with the spec, and still the better compromise. As the core team’s Rails Plugin quickly evolves, expect details and directions to change.

Why the lack of OpenID-enabled Rails apps?

OpenID has been quickly gaining momentum this year, with Microsoft’s future role as an identity provider, and AOL’s sudden, wonderful announcement that all 60+ million AOL/AIM users now have an identity provider.

But where are the OpenID-enabled web applications to log into? What we have so far is nice, but it’s not the kind of riches we’re seeing on the provider side of the OpenID equation.

With Rails being the platform of choice for many new & emerging web sites, you’d expect to see OpenID support here first. So really the question is — Why don’t we see more Rails apps with OpenID support?

  • Most OpenID-enabled sites still need to support password authentication. There are some good choices today for creating a new Rails app that only supports OpenID login (the ruby-openid gem’s generator is good for that), but it’ll be some time before all users are comfortable with OpenID. So sites need to be able to add OpenID support alongside password login — and that’s a non-trivial challenge today (see bookmarks for one example, but it’s not yet solid).
  • Competing authentication plug-ins. For OpenID, there are two major competing plugins: JanRain’s generator that is included in the ruby-openid gem, and Eastmedia’s generator (used in the bookmarks example). And to combine with password authentication, there’s a more confusing jumble of choices. If you’re running Rails 1.2, restful_authentication is currently the strongest choice for password login because of its cleanliness, tests, and feature support for remembered logins (cookies) and optional email activation, etc (<1.2, acts_as_authenticated is strongest). And on the OpenID side, Eastmedia's generator is better configured to mashup with other login systems, but it still requires a substantial amount of customization, and it suffers from lack of tests and some out of sync code.
  • The right user interface hasn’t been settled on. Should we present password & openid login on the same page? A set of choices with fancy UI (tabs)? Should account creation be automatic for OpenID? Should OpenID SRE nickname and email be assumed to be configured?
  • The right internal structure involves some difficult tradeoffs. Just at the top level — should different authentication methods all store their data in a unified user model? Should the application’s login and OpenID’s nickname be treated as equivalent? If so, how to handle uniqueness? etc. etc.
  • Disagreements on the wisdom of drop-in authentication. The best hope for making this all more approachable is better plugin support, including authentication plugins that play well together so a single application can support multiple authentication mechanisms. But there has been some disagreement among the community — some would argue that authentication of this type is too tied to unique aspects of the application and too important from a security point of view to be realistic as a dynamic plugin or works-out-of-the-box generator. But without out-of-the-box ease (like what aaa or restful_authentication provides for password authentication), combined OpenID+password authentication will trail in adoption.
  • In short, the killer OpenID plugin has yet to be written. For an excellent spec for what is needed and an incomplete implementation, see Hark.

OpenID is poised to take off. Support from an army of up-and-coming Rails sites could be the turning point.

Are there other tools that make this more approachable for Rails developers?

Latest news on Mephisto and OpenID

Mephisto is still developing, but seems to be coming into its own as a blog engine of choice for Rails.

Since Mephisto does not yet have OpenID support in its trunk, this seemed like a good project as the running example for my peepcode screencast on OpenID.

There is some very active ongoing work, though, that if I go forward with Mephisto I will certainly build on. Here’s the latest I know of.

First, is Justin at transphorm’s Mephisto port of the OpenID Consumer plug-in for Rails. Normally, outside of Mephisto, the OpenID Consumer plug-in could be be used in conjunction with a authentication generator like ActsAsAuthenticated. Justin’s port is nearly fully baked, but does require hand editing several significant areas.

Second is Frank’s work at nullsense, which builds on Justin’s port and works to turn it into a full Mephisto plugin. This work isn’t yet released (and, when it is, may require some changes in Mephisto trunk), but it looks like a full Mephisto plug-in for OpenID is imminent.

For myself, where I want to show adding OpenID to Rails from the ground up, this raises some question of doing the screencast with Mephisto or with a project where there is no existing OpenID activity that i know of.

Also, if Mephisto remains the direction, there’s the question of whether OpenID should be a standard feature in Mephisto trunk, or kept separate as a plug-in.

If anyone has thoughts, let me know!

OpenID, Rails, and Peepcode

OpenID LogoOpenID is an exciting, up-and-coming technology which will make website registration and login simpler (Finally! Fewer passwords to remember!)

I’m hopeful that, over the next year, you’ll see a flood of web apps add support for it.

But today there are only a few dozen web apps that have that support. Support in web frameworks like Ruby on Rails is here or coming soon, but word hasn’t reached the masses yet.

To play some small part in filling that need, I’ll be helping to create a screencast which walks the viewer through adding support for OpenID to an existing Rails app. As this work is done, I’ll post here with some of the information and questions that come up, along with a little on the general process of creating a screencast. Subscribe if you’re interesting in reading this series of posts, and you can also see some of the resources I use at my openid tagged pages (del.icio.us).

The screencast will be posted on peepcode.com, Geoffrey Grossenbach’s repository of professional, high-value screencasts on a specific topics. I’ve admired Geoffrey’s work and various projects for a long time, and am looking forward to working on one of his efforts.

Please let me know if you have any feedback — a question or topic you’d like covered, for example.

Here’s the tentative topics:

5m Getting an OpenID for ourselves
10m Installing the Mephisto Rails-based blog engine
5m Plugging an OpenID login into Rails
10m Creating our OpenID-unique tests
10m Analyzing and migrating our models
10m Merging our views and controller logic
5m The final product

Here are some examples of the early questions I need to answer:

  • How much should I summarize topics already hit by Simon’s introductory screencast for non-technical OpenID users?
  • For the example project, add OpenID support to Mephisto (blog) or Junebug (wiki)?
  • Will I need any major dependencies beyond ruby-openid (and its login generator)?
  • Will there be time in the screencast (targeted at 40 mins) to make a standard plug-in?
  • What are the top 3-5 gotchas that cause people to loose time when embarking on OpenID themselves?

Ruby as an OS-independent application platform

I originally wanted to write a little post to help non-nerdy friends install filebydate, my simplistic picture organizer. This does that, but also covers some larger issues that were so well put in this email I got:


As I sit here building a new machine, I’m thinking of all the little shareware utilities I have and how long it takes to set them up. Last time I built a machine, I spent forever just finding installers for all these buggers. It strikes me there are three problems:

  1. Finding a useful utility
  2. Deploying utilities on any computers you have – not just installing a new utility, but having a list of your favorites and being able to say Set Me Up and it’ll install everything on your list.
  3. Keeping them up to date – I like to have the latest versions, but it takes forever to go to each site and check for an update – especially when several of these apps have plugins. (just getting a slimserver up to date with all its plugins can take a half hour).

‘twould seem like a niche begging to happen…

This email came from my friend Rob, a very computer-savvy guy. These kinds of problems are much worse for a novice user.

The trouble has been, although there are some good single-platform solutions to this kind of problem for open source software on Linux or Mac (which you can see below in the Ruby install steps), there hasn’t been a good, unified cross-platform solution. But working on my little ‘filebydate’ Ruby gem has got me thinking how the Ruby language, libraries, and runtime are getting tantalizingly close.

Even for a novice, it’s easy to install Ruby. Even if you never want to write a line of code, this can be nice, because Ruby includes its own package manager (rubygems) which makes finding and installing useful ad-ons easy. All this is cross-platform — it can work whether you’re using a Windows, Mac, or Linux box. Getting started can be summarized in one or two steps.

Windows

  1. One-click install (1.8.5 r21)

Mac

  1. Get DarwinPorts
  2. % port install ruby rubygems

Linux (Ubuntu)

  1. % sudo apt-get install ruby irb rdoc rubygems

Try it if you don’t already have Ruby! Once you’ve got this done, installing a ruby library or application on any of these three platforms is as simple as running

% gem install filebydate

on the command line. This command will go up onto the internet, see if this thing called ‘filebydate’ exists, download it, install it, and put any scripts (like ‘renwdate’) in your path so they’re also usable from the command line.

It’s like downloading a typical program installer, except that

  1. The installation process is standardized
  2. Upgrades are as simple as
    % gem update
  3. You can tell what’s previously been installed with a simple
    % gem list
  4. Gems build on each other, and are able to install what’s needed automatically (dependency handling)
  5. When you move to a new computer (even running a different OS), it’s easier to get the same programs re-installed

All this is nice, but it’s obvious that most normal computer users will simply say “you lost me at ‘command line’”. To make Ruby more viable as an OS-independent application platform, there’s a few things we Ruby developers have to do.

  1. Gems should provide a bit more consistency in supporting multiple platforms, or declaring any platform dependencies
  2. Gems should consider adding GUI frontend for any scripts (as I should do for filebydate)
  3. And some ideas for rubygems …
    1. Create a gui frontend for rubygems itself
    2. Add a section in the gemspec for some post-install, platform-specific processing for all supported platforms (e.g. to add shortcuts to start menu on Windows, etc.)

Is Ruby the only game in town? Not by a long shot. There’s ppm for Perl, pypan for Python, any of the Linux package managers, solutions like Macromedia Central (Flash), or any number of others — but most are either not multi-vendor, not multi-platform, or aren’t as well matched to the problem as Ruby and rubygems.

So are Ruby and rubygems ready for prime-time as an OS-independent application platform? Not yet, but they’re usable today and getting closer all the time.

Do you have a better, preferred set of technologies to start solving these problems?

Technorati tags: computers and Internet, software, ruby

Simpler photo library management (filebydate)

Looking for a simpler way to manage your digital photo library?

A lot of people we know are burying themselves under a mountain of media files, loosing things.

And the software out there can really get you in trouble — tie you to one vendor or one platform, prevent you from organizing “your way”, hide information from you so you can’t back stuff up properly or use other programs to manage the library, etc.

A few years back I wondered if there wasn’t a simpler way. What I really wanted was to just use the filesystem directly, no fancy photo database or metadata. And then just use the nice, built-in Windows or Mac shell functionality to view the picture folders. But I wanted the files organized, and the date the photo was taken was the one thing that would never change — the primary way I wanted to look for pictures later. Unfortunately, I couldn’t trust the OS or the apps I was using to never touch that file date, and I needed it to be easily seen in all views.

So I wrote a simple little perl script to prepend the last modification date to the image files. “PIC_023812″ becomes “2005-12-04 180624 PIC_023812″ (you can, of course, then rename the PIC… part). We’ve been using it the last 5 years, a few friends have been using it, and that plain & simple solution has stood the test of time and been surprisingly useful.

So now, I’ve finally given it an upgrade to life as a Ruby gem, and gotten it out on a repository. The gem is called filebydate, and the renaming script which will get added to your path on installation is called renwdate.

I’ll post more later once the first release has propogated from rubyforge (once it has, installation will be as simple as ‘gem install filebydate’ for ruby users). Until then, please visit the rubyforge page.

Of course, turning it into a nice gem with complete docs, unit tests, etc. has made it a larger package. Here’s the original perl script, if that’s more to your liking.

=head1

Takes a wildcard as input, reads the date on each file, and
prepends that date into the file name (if the filename doesn't already
have a YYYY-MM-DD in it).  The purpose is to allow files (usually image
files) to be tagged with their creation date in the filename itself, so
that the creation date isn't lost when the file is further renamed (beyond
the date characters) or manipulated (such as rotating it or fixing red eye).
The filename is also used by many on-line photo printing services to print
the description of the picture, and this makes sure the date is part of
that string.

Bernie Thompson Jan 2001

=cut

use File::Basename;

@files= <$ARGV[0]>;

foreach $oldname (@files)
{
        if ($oldname =~ m/\d\d\d\d-\d\d-\d\d/) { next; }
	($readtime, $writetime) = (stat($oldname))[8,9];
        ($name, $dir, $ext) = fileparse($oldname,'\..*');
        ($sec, $min, $hour, $day, $month, $year, $junk) = (localtime($writetime));
        $year += 1900; $month += 1;
        $newname = sprintf("%s%04d-%02d-%02d %02d%02d%02d %s%s%s", $dir, $year, $month, $day, $hour, $min, $sec, $name, $ext);
        print "$newname\n";
	rename $oldname, $newname;
	utime($readtime, $writetime, $newname);
}

I’m hoping we can get a few more utilities created around this simple solution, to cover things like automatic renaming when picture files are imported, etc. And this Ruby gem could be a place to collect them.

Please let me know if you have any feedback or ideas for filebydate.