about archives code photos tumblr twitter

Hancock-Client: Middleware

With the release of sinatra version 0.9.1, programmers have the option to write micro-apps that double as middleware in any other rack enabled application. The beauty in this is that you can write rack middleware without getting bogged down in the details of writing rack directly. Perhaps it’s your first time leveraging rack and you want to test the waters or perhaps you’re just wanting to slap a little bit of functionality onto someone else’s code; sinatra is emerging as a great way for folks to start really sinking their teeth into how rack functions.

I recently found myself waist-deep in rack. A lot of my co-workers at EY have been telling me for some time where rack made sense and where it didn’t. I didn’t really grasp it all. I understood it as a concept but there was nothing in my day to day work that made me say “Hey! I’m gonna use rack here!” At least until the other day. Jon Crosby rocked out with a great talk at MWRC and one of my friends at work had written a little sinatra app that we needed to merge into our Single Sign On(SSO) infrastructure. Tim took advantage of an existing rack openid library and made the necessary modifications to hook it in cleanly, he then went on vacation and left the gem abstraction to me. I’m really grateful for this because it really made me sit down and acquaint myself with sinatra. What I found was something pleasurable, elegant, and useful.

The hancock-client gem is an abstraction of our rack based SSO middleware in use at Engine Yard but modified to communicate with the hancock sso server. The gem provides a sinatra application that can be run as a standalone application or used as middleware in rails or merb. The application itself encompasses all of the logic required to negotiate the SSO protocol with a provider and populate session variables. You can pretty much expect that the sinatra app provided by the hancock-client gem will integrate well with a hancock provider of the same version.

So when I started trying to get the middleware going I decided on three things that were necessary for it:

This makes sense for the simplest possible consumer that does something useful. The login and logout actions are mapped to /sso/login and /sso/logout respectively. Does the “after you login you should be greeted” step really make sense for middleware though? I feel like the answer is no in this situation and it’s where the beauty of rack really comes to light. Since my code shares the same rack session that my framework code will share, maybe I should leave that greeting page up to the app that’s using the middleware.

Middleware

The SSO middleware handles the authentication earlier in the stack than your framework and all you need to do is rely on a set of conventions that the middleware provides to the framework layer. In the case of hancock-client it sets the :user_id session variable. Depending on your middleware ordering this happens way before your framework is hit. The basic approach for the initial release of hancock-client went something like this, “only implement login and logout but provide examples of how you might use it in your framework of choice.”

What we created was a class that inherited from Sinatra::Default called Hancock::Client::Default. This class was created with the idea that an application developer would inherit from it and implement the greeting page at ”/”. So in its simplest form you can implement a hancock-client app in the following fashion: