Testing SSL in Rails

Posted by Luke Francl
on Friday, September 12

Here’s a quick tip for how to test that your application is using SSL correctly.

Enabling SSL in tests

You can turn SSL on in functional tests like this:

@request.env['HTTPS'] = 'on'

I have this turned on in my setup method and then override it for tests that don’t use SSL. To turn SSL off, use this:

@request.env['HTTPS'] = nil

(Via snippets)

Testing for SSL redirect

To test and see if you users will get redirected to SSL for particular actions, you can write a test like this. First, it turns off SSL. Then it makes a request to a method that should require SSL, and asserts that the request is redirected to the same URL, but using the https protocol.

1
2
3
4
5
6

def test_get_new_with_http_should_redirect_to_ssl
  @request.env['HTTPS'] = nil
  get :new
  assert_redirected_to "https://" + @request.host + @request.request_uri
end

Implementing the code

Having done this, you probably have a bunch of failing tests. To make them pass, get the SslRequirement plugin (I’m actually using Doug Johnson’s fork that adds support for different SSL domains, like secure.example.com).

Include SslRequirement in application.rb, and then in your secure controllers, add a line like this:

ssl_required :new, :create

Then run your tests.

Now the thing about this is that it is also going to try to send you to an HTTPS URL in development mode. Since most people don’t actually have SSL set up on their development environment, it makes sense to disable this in development.

ssl_required :new, :create if RAILS_ENV 'production' || RAILS_ENV ‘test’

Or for you fancy-pants Rails 2.1 types:

ssl_required :new, :create if Rails.env.production? || Rails.env.test?

(Yeah, you could also use unless Rails.env.development?, but I actually have a couple other environments configured that I do not want to enable SSL for.)

Photo by Darwin Bell.

Comments

Leave a response

  1. Eric ChapweskeSeptember 12, 2008 @ 01:27 PM

    I wanted to disable SSL in development as well, but ended up having lots of duplication. This cleaned things up a bit:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    
        SSL_ENVIRONMENTS = Set[ 'production', 'staging', 'test' ]
      
        protected
    
        def ssl_required_with_environment?
          SSL_ENVIRONMENTS.include?(Rails.env) && ssl_required_without_environment?
        end   
        alias_method_chain :ssl_required?, :environment
    

    In retrospect I probably should’ve specified NON_SSL_ENVIRONMENTS instead.