request_forgery_protection_test.rb 6.0 KB
Newer Older
1
require 'abstract_unit'
M
Michael Koziarski 已提交
2
require 'digest/sha1'
3 4 5 6 7

ActionController::Routing::Routes.draw do |map|
  map.connect ':controller/:action/:id'
end

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
# simulates cookie session store
class FakeSessionDbMan
  def self.generate_digest(data)
    Digest::SHA1.hexdigest("secure")
  end
end

# common controller actions
module RequestForgeryProtectionActions
  def index
    render :inline => "<%= form_tag('/') {} %>"
  end
  
  def show_button
    render :inline => "<%= button_to('New', '/') {} %>"
  end
  
  def unsafe
    render :text => 'pwn'
  end
  
  def rescue_action(e) raise e end
end

# sample controllers
class RequestForgeryProtectionController < ActionController::Base
  include RequestForgeryProtectionActions
  protect_from_forgery :only => :index, :secret => 'abc'
end

class RequestForgeryProtectionWithoutSecretController < ActionController::Base
  include RequestForgeryProtectionActions
  protect_from_forgery
end

# no token is given, assume the cookie store is used
class CsrfCookieMonsterController < ActionController::Base
  include RequestForgeryProtectionActions
  protect_from_forgery :only => :index
end

class FreeCookieController < CsrfCookieMonsterController
  self.allow_forgery_protection = false
  
  def index
    render :inline => "<%= form_tag('/') {} %>"
  end
  
  def show_button
    render :inline => "<%= button_to('New', '/') {} %>"
  end
end

# common test methods

63
module RequestForgeryProtectionTests
64 65 66
  def teardown
    ActionController::Base.request_forgery_protection_token = nil
  end
67
  
68 69
  def test_should_render_form_with_token_tag
    get :index
70
    assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
71
  end
72 73 74 75 76
  
  def test_should_render_button_to_with_token_tag
    get :show_button
    assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
  end
77 78 79 80 81 82 83 84 85 86 87 88

  def test_should_allow_get
    get :index
    assert_response :success
  end
  
  def test_should_allow_post_without_token_on_unsafe_action
    post :unsafe
    assert_response :success
  end
  
  def test_should_not_allow_post_without_token
89
    assert_raises(ActionController::InvalidAuthenticityToken) { post :index }
90 91 92
  end
  
  def test_should_not_allow_put_without_token
93
    assert_raises(ActionController::InvalidAuthenticityToken) { put :index }
94 95 96
  end
  
  def test_should_not_allow_delete_without_token
97
    assert_raises(ActionController::InvalidAuthenticityToken) { delete :index }
98 99 100
  end
  
  def test_should_not_allow_xhr_post_without_token
101
    assert_raises(ActionController::InvalidAuthenticityToken) { xhr :post, :index }
102 103 104
  end
  
  def test_should_not_allow_xhr_put_without_token
105
    assert_raises(ActionController::InvalidAuthenticityToken) { xhr :put, :index }
106 107 108
  end
  
  def test_should_not_allow_xhr_delete_without_token
109
    assert_raises(ActionController::InvalidAuthenticityToken) { xhr :delete, :index }
110 111 112
  end
  
  def test_should_allow_post_with_token
113
    post :index, :authenticity_token => @token
114 115 116 117
    assert_response :success
  end
  
  def test_should_allow_put_with_token
118
    put :index, :authenticity_token => @token
119 120 121 122
    assert_response :success
  end
  
  def test_should_allow_delete_with_token
123
    delete :index, :authenticity_token => @token
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    assert_response :success
  end
  
  def test_should_allow_post_with_xml
    post :index, :format => 'xml'
    assert_response :success
  end
  
  def test_should_allow_put_with_xml
    put :index, :format => 'xml'
    assert_response :success
  end
  
  def test_should_allow_delete_with_xml
    delete :index, :format => 'xml'
    assert_response :success
  end
end

143
# OK let's get our test on
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158

class RequestForgeryProtectionControllerTest < Test::Unit::TestCase
  include RequestForgeryProtectionTests
  def setup
    @controller = RequestForgeryProtectionController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
    class << @request.session
      def session_id() '123' end
    end
    @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
    ActionController::Base.request_forgery_protection_token = :authenticity_token
  end
end

159 160 161 162 163 164 165 166 167 168
class RequestForgeryProtectionWithoutSecretControllerTest < Test::Unit::TestCase
  def setup
    @controller = RequestForgeryProtectionWithoutSecretController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
    class << @request.session
      def session_id() '123' end
    end
    @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
    ActionController::Base.request_forgery_protection_token = :authenticity_token
169 170
  end
  
171 172 173 174
  def test_should_raise_error_without_secret
    assert_raises ActionController::InvalidAuthenticityToken do
      get :index
    end
175 176 177 178
  end
end

class CsrfCookieMonsterControllerTest < Test::Unit::TestCase
179
  include RequestForgeryProtectionTests
180 181 182 183 184
  def setup
    @controller = CsrfCookieMonsterController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
    class << @request.session
185
      attr_accessor :dbman
186
    end
187 188
    # simulate a cookie session store
    @request.session.dbman = FakeSessionDbMan
189
    @token = Digest::SHA1.hexdigest("secure")
190
    ActionController::Base.request_forgery_protection_token = :authenticity_token
191 192 193
  end
end

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
class FreeCookieControllerTest < Test::Unit::TestCase
  def setup
    @controller = FreeCookieController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
    @token      = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
  end
  
  def test_should_not_render_form_with_token_tag
    get :index
    assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false
  end
  
  def test_should_not_render_button_to_with_token_tag
    get :show_button
    assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false
  end
  
  def test_should_allow_all_methods_without_token
    [:post, :put, :delete].each do |method|
      assert_nothing_raised { send(method, :index)}
    end
  end
217
end