cancan 1.6.9 → 1.6.10

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.
@@ -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