July 16th, 2008
I had a peculiar requirement in a recent project recently, in which we used restful_authentication, where we needed to protect every controller and action from access without authentication. However these same actions also responded to XML requests for ActiveResource models in another app. The XML needed to be available without authentication. This posed more difficulties than I thought it would.
I created a controller class to act as the parent class for all controllers that required authentication (the wisdom of the inheritance strategy here is yet to be established). It applies the login_required filter to all actions, thus protecting all inherited controllers.
To filter out XML requests I took my inspiration from the respond_to method in Rails. This uses a Responder, which in turn uses some sort of mime-type lookup of the format requested by the client. I used this approach in an overridden version of login_required.
# ... class Responder def initialize(controller) @controller = controller @request = controller.request @response = controller.response @mime_type_priority = Array(Mime::Type.lookup_by_extension(@request.parameters[:format]) || @request.accepts) @order = [] @responses = {} end # ... end # ...
The one stumbling block I encountered was that I couldn’t get at the instance properties of Mime::Type in order to decide whether we needed authentication or not. This was because there were no accessors for those properties. In order to get access to them I extended the instance of Mime::Type with a new method to expose the symbol instance property.
class ApplicationAuthController < ApplicationController before_filter :login_required protected # Overidden login_required to allow XML requests through def login_required mime_type = Array(Mime::Type.lookup_by_extension(request.parameters[:format]) || request.accepts).first # We need to get access to the @symbol property of this object. However it has no accessor. # We extend this instance only to have a to_sym method class << mime_type def to_sym @symbol end end logger.debug "Request format: #{mime_type.to_sym}" super if mime_type.to_sym != :xml end end
As you can see, XML requests bypass authentication altogether.
There are dangers in this approach, especially when the assumption of the presence of a valid current_user is made in actions that might deliver both normal application output as well as XML. Some suitably targeted specs should limit the scope for broken actions here.
Sorry, comments are closed for this article.