cancan 1.6.9 → 1.6.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,15 @@
1
+ 1.6.10 (May 7, 2013)
2
+
3
+ * fix matches_conditons_hash for string values on 1.8 (thanks rrosen)
4
+
5
+ * work around SQL injection vulnerability in older Rails versions (thanks steerio) - issue #800
6
+
7
+ * add support for nested join conditions (thanks yuszuv) - issue #806
8
+
9
+ * fix load_resource "find_by" in mongoid resources (thanks albertobajo) - issue #705
10
+
11
+ * fix namespace split behavior (thanks xinuc) - issue #668
12
+
1
13
  1.6.9 (February 4, 2013)
2
14
 
3
15
  * fix inserting AND (NULL) to end of SQL queries (thanks jonsgreen) - issue #687
@@ -96,6 +96,11 @@ module CanCan
96
96
  #
97
97
  # load_resource :find_by => :permalink # will use find_by_permalink!(params[:id])
98
98
  #
99
+ # [:+id_param+]
100
+ # Find using a param key other than :id. For example:
101
+ #
102
+ # load_resource :id_key => :url # will use find(params[:url])
103
+ #
99
104
  # [:+collection+]
100
105
  # Specify which actions are resource collection actions in addition to :+index+. This
101
106
  # is usually not necessary because it will try to guess depending on if the id param is present.
@@ -107,6 +107,8 @@ module CanCan
107
107
  if @options[:find_by]
108
108
  if resource_base.respond_to? "find_by_#{@options[:find_by]}!"
109
109
  resource_base.send("find_by_#{@options[:find_by]}!", id_param)
110
+ elsif resource_base.respond_to? "find_by"
111
+ resource_base.send("find_by", { @options[:find_by].to_sym => id_param })
110
112
  else
111
113
  resource_base.send(@options[:find_by], id_param)
112
114
  end
@@ -129,7 +131,7 @@ module CanCan
129
131
  @params[@options[:id_param]]
130
132
  else
131
133
  @params[parent? ? :"#{name}_id" : :id]
132
- end
134
+ end.to_s
133
135
  end
134
136
 
135
137
  def member_action?
@@ -225,7 +227,7 @@ module CanCan
225
227
  end
226
228
 
227
229
  def namespace
228
- @params[:controller].split("::")[0..-2]
230
+ @params[:controller].split(/::|\//)[0..-2]
229
231
  end
230
232
 
231
233
  def namespaced_name
@@ -66,11 +66,22 @@ module CanCan
66
66
  return conditions unless conditions.kind_of? Hash
67
67
  conditions.inject({}) do |result_hash, (name, value)|
68
68
  if value.kind_of? Hash
69
+ value = value.dup
69
70
  association_class = model_class.reflect_on_association(name).class_name.constantize
70
- name = model_class.reflect_on_association(name).table_name.to_sym
71
- value = tableized_conditions(value, association_class)
71
+ nested = value.inject({}) do |nested,(k,v)|
72
+ if v.kind_of? Hash
73
+ value.delete(k)
74
+ nested[k] = v
75
+ else
76
+ name = model_class.reflect_on_association(name).table_name.to_sym
77
+ result_hash[name] = value
78
+ end
79
+ nested
80
+ end
81
+ result_hash.merge!(tableized_conditions(nested,association_class))
82
+ else
83
+ result_hash[name] = value
72
84
  end
73
- result_hash[name] = value
74
85
  result_hash
75
86
  end
76
87
  end
@@ -116,7 +116,7 @@ module CanCan
116
116
  else
117
117
  !attribute.nil? && matches_conditions_hash?(attribute, value)
118
118
  end
119
- elsif value.kind_of?(Enumerable)
119
+ elsif !value.is_a?(String) && value.kind_of?(Enumerable)
120
120
  value.include? attribute
121
121
  else
122
122
  attribute == value
@@ -269,6 +269,12 @@ describe CanCan::Ability do
269
269
  @ability.can?(:read, []).should be_false
270
270
  end
271
271
 
272
+ it "should match strings but not substrings specified in a conditions hash" do
273
+ @ability.can :read, String, :presence => "declassified"
274
+ @ability.can?(:read, "declassified").should be_true
275
+ @ability.can?(:read, "classified").should be_false
276
+ end
277
+
272
278
  it "should not stop at cannot definition when comparing class" do
273
279
  @ability.can :read, Range
274
280
  @ability.cannot :read, Range, :begin => 1
@@ -20,7 +20,7 @@ describe CanCan::ControllerResource do
20
20
  end
21
21
 
22
22
  it "should not load resource into an instance variable if already set" do
23
- @params.merge!(:action => "show", :id => 123)
23
+ @params.merge!(:action => "show", :id => "123")
24
24
  @controller.instance_variable_set(:@project, :some_project)
25
25
  resource = CanCan::ControllerResource.new(@controller)
26
26
  resource.load_resource
@@ -67,6 +67,16 @@ describe CanCan::ControllerResource do
67
67
  @controller.instance_variable_get(:@project).should == project
68
68
  end
69
69
 
70
+ it "has the specified nested resource_class when using / for namespace" do
71
+ module Admin
72
+ class Dashboard; end
73
+ end
74
+ @ability.can(:index, "admin/dashboard")
75
+ @params.merge!(:controller => "admin/dashboard", :action => "index")
76
+ resource = CanCan::ControllerResource.new(@controller, :authorize => true)
77
+ resource.send(:resource_class).should == Admin::Dashboard
78
+ end
79
+
70
80
  it "should build a new resource with hash if params[:id] is not specified" do
71
81
  @params.merge!(:action => "create", :project => {:name => "foobar"})
72
82
  resource = CanCan::ControllerResource.new(@controller)
@@ -148,7 +158,7 @@ describe CanCan::ControllerResource do
148
158
  end
149
159
 
150
160
  it "should perform authorization using controller action and loaded model" do
151
- @params.merge!(:action => "show", :id => 123)
161
+ @params.merge!(:action => "show", :id => "123")
152
162
  @controller.instance_variable_set(:@project, :some_project)
153
163
  stub(@controller).authorize!(:show, :some_project) { raise CanCan::AccessDenied }
154
164
  resource = CanCan::ControllerResource.new(@controller)
@@ -156,14 +166,14 @@ describe CanCan::ControllerResource do
156
166
  end
157
167
 
158
168
  it "should perform authorization using controller action and non loaded model" do
159
- @params.merge!(:action => "show", :id => 123)
169
+ @params.merge!(:action => "show", :id => "123")
160
170
  stub(@controller).authorize!(:show, Project) { raise CanCan::AccessDenied }
161
171
  resource = CanCan::ControllerResource.new(@controller)
162
172
  lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
163
173
  end
164
174
 
165
175
  it "should call load_resource and authorize_resource for load_and_authorize_resource" do
166
- @params.merge!(:action => "show", :id => 123)
176
+ @params.merge!(:action => "show", :id => "123")
167
177
  resource = CanCan::ControllerResource.new(@controller)
168
178
  mock(resource).load_resource
169
179
  mock(resource).authorize_resource
@@ -171,7 +181,7 @@ describe CanCan::ControllerResource do
171
181
  end
172
182
 
173
183
  it "should not build a single resource when on custom collection action even with id" do
174
- @params.merge!(:action => "sort", :id => 123)
184
+ @params.merge!(:action => "sort", :id => "123")
175
185
  resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list])
176
186
  resource.load_resource
177
187
  @controller.instance_variable_get(:@project).should be_nil
@@ -187,7 +197,7 @@ describe CanCan::ControllerResource do
187
197
  end
188
198
 
189
199
  it "should build a resource when on custom new action even when params[:id] exists" do
190
- @params.merge!(:action => "build", :id => 123)
200
+ @params.merge!(:action => "build", :id => "123")
191
201
  stub(Project).new { :some_project }
192
202
  resource = CanCan::ControllerResource.new(@controller, :new => :build)
193
203
  resource.load_resource
@@ -238,30 +248,30 @@ describe CanCan::ControllerResource do
238
248
  end
239
249
 
240
250
  it "should load resource through the association of another parent resource using instance variable" do
241
- @params.merge!(:action => "show", :id => 123)
251
+ @params.merge!(:action => "show", :id => "123")
242
252
  category = Object.new
243
253
  @controller.instance_variable_set(:@category, category)
244
- stub(category).projects.stub!.find(123) { :some_project }
254
+ stub(category).projects.stub!.find("123") { :some_project }
245
255
  resource = CanCan::ControllerResource.new(@controller, :through => :category)
246
256
  resource.load_resource
247
257
  @controller.instance_variable_get(:@project).should == :some_project
248
258
  end
249
259
 
250
260
  it "should load resource through the custom association name" do
251
- @params.merge!(:action => "show", :id => 123)
261
+ @params.merge!(:action => "show", :id => "123")
252
262
  category = Object.new
253
263
  @controller.instance_variable_set(:@category, category)
254
- stub(category).custom_projects.stub!.find(123) { :some_project }
264
+ stub(category).custom_projects.stub!.find("123") { :some_project }
255
265
  resource = CanCan::ControllerResource.new(@controller, :through => :category, :through_association => :custom_projects)
256
266
  resource.load_resource
257
267
  @controller.instance_variable_get(:@project).should == :some_project
258
268
  end
259
269
 
260
270
  it "should load resource through the association of another parent resource using method" do
261
- @params.merge!(:action => "show", :id => 123)
271
+ @params.merge!(:action => "show", :id => "123")
262
272
  category = Object.new
263
273
  stub(@controller).category { category }
264
- stub(category).projects.stub!.find(123) { :some_project }
274
+ stub(category).projects.stub!.find("123") { :some_project }
265
275
  resource = CanCan::ControllerResource.new(@controller, :through => :category)
266
276
  resource.load_resource
267
277
  @controller.instance_variable_get(:@project).should == :some_project
@@ -298,10 +308,10 @@ describe CanCan::ControllerResource do
298
308
  end
299
309
 
300
310
  it "should load through first matching if multiple are given" do
301
- @params.merge!(:action => "show", :id => 123)
311
+ @params.merge!(:action => "show", :id => "123")
302
312
  category = Object.new
303
313
  @controller.instance_variable_set(:@category, category)
304
- stub(category).projects.stub!.find(123) { :some_project }
314
+ stub(category).projects.stub!.find("123") { :some_project }
305
315
  resource = CanCan::ControllerResource.new(@controller, :through => [:category, :user])
306
316
  resource.load_resource
307
317
  @controller.instance_variable_get(:@project).should == :some_project
@@ -367,7 +377,7 @@ describe CanCan::ControllerResource do
367
377
  end
368
378
 
369
379
  it "should authorize based on resource name if class is false" do
370
- @params.merge!(:action => "show", :id => 123)
380
+ @params.merge!(:action => "show", :id => "123")
371
381
  stub(@controller).authorize!(:show, :project) { raise CanCan::AccessDenied }
372
382
  resource = CanCan::ControllerResource.new(@controller, :class => false)
373
383
  lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
@@ -390,6 +400,13 @@ describe CanCan::ControllerResource do
390
400
  @controller.instance_variable_get(:@project).should == project
391
401
  end
392
402
 
403
+ # CVE-2012-5664
404
+ it "should always convert id param to string" do
405
+ @params.merge!(:action => "show", :the_project => { :malicious => "I am" })
406
+ resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project)
407
+ resource.send(:id_param).class.should == String
408
+ end
409
+
393
410
  it "should load resource using custom find_by attribute" do
394
411
  project = Project.create!(:name => "foo")
395
412
  @params.merge!(:action => "show", :id => "foo")
@@ -207,6 +207,16 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
207
207
  @ability.model_adapter(Article, :read).conditions.should == "'t'='t'"
208
208
  end
209
209
 
210
+ it "should return appropriate sql conditions in complex case with nested joins" do
211
+ @ability.can :read, Comment, :article => { :category => { :visible => true } }
212
+ @ability.model_adapter(Comment, :read).conditions.should == { Category.table_name.to_sym => { :visible => true } }
213
+ end
214
+
215
+ it "should return appropriate sql conditions in complex case with nested joins of different depth" do
216
+ @ability.can :read, Comment, :article => { :published => true, :category => { :visible => true } }
217
+ @ability.model_adapter(Comment, :read).conditions.should == { Article.table_name.to_sym => { :published => true }, Category.table_name.to_sym => { :visible => true } }
218
+ end
219
+
210
220
  it "should not forget conditions when calling with SQL string" do
211
221
  @ability.can :read, Article, :published => true
212
222
  @ability.can :read, Article, ['secret=?', false]
@@ -20,6 +20,18 @@ RSpec.configure do |config|
20
20
  config.extend WithModel if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
21
21
  end
22
22
 
23
+ # Working around CVE-2012-5664 requires us to convert all ID params
24
+ # to strings. Let's switch to using string IDs in tests, otherwise
25
+ # SuperModel and/or RR will fail (as strings are not fixnums).
26
+
27
+ module SuperModel
28
+ class Base
29
+ def generate_id
30
+ object_id.to_s
31
+ end
32
+ end
33
+ end
34
+
23
35
  class Ability
24
36
  include CanCan::Ability
25
37
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cancan
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 6
9
- - 9
10
- version: 1.6.9
9
+ - 10
10
+ version: 1.6.10
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Bates
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-02-04 00:00:00 -08:00
18
+ date: 2013-05-07 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency