strong_parameters 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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