strong_parameters 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,9 +15,9 @@ In addition, parameters can be marked as required and flow through a predefined
15
15
  # it'll raise a ActionController::MissingParameter exception, which will get caught by
16
16
  # ActionController::Base and turned into that 400 Bad Request reply.
17
17
  def update
18
- redirect_to current_account.people.find(params[:id]).tap { |person|
19
- person.update_attributes!(person_params)
20
- }
18
+ person = current_account.people.find(params[:id])
19
+ person.update_attributes!(person_params)
20
+ redirect_to person
21
21
  end
22
22
 
23
23
  private
@@ -29,12 +29,50 @@ In addition, parameters can be marked as required and flow through a predefined
29
29
  end
30
30
  end
31
31
 
32
+ == Permitted Scalar Values
33
+
34
+ Given
35
+
36
+ params.permit(:id)
37
+
38
+ the key +:id+ will pass the whitelisting if it appears in +params+ and it has a permitted scalar value associated. Otherwise the key is going to be filtered out, so arrays, hashes, or any other objects cannot be injected.
39
+
40
+ The permitted scalar types are +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+, +Date+, +Time+, +DateTime+, +StringIO+, +IO+, and +ActionDispatch::Http::UploadedFile+.
41
+
42
+ To declare that the value in +params+ must be an array of permitted scalar values map the key to an empty array:
43
+
44
+ params.permit(:id => [])
45
+
46
+ == Nested Parameters
47
+
32
48
  You can also use permit on nested parameters, like:
33
49
 
34
- params.permit(:name, friends: [ :name, { family: [ :name ] }])
50
+ params.permit(:name, {:emails => []}, :friends => [ :name, { :family => [ :name ], :hobbies => [] }])
51
+
52
+ This declaration whitelists the +name+, +emails+ and +friends+ attributes. It is expected that +emails+ will be an array of permitted scalar values and that +friends+ will be an array of resources with specific attributes : they should have a +name+ attribute (any permitted scalar values allowed), a +hobbies+ attribute as an array of permitted scalar values, and a +family+ attribute which is restricted to having a +name+ (any permitted scalar values allowed, too).
35
53
 
36
54
  Thanks to Nick Kallen for the permit idea!
37
55
 
56
+ == Handling of Unpermitted Keys
57
+
58
+ By default parameter keys that are not explicitly permitted will be logged in the development and test environment. In other environments these parameters will simply be filtered out and ignored.
59
+
60
+ Additionally, this behaviour can be changed by changing the +config.action_controller.action_on_unpermitted_parameters+ property in your environment files. If set to +:log+ the unpermitted attributes will be logged, if set to +:raise+ an exception will be raised.
61
+
62
+ == Use Outside of Controllers
63
+
64
+ While Strong Parameters will enforce permitted and required values in your application controllers, keep in mind
65
+ that you will need to sanitize untrusted data used for mass assignment when in use outside of controllers.
66
+
67
+ For example, if you retrieve JSON data from a third party API call and pass the unchecked parsed result on to
68
+ +Model.create+, undesired mass assignments could take place. You can alleviate this risk by slicing the hash data,
69
+ or wrapping the data in a new instance of +ActionController::Parameters+ and declaring permissions the same as
70
+ you would in a controller. For example:
71
+
72
+ raw_parameters = { :email => "john@example.com", :name => "John", :admin => true }
73
+ parameters = ActionController::Parameters.new(raw_parameters)
74
+ user = User.create(parameters.permit(:name, :email))
75
+
38
76
  == Installation
39
77
 
40
78
  In Gemfile:
@@ -48,6 +86,10 @@ every model you want protected.
48
86
  include ActiveModel::ForbiddenAttributesProtection
49
87
  end
50
88
 
89
+ Alternatively, you can protect all Active Record resources by default by creating an initializer and pasting the line:
90
+
91
+ ActiveRecord::Base.send(:include, ActiveModel::ForbiddenAttributesProtection)
92
+
51
93
  If you want to now disable the default whitelisting that occurs in later versions of Rails, change the +config.active_record.whitelist_attributes+ property in your +config/application.rb+:
52
94
 
53
95
  config.active_record.whitelist_attributes = false
@@ -57,3 +99,4 @@ This will allow you to remove / not have to use +attr_accessible+ and do mass as
57
99
  == Compatibility
58
100
 
59
101
  This plugin is only fully compatible with Rails versions 3.0, 3.1 and 3.2 but not 4.0+, as it is part of Rails Core in 4.0.
102
+ An unofficial Rails 2 version is {strong_parameters_rails2}[https://github.com/grosser/strong_parameters/tree/rails2].
@@ -1,6 +1,11 @@
1
+ require 'date'
2
+ require 'bigdecimal'
3
+ require 'stringio'
4
+
1
5
  require 'active_support/concern'
2
6
  require 'active_support/core_ext/hash/indifferent_access'
3
7
  require 'action_controller'
8
+ require 'action_dispatch/http/upload'
4
9
 
5
10
  module ActionController
6
11
  class ParameterMissing < IndexError
@@ -12,9 +17,24 @@ module ActionController
12
17
  end
13
18
  end
14
19
 
20
+ class UnpermittedParameters < IndexError
21
+ attr_reader :params
22
+
23
+ def initialize(params)
24
+ @params = params
25
+ super("found unpermitted parameters: #{params.join(", ")}")
26
+ end
27
+ end
28
+
15
29
  class Parameters < ActiveSupport::HashWithIndifferentAccess
16
30
  attr_accessor :permitted
17
31
  alias :permitted? :permitted
32
+
33
+ cattr_accessor :action_on_unpermitted_parameters, :instance_accessor => false
34
+
35
+ # Never raise an UnpermittedParameters exception because of these params
36
+ # are present. They are added by Rails and it's of no concern.
37
+ NEVER_UNPERMITTED_PARAMS = %w( controller action )
18
38
 
19
39
  def initialize(attributes = nil)
20
40
  super(attributes)
@@ -42,29 +62,15 @@ module ActionController
42
62
 
43
63
  filters.each do |filter|
44
64
  case filter
45
- when Symbol, String then
46
- params[filter] = self[filter] if has_key?(filter)
47
- keys.grep(/\A#{Regexp.escape(filter.to_s)}\(\d+[if]?\)\z/).each { |key| params[key] = self[key] }
65
+ when Symbol, String
66
+ permitted_scalar_filter(params, filter)
48
67
  when Hash then
49
- filter = filter.with_indifferent_access
50
-
51
- self.slice(*filter.keys).each do |key, value|
52
- return unless value
53
-
54
- key = key.to_sym
55
-
56
- params[key] = each_element(value) do |value|
57
- # filters are a Hash, so we expect value to be a Hash too
58
- next if filter.is_a?(Hash) && !value.is_a?(Hash)
59
-
60
- value = self.class.new(value) if !value.respond_to?(:permit)
61
-
62
- value.permit(*Array.wrap(filter[key]))
63
- end
64
- end
68
+ hash_filter(params, filter)
65
69
  end
66
70
  end
67
71
 
72
+ unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters
73
+
68
74
  params.permit!
69
75
  end
70
76
 
@@ -103,6 +109,7 @@ module ActionController
103
109
  end
104
110
 
105
111
  private
112
+
106
113
  def convert_hashes_to_parameters(key, value)
107
114
  if value.is_a?(Parameters) || !value.is_a?(Hash)
108
115
  value
@@ -112,18 +119,113 @@ module ActionController
112
119
  end
113
120
  end
114
121
 
115
- def each_element(object)
116
- if object.is_a?(Array)
117
- object.map { |el| yield el }.compact
118
- # fields_for on an array of records uses numeric hash keys
119
- elsif object.is_a?(Hash) && object.keys.all? { |k| k =~ /\A-?\d+\z/ }
120
- hash = object.class.new
121
- object.each { |k,v| hash[k] = yield v }
122
+ #
123
+ # --- Filtering ----------------------------------------------------------
124
+ #
125
+
126
+ # This is a white list of permitted scalar types that includes the ones
127
+ # supported in XML and JSON requests.
128
+ #
129
+ # This list is in particular used to filter ordinary requests, String goes
130
+ # as first element to quickly short-circuit the common case.
131
+ #
132
+ # If you modify this collection please update the README.
133
+ PERMITTED_SCALAR_TYPES = [
134
+ String,
135
+ Symbol,
136
+ NilClass,
137
+ Numeric,
138
+ TrueClass,
139
+ FalseClass,
140
+ Date,
141
+ Time,
142
+ # DateTimes are Dates, we document the type but avoid the redundant check.
143
+ StringIO,
144
+ IO,
145
+ ActionDispatch::Http::UploadedFile,
146
+ ]
147
+
148
+ def permitted_scalar?(value)
149
+ PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)}
150
+ end
151
+
152
+ def array_of_permitted_scalars?(value)
153
+ if value.is_a?(Array)
154
+ value.all? {|element| permitted_scalar?(element)}
155
+ end
156
+ end
157
+
158
+ def permitted_scalar_filter(params, key)
159
+ if has_key?(key) && permitted_scalar?(self[key])
160
+ params[key] = self[key]
161
+ end
162
+
163
+ keys.grep(/\A#{Regexp.escape(key.to_s)}\(\d+[if]?\)\z/).each do |key|
164
+ if permitted_scalar?(self[key])
165
+ params[key] = self[key]
166
+ end
167
+ end
168
+ end
169
+
170
+ def array_of_permitted_scalars_filter(params, key)
171
+ if has_key?(key) && array_of_permitted_scalars?(self[key])
172
+ params[key] = self[key]
173
+ end
174
+ end
175
+
176
+ def hash_filter(params, filter)
177
+ filter = filter.with_indifferent_access
178
+
179
+ # Slicing filters out non-declared keys.
180
+ slice(*filter.keys).each do |key, value|
181
+ return unless value
182
+
183
+ if filter[key] == []
184
+ # Declaration {:comment_ids => []}.
185
+ array_of_permitted_scalars_filter(params, key)
186
+ else
187
+ # Declaration {:user => :name} or {:user => [:name, :age, {:adress => ...}]}.
188
+ params[key] = each_element(value) do |element|
189
+ if element.is_a?(Hash)
190
+ element = self.class.new(element) unless element.respond_to?(:permit)
191
+ element.permit(*Array.wrap(filter[key]))
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ def each_element(value)
199
+ if value.is_a?(Array)
200
+ value.map { |el| yield el }.compact
201
+ # fields_for on an array of records uses numeric hash keys.
202
+ elsif value.is_a?(Hash) && value.keys.all? { |k| k =~ /\A-?\d+\z/ }
203
+ hash = value.class.new
204
+ value.each { |k,v| hash[k] = yield v }
122
205
  hash
123
206
  else
124
- yield object
207
+ yield value
125
208
  end
126
209
  end
210
+
211
+ def unpermitted_parameters!(params)
212
+ return unless self.class.action_on_unpermitted_parameters
213
+
214
+ unpermitted_keys = unpermitted_keys(params)
215
+
216
+ if unpermitted_keys.any?
217
+ case self.class.action_on_unpermitted_parameters
218
+ when :log
219
+ ActionController::Base.logger.debug "Unpermitted parameters: #{unpermitted_keys.join(", ")}"
220
+ when :raise
221
+ raise ActionController::UnpermittedParameters.new(unpermitted_keys)
222
+ end
223
+ end
224
+ end
225
+
226
+ def unpermitted_keys(params)
227
+ self.keys - params.keys - NEVER_UNPERMITTED_PARAMS
228
+ end
127
229
  end
128
230
 
129
231
  module StrongParameters
@@ -13,5 +13,3 @@ module ActiveModel
13
13
  end
14
14
  end
15
15
  end
16
-
17
- ActiveModel.autoload :ForbiddenAttributesProtection
@@ -7,5 +7,11 @@ module StrongParameters
7
7
  else
8
8
  config.generators.scaffold_controller = :strong_parameters_controller
9
9
  end
10
+
11
+ initializer "strong_parameters.config", :before => "action_controller.set_configs" do |app|
12
+ ActionController::Parameters.action_on_unpermitted_parameters = app.config.action_controller.delete(:action_on_unpermitted_parameters) do
13
+ (Rails.env.test? || Rails.env.development?) ? :log : false
14
+ end
15
+ end
10
16
  end
11
17
  end
@@ -1,3 +1,3 @@
1
1
  module StrongParameters
2
- VERSION = "0.1.6"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -14,19 +14,19 @@ class StrongParametersControllerGeneratorTest < Rails::Generators::TestCase
14
14
  assert_file "app/controllers/users_controller.rb" do |content|
15
15
 
16
16
  assert_instance_method :create, content do |m|
17
- assert_match(/@user = User\.new\(user_params\)/, m)
18
- assert_match(/@user\.save/, m)
19
- assert_match(/@user\.errors/, m)
17
+ assert_match '@user = User.new(user_params)', m
18
+ assert_match '@user.save', m
19
+ assert_match '@user.errors', m
20
20
  end
21
21
 
22
22
  assert_instance_method :update, content do |m|
23
- assert_match(/@user = User\.find\(params\[:id\]\)/, m)
24
- assert_match(/@user\.update_attributes\(user_params\)/, m)
25
- assert_match(/@user\.errors/, m)
23
+ assert_match '@user = User.find(params[:id])', m
24
+ assert_match '@user.update_attributes(user_params)', m
25
+ assert_match '@user.errors', m
26
26
  end
27
27
 
28
- assert_match(/def user_params/, content)
29
- assert_match(/params\.require\(:user\)\.permit\(:age, :name\)/, content)
28
+ assert_match 'def user_params', content
29
+ assert_match 'params.require(:user).permit(:age, :name)', content
30
30
  end
31
31
  end
32
32
  end
File without changes
@@ -0,0 +1,88 @@
1
+  (0.2ms) begin transaction
2
+  (0.0ms) rollback transaction
3
+  (0.0ms) begin transaction
4
+  (0.0ms) rollback transaction
5
+  (0.0ms) begin transaction
6
+  (0.0ms) rollback transaction
7
+  (0.0ms) begin transaction
8
+  (0.0ms) rollback transaction
9
+  (0.0ms) begin transaction
10
+  (0.0ms) rollback transaction
11
+  (0.0ms) begin transaction
12
+  (0.0ms) rollback transaction
13
+  (0.2ms) begin transaction
14
+  (0.0ms) rollback transaction
15
+  (0.0ms) begin transaction
16
+  (0.0ms) rollback transaction
17
+  (0.0ms) begin transaction
18
+  (0.0ms) rollback transaction
19
+  (0.0ms) begin transaction
20
+  (0.0ms) rollback transaction
21
+  (0.0ms) begin transaction
22
+  (0.0ms) rollback transaction
23
+  (0.0ms) begin transaction
24
+  (0.0ms) rollback transaction
25
+  (0.2ms) begin transaction
26
+  (0.0ms) rollback transaction
27
+  (0.0ms) begin transaction
28
+  (0.0ms) rollback transaction
29
+  (0.0ms) begin transaction
30
+  (0.0ms) rollback transaction
31
+  (0.0ms) begin transaction
32
+  (0.0ms) rollback transaction
33
+  (0.0ms) begin transaction
34
+  (0.0ms) rollback transaction
35
+  (0.0ms) begin transaction
36
+  (0.0ms) rollback transaction
37
+  (0.2ms) begin transaction
38
+  (0.0ms) rollback transaction
39
+  (0.0ms) begin transaction
40
+  (0.0ms) rollback transaction
41
+  (0.0ms) begin transaction
42
+  (0.0ms) rollback transaction
43
+  (0.0ms) begin transaction
44
+  (0.0ms) rollback transaction
45
+  (0.0ms) begin transaction
46
+  (0.0ms) rollback transaction
47
+  (0.0ms) begin transaction
48
+  (0.0ms) rollback transaction
49
+  (0.2ms) begin transaction
50
+  (0.0ms) rollback transaction
51
+  (0.0ms) begin transaction
52
+  (0.0ms) rollback transaction
53
+  (0.0ms) begin transaction
54
+  (0.0ms) rollback transaction
55
+  (0.0ms) begin transaction
56
+  (0.0ms) rollback transaction
57
+  (0.0ms) begin transaction
58
+  (0.0ms) rollback transaction
59
+  (0.0ms) begin transaction
60
+  (0.0ms) rollback transaction
61
+  (0.2ms) begin transaction
62
+  (0.0ms) rollback transaction
63
+  (0.0ms) begin transaction
64
+  (0.0ms) rollback transaction
65
+  (0.0ms) begin transaction
66
+  (0.0ms) rollback transaction
67
+  (0.0ms) begin transaction
68
+  (0.0ms) rollback transaction
69
+  (0.0ms) begin transaction
70
+  (0.0ms) rollback transaction
71
+  (0.0ms) begin transaction
72
+  (0.0ms) rollback transaction
73
+  (0.2ms) begin transaction
74
+  (0.0ms) rollback transaction
75
+  (0.0ms) begin transaction
76
+  (0.0ms) rollback transaction
77
+  (0.0ms) begin transaction
78
+  (0.0ms) rollback transaction
79
+  (0.0ms) begin transaction
80
+  (0.0ms) rollback transaction
81
+  (0.0ms) begin transaction
82
+  (0.0ms) rollback transaction
83
+  (0.0ms) begin transaction
84
+  (0.0ms) rollback transaction
85
+  (0.3ms) begin transaction
86
+  (0.0ms) rollback transaction
87
+  (0.3ms) begin transaction
88
+  (0.0ms) rollback transaction
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+ require 'action_controller/parameters'
3
+
4
+ class LogOnUnpermittedParamsTest < ActiveSupport::TestCase
5
+ def setup
6
+ ActionController::Parameters.action_on_unpermitted_parameters = :log
7
+ end
8
+
9
+ def teardown
10
+ ActionController::Parameters.action_on_unpermitted_parameters = false
11
+ end
12
+
13
+ test "logs on unexpected params" do
14
+ params = ActionController::Parameters.new({
15
+ :book => { :pages => 65 },
16
+ :fishing => "Turnips"
17
+ })
18
+
19
+ assert_logged("Unpermitted parameters: fishing") do
20
+ params.permit(:book => [:pages])
21
+ end
22
+ end
23
+
24
+ test "logs on unexpected nested params" do
25
+ params = ActionController::Parameters.new({
26
+ :book => { :pages => 65, :title => "Green Cats and where to find then." }
27
+ })
28
+
29
+ assert_logged("Unpermitted parameters: title") do
30
+ params.permit(:book => [:pages])
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def assert_logged(message)
37
+ old_logger = ActionController::Base.logger
38
+ log = StringIO.new
39
+ ActionController::Base.logger = Logger.new(log)
40
+
41
+ begin
42
+ yield
43
+
44
+ log.rewind
45
+ assert_match message, log.read
46
+ ensure
47
+ ActionController::Base.logger = old_logger
48
+ end
49
+ end
50
+ end
@@ -1,7 +1,136 @@
1
1
  require 'test_helper'
2
2
  require 'action_controller/parameters'
3
+ require 'action_dispatch/http/upload'
3
4
 
4
5
  class NestedParametersTest < ActiveSupport::TestCase
6
+ def assert_filtered_out(params, key)
7
+ assert !params.has_key?(key), "key #{key.inspect} has not been filtered out"
8
+ end
9
+
10
+ #
11
+ # --- Basic interface --------------------------------------------------------
12
+ #
13
+
14
+ # --- nothing ----------------------------------------------------------------
15
+
16
+ test 'if nothing is permitted, the hash becomes empty' do
17
+ params = ActionController::Parameters.new(:id => '1234')
18
+ permitted = params.permit
19
+ permitted.permitted?
20
+ permitted.empty?
21
+ end
22
+
23
+ # --- key --------------------------------------------------------------------
24
+
25
+ test 'key: permitted scalar values' do
26
+ values = ['a', :a, nil]
27
+ values += [0, 1.0, 2**128, BigDecimal.new('1')]
28
+ values += [true, false]
29
+ values += [Date.today, Time.now, DateTime.now]
30
+ values += [StringIO.new, STDOUT, ActionDispatch::Http::UploadedFile.new(:tempfile => __FILE__)]
31
+
32
+ values.each do |value|
33
+ params = ActionController::Parameters.new(:id => value)
34
+ permitted = params.permit(:id)
35
+ assert_equal value, permitted[:id]
36
+
37
+ %w(i f).each do |suffix|
38
+ params = ActionController::Parameters.new("foo(000#{suffix})" => value)
39
+ permitted = params.permit(:foo)
40
+ assert_equal value, permitted["foo(000#{suffix})"]
41
+ end
42
+ end
43
+ end
44
+
45
+ test 'key: unknown keys are filtered out' do
46
+ params = ActionController::Parameters.new(:id => '1234', :injected => 'injected')
47
+ permitted = params.permit(:id)
48
+ assert_equal '1234', permitted[:id]
49
+ assert_filtered_out permitted, :injected
50
+ end
51
+
52
+ test 'key: arrays are filtered out' do
53
+ [[], [1], ['1']].each do |array|
54
+ params = ActionController::Parameters.new(:id => array)
55
+ permitted = params.permit(:id)
56
+ assert_filtered_out permitted, :id
57
+
58
+ %w(i f).each do |suffix|
59
+ params = ActionController::Parameters.new("foo(000#{suffix})" => array)
60
+ permitted = params.permit(:foo)
61
+ assert_filtered_out permitted, "foo(000#{suffix})"
62
+ end
63
+ end
64
+ end
65
+
66
+ test 'key: hashes are filtered out' do
67
+ [{}, {:foo => 1}, {:foo => 'bar'}].each do |hash|
68
+ params = ActionController::Parameters.new(:id => hash)
69
+ permitted = params.permit(:id)
70
+ assert_filtered_out permitted, :id
71
+
72
+ %w(i f).each do |suffix|
73
+ params = ActionController::Parameters.new("foo(000#{suffix})" => hash)
74
+ permitted = params.permit(:foo)
75
+ assert_filtered_out permitted, "foo(000#{suffix})"
76
+ end
77
+ end
78
+ end
79
+
80
+ test 'key: non-permitted scalar values are filtered out' do
81
+ params = ActionController::Parameters.new(:id => Object.new)
82
+ permitted = params.permit(:id)
83
+ assert_filtered_out permitted, :id
84
+
85
+ %w(i f).each do |suffix|
86
+ params = ActionController::Parameters.new("foo(000#{suffix})" => Object.new)
87
+ permitted = params.permit(:foo)
88
+ assert_filtered_out permitted, "foo(000#{suffix})"
89
+ end
90
+ end
91
+
92
+ test 'key: it is not assigned if not present in params' do
93
+ params = ActionController::Parameters.new(:name => 'Joe')
94
+ permitted = params.permit(:id)
95
+ assert !permitted.has_key?(:id)
96
+ end
97
+
98
+ # --- key to empty array -----------------------------------------------------
99
+
100
+ test 'key to empty array: empty arrays pass' do
101
+ params = ActionController::Parameters.new(:id => [])
102
+ permitted = params.permit(:id => [])
103
+ assert_equal [], permitted[:id]
104
+ end
105
+
106
+ test 'key to empty array: arrays of permitted scalars pass' do
107
+ [['foo'], [1], ['foo', 'bar'], [1, 2, 3]].each do |array|
108
+ params = ActionController::Parameters.new(:id => array)
109
+ permitted = params.permit(:id => [])
110
+ assert_equal array, permitted[:id]
111
+ end
112
+ end
113
+
114
+ test 'key to empty array: permitted scalar values do not pass' do
115
+ ['foo', 1].each do |permitted_scalar|
116
+ params = ActionController::Parameters.new(:id => permitted_scalar)
117
+ permitted = params.permit(:id => [])
118
+ assert_filtered_out permitted, :id
119
+ end
120
+ end
121
+
122
+ test 'key to empty array: arrays of non-permitted scalar do not pass' do
123
+ [[Object.new], [[]], [[1]], [{}], [{:id => '1'}]].each do |non_permitted_scalar|
124
+ params = ActionController::Parameters.new(:id => non_permitted_scalar)
125
+ permitted = params.permit(:id => [])
126
+ assert_filtered_out permitted, :id
127
+ end
128
+ end
129
+
130
+ #
131
+ # --- Nesting ----------------------------------------------------------------
132
+ #
133
+
5
134
  test "permitted nested parameters" do
6
135
  params = ActionController::Parameters.new({
7
136
  :book => {
@@ -11,6 +140,8 @@ class NestedParametersTest < ActiveSupport::TestCase
11
140
  :born => "1564-04-26"
12
141
  }, {
13
142
  :name => "Christopher Marlowe"
143
+ }, {
144
+ :name => %w(malicious injected names)
14
145
  }],
15
146
  :details => {
16
147
  :pages => 200,
@@ -27,9 +158,12 @@ class NestedParametersTest < ActiveSupport::TestCase
27
158
  assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
28
159
  assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
29
160
  assert_equal 200, permitted[:book][:details][:pages]
30
- assert_nil permitted[:book][:details][:genre]
31
- assert_nil permitted[:book][:authors][1][:born]
32
- assert_nil permitted[:magazine]
161
+
162
+ assert_filtered_out permitted[:book][:authors][2], :name
163
+
164
+ assert_filtered_out permitted, :magazine
165
+ assert_filtered_out permitted[:book][:details], :genre
166
+ assert_filtered_out permitted[:book][:authors][0], :born
33
167
  end
34
168
 
35
169
  test "permitted nested parameters with a string or a symbol as a key" do
@@ -64,7 +198,7 @@ class NestedParametersTest < ActiveSupport::TestCase
64
198
  }
65
199
  })
66
200
 
67
- permitted = params.permit :book => :genres
201
+ permitted = params.permit :book => {:genres => []}
68
202
  assert_equal ["Tragedy"], permitted[:book][:genres]
69
203
  end
70
204
 
@@ -123,7 +257,8 @@ class NestedParametersTest < ActiveSupport::TestCase
123
257
  :book => {
124
258
  :authors_attributes => {
125
259
  :'0' => { :name => 'William Shakespeare', :age_of_death => '52' },
126
- :'1' => { :name => 'Unattributed Assistant' }
260
+ :'1' => { :name => 'Unattributed Assistant' },
261
+ :'2' => { :name => %w(injected names)}
127
262
  }
128
263
  }
129
264
  })
@@ -131,9 +266,11 @@ class NestedParametersTest < ActiveSupport::TestCase
131
266
 
132
267
  assert_not_nil permitted[:book][:authors_attributes]['0']
133
268
  assert_not_nil permitted[:book][:authors_attributes]['1']
134
- assert_nil permitted[:book][:authors_attributes]['0'][:age_of_death]
269
+ assert permitted[:book][:authors_attributes]['2'].empty?
135
270
  assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['0'][:name]
136
271
  assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['1'][:name]
272
+
273
+ assert_filtered_out permitted[:book][:authors_attributes]['0'], :age_of_death
137
274
  end
138
275
 
139
276
  test "fields_for_style_nested_params with negative numbers" do
@@ -149,8 +286,9 @@ class NestedParametersTest < ActiveSupport::TestCase
149
286
 
150
287
  assert_not_nil permitted[:book][:authors_attributes]['-1']
151
288
  assert_not_nil permitted[:book][:authors_attributes]['-2']
152
- assert_nil permitted[:book][:authors_attributes]['-1'][:age_of_death]
153
289
  assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['-1'][:name]
154
290
  assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['-2'][:name]
291
+
292
+ assert_filtered_out permitted[:book][:authors_attributes]['-1'], :age_of_death
155
293
  end
156
294
  end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+ require 'action_controller/parameters'
3
+
4
+ class RaiseOnUnpermittedParamsTest < ActiveSupport::TestCase
5
+ def setup
6
+ ActionController::Parameters.action_on_unpermitted_parameters = :raise
7
+ end
8
+
9
+ def teardown
10
+ ActionController::Parameters.action_on_unpermitted_parameters = false
11
+ end
12
+
13
+ test "raises on unexpected params" do
14
+ params = ActionController::Parameters.new({
15
+ :book => { :pages => 65 },
16
+ :fishing => "Turnips"
17
+ })
18
+
19
+ assert_raises(ActionController::UnpermittedParameters) do
20
+ params.permit(:book => [:pages])
21
+ end
22
+ end
23
+
24
+ test "raises on unexpected nested params" do
25
+ params = ActionController::Parameters.new({
26
+ :book => { :pages => 65, :title => "Green Cats and where to find then." }
27
+ })
28
+
29
+ assert_raises(ActionController::UnpermittedParameters) do
30
+ params.permit(:book => [:pages])
31
+ end
32
+ end
33
+ end
@@ -2,6 +2,13 @@
2
2
  ENV["RAILS_ENV"] = "test"
3
3
 
4
4
  require 'test/unit'
5
+ require 'rails'
6
+
7
+ class FakeApplication < Rails::Application; end
8
+
9
+ Rails.application = FakeApplication
10
+ Rails.configuration.action_controller = ActiveSupport::OrderedOptions.new
11
+
5
12
  require 'strong_parameters'
6
13
  require 'mocha'
7
14
 
@@ -23,6 +30,7 @@ module ActionController
23
30
  end
24
31
  end
25
32
 
33
+ ActionController::Parameters.action_on_unpermitted_parameters = false
26
34
 
27
35
  # Load support files
28
36
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strong_parameters
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-15 00:00:00.000000000 Z
12
+ date: 2013-02-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -113,16 +113,20 @@ files:
113
113
  - test/action_controller_tainted_params_test.rb
114
114
  - test/active_model_mass_assignment_taint_protection_test.rb
115
115
  - test/controller_generator_test.rb
116
+ - test/dummy/db/test.sqlite3
117
+ - test/dummy/log/test.log
116
118
  - test/gemfiles/Gemfile.rails-3.0.x
117
119
  - test/gemfiles/Gemfile.rails-3.0.x.lock
118
120
  - test/gemfiles/Gemfile.rails-3.1.x
119
121
  - test/gemfiles/Gemfile.rails-3.2.x
122
+ - test/log_on_unpermitted_params_test.rb
120
123
  - test/multi_parameter_attributes_test.rb
121
- - test/nested_parameters_test.rb
124
+ - test/parameters_permit_test.rb
122
125
  - test/parameters_require_test.rb
123
126
  - test/parameters_taint_test.rb
127
+ - test/raise_on_unpermitted_params_test.rb
124
128
  - test/test_helper.rb
125
- homepage:
129
+ homepage: https://github.com/rails/strong_parameters
126
130
  licenses: []
127
131
  post_install_message:
128
132
  rdoc_options: []
@@ -151,12 +155,16 @@ test_files:
151
155
  - test/action_controller_tainted_params_test.rb
152
156
  - test/active_model_mass_assignment_taint_protection_test.rb
153
157
  - test/controller_generator_test.rb
158
+ - test/dummy/db/test.sqlite3
159
+ - test/dummy/log/test.log
154
160
  - test/gemfiles/Gemfile.rails-3.0.x
155
161
  - test/gemfiles/Gemfile.rails-3.0.x.lock
156
162
  - test/gemfiles/Gemfile.rails-3.1.x
157
163
  - test/gemfiles/Gemfile.rails-3.2.x
164
+ - test/log_on_unpermitted_params_test.rb
158
165
  - test/multi_parameter_attributes_test.rb
159
- - test/nested_parameters_test.rb
166
+ - test/parameters_permit_test.rb
160
167
  - test/parameters_require_test.rb
161
168
  - test/parameters_taint_test.rb
169
+ - test/raise_on_unpermitted_params_test.rb
162
170
  - test/test_helper.rb