canner 0.2.2 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b38821b91d8d2e75bd9c8128ebccec6c7df8e4a4
4
- data.tar.gz: a4e8c7d7d932d44e0de2e961233515b703b5bde4
3
+ metadata.gz: 7b7de0bc3ce06cfa8e719a5b4cd3da5d8847007b
4
+ data.tar.gz: 25cb560b1410ca7661df5ef6c1baf77c0c5dba7e
5
5
  SHA512:
6
- metadata.gz: 0fe967328a50168959e3271f728fef82f6ce94d00ab912a377cc3e2275559efb342786f8776a27a71162dba42423aaca200765b62b2b252d8344308f79f8709d
7
- data.tar.gz: 7b0520fb887872d41334349a22d7239f27392e92af24fff476339db26582afea3013fc6269a05baefe8f7820d17ca832db8c01eb3fa12a0b951ffab412e3d4d5
6
+ metadata.gz: e70bd029306bb3c7a4a6d4666d9452320dc7e43c284492173b243e1fbf0d860c0466e7ddc437a6827959a7a5d9e7f173cbf694817380f0f0ec5ff83a688c4aab
7
+ data.tar.gz: 4e70d8b65ab9f19a2665235dc9f7ed856e002a098648b900ddd9b60288b01f0885b058b0c14fc2175f2e52a0d42037087d34033fb990b893d1281d8ed0295392
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![Code Climate](https://codeclimate.com/github/jacklin10/canner/badges/gpa.svg)](https://codeclimate.com/github/jacklin10/canner)
4
4
  [![Build Status](https://travis-ci.org/jacklin10/canner.svg?branch=master)](https://travis-ci.org/jacklin10/canner)
5
+ [![Gem Version](https://badge.fury.io/rb/canner.svg)](http://badge.fury.io/rb/canner)
5
6
 
6
7
  Canner is an authorization gem heavily modeled after Pundit.
7
8
 
@@ -130,7 +131,7 @@ Also if your policy changes at some point its a one place fix.
130
131
 
131
132
  ### can?
132
133
 
133
- You use the can method to determine if the current_user is able to access an action or resource.
134
+ You use the can? method to determine if the current_user is able to access an action or resource.
134
135
 
135
136
  The example above uses a straightforward case statement to determine if the current_user can
136
137
  access the current action or resource.
@@ -166,6 +167,70 @@ end
166
167
 
167
168
  in your base_policy's `can?` method
168
169
 
170
+ ### instance_can?
171
+
172
+ You use the instance_can? method to determine if the current_user is able to modify a particular instance
173
+ of an object.
174
+
175
+ For example, if a user who belongs to company A wants to edit a particular item they maybe end up here:
176
+
177
+ ```
178
+ /items/3/edit
179
+ ```
180
+
181
+ Normal stuff. The user changes the item price and moves on.
182
+
183
+ But now we have another user who decides they want to see what happens when they manually change the url:
184
+
185
+ ```
186
+ /items/13/edit
187
+ ```
188
+
189
+ If you don't defend against this the user would be granted access to edit item with id=13 which
190
+ belongs to a different company.
191
+
192
+ The instance_can? method helps in these situations.
193
+
194
+ In your items controller for the **edit, update and destroy** methods add something like:
195
+
196
+ ``` ruby
197
+ @item = Item.find params[:id]
198
+ instance_can? :manage, :item, @item
199
+ ```
200
+
201
+ Your item_policy.rb will have something like:
202
+
203
+ ``` ruby
204
+ def instance_can?(item)
205
+ case @method
206
+ when :manage
207
+ return @current_user.company == item.company
208
+ else
209
+ false
210
+ end
211
+ end
212
+ ```
213
+
214
+ Now if a user attempts to edit an item for another company they will see the canner access denied message.
215
+
216
+ Your policy can be more complex if needed. Canner is just a framework so you can get as creative as you want
217
+ just so long as you eventually return true or false.
218
+
219
+ For example, maybe your admin user is allowed to edit any items? You could do something like this:
220
+ ``` ruby
221
+ def instance_can?(item)
222
+ case @method
223
+ when :manage
224
+ return has_role?(:admin) ? true : @current_user.company == item.company
225
+ else
226
+ false
227
+ end
228
+ end
229
+ ```
230
+
231
+ You can enforce that your methods check for this just like you can for canner_scope or can?.
232
+ See 'Forcing Controller Authorization'
233
+
169
234
  ### Forcing Controller Authorization
170
235
 
171
236
  You are able to force the use of controller authorization with canner.
@@ -186,13 +251,17 @@ after_action :ensure_scope, only: :index
186
251
  Note the use of only here. You usually won't need the canner_scope on anything except
187
252
  for the index to be strictly enforced.
188
253
 
189
- If you would like to skip for a particular controller just add:
254
+ And finally, if you want to enforce that you are using instance_can? use something like:
190
255
  ``` ruby
191
- skip_filter :ensure_scope
256
+ after_action :ensure_instance_checking, only: [:edit, :destroy, :update]
192
257
  ```
193
- And / Or
258
+
259
+ If you would like to skip one of the enforcements for a specific controller add one or all of these:
260
+
194
261
  ``` ruby
262
+ skip_filter :ensure_scope
195
263
  skip_filter :ensure_auth
264
+ skip_filter :ensure_instance_checking
196
265
  ```
197
266
 
198
267
  ### Handle Canner Authorization Failures
@@ -1,3 +1,3 @@
1
1
  module Canner
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/canner.rb CHANGED
@@ -22,6 +22,7 @@ module Canner
22
22
 
23
23
  class AuthNotUsedError < StandardError; end
24
24
  class ScopeNotUsedError < StandardError; end
25
+ class InstanceNotProtectedError < StandardError; end
25
26
 
26
27
  def auth_used
27
28
  @auth_used ||= false
@@ -31,12 +32,17 @@ module Canner
31
32
  @scope_used ||= false
32
33
  end
33
34
 
35
+ def instance_checked
36
+ @instance_checked ||= false
37
+ end
38
+
34
39
  # method_name - The controller action method that you are concerned with access
35
40
  # target_model - Name of the object you are limiting access to. ( :user, :pet, :customer )
36
41
  # target_obj - The instance obj for what you want to test. ( does user 1 have access to company 1?)
37
42
  def instance_can?(method_name, target_model, target_obj)
43
+ @instance_checked = true
38
44
  policy = canner_policy(method_name, target_model)
39
- raise NotAuthorizedError.new("You do not have access to this #{target_model.capitalize}") unless policy.instance_can?(target_obj)
45
+ raise NotAuthorizedError.new("You do not have access to this #{target_model.to_s.humanize.capitalize}") unless policy.instance_can?(target_obj)
40
46
  true
41
47
  end
42
48
 
@@ -79,6 +85,12 @@ module Canner
79
85
  true
80
86
  end
81
87
 
88
+ def ensure_instance_checking
89
+ return if devise_controller? rescue false
90
+ raise AuthNotUsedError.new("Must use instance_can? method or exclude this action from the after_action") unless instance_checked
91
+ true
92
+ end
93
+
82
94
  def canner_policy(method_name, target_model)
83
95
  derive_class_name(target_model).constantize.new(canner_user, method_name, canner_branch)
84
96
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Acklin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-09 00:00:00.000000000 Z
11
+ date: 2015-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -158,11 +158,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
158
  version: '0'
159
159
  requirements: []
160
160
  rubyforge_project:
161
- rubygems_version: 2.4.2
161
+ rubygems_version: 2.4.6
162
162
  signing_key:
163
163
  specification_version: 4
164
164
  summary: Rails Auth
165
165
  test_files:
166
166
  - spec/canner_spec.rb
167
167
  - spec/spec_helper.rb
168
- has_rdoc: