Search code examples
ruby-on-railsrspecintegration-testingsession-fixation

Rails/RSpec: reset_session not changing Set-Cookie HTTP header value during integration tests


I'm writing an integration test to make sure my webapp isn't vulnerable to session fixation.

I have manually verified that reset_session is actually firing in the authentication logic, and further that the cookie does indeed change when I log in with my web browser (so, I'm not vulnerable to session fixation anymore), but I can't get my RSpec integration test to successfully verify this.

Here is my RSpec integration test.

require 'spec_helper'

describe "security" do

  self.use_transactional_fixtures = false

  append_after(:each) do
    ALL_MODELS.each &:delete_all
  end

  describe "session fixation" do
    it "should change the cookie session id after logging in" do

      u = test_user :active_user => true,
                    :username => "[email protected]",
                    :password => "asdfasdf"
      u.save!

      https!

      get_via_redirect "/login"
      assert_response :success
      cookie = response.header["Set-Cookie"].split(";").select{|x| x.match(/_session/)}[0].split("=")[1].strip

      post_via_redirect "/login", "user[email]" => "[email protected]",
                                  "user[password]" => "asdfasdf",
                                  "user[remember_me]" => "1"
      assert_response :success
      path.should eql("/dashboard")
      cookie.should_not eql(response.header["Set-Cookie"].split(";").select{|x| x.match(/_session/)}[0].split("=")[1].strip)
    end
  end
end

Everything works except for the very last assert. The cookie doesn't change.

Are there any known issues with RSpec/Rails integration tests where reset_session doesn't work as expected? What can I do to write a test that verifies session fixation is not an issue?


Solution

  • So I eventually did end up figuring this out.

    I was trying to edit the response header directly to test cookies, but I guess that's not the blessed way.

    In integration tests with Rails 2.x anyway, there's a cookies hash that you can use. Here's what the test ended up looking like:

      u = test_user :active_user => true,
                    :username => "[email protected]",
                    :password => "asdfasdf"
      u.save!
    
      https!
    
      get_via_redirect "/login"
      assert_response :success
      cookie = cookies['_session']
      cookie.should be_present
      path.should == "/login"
    
      post_via_redirect "/login", "user[email]" => "[email protected]",
                                  "user[password]" => "asdfasdf",
                                  "user[remember_me]" => "1"
      assert_response :success
      path.should eql("/?login_success=1")
      new_cookie = cookies['_session']
      new_cookie.should be_present
      cookie.should_not eql(new_cookie)