diff --git a/lib/active_resource/base.rb b/lib/active_resource/base.rb index 9f5aa63531..494394d85b 100644 --- a/lib/active_resource/base.rb +++ b/lib/active_resource/base.rb @@ -1066,6 +1066,7 @@ def all(*args) end def where(clauses = {}) + clauses = sanitize_forbidden_attributes(clauses) raise ArgumentError, "expected a clauses Hash, got #{clauses.inspect}" unless clauses.is_a? Hash find(:all, params: clauses) end @@ -1498,6 +1499,7 @@ def load(attributes, remove_root = false, persisted = false) raise ArgumentError, "expected attributes to be able to convert to Hash, got #{attributes.inspect}" end + attributes = sanitize_forbidden_attributes(attributes) attributes = attributes.to_hash @prefix_options, attributes = split_options(attributes) @@ -1745,11 +1747,13 @@ def method_missing(method_symbol, *arguments) # :nodoc: end class Base + extend ActiveModel::ForbiddenAttributesProtection extend ActiveModel::Naming extend ActiveResource::Associations include Callbacks, CustomMethods, Validations include ActiveModel::Conversion + include ActiveModel::ForbiddenAttributesProtection include ActiveModel::Serializers::JSON include ActiveModel::Serializers::Xml include ActiveResource::Reflection, ActiveResource::Rescuable diff --git a/test/abstract_unit.rb b/test/abstract_unit.rb index 2fba33da32..1f76dbf8f8 100644 --- a/test/abstract_unit.rb +++ b/test/abstract_unit.rb @@ -11,6 +11,7 @@ require "active_support" require "active_support/test_case" require "setter_trap" +require "strong_parameters" require "active_support/logger" require "base64" diff --git a/test/cases/base/load_test.rb b/test/cases/base/load_test.rb index a78451813b..50028f9c09 100644 --- a/test/cases/base/load_test.rb +++ b/test/cases/base/load_test.rb @@ -127,6 +127,16 @@ def test_load_object_with_implicit_conversion_to_hash assert_equal @matz.stringify_keys, @person.load(FakeParameters.new(@matz)).attributes end + def test_load_object_with_unpermitted_strong_parameters + params = StrongParameters.new(@matz) + assert_raises(ActiveModel::ForbiddenAttributesError) { @person.load(params) } + end + + def test_load_object_with_permitted_strong_parameters + params = StrongParameters.new(@matz).tap(&:permit!) + assert_equal @matz.stringify_keys, @person.load(params).attributes + end + def test_after_load_attributes_are_accessible assert_equal Hash.new, @person.attributes assert_equal @matz.stringify_keys, @person.load(@matz).attributes diff --git a/test/cases/base_test.rb b/test/cases/base_test.rb index d0ad43c995..7935d62637 100644 --- a/test/cases/base_test.rb +++ b/test/cases/base_test.rb @@ -817,7 +817,11 @@ def test_collection_url_with_parameters assert Person.collection_url(name: "Test", student: true).include?("name=Test") assert Person.collection_url(name: "Test", student: true).include?("student=true") - assert_equal "http://37s.sunrise.i:3000/people.json?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D=&name%5B%5D=false", Person.collection_url(name: [ "bob", "your uncle+me", nil, false ]) + if ActiveSupport::VERSION::MAJOR < 8 || ActiveSupport::VERSION::MINOR < 1 + assert_equal "http://37s.sunrise.i:3000/people.json?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D=&name%5B%5D=false", Person.collection_url(name: [ "bob", "your uncle+me", nil, false ]) + else + assert_equal "http://37s.sunrise.i:3000/people.json?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D&name%5B%5D=false", Person.collection_url(name: [ "bob", "your uncle+me", nil, false ]) + end assert_equal "http://37s.sunrise.i:3000/people.json?struct%5Ba%5D%5B%5D=2&struct%5Ba%5D%5B%5D=1&struct%5Bb%5D=fred", Person.collection_url(struct: { :a => [ 2, 1 ], "b" => "fred" }) end diff --git a/test/cases/finder_test.rb b/test/cases/finder_test.rb index a13a11290a..2682fe2eb4 100644 --- a/test/cases/finder_test.rb +++ b/test/cases/finder_test.rb @@ -63,6 +63,18 @@ def test_where_with_clauses assert_kind_of StreetAddress, addresses.first end + def test_where_clause_with_unpermitted_params + params = StrongParameters.new(person_id: "1") + assert_raises(ActiveModel::ForbiddenAttributesError) { StreetAddress.where(params) } + end + + def test_where_clause_with_permitted_params + params = StrongParameters.new(person_id: "1").tap(&:permit!) + addresses = StreetAddress.where(params) + assert_equal 1, addresses.size + assert_kind_of StreetAddress, addresses.first + end + def test_where_with_clause_in ActiveResource::HttpMock.respond_to { |m| m.get "/people.json?id%5B%5D=2", {}, @people_david } people = Person.where(id: [ 2 ]) diff --git a/test/strong_parameters.rb b/test/strong_parameters.rb new file mode 100644 index 0000000000..52dbd68c73 --- /dev/null +++ b/test/strong_parameters.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class StrongParameters + def initialize(parameters = {}) + @parameters = parameters + @permitted = false + end + + def permitted? + @permitted + end + + def permit! + @permitted = true + end + + def to_hash + @parameters.to_hash + end + alias to_h to_hash +end