10.19.06

Authentication for your API or Feed

by Chris Abad

Getting authentication for your your API or your RSS /Atom feed is a lot simpler than you might think. Long story short, restful_authentication will default to act like HTTP Basic Auth for xml requests. Its just a small step from there to get the same functionality for your RSS feeds.

I’ve always liked acts_as_authenticated for my authentication needs. restful_authentication is simply a more “RESTful” version of this plugin. When I realized I could continue using this same authentication system for all my authentication needs, I knew I had a winner.

Enough talking, let’s jump in! Start off by installing the simply_restful plugin:

script/plugin install -x http://svn.techno-weenie.net/projects/plugins/restful_authentication

Follow the README to get the plugin up and running. We’ll start off with an easy one. Let’s look at adding authentication to our REST API . Be sure to require authentication your controller:

before_filter :login_required

That’s more or less it. Here’s where the magic happens (you’ll find this in lib/authenticated_system.rb):

def login_required
username, passwd = get_auth_data
self.current_user ||= User.authenticate(username, passwd, current_subdomain) || :false if username && passwd
logged_in? && authorized? ? true : access_denied
end
def get_auth_data
user, pass = nil, nil
# extract authorisation credentials 
if request.env.has_key? 'X-HTTP_AUTHORIZATION' 
# try to get it where mod_rewrite might have put it 
authdata = request.env['X-HTTP_AUTHORIZATION'].to_s.split 
elsif request.env.has_key? 'HTTP_AUTHORIZATION' 
# this is the regular location 
authdata = request.env['HTTP_AUTHORIZATION'].to_s.split  
end 
# at the moment we only support basic authentication 
if authdata && authdata[0] == 'Basic' 
user, pass = Base64.decode64(authdata[1]).split(':')[0..1] 
end 
return [user, pass] 
end
def access_denied
respond_to do |accepts|
accepts.html do
store_location
redirect_to :controller => '/sessions', :action => 'new'
end
accepts.xml do
headers["Status"]           = "Unauthorized" 
headers["WWW-Authenticate"] = %(Basic realm="Outlandish API")
render :text => "Could't authenticate you", :status => '401 Unauthorized'
end
end
false
end

What this does have your login_required before_filter re-grab your login/password if its available via HTTP Basic Auth. If you try to login through XML and you’re denied, it’ll return the proper 401 Unauthorized status.

Adding the same authentication functionality to your RSS feeds is pretty simple. The only change you need to make is to make sure that the proper status is returned for your RSS requests if the login fails. Just modify the access_denied method:

def access_denied
respond_to do |accepts|
accepts.html do
store_location
redirect_to :controller => '/sessions', :action => 'new'
end
accepts.xml do
headers["Status"]           = "Unauthorized" 
headers["WWW-Authenticate"] = %(Basic realm="Outlandish API")
render :text => "Could't authenticate you", :status => '401 Unauthorized'
end
accepts.rss do
headers["Status"]           = "Unauthorized" 
headers["WWW-Authenticate"] = %(Basic realm="Outlandish RSS Feed")
render :text => "Could't authenticate you", :status => '401 Unauthorized'
end
end
false
end

There you go, that takes care of it. Simple Basic HTTP Auth for your API and feed, all mixed in with the authentication goodness the rest of your app gets with restful_authentication.

Comments

There are no comments.

Leave a Comment