aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/test/controller
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/test/controller')
-rw-r--r--actionpack/test/controller/helper_test.rb10
-rw-r--r--actionpack/test/controller/http_basic_authentication_test.rb2
-rw-r--r--actionpack/test/controller/metal/renderers_test.rb42
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb46
-rw-r--r--actionpack/test/controller/redirect_test.rb42
-rw-r--r--actionpack/test/controller/render_other_test.rb24
-rw-r--r--actionpack/test/controller/renderers_test.rb90
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb172
-rw-r--r--actionpack/test/controller/test_case_test.rb2
-rw-r--r--actionpack/test/controller/url_for_test.rb7
10 files changed, 395 insertions, 42 deletions
diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb
index 3ecfedefd1..feb882a2b3 100644
--- a/actionpack/test/controller/helper_test.rb
+++ b/actionpack/test/controller/helper_test.rb
@@ -141,20 +141,10 @@ class HelperTest < ActiveSupport::TestCase
def test_helper_for_nested_controller
assert_equal 'hello: Iz guuut!',
call_controller(Fun::GamesController, "render_hello_world").last.body
- # request = ActionController::TestRequest.new
- #
- # resp = Fun::GamesController.action(:render_hello_world).call(request.env)
- # assert_equal 'hello: Iz guuut!', resp.last.body
end
def test_helper_for_acronym_controller
assert_equal "test: baz", call_controller(Fun::PdfController, "test").last.body
- #
- # request = ActionController::TestRequest.new
- # response = ActionDispatch::TestResponse.new
- # request.action = 'test'
- #
- # assert_equal 'test: baz', Fun::PdfController.process(request, response).body
end
def test_default_helpers_only
diff --git a/actionpack/test/controller/http_basic_authentication_test.rb b/actionpack/test/controller/http_basic_authentication_test.rb
index 0a5e5402b9..194f5b3790 100644
--- a/actionpack/test/controller/http_basic_authentication_test.rb
+++ b/actionpack/test/controller/http_basic_authentication_test.rb
@@ -100,7 +100,7 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
assert_no_match(/\n/, result)
end
- test "succesful authentication with uppercase authorization scheme" do
+ test "successful authentication with uppercase authorization scheme" do
@request.env['HTTP_AUTHORIZATION'] = "BASIC #{::Base64.encode64("lifo:world")}"
get :index
diff --git a/actionpack/test/controller/metal/renderers_test.rb b/actionpack/test/controller/metal/renderers_test.rb
new file mode 100644
index 0000000000..007866a559
--- /dev/null
+++ b/actionpack/test/controller/metal/renderers_test.rb
@@ -0,0 +1,42 @@
+require 'abstract_unit'
+require 'active_support/core_ext/hash/conversions'
+
+class MetalRenderingJsonController < MetalRenderingController
+ class Model
+ def to_json(options = {})
+ { a: 'b' }.to_json(options)
+ end
+
+ def to_xml(options = {})
+ { a: 'b' }.to_xml(options)
+ end
+ end
+
+ use_renderers :json
+
+ def one
+ render json: Model.new
+ end
+
+ def two
+ render xml: Model.new
+ end
+end
+
+class RenderersMetalTest < ActionController::TestCase
+ tests MetalRenderingJsonController
+
+ def test_render_json
+ get :one
+ assert_response :success
+ assert_equal({ a: 'b' }.to_json, @response.body)
+ assert_equal 'application/json', @response.content_type
+ end
+
+ def test_render_xml
+ get :two
+ assert_response :success
+ assert_equal(" ", @response.body)
+ assert_equal 'text/plain', @response.content_type
+ end
+end
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index 87816515e7..896bda2597 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -294,7 +294,49 @@ class ParametersPermitTest < ActiveSupport::TestCase
end
test "to_unsafe_h returns unfiltered params" do
- assert @params.to_h.is_a? ActiveSupport::HashWithIndifferentAccess
- assert_not @params.to_h.is_a? ActionController::Parameters
+ assert @params.to_unsafe_h.is_a? ActiveSupport::HashWithIndifferentAccess
+ assert_not @params.to_unsafe_h.is_a? ActionController::Parameters
+ end
+
+ test "to_unsafe_h returns unfiltered params even after accessing few keys" do
+ params = ActionController::Parameters.new("f"=>{"language_facet"=>["Tibetan"]})
+ expected = {"f"=>{"language_facet"=>["Tibetan"]}}
+
+ assert params['f'].is_a? ActionController::Parameters
+ assert_equal expected, params.to_unsafe_h
+ end
+
+ test "to_h only deep dups Ruby collections" do
+ company = Class.new do
+ attr_reader :dupped
+ def dup; @dupped = true; end
+ end.new
+
+ params = ActionController::Parameters.new(prem: { likes: %i( dancing ) })
+ assert_equal({ 'prem' => { 'likes' => %i( dancing ) } }, params.permit!.to_h)
+
+ params = ActionController::Parameters.new(companies: [ company, :acme ])
+ assert_equal({ 'companies' => [ company, :acme ] }, params.permit!.to_h)
+ assert_not company.dupped
+ end
+
+ test "to_unsafe_h only deep dups Ruby collections" do
+ company = Class.new do
+ attr_reader :dupped
+ def dup; @dupped = true; end
+ end.new
+
+ params = ActionController::Parameters.new(prem: { likes: %i( dancing ) })
+ assert_equal({ 'prem' => { 'likes' => %i( dancing ) } }, params.to_unsafe_h)
+
+ params = ActionController::Parameters.new(companies: [ company, :acme ])
+ assert_equal({ 'companies' => [ company, :acme ] }, params.to_unsafe_h)
+ assert_not company.dupped
+ end
+
+ test "included? returns true when the key is present" do
+ assert @params.include? :person
+ assert @params.include? 'person'
+ assert_not @params.include? :gorilla
end
end
diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb
index 631ff7d02a..0b184eace9 100644
--- a/actionpack/test/controller/redirect_test.rb
+++ b/actionpack/test/controller/redirect_test.rb
@@ -42,6 +42,10 @@ class RedirectController < ActionController::Base
redirect_to :back, :status => 307
end
+ def redirect_back_with_status
+ redirect_back(fallback_location: "/things/stuff", status: 307)
+ end
+
def host_redirect
redirect_to :action => "other_host", :only_path => false, :host => 'other.test.host'
end
@@ -187,7 +191,11 @@ class RedirectTest < ActionController::TestCase
def test_redirect_to_back_with_status
@request.env["HTTP_REFERER"] = "http://www.example.com/coming/from"
- get :redirect_to_back_with_status
+
+ assert_deprecated do
+ get :redirect_to_back_with_status
+ end
+
assert_response 307
assert_equal "http://www.example.com/coming/from", redirect_to_url
end
@@ -236,7 +244,11 @@ class RedirectTest < ActionController::TestCase
def test_redirect_to_back
@request.env["HTTP_REFERER"] = "http://www.example.com/coming/from"
- get :redirect_to_back
+
+ assert_deprecated do
+ get :redirect_to_back
+ end
+
assert_response :redirect
assert_equal "http://www.example.com/coming/from", redirect_to_url
end
@@ -244,10 +256,32 @@ class RedirectTest < ActionController::TestCase
def test_redirect_to_back_with_no_referer
assert_raise(ActionController::RedirectBackError) {
@request.env["HTTP_REFERER"] = nil
+
+ assert_deprecated do
+ get :redirect_to_back
+ end
+
get :redirect_to_back
}
end
+ def test_redirect_back
+ referer = "http://www.example.com/coming/from"
+ @request.env["HTTP_REFERER"] = referer
+
+ get :redirect_back_with_status
+
+ assert_response 307
+ assert_equal referer, redirect_to_url
+ end
+
+ def test_redirect_back_with_no_referer
+ get :redirect_back_with_status
+
+ assert_response 307
+ assert_equal "http://test.host/things/stuff", redirect_to_url
+ end
+
def test_redirect_to_record
with_routing do |set|
set.draw do
@@ -273,10 +307,10 @@ class RedirectTest < ActionController::TestCase
end
def test_redirect_to_params
- error = assert_raise(ActionController::ActionControllerError) do
+ error = assert_raise(ArgumentError) do
get :redirect_to_params
end
- assert_equal "Cannot redirect to a parameter hash!", error.message
+ assert_equal "Generating an URL from non sanitized request parameters is insecure!", error.message
end
def test_redirect_to_with_block
diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb
deleted file mode 100644
index 1f5215ac55..0000000000
--- a/actionpack/test/controller/render_other_test.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require 'abstract_unit'
-
-
-class RenderOtherTest < ActionController::TestCase
- class TestController < ActionController::Base
- def render_simon_says
- render :simon => "foo"
- end
- end
-
- tests TestController
-
- def test_using_custom_render_option
- ActionController.add_renderer :simon do |says, options|
- self.content_type = Mime[:text]
- self.response_body = "Simon says: #{says}"
- end
-
- get :render_simon_says
- assert_equal "Simon says: foo", @response.body
- ensure
- ActionController.remove_renderer :simon
- end
-end
diff --git a/actionpack/test/controller/renderers_test.rb b/actionpack/test/controller/renderers_test.rb
new file mode 100644
index 0000000000..e6c2e4636e
--- /dev/null
+++ b/actionpack/test/controller/renderers_test.rb
@@ -0,0 +1,90 @@
+require 'abstract_unit'
+require 'controller/fake_models'
+require 'active_support/logger'
+
+class RenderersTest < ActionController::TestCase
+ class XmlRenderable
+ def to_xml(options)
+ options[:root] ||= "i-am-xml"
+ "<#{options[:root]}/>"
+ end
+ end
+ class JsonRenderable
+ def as_json(options={})
+ hash = { :a => :b, :c => :d, :e => :f }
+ hash.except!(*options[:except]) if options[:except]
+ hash
+ end
+
+ def to_json(options = {})
+ super :except => [:c, :e]
+ end
+ end
+ class CsvRenderable
+ def to_csv
+ "c,s,v"
+ end
+ end
+ class TestController < ActionController::Base
+
+ def render_simon_says
+ render :simon => "foo"
+ end
+
+ def respond_to_mime
+ respond_to do |type|
+ type.json do
+ render json: JsonRenderable.new
+ end
+ type.js { render json: 'JS', callback: 'alert' }
+ type.csv { render csv: CsvRenderable.new }
+ type.xml { render xml: XmlRenderable.new }
+ type.html { render body: "HTML" }
+ type.rss { render body: "RSS" }
+ type.all { render body: "Nothing" }
+ type.any(:js, :xml) { render body: "Either JS or XML" }
+ end
+ end
+ end
+
+ tests TestController
+
+ def setup
+ # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
+ # a more accurate simulation of what happens in "real life".
+ super
+ @controller.logger = ActiveSupport::Logger.new(nil)
+ end
+
+ def test_using_custom_render_option
+ ActionController.add_renderer :simon do |says, options|
+ self.content_type = Mime[:text]
+ self.response_body = "Simon says: #{says}"
+ end
+
+ get :render_simon_says
+ assert_equal "Simon says: foo", @response.body
+ ensure
+ ActionController.remove_renderer :simon
+ end
+
+ def test_raises_missing_template_no_renderer
+ assert_raise ActionView::MissingTemplate do
+ get :respond_to_mime, format: 'csv'
+ end
+ assert_equal Mime[:csv], @response.content_type
+ assert_equal "", @response.body
+ end
+
+ def test_adding_csv_rendering_via_renderers_add
+ ActionController::Renderers.add :csv do |value, options|
+ send_data value.to_csv, type: Mime[:csv]
+ end
+ @request.accept = "text/csv"
+ get :respond_to_mime, format: 'csv'
+ assert_equal Mime[:csv], @response.content_type
+ assert_equal "c,s,v", @response.body
+ ensure
+ ActionController::Renderers.remove :csv
+ end
+end
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 87a8ed3dc9..1984ad8825 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -128,6 +128,23 @@ class CustomAuthenticityParamController < RequestForgeryProtectionControllerUsin
end
end
+class PerFormTokensController < ActionController::Base
+ protect_from_forgery :with => :exception
+ self.per_form_csrf_tokens = true
+
+ def index
+ render inline: "<%= form_tag (params[:form_path] || '/per_form_tokens/post_one'), method: (params[:form_method] || :post) %>"
+ end
+
+ def post_one
+ render plain: ''
+ end
+
+ def post_two
+ render plain: ''
+ end
+end
+
# common test methods
module RequestForgeryProtectionTests
def setup
@@ -623,3 +640,158 @@ class CustomAuthenticityParamControllerTest < ActionController::TestCase
end
end
end
+
+class PerFormTokensControllerTest < ActionController::TestCase
+ def test_per_form_token_is_same_size_as_global_token
+ get :index
+ expected = ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH
+ actual = @controller.send(:per_form_csrf_token, session, '/path', 'post').size
+ assert_equal expected, actual
+ end
+
+ def test_accepts_token_for_correct_path_and_method
+ get :index
+
+ form_token = nil
+ assert_select 'input[name=custom_authenticity_token]' do |elts|
+ form_token = elts.first['value']
+ assert_not_nil form_token
+ end
+
+ actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
+ expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', 'post')
+ assert_equal expected, actual
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one'
+ assert_nothing_raised do
+ post :post_one, params: {custom_authenticity_token: form_token}
+ end
+ assert_response :success
+ end
+
+ def test_rejects_token_for_incorrect_path
+ get :index
+
+ form_token = nil
+ assert_select 'input[name=custom_authenticity_token]' do |elts|
+ form_token = elts.first['value']
+ assert_not_nil form_token
+ end
+
+ actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
+ expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', 'post')
+ assert_equal expected, actual
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_two'
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ post :post_two, params: {custom_authenticity_token: form_token}
+ end
+ end
+
+ def test_rejects_token_for_incorrect_method
+ get :index
+
+ form_token = nil
+ assert_select 'input[name=custom_authenticity_token]' do |elts|
+ form_token = elts.first['value']
+ assert_not_nil form_token
+ end
+
+ actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
+ expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', 'post')
+ assert_equal expected, actual
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one'
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ patch :post_one, params: {custom_authenticity_token: form_token}
+ end
+ end
+
+ def test_accepts_global_csrf_token
+ get :index
+
+ token = @controller.send(:form_authenticity_token)
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one'
+ assert_nothing_raised do
+ post :post_one, params: {custom_authenticity_token: token}
+ end
+ assert_response :success
+ end
+
+ def test_ignores_params
+ get :index, params: {form_path: '/per_form_tokens/post_one?foo=bar'}
+
+ form_token = nil
+ assert_select 'input[name=custom_authenticity_token]' do |elts|
+ form_token = elts.first['value']
+ assert_not_nil form_token
+ end
+
+ actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token))
+ expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', 'post')
+ assert_equal expected, actual
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one?foo=baz'
+ assert_nothing_raised do
+ post :post_one, params: {custom_authenticity_token: form_token, baz: 'foo'}
+ end
+ assert_response :success
+ end
+
+ def test_ignores_trailing_slash_during_generation
+ get :index, params: {form_path: '/per_form_tokens/post_one/'}
+
+ form_token = nil
+ assert_select 'input[name=custom_authenticity_token]' do |elts|
+ form_token = elts.first['value']
+ assert_not_nil form_token
+ end
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one'
+ assert_nothing_raised do
+ post :post_one, params: {custom_authenticity_token: form_token}
+ end
+ assert_response :success
+ end
+
+ def test_ignores_trailing_slash_during_validation
+ get :index
+
+ form_token = nil
+ assert_select 'input[name=custom_authenticity_token]' do |elts|
+ form_token = elts.first['value']
+ assert_not_nil form_token
+ end
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one/'
+ assert_nothing_raised do
+ post :post_one, params: {custom_authenticity_token: form_token}
+ end
+ assert_response :success
+ end
+
+ def test_method_is_case_insensitive
+ get :index, params: {form_method: "POST"}
+
+ form_token = nil
+ assert_select 'input[name=custom_authenticity_token]' do |elts|
+ form_token = elts.first['value']
+ assert_not_nil form_token
+ end
+
+ # This is required because PATH_INFO isn't reset between requests.
+ @request.env['PATH_INFO'] = '/per_form_tokens/post_one/'
+ assert_nothing_raised do
+ post :post_one, params: {custom_authenticity_token: form_token}
+ end
+ assert_response :success
+ end
+end
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index e50373a0cc..b9caddcdb7 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -172,7 +172,7 @@ XML
before_action { @dynamic_opt = 'opt' }
def test_url_options_reset
- render plain: url_for(params)
+ render plain: url_for
end
def default_url_options
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 78e883f134..67212fea38 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -375,6 +375,13 @@ module AbstractController
assert_equal({'query[person][position][]' => 'prof' }.to_query, params[3])
end
+ def test_url_action_controller_parameters
+ add_host!
+ assert_raise(ArgumentError) do
+ W.new.url_for(ActionController::Parameters.new(:controller => 'c', :action => 'a', protocol: 'javascript', f: '%0Aeval(name)'))
+ end
+ end
+
def test_path_generation_for_symbol_parameter_keys
assert_generates("/image", :controller=> :image)
end