Why have thee forsaken me, oh SSO?

OpenIDImage via Wikipedia

As I've talked about before, I'll talk about the requirement gathering first.

Currently, I'm looking into SSO solutions on *NIX like systems. Which is a certainly interesting field (lots of commercial vendors, in case you need somebody to sue, as Justin Gehtland put it in his RubyConf '07 presentation Ruby and Identity: OpenID, CAS and Information Card at RubyConf 2007).

However, I don't want to buy a solution. My solution shall work with open source software as much as possible (which is a topic for another day).

Since I am using Ruby, my options are currently severely limited:
These two options are the best supported for Ruby, which means that both the client as well as the server are available in Ruby. There are quite a few SSO solutions available, but most run as a Java application, or as a C solution. While the latter isn't much of an issue, the former is. I don't want to suck out the whole memory and CPU of a small server just for single sign on!

[Edit for clarity: I am taking a look at the storage and retrieval of users and their credentials, before I actually use SSO. On the one hand: I can create the infrastructure from scratch, on the other hand I have to create the infrastructure from scratch, and can't just gear it all towards my little app, but have to consider a lot of usage scenarios. The information about SSO solutions is more about context, than the focus of my post. - Phill]

But what about the backend? How do you integrate the user database, I hear you ask.

This is the fun part (or frustrating):

Almost all SSO solutions come back, in one way or another, to OpenLDAP (or another LDAPv3 compatible directory service), as storage service for user data. The authentication is, usually, done via Kerberos.

Quoth Wikipedia:
Kerberos is the name of a computer network authentication protocol, which allows individuals communicating over a non-secure network to prove their identity to one another in a secure manner.
And while I like to apply a certain extend of.. overkill to a solution, this isn't really feasible. It is one (1) server that is being used, with three (3) users (current projection). Not concurrent users. Maximum users. Even LDAP is over the top for this solution (however, it allows for 'true' SSO on *NIX, via PAM).

Both OpenID and CAS can plug into LDAP, and you can use LDAP as authentication source.

But what about if you cannot use LDAP? Well, the other option is to authenticate a user against /etc/passwd. Ruby surely is able to do that out of the box. It comes with the Etc module, after all. Well, yes, but no. While it does come with the Etc module, I haven't found a way to use built-in Ruby tools to authenticate against /etc/passwd (well, there's Ruby-PAM, but the last release was in 2004. Not quite trust-generating for authentication).

So, at the moment I am considering using (parts) of Jamis Buck's Net::SSH to hack together an OpenID or Ruby-CAS authenticator. This solution has The Smell, though, and already feels brittle. I cringe just thinking about it.

The benefit of this hackish solution would be, though, that no server excpet the SSH daemon would be required. And that one is already available (also, I don't have to care about details like user maintenance, since the SSH daemon handles that for me).

But would the pain of maintaining something like this outweigh the pain of installing and configuring OpenLDAP? That is for the client to decide. I'll talk about the actual solution once a decision has been made.

Also, if you have worked with ruby-pam and pam-ruby or have valuable experience regarding OpenLDAP (Especially on FreeBSD 5.4!), it'd be great if you could leave a comment.

11 comments:

Anonymous said...

If you need to use an LDAP server, OpenLDAP is not the easiest to get going, unless it's pre-installed on your *NIX server.

ApacheDS is easier (but beware: 1.0.2 does not support changing passwords without a restart!). It's Java.

Sun's OpenDS looks promising too. Again, Java.

Java apps don't _have_ to hog the whole machine - Crowd runs very happily in 64MB, handling several thousand requests a minute. ApacheDS is also pretty lightweight in terms of resource usage. I haven't played enough with OpenDS to have a decent picture of how it performs.

Unknown said...

Wow, thanks for this. :)

I'll look into them, too.

Unfortunately, I have no clue if I can get the JRE 1.5 to work or not on FreeBSD 5.4 (and my VM is uncooperative).

Nonetheless, I'll look into them. If everything works as I hope it will, I should be able to add the Java based LDAP services to the Java app server.

The question is: How well do these integrate into the *NIX infrastructure? I guess I'll find out (ideally, there is only one point to add users and *all* the *NIX services access this one. Something I can't quite imagine will be possible with the Java based LDAP.

I will investigate, though.

Anonymous said...

The keywords for you are RFC2307 and "POSIX LDAP Schema".

This allows you to put all the stuff *NIX needs for authN/authZ - such as uid, gid, home dir, and the like - into your LDAP directory.

Then you point your NIS wotsit at your LDAP directory and supposedly it all just works.

You should be able to load an RFC2307 schema into pretty much any LDAP directory.

Unknown said...

Wonderful, more technical documentation to read. :P

Thanks, and now I'm going to tackle RFC2307..

After I made coffee. ;)

Anonymous said...

I'm not quite sure what you're after in terms of Ruby bits and pieces to start you off, but the new Masquerade OpenID Rails server looks promising and you might be interested in the SO project or it's parent, CloudKit.

Unknown said...

At the moment, I'm looking at implementing a datasource, so that I can actually use a SSO scheme for authentication.

So, the actual server that I use to access this data is a bit fuzzy right now, since it depends on what the backend will be.

After I have the backend, I'll look at interfaces to my databse of users. I guess implementing an OpenID or CAS server (or whatever else I dig up) after that will be trivial.

In the worst case, I'll have to use something like pam_mysql, and connect to this database for authentication.

Still, it hinges on the backend used for storage.

Matt Zukowski said...
This comment has been removed by the author.
Matt Zukowski said...

Phill, I'm the developer behind RubyCAS. From your post I can't quite understand what you'd like to see improved in the CAS server? Do you want a pam-integrated authenticator (to use *nix) accounts for back-end logins? This shouldn't be too hard to do. I can look into implementing it at some point in the near future if this is what you're looking for.

Or is it something else?

Unknown said...

Matt, I can't really talk a lot about Ruby-CAS (except that I like the principle, and how lightweight it is).

I haven't used it yet, and I'll have to look at it in detail (not just the wiki on Google Code), so I can't say if or where needs improvement.

(Justin's RubyConf 2007 presentation looks like it is quite feature complete, and I don't think that you neglected RubyCAS since then ;).

Currently I am looking into what *back-end* I'll have available for user administration, which I *then* can use with Ruby-OpenID or RubyCAS (and RubyCAS looks like the better choice, here, since creating an authenticator for it should be easier, and more geared towards internal uses, than OpenID is).

And yes, a PAM authenticator would be nice. And I'll have to investigate Ruby PAM a bit more (the project shows activity), and write it and contribute it to RubyCAS.

So, my post isn't about anything specific regarding the options I have (except that all authentication leads back to LDAP in one way or another, given what I see), and particularly not a gripe about RubyCAS, at all. My apologies if you saw it as such.

Matt Zukowski said...

RubyCAS-Server has a bunch of authentication backends built-in. LDAP, ActiveDirectory, and SQL (via ActiveRecord) work out of the box. There are plans for integration with Google accounts and OpenID. Integration with PAM might also be worth looking into, especially if it can be easily done via Ruby PAM, but in my experience most people who use RubyCAS server are in larger organizations where LDAP is already widely used. Those who want something simple tend to just opt for using a SQLite or MySQL for their user datagbase.

Unknown said...

Yeah, I know about the available Authenticators for RubyCAS, and the choice is reasonable, can't fault that.

It seems that Ruby-PAM (or PAM-Ruby, confusing naming scheme) might be good enough for my purposes, so that I could hook into that, or an LDAP backend, depending on the properties.

However, my gripe isn't as much with 'OMG, Ruby tools can do so little!' but with 'Dang, LDAP by default, everything else is roll your own' (essentially).

There is also PAM-MySQL, so that a MySQL DB could be used for authentication.

The trouble is, I'm building on a contract. And while I have a lot of options, I'm severely limited (for example that the OS in question is FreeBSD 5.4. ARGH!) in other regards.

Also, I don't want to use more than is necessary to solve the SSO problem I have. I could drop this feature entirely, but I don't want to, since it is an elegant solution in principle. I just don't like the details involved. :P

What is a big selling point for me is, that RubyCAS' documentation mentions that it is easy to write an Authenticator. With Ruby- OpenID, my options are to either use an internal OpenID server (back to the choice of back ends), or use an external OpenID server (doable, but not good for something that is, essentially, an intranet on a WAN).