Thursday 29 April 2010

current_user in rubyCAS-client

With restful_authentication (or other schemes) we have a requires_login before_filter which you stick at the top of your controllers, to make sure certain actions are protected by login. It also tends to take care of the slightly messy logic involved in setting up the extremely useful current_user variable.

Obviously our applications have already been built around this logic existing, so a smooth transition requires the same sort of functionality.

The ruby-CAS (client) provides a basic before_filter for us that takes care of the nasty talking-to-the-rubyCAS-server logic... at the end of which we know whether or not the person talking to us is known to the system. But we still to actually associate this person with a real live User model on our system, and save them into the current-user variable.

On our system, after going through the provided before_filter, we have configured the server to provide two things in the session:

  1. the :cas_user, which is the user's username and
  2. a set of :extra_attributes which is a set of other fields we've asked CAS to provide and which we'll use later for roles (see authorisation for more on that)

If we want any other user information - we will need to go fetch it by hand from our local db, and we'll need to do this directly after the main rubyCAS before_filter. So, we'll need something like the following, probably put into ApplicationController

  # this is the before_filter provided by rubyCAS client
  before_filter CASClient::Frameworks::Rails::Filter
  # this is a call to our own new before_filter
  before_filter :setup_cas_user

  # actions go here...

  # and at the bottom of the controller file...
  private
    # this before_filter takes the results of the rubyCAS-client filter and sets up the current_user
    def setup_cas_user
      # save the login_url into an @var so that we can later use it in views (eg a login form)
      @login_url = CASClient::Frameworks::Rails::Filter.login_url(self)

      # if we don't have the :cas_user in the session, then we are not logged into rubyCAS
      # we could have none because:
      #   1) we have failed login or 
      #   2) because we don't necessarily need to login to get here
      # either way we need to skip out here
      return unless session[:cas_user].present?

      # so now we go find the user in our db
      @current_user = User.find_by_username(session[:cas_user])
      @current_user.present?
    end

Pretty simple

What if the user isn't on this application yet?

Good question - it is possible to have created a user on one application and of course, using single sign-on, you may want to automatically sign your users up into another application. This could easily be done here with a slight addition to the before_filter:

      # so now we go find the user in our db - or create them if they don't yet exist.
      @current_user = User.find_or_create_by_username(session[:cas_user])
      @current_user.present?

Note: the only information linking the two user-records will be the username. You won't be able to access any other information (eg address or other details) unless you physically query your other application's user record... though this is a good use-case for passing extra information through the extra_attributes fields. Still, it does allow your users to seamlessly transition from one of your applications to another.

This is one article in a series on Rails single-sign-on with rubyCAS

3 comments:

Sudipto said...

Thank you for your post.
I am new to redmine and ruby. I have implemented cas in my local machine connecting to the cas server for my application but when i trying to implement cas to my live server the server is coming to a halt.This is because cas_user is missing.I have the user in my server based application database as well as at cas server database.Thus i am getting the session but user is not getting validated at my application.I assume this is because of some service which is not running at my server. I am using linux suse enterprise version ,mongrel as my application server.Any help will be really appreciated.
Thanks
sudiptodey.4u@gmail.com

Taryn East said...

Hi Sudipto. This sounds like a question that you should ask on StackOverflow.com
It's been a long while (1.5 years) since I've done anything in RubyCAS, so you'll probably get far better help there.

Sudipto said...

Thank u Mam I will put this issue in stackoverflow. I m just a fresher.Actually i went through your posts they are really helpful.But I checked for this issue in various forums and even logged it in redmine. This issue is already logged in stackoverflow by someone else but didn't have a reply to it.