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
railsapp/lib/custom_auth.rb
module
CustomAuth
module
Devise
module
Strategies
class
FromSession < ::Devise::Strategies::Base
def
valid?
# this strategy is only valid if there is a url_token
# in the params hash.
params[
:url_token
]
end
def
authenticate!
# 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
if
session_data[
'error'
]
# session lookup failed so fail authentication with message from api
fail!(session_data[
'error'
])
else
# we got some valid user data
success!(User.find(session_data[
'user_id'
]))
end
end
end
end
end
end
config.warden
do
|manager|
manager.strategies.add(
:custom_auth
, CustomAuth::Devise::Strategies::FromSession)
manager.default_strategies(
:scope
=>
:user
).unshift
:custom_auth
end
- The HTTP request enters the rack stack.
- Warden gets the request and forwards it in the rack stack, adding an environment variable “warden” that points to an authentication proxy.
- 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).
- The warden proxy picks an authentication strategy. Any strategy for which valid? returns true is tried.
- 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!.