Company wide Single Sign On(SSO) using Devise custom authentication strategy

It is a common requirement to have a single sign on for multiple software services provided by a company, something like google account with multiple google services like gmail,docs,google+ . In order to do this it would be best to have a RESTful application responsible for authentication and have all other services authenticate against this application.

To authenticate users of our rails application against an external API we add a custom authentication strategy to devise. Devise is a flexible authentication solution for Rails based on Warden. Warden uses the concept of cascading strategies to determine if a request should be authenticated. Warden will try strategies one after another until either, – One succeeds – No Strategies are found relevant – A strategy Fails.

These are the steps to add custom authentication strategy.

1. Create your own strategy implementation inheriting from Devise::Strategies::Base



      classFromSession < ::Devise::Strategies::Base
          # this strategy is only valid if there is a url_token
          # in the params hash.
          # e.g. http://myapp?url_token=mysecrettoken
          # lookup session data with external api
          session_data = get_session_data_from_api(params[:url_token])
          # check if token was valid and authorise if so
            # session lookup failed so fail authentication with message from api 
            # we got some valid user data
2. Add this strategy to warden
config.warden do|manager|

  manager.strategies.add(:custom_auth, CustomAuth::Devise::Strategies::FromSession)
  manager.default_strategies(:scope=> :user).unshift :custom_auth
Devise flow diagram
  1. The HTTP request enters the rack stack.
  2. Warden gets the request and forwards it in the rack stack, adding an environment variable “warden” that points to an authentication proxy.
  3. The request gets dispatched to the rails controller, which may call authenticate_user! from a filter. This is an alias for request.env[‘warden’].authenticate!(:scope => :user).
  4. The warden proxy picks an authentication strategy. Any strategy for which valid? returns true is tried.
  5. When authentication succeeds, a user object is returned to the controller. When it fails, the symbol :warden is thrown down the stack, and caught by the warden rack application. The latter will return a response, which is a redirect to the login page by default. This can be overridden by calling warden.custom_response!.
Testing custom authentication strategy
To test the custom authentication strategy use Fakeweb and get a list of responses from the external API an add different test cases.

Deployment with Capistrano

To understand the deployment process of a rails application, I planned on deploying the paperclip_sample_app  from the previous post to an Amazon EC2 instance using capistrano. In this post I will list the various steps involved in the deployment process. Deploying any application is pretty time consuming so be prepared to give your self enough time.

The first step is to create an instance and setup it up. For a personal ruby project the amazon micro instance is an ideal candidate ( Log in to you aws management console (

Select the EC2 tab and hit the Launch Instance button.

Select the Community AMIs tab and search for “ubuntu 10.04”. I have had package dependency issues with the “ubuntu 10.10”.  Select the ami-054e9a6c instance.

Double check that it is the micro instance and hit continue.

Hit Continue

Hit Continue

Hit Continue and select the create new key pair button and download the keys.

Create a security group from the EC2 tab with the following permissions.

Port 22 – ssh

Port 80 – HTTP

Port 3306 – mysql

Select the security group and hit continue.

Launch the instance.

Connecting to the instance – It is very important to follow the steps in the link given below in order to avoid permission issues during application deployment.

$ cd ~/.ec2

ssh -i key1.pem

To deploy the rails application, the EC2 instance has to be setup with Ruby, Apache server, Phusion Passenger. These are the following steps:

$ sudo apt-get update

$ sudo apt-get dist-upgrade

$ sudo apt-get install openssh-server

$ sudo apt-get install mysql-server

$ sudo apt-get update

$ sudo apt-get dist-upgrade

$ sudo apt-get install build-essential

Install rvm and dependencies

sudo apt-get install zlib1g-dev libssl-dev libreadline5-dev libxml2-dev libsqlite3-dev

$ bash -s stable < <(curl -s

$ echo “[[ -s $HOME/.rvm/scripts/rvm ]] && source $HOME/.rvm/scripts/rvm” >> ~/.bash_profile

$ source ~/.bash_profile

$ sudo apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion

$rvm install 1.9.2

This will take around 15 to 20 minutes.

$rvm use 1.9.2

Installing passenger and its dependencies

$ sudo apt-get install apache2-prefork-dev libapr1-dev libaprutil1-dev

$ gem install passenger

$ passenger-install-apache2-module

$ sudo apt-get install libcurl4-openssl-dev

$ sudo apt-get install apache2-mpm-prefork

$ passenger-install-apache2-module

Edit /etc/apache2/apache2.conf

$ sudo vi /etc/apache2/apache2.conf

Navigate to the bottom of the file and hit i.

Hit enter and paste the following lines.

LoadModule passenger_module /home/ubuntu/.rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11/ext/apache2/
PassengerRoot /home/ubuntu/.rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11
PassengerRuby /home/ubuntu/.rvm/wrappers/ruby-1.9.2-p290/ruby

Hit ESC and type :wq!

This saves the changes.

This is a useful tutorial on vi editor.

Restart apache server

$ sudo /etc/init.d/apache2 restart

To verify, enter the public DNS of your instance in a browser.

Sync github to the server

$ chmod 700 .ssh/

Deploying rails app using capistrano

$ cd /var/www

$ sudo mkdir apps

$ cd apps

$ sudo mkdir paperclip_sample_app

Set correct permissions for ubuntu by making ubuntu the owner of the following directories.

$ chown ubuntu /var/www/apps

$ chown ubuntu /var/www/apps/paperclip_sample_app

copy the public key(~/.ssh/ on your machine to the ~/.ssh/authorized_keys folder

cat ~/.ssh/ | ssh -i key1.pem ‘cat >> .ssh/authorized_keys’

This is very important, otherwise capistrano asks for password during  deployment.

$ capify .

Here is the config/deploy.rb file

commit to github

$ cap deploy:setup

$ cap deploy:check

If we get this error

$ cd /var/www/apps/paperclip_sample_app/current

$ rvm use 1.9.2

$ rvm gemset use global

$ gem install rake

create the db(should have the same name as that in the config/db file)

Before configuring apache server we need to associate the amazon instance with an IP address and buy a domain name.

Configuring apache to render the newly deployed app.

$ sudo vi /etc/apache2/sites-available/paperclip_sample_app

Add the following content to /etc/apache2/sites-available/paperclip_sample_app

<VirtualHost *:80>
DocumentRoot /var/www/apps/paperclip_sample_app/current/public
<Directory /var/www/apps/paperclip_sample_app/current/public>
AllowOverride all
Options -MultiViews

$ sudo a2dissite default

$ sudo a2ensite paperclip_sample_app

$ sudo /etc/init.d/apache2 reload

Open a browser and enter the domain name or IP address of you instance. You should now be able to see the newly deployed site.