Story Telling

To provide an application that does what the user wants and does what the user wants, we need, obviously enough, requirements and maybe even a specification (depending on where and how the application gets deployed, if legal requirements have to be figured in, or high availability has to be guaranteed, for example).

For the scope of this project (quick recap: Document management), requirements are enough.

Now, we have to capture these requirements in a way that our client (who isn't necessarily tech-savvy) understands, and that allows us, the developers, to know exactly what has to be done to fulfill the user's needs.

That means we have to use a language that both sides understand and that is free from ambiguities.

Both vanilla English or your native language as well as a programming language are ill suited to this task: Spoken languages are filled with ambiguities, and programming languages are not necessarily understood by the client.

What we need is something that is non-ambiguous, but easily understood.

The solution is rather obvious: An English (or your native language) with limited vocabulary, that can be intuitively understood and has only a few rules, internalized quickly.

For that, we should look at what Extreme Programming has to offer: User stories.

And we can take this to the extreme (so to speak, and pardon the pun) in the Ruby world with RSpec, a BDD testing framework. In the next few posts I'll take a look at RSpec and BDD, and share my thoughts and examples (bear with me: I'm taking a serious look at BDD/RSpec for the first time, myself).

Collecting requirements: Tedious, but fun

My client finally decided on a back end for a central storage solution for the users: LDAP.

With that said, I have decided to use RubyCAS server and client for my user authentication scheme. It supports SSL, which is a big win for security.

With that knowledge, I can now work on how to handle users. Fortunately, the role system isn't all too complex: there's users, and there's admins. That's it.

Users shall be able to manage documents in the app, and admins can, additionally, configure the application.

However, I wonder if I really need an admin panel for this application. After all, I could use YAML for application configuration, where settings are necessary. Which won't be a whole lot of options, either, as the application is simple.

Let's recap for a bit:

My client wants a document management system, that stores electronic representations, and the physical location of documents.

To achieve that, users need to be able to add documents (obvious), and add metadata.

Of course, we are using computers here, so we should automate as much as possible. A prime candidate is importing the documents.

How can we do that?
Basically, there are three options coming to my mind:

  1. Using an application running on the client computers that scans the client, gathers new documents, and pushes that information into the web application.
  2. Mounting a network share (via SMB or NFS, for example), and put the electronic documents on that, and have the web application scan this network share to import the documents.
  3. Use a script that scans an upload directory for new documents, and add them to the web application's dataset.
Let's look at these approaches in detail:

Number 1 has several downsides: It requires an install on the client, it requires syncronization of data between the server and the client to figure out what is new (or we need an 'imported' flag), we add to the overhead that is transmitted over the network (not by much, but every little bit matters).
On the upside, we could import only only what the user wants to import, and he can add all the metadata befopre the data is imported.

With approach 2, we have to break the web application out of the webserver's environment, and grant it access to an external (to the web-root) directory. This is a really bad choice from a security standpoint.

Approach number 3 side steps several issues: It allows to import data from an arbitrarily chosen directory, we can hook up virus scanners if we needed, we don't have to expose the webserver more than necessary, we can use the SMB/NFS/whatever security for file transfers, and we don't have to worry about syncronization issues.

Additionally, we can use the server's file system to fill in a bit of metadata (date created, user who created it). And we also don't have to worry about uploads, either, and we can secure the network share via, for example, TLS.

We also don't need to do fancy tricks. The application can do one thing, and do it well, the script does one thing, and do it well.

So, where do administrative tasks figure into this? Apparently, they don't. The web application doesn't need to be configured, or administrate anything as it stands.

So, all we need is to configure the script which directory and sub-directories to scan, how to get the metadata for the files imported, and have it import the data into the database.

The script can also send out alerts if documents need additional information, and provide one or multiple links to the documents needing additional treatment from within the webapplication itself.

That sounds like a good approach, doesn't it?

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.

I am lazy. That's why I like J2EE

No, really. Without J2EE, I wouldn't have access to Glassfish, with its wonderful autodeploy directory to, well, autmatically delpoy applications on it.

Without Java, I wouldn't be able to use JRuby.

And neither would I be able to use Warbler to create .war-files for drag and drop deployment.

In the span of 30 minutes (half of which is related to my underspec'd development environment), I was able to deploy a Rails application.

First, you need to setup your Rails application for use with JDBC. In Rails 2.0 it is as easy as this database.yml:

development:
host: localhost
adapter: jdbc
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/application_db
username:
password:
With the Warbler gem, you can easily create a war file:
jruby -S warble war
To fine-tune your configuration (if Warble's defaults aren't as good for you as they could), just run
jruby -S warble config
You can edit the resulting config\warble.rb for some fine tuning (I'll have to look into it, for example how to tell it to use a specific JRuby version).

Once you are ready to create your .war-file:
jruby -S rake war:standalone:create
Thsi creates a war file inculding the JRuby runtime. Drop into your domain's autodeploy folder, and wait until Glassfish is done deploying it. Done. You have a working, deployed, and automagically scaling Rails application. No need to herd a pack of Mongrels, futy with mod_proxy, or anything else. Wonderful.

BUT there is one issue you migth have (whcih is unrelated to Ruby, JRuby, or Glassfish):

It is possible that your Rails app throws the following exception:
No :secret given to the #protect_from_forgery call. Set that or use a session store capable of generating its own keys (Cookie Session Store).
Don't fret. Either use the correct security, or change your app/controllers/application.rb so it looks like this:
protect_from_forgery :secret => 'a_really_long_pseudo_random_hash_thing'

Simply remove the comment in front of the :secret. Done. Enjoy the bonus you just ensured for yourself, since you avoided at least a day of additional deployment and configuration, and/or learning capistrano.

P.S.: Still working on the comparison of OpenID and CAS for Ruby, so this is a bit of filler content.

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.

Kicking off the blog (and the project, too)

I promised myself, that I'd chronicle my efforts in developing a project from start to finish.

Well, this won't quite work out, since I already have the contract in hand. ;)

However, I'll write up what I am going to do, what I am doing, and the milestones reached. Well, a software development blog.


So, what's the project about?

I have to build a web-based Document management system.

Requested Features:

  • Single Sign On
  • Import documents from a network share
  • Storage of metadata (an odd one in this case is, that physical locations have to be recorded, too, in case the government agency sending it cannot deal with electronic documents. Legal requirements are fun like that)
  • Fortunately, no detailed tracking for SOX or other such regulations.

What's coming up

At first, I'll post progress about gathering requirements, proposals and recommendations of solutions for these requirements that go out to the client (after I've sent them, though).

After that, I'll report my progress with the application: What I did, why I did it, and what the challenges were.

And last but not least, I'll talk about the deployment of the application, and its maintenance.

So, what are you using?

The web application framework is going to be Ruby on Rails, the database back-end MySQL, the webserver will be Apache of some sort. What'll serve the Rails pages I don't know yet. Maybe Glassfish with JRuby, maybe mod_rails, possibly the classic Apache + Pack of Mongrels solution. We'll see when I get there.

My development OS will be Windows XP together with a Debian VM and a Kubuntu 8.04 installation as primary development OS.

The deployment will be on FreeBSD 5.4 (I know, I can't influence that, and neither can my client).

The approach I'll be using, even though I'm just one person, is a simple variant of Agile Development: Sprints, and loads of tests before I write the actual code.