Ruby On Rails, Design, Simplicity, Web 2.0, Ajax, Mac and Tons of Pizza.

Jul 10

HOWTO Put a controller under a SSL subdomain

Posted by Sandro Paganotti in Ruby on Rails - comments are closed digg this add to delicious

Let’s imagine that you need to create a secure login area, for example if you own http://www.domain.com you may want to put the user login page on https://secure.domain.com. How can you do it?

The best solution in my opinion is to put all the login procedures in a dedicated login controller (eg the ‘sessions’ controller if you are using the RESTful authentication plugin) and then modify a bit the url_for method in order to modify the calls to that controller.

Part 1, A little configuration.

In our environment.rb we’re going to create an array with the name of the controllers we want to put under a different subdomain and under SSL:

SECURE_MODE = [ /\/sessions$/ ].freeze
SECURE_SUBDOMAIN = "secure".freeze

Part 2, Url_for tweaking

Then in our application.rb we have to tweak a bit the url_for function in order to let the defined controllers being handled correctly.


def url_for(options = {}, *parameters_for_method_reference)
    tmp_result = super((options.is_a?(Hash) ? options.merge({:only_path => false}) : options), parameters_for_method_reference)
    if not (tmp_result =~ Regexp.new(request.host)).nil?

      # this tweak is necessary just beacuse I use WebBrick for my development environment (aka I need to specify the port)
      if ENV['RAILS_ENV'] == 'production'
        cut_result = tmp_result.to_s.gsub( Regexp.new("#{request.protocol}#{request.host}") ,"" )
      elsif ENV['RAILS_ENV'] == 'development'
        cut_result = tmp_result.to_s.gsub( Regexp.new("#{request.protocol}#{request.host_with_port}"), "" )
      end

      # We're going to talk about this function later
      url_to_go = dispatch_ssl(cut_result)
    end

    super((url_to_go.nil? ? tmp_result : url_to_go), parameters_for_method_reference)

end


Part 3 Dispatching urls

dispatch_ssl is a function I wrote that receive a partial url (eg /session) and returns the path modified in order to match the new subdomain and protocol rules.


  def dispatch_ssl(tmp_result = request.request_uri)
    subdomain = SECURE_SUBDOMAIN.blank? ? "" : SECURE_SUBDOMAIN + "." 
    # need secure is a function that simply check if this path need to be put under SSL
    if need_secure?(tmp_result)
      if request.protocol == 'http://'
        url_to_go = "https://#{subdomain}" + request.host + tmp_result 
      end
    else
      if request.protocol == 'https://'
        host = request.host.gsub(Regexp.new(subdomain),"")
        url_to_go = 'http://' + host + tmp_result 
      end
    end
    return url_to_go
  end

Last but not Least: need_secure? and ssl_require

The first function is used by dispatch_ssl to check if the current url match the SECURE_MODE array, the second one (ssl_require) have to be called in a before_filter directive and detects if the user is trying to access a secure area without the correct subdomain and protocol; if this happens the user will be redirected to the correct url.



  def need_secure?(uri)
    SECURE_MODE.each{ |s|  
      a = (uri =~ s)
      return true unless a.nil? 
    }
    return false;
  end

  def ssl_required 
    if not (redir = dispatch_ssl.to_s).blank?
      redirect_to(redir) and return false
    end
  end


I hope this little tutorial will help you somehow :-)

Sandro

Comments

  • Kyle

    Posted on July 16

    Hello, I'm trying to use your method but with one slight twist. My ssl certificate is a shared one, and when I use it i'm redirected to a url as follows: ssl.hostingcompany.com/mydomain.com/my/rails/app I modified your code and can now get the urls modified, but, I just enter an endless loop now where I'm constantly redirect between a couple of urls. Any Ideas, Kyle
  • Sandro

    Posted on July 17

    Hi Kyle Could you please send me an email (sandro at railsonwave dot com) with the exact sequence of the urls your application ping ? It is surely a problem related with the before_filter function that somehow don't recognize your SSL url properly. Also check (via console) if all the urls you want to put under SSL are listed into your SECURE_MODE array. Sandro.

Post a comment

Categories:

Tags:

Powered by Mephisto, Valid XHTML 1.1, Valid CSS - Supported by Wave Factory