Enabling url parameter based sessions in Ruby on Rails

Posted by Paul McMahon Fri, 09 Apr 2010 04:33:00 GMT

Out of the box, Ruby on Rails uses cookies to store a user's session ID. This is fine for most applications, but doesn't work if your application needs to support browsers that don't support cookies, such as some mobile browsers. Instead of putting the session ID in a cookie, it must be put in the URL. This increases the possibility of session fixation attacks, where one user can take over another's session, however if security isn't paramount, this is an acceptable trade off. See the Ruby on Rails Security Guide for more details on these kinds of attacks.

To enable parameter based sessions in Rails, there are a number of changes you need to make. First, in config/initializers/session_store.rb, change the default file from containing something like

ActionController::Base.session = {
  :key         => '_application_session',
  :secret      => 'secret'
}

to

ActionController::Base.session = {
  :key         => '_application_session',
  :secret      => 'secret',
  :cookie_only => false # allow session to be loaded from params
}

# Overwrite default cookie based store
ActionController::Base.session_store = :active_record_store

Now Rails can read the session ID from the URL parameters, and doesn't store the session in a cookie (the default behaviour). Besides the ActiveRecord session store, other server based stores, such as the memcache store, work as well.

In addition to enabling Rails to read the session ID from the URL parameters, the session ID must be added as a parameter. The most basic way of doing this is to define default_url_options in the ApplicationController:

def default_url_options(options = nil)
  { request.session_options[:key] => request.session_options[:id] }
end

This will ensure that the session ID is always set in the URL.

The session ID can also be added conditionally, by doing something like the following:

def default_url_options(options = nil)
  if cookies_supported?
    super
  else
    { request.session_options[:key] => request.session_options[:id] }
  end
end

If the session ID is not included in the parameters, it will fall back to the cookie.

mobalean releases Japanese WURFL patch, ruby libraries 2

Posted by Paul McMahon Tue, 09 Jun 2009 22:45:00 GMT

mobalean is a strong believer in open source.  Collaboration and sharing are at the core of our philosophy.  So we are proud to announce three contributions to the developer community: a WURFL patch file containing about 700 Japanese handsets, a ruby script for parsing the Japanese carrier data and converting it to the WURFL patch file format, and a major update to the ruby WURFL api.

The WURFL is an XML file containing mobile device information such as supported markup types, screen dimensions, and flash lite support.  While the WURFL has a lot of devices in it, including some Japanese ones, the data for them is both poor in quality, and incomplete.  To remedy this, mobalean has created a WURFL patch containing data on all handsets available from the major Japanese carriers (docomo, au, and SoftBank). 

This patch contains data on approximately 700 handsets and has the carrier values for the WURFL capabilities resolution_height, resolution_width, max_image_width, colors, brand_name, model_name, flash_lite_version, xhtml_table_support, and preferred_markup.  While the base WURFL contains additional capabilities for some Japanese handsets, the values of these capabilities are often wrong.  Rather than trying to validate the data in the base WURFL, this patch takes a blank slate approach, and ignores the devices in the base WURFL (with the exception of fallbacks).  All the data in this patch comes from the carrier's official data, and as such is believed to be correct.

mobalean releases this patch to the community in the hope that other members of the community can help improve it.  As with the base WURFL, you are free to use this patch in any manner you so choose.  Our only request is that if you improve the data within, that you also contribute back this data.  Additionally, we hope this patch can eventually be merged back into the core WURFL so that all WURFL users may benefit from it.

To generate this patch, we scraped the carriers' data using a ruby script.  The script transforms the data into an intermediary result, and from that result into a WURFL patch file.  In addition to the WURFL patch file, we have also released our parsing script.  By open sourcing this script, we believe others in the Japanese mobile community, even those who are not using the WURFL, can benefit.  Additionally, we hope that modifications to the WURFL patch be made via this script instead of directly to the patch.  This way, we believe we can more easily keep the patch up to date with new handsets.

In the process of generating the patch, we wanted a way to test the resultant patch file.  We did not want to parse the XML directly, as that would not take in to account the fallback structure.  So we turned to the ruby WURFL API, but found that it did not work out of the box.  As no one else was currently maintaining this API, we decided to take over it.  In doing so, we've turned it into a ruby gem, and have released version 1.1.0 of it.  We hope that this new, easier to install version will encourage further WURFL development within the ruby community.

mobalean hopes these contributions will be useful to other developers.  If you have any questions about these projects, or anything else, don't hesitate to contact us.

Hacking Ruby's default arguments 2

Posted by Paul McMahon Fri, 27 Feb 2009 22:34:00 GMT

The value of a default argument in Ruby is the result of an executed expression. Most of the time the value is set to some object:

def int(i=1) i; end
def str(s="") s; end

Under normal usage, the fact that the value can be arbitrary code isn't immediately apparent. However, the value really can be any code:

def foo(a = puts("bar")); end

Furthermore, previous arguments can be referenced in the default argument expression:

def bar(a,b=a) puts "a: #{a} b: #{b}"; end

I wondered how far I could take this, and came up with the following method:

def fib(n, t = n < 2 ? n : fib(n-1) + fib(n-2)) t; end

Although it makes little sense to define methods this way, it does highlight the power of Ruby's default arguments.


- 2010 mobalean