Showing posts with label Single sign-on. Show all posts
Showing posts with label Single sign-on. Show all posts

Choices, choices, choices: CAS or OpenID?

With RubyCAS and Ruby-OpenID you have two choices to enable authentication for your application.

But which choice is the best one? Or rather the correct one? That depends on your usage scenario.

RubyCAS and OpenID solve, roughly, two different problems:

  • Single Sign On
  • User account management
Solving the Single Sign On problem
This is RubyCAS' strength. If you want to offer multiple applications to your users (be it on the internet, or in an intranet), RubyCAS is the better choice. Since it allows proxy authentication, users only have to sign into their account once, and all applications available to them can be used without retyping their credentials when switching applications.

This is the classic environment prompting the need for SSO solutions in general, and RubyCAS fits the bill (especially since it provides Authenticators for common enterprisey storage solutions, like LDAP).

Simplifying sign up
This is where OpenID shines. User's only have to maintain one set of credentials, and can use it whereever they can log in with OpenID. This is a big bonus for you. No need to store passwords, you can automate account creation at the first sign in of your users (you can request account data like passwords, nicknames, first and last names, etc.), and don't have to worry ( alot) about validation of this data. The user's OpenID provider took care of that for them.

You can of course offer them an OpenID services with your application, allowing them to use the credentials they use for your application to login everywhere else.

However, it seems that OpenID doesn't allow proxy authentication out of the box (you could add it, or maybe the next version will provide support for that, but that is difficult to do in an essentially untrusted network, which leads to things like Kerberos).

So, what should you use?

If you are user-centric, use RubyCAS. Examples of user-centric scenarios would be Google Apps for Domains: One account for all these services.

If you are application-centric use OpenID. Users will only use one or few applications you offer, and you can thusly simplify the process for them, by cutting the amount of username/password credentials your users have to maintain drastically.

Remember, though, that OpenID is not an ID verification service! If you plan to use OpenID in an intranet, you should have users use an OpenID server you provide on the intranet, and not have them authenticate via, say myopenid.com. This also allows you to fine-tune the data stored with OpenID accounts, for example organizational units, supervisors, etc.

As you can see, there is no single correct answer. Neither RubyCAS nor Ruby-OpenID are silver bullets, solving all your account problems. It is a question of what fits your usage-scenario the best.

Wide OpenID. SSO for the user.

OpenID. Doesn't that sound wonderful? It is open. Right there in the name it says that it is! And it is about IDs, too! Er, wait. What is it?

OpenID is an open standard that is not vendor controlled. That is, neither Google, nor Microsoft, nor Apple could change the nature of the standard and 'neglect' to tell everybody about it.

The aim of OpenID is to provide users with a means to log in at websites without creating an account with a specific site (if you run your own OpenID server, you don't have to tell anybody your username/password).

After this little overview of OpenID, let's get into Ruby-OpenID:

Like Ruby-CAS, this package comes in two flavors: A server component, and a client component.


My own OpenID server? Anyone? Bueller? Bueller?

However, compared to Ruby-CAS, the server component is limited. The OpenID server (based on Rails) is an example only, and doesn't even come with tests to take a look at how it works. A shame, really. So, without this, you'll have to roll your own solution to this. Since this is a Ruby gem, you can easily create a server and roll with it, using any storage solution you chose. However, the investment on your part is much higher than with Ruby-CAS' server, which provides a turn-key solution, unless you need something that is very uncommon (like me ;).

My client has OpenID. He showed me the URL.

The client side is a bit more complex. For login, users have to provide an OpenID enabled URL, from one of the many OpenID providers. Chances are, that you already have an OpenID URL, without knowing it (off the top of my head, Blogger, Yahoo!, LiveJournal, and AOL provide OpenID URLs already)!

With this URL, a web application can authenticate a user. You get redirected to the provider (discovered via the Yadis protocol, to standardize the data protocol. Isn't interoperability fun?), and have to provide your credentials there, and then you have to approve the application (just once, or permanently), too. Or rather, the application's URL. And you have to repeat this process for every single account you create someplace else. After approving the URL, you get redirected back to the site that requested your authentication, and you are being logged into the app (or an account is created for you, and then you are logged in, or however this is handled).

This solution is ideal for the internet (where services rarely know about each other), but not so good for an intranet (where services and people know about each other).

Ceterum censeo Carthaginem esse delendam

If you want to create trust, without forcing people to create accounts and maintain yet another set of username/passwords/mock-two-factor-authentication-security-question, OpenID is certainly the way to go. Even to create accounts for your web service's users.

The big downside is, that proxy-authentication (like with CAS) isn't possible, or you have to roll your own, somehow.

Also, since OpenID is pretty much roll your own on the server side, other solutions are probably better for you if you want to have SSO for an intranet.

If you want to read more about Ruby-CAS, I wrote an entry about that, too.

Coming soon: Oh my God, what did I get myself into this time? Or: Comparing Ruby-CAS and Ruby-OpenID.

A case for CAS

A couple of days ago, I talked about the limited options of SSO on the Ruby side of things. This turned out to be a bit of a mistake. In fact, the two viable SSO solutions are viable, and feature rich, providing what you need on the authentication server's side, as well as the client's side.

The issue was more that there are only these two options in the first place.

However, I'm going to take a deeper look at these two options. I'll do this in three articles, focusing on RubyCAS client and server first, OpenID client and server second, and comparing these against each other in the last episode.

Now, without further ado, a look into CAS.

CAS is Yale's solution to the SSO problem. It provides a client/server architecture, allowing each application to authenticate users against a single server.

Matt Zukowski (his RubyForge profile) implemented the Ruby variants of the Central Authentication Service Protocol (short CAS), both on the server side (RubyCAS server), and the client side (RubyCAS client).

Clientèle dealings

The client simply enables to authenticate against a server implementing the CAS protocol. That's it. Well, not quite.

Actually, a CAS enabled website hands authentication off to the CAS server login page, which checks the user's credentials, and redirects back to the requested webpage on successful authentication. The web application verifies that the user has, indeed, logged in, and works as expected.

The benefit of CAS for web-based SSO is, that any CAS-enabled application can use the ticket issued by the CAS server for authentication, as long as the server can read the cookie placed (so, it has to be the same URI that reads the cookie, not necessarily the same server).

Serving the greater good

The server works a bit different, and necessarily so. It takes the user's credentials, authenticates the user against the configured form of storage, and redirects back to the application requesting the authentication of the user.

For authentication, RubyCAS server brings three pre-configured Authenticators:

  • CASServer::Authenticators::LDAP to authenticate against an LDAP directory service, and LDAP's cousin Active Directory gets its own Authenticator, called.
  • Additionally, there is an SQL authenticator CASServer::Authenticators::SQL, which can use any SQL database that ActiveRecord can talk to.
  • If none of these fit the bill, you can apparently use CASServer::Authenticators::Base to roll your own authenticator (the RDoc documentation is rather silent on the issue, and I haven't dug into the source code yet).

Concluding the obvious

As long as you use Ruby, you should be able to use RubyCAS client (you'll probably have to do some source code hacking if you don't use ActiveRecord for the RubyCAS server, though).

This should be of a great boon in any organization using the CAS system already. And the wealth of client options provided by the CAS ecosystem should make CAS an easy sell if you are looking for an SSO solution.

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.