Skip to content

Commit

Permalink
change ActionController::RequestForgeryProtection to use Mime::Type#v…
Browse files Browse the repository at this point in the history
…erify_request? [#73]
  • Loading branch information
rick committed May 6, 2008
1 parent 92e2e59 commit c8451ae
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 12 deletions.
19 changes: 16 additions & 3 deletions actionpack/lib/action_controller/mime_type.rb
Expand Up @@ -17,6 +17,10 @@ module Mime
# end
# end
class Type
@@html_types = Set.new [:html, :all]
@@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
cattr_reader :html_types, :unverifiable_types

# A simple helper class used in parsing the accept header
class AcceptItem #:nodoc:
attr_accessor :order, :name, :q
Expand Down Expand Up @@ -153,12 +157,21 @@ def ==(mime_type)
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
end
end


# Returns true if ActionPack should check requests using this Mime Type for possible request forgery. See
# ActionController::RequestForgerProtection.
def verify_request?
!@@unverifiable_types.include?(to_sym)
end

def html?
@@html_types.include?(to_sym) || @string =~ /html/
end

private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
mime_type = $1.downcase.to_sym
mime_type == @symbol || (mime_type == :html && @symbol == :all)
$1.downcase.to_sym == to_sym
else
super
end
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/action_controller/mime_types.rb
Expand Up @@ -17,4 +17,4 @@
Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form

# http://www.ietf.org/rfc/rfc4627.txt
Mime::Type.register "application/json", :json, %w( text/x-json )
Mime::Type.register "application/json", :json, %w( text/x-json )
Expand Up @@ -99,7 +99,7 @@ def verified_request?
end

def verifiable_request_format?
request.content_type.nil? || request.content_type.html?
request.content_type.nil? || request.content_type.verify_request?
end

# Sets the token value for the current session. Pass a <tt>:secret</tt> option
Expand Down
25 changes: 21 additions & 4 deletions actionpack/test/controller/mime_type_test.rb
Expand Up @@ -52,16 +52,33 @@ def test_type_should_be_equal_to_symbol
end

def test_type_convenience_methods
types = [:html, :xml, :png, :pdf, :yaml, :url_encoded_form]
# Don't test Mime::ALL, since it Mime::ALL#html? == true
types = Mime::SET.to_a.map(&:to_sym).uniq - [:all]

# Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE
types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) }

types.each do |type|
mime = Mime.const_get(type.to_s.upcase)
assert mime.send("#{type}?"), "Mime::#{type.to_s.upcase} is not #{type}?"
(types - [type]).each { |t| assert !mime.send("#{t}?"), "Mime::#{t.to_s.upcase} is #{t}?" }
assert mime.send("#{type}?"), "#{mime.inspect} is not #{type}?"
(types - [type]).each { |other_type| assert !mime.send("#{other_type}?"), "#{mime.inspect} is #{other_type}?" }
end
end

def test_mime_all_is_html
assert Mime::ALL.all?, "Mime::ALL is not all?"
assert Mime::ALL.html?, "Mime::ALL is not html?"
end

def test_verifiable_mime_types
unverified_types = Mime::Type.unverifiable_types
all_types = Mime::SET.to_a.map(&:to_sym)
all_types.uniq!
# Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE
all_types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) }

unverified, verified = all_types.partition { |type| Mime::Type.unverifiable_types.include? type }
assert verified.all? { |type| Mime.const_get(type.to_s.upcase).verify_request? }, "Not all Mime Types are verified: #{verified.inspect}"
assert unverified.all? { |type| !Mime.const_get(type.to_s.upcase).verify_request? }, "Some Mime Types are verified: #{unverified.inspect}"
end
end
48 changes: 45 additions & 3 deletions actionpack/test/controller/request_forgery_protection_test.rb
Expand Up @@ -107,19 +107,61 @@ def test_should_not_allow_delete_without_token
end

def test_should_not_allow_api_formatted_post_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
assert_raises(ActionController::InvalidAuthenticityToken) do
post :index, :format => 'xml'
end
end

def test_should_not_allow_put_without_token
def test_should_not_allow_api_formatted_put_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
put :index, :format => 'xml'
end
end

def test_should_not_allow_delete_without_token
def test_should_not_allow_api_formatted_delete_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
delete :index, :format => 'xml'
end
end

def test_should_not_allow_api_formatted_post_sent_as_url_encoded_form_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
post :index, :format => 'xml'
end
end

def test_should_not_allow_api_formatted_put_sent_as_url_encoded_form_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
put :index, :format => 'xml'
end
end

def test_should_not_allow_api_formatted_delete_sent_as_url_encoded_form_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
@request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
delete :index, :format => 'xml'
end
end

def test_should_not_allow_api_formatted_post_sent_as_multipart_form_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
post :index, :format => 'xml'
end
end

def test_should_not_allow_api_formatted_put_sent_as_multipart_form_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
put :index, :format => 'xml'
end
end

def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_token
assert_raises(ActionController::InvalidAuthenticityToken) do
@request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
delete :index, :format => 'xml'
end
end
Expand Down

0 comments on commit c8451ae

Please sign in to comment.