canner 0.0.2 → 0.1.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 +4 -4
- data/README.md +63 -47
- data/canner.gemspec +1 -1
- data/lib/canner/policy.rb +60 -0
- data/lib/canner/util.rb +1 -1
- data/lib/canner/version.rb +1 -1
- data/lib/canner.rb +38 -7
- data/lib/generators/canner/fetch_roles/USAGE +3 -0
- data/lib/generators/canner/{install/install_generator.rb → fetch_roles/fetch_roles_generator.rb} +1 -1
- data/lib/generators/canner/fetch_roles/templates/base_policy.rb +8 -0
- data/lib/generators/canner/policy/USAGE +9 -3
- data/lib/generators/canner/policy/policy_generator.rb +12 -0
- data/lib/generators/canner/policy/templates/policy.rb +1 -1
- data/lib/generators/test_unit/policy_generator.rb +11 -0
- data/lib/generators/test_unit/templates/policy_test.rb +11 -0
- data/spec/canner_spec.rb +151 -0
- data/spec/spec_helper.rb +17 -0
- metadata +33 -28
- data/lib/canner/rspec.rb +0 -0
- data/lib/generators/canner/install/USAGE +0 -2
- data/lib/generators/canner/install/templates/base_policy.rb +0 -52
- data/spec/Gemfile +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fe7375f518e4b28b54badd6031ace79365f8105
|
4
|
+
data.tar.gz: 8939b3f2f12e4a4dbb6cb4cf76e288369bbf0e5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62a5ea258681115223f0f122d13246ef36f29eae14b8725831d0e79d1ec81f4a07f91189ba4a44d7465b2639581cc530ea409028bf508dce52e04b2adda0b86a
|
7
|
+
data.tar.gz: 5ec594066b2daeeff61bdb71f7580dcb71bd6ce427549dbc74a9ae9f48700d9411312d1edb1ce3323321e6ae52307161f1854556f0b19d5d24beac9f20db4df1
|
data/README.md
CHANGED
@@ -1,35 +1,22 @@
|
|
1
1
|
Canner
|
2
2
|
======
|
3
3
|
|
4
|
-
Canner is an authorization gem heavily modeled after Pundit.
|
5
|
-
The goal is to take away some of the magic that exists in other auth gems out there and
|
6
|
-
provide the flexibility needed for your specific app.
|
4
|
+
Canner is an authorization gem heavily modeled after Pundit.
|
7
5
|
|
8
|
-
|
9
|
-
|
6
|
+
Canner's intention is to provide you a framework for authorization that has little to no magic.
|
7
|
+
Your canner policies can be as simple or as complicated as your app requires.
|
10
8
|
|
11
|
-
|
12
|
-
|
9
|
+
Who needs another auth gem? There's a bunch of very good ones out there.
|
10
|
+
Pundit, cancan, cancancan and Declarative Authorization to name a few alternatives.
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
Cleveland is a perfect place to open another store location.
|
12
|
+
Unfortunately for me, none of those solutions had built in support for a requirement I have on the
|
13
|
+
project [Kennel Captain](http://www.kennelcaptain.com)
|
17
14
|
|
18
|
-
|
19
|
-
In any of the above listed gems if you have a manager role you could see all the reports regardless
|
20
|
-
of the store location aka store branch.
|
15
|
+
We need to authorize a user at a given store location, and that's a feature canner will support.
|
21
16
|
|
22
|
-
|
23
|
-
Instead of saying:
|
24
|
-
Can the currently signed in user access this particular report.
|
25
|
-
Canner can say:
|
26
|
-
Can the currently signed in user access this particular report for this particular branch.
|
17
|
+
For details see the wiki page [Authorize with Branches ( Store Locations )](https://github.com/jacklin10/canner/wiki/Authorize-with-Branches)
|
27
18
|
|
28
|
-
|
29
|
-
pittsburgh_manager and cleveland_manager. Or maybe writing some monkey patches to hack in what you need.
|
30
|
-
|
31
|
-
Canner is designed to give you an outline of what you'll need for your app's auth needs and leaves
|
32
|
-
the level of complexity needed up to the requirements of your particular application.
|
19
|
+
Also note that canner works fine if you don't need this particular feature, its just there if you do.
|
33
20
|
|
34
21
|
## Installation
|
35
22
|
|
@@ -46,14 +33,6 @@ Then run
|
|
46
33
|
bundle install
|
47
34
|
```
|
48
35
|
|
49
|
-
After the gem is installed you'll need to run the install generator:
|
50
|
-
|
51
|
-
``` ruby
|
52
|
-
rails g canner:install
|
53
|
-
```
|
54
|
-
|
55
|
-
This will create a policies directory and create the base_policy.rb
|
56
|
-
|
57
36
|
Now include canner in your application_controller.rb
|
58
37
|
|
59
38
|
``` ruby
|
@@ -66,13 +45,24 @@ You'll then need to create a Policy class for the models you'd like to authorize
|
|
66
45
|
rails g canner:policy user
|
67
46
|
```
|
68
47
|
|
69
|
-
|
48
|
+
If your app gets roles from a user in a way other than @current_user.roles then you'll
|
49
|
+
need to override the fetch_roles policy method.
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
rails g canner:fetch_roles
|
53
|
+
```
|
54
|
+
|
55
|
+
More details are available in the wiki:
|
56
|
+
[Overriding the Fetching of Roles](https://github.com/jacklin10/canner/wiki/Feed-Roles)
|
70
57
|
|
71
58
|
## Policies
|
72
59
|
|
73
60
|
As mentioned Canner is strongly influenced by Pundit and is also based on Policy objects.
|
74
|
-
Your policy objects should be named using the pattern
|
75
|
-
|
61
|
+
Your policy objects should be named using the following pattern:
|
62
|
+
UserPolicy, CustomerPolicy, AppPolicy.
|
63
|
+
|
64
|
+
Use the generator to save you some time:
|
65
|
+
``` rails g canner:policy <model name> ```
|
76
66
|
|
77
67
|
Your policy models need to implement 2 methods:
|
78
68
|
``` ruby
|
@@ -85,7 +75,9 @@ end
|
|
85
75
|
|
86
76
|
### canner_scope
|
87
77
|
|
88
|
-
|
78
|
+
You'll want to implement this method for each of your model policies that extend from base_policy.rb.
|
79
|
+
|
80
|
+
The canner_scope method is used to scope the authorized models consistently in your app.
|
89
81
|
|
90
82
|
For example in my app the Customers controller uses the canner_scope to
|
91
83
|
ensure only Users from the current_company are displayed.
|
@@ -129,9 +121,12 @@ class CustomerPolicy < BasePolicy
|
|
129
121
|
end
|
130
122
|
```
|
131
123
|
|
132
|
-
|
124
|
+
Now you don't really need to think about the auth logic when fetching a list of customers.
|
125
|
+
Just make sure you use the policy and you'll only show the users what is intended.
|
133
126
|
|
134
|
-
|
127
|
+
Also if your policy changes at some point its a one place fix.
|
128
|
+
|
129
|
+
### can?
|
135
130
|
|
136
131
|
You use the can method to determine if the current_user is able to access an action or resource.
|
137
132
|
|
@@ -148,10 +143,9 @@ when :something_random
|
|
148
143
|
else
|
149
144
|
false
|
150
145
|
end
|
151
|
-
|
152
|
-
# Then in controller do:
|
153
|
-
can?(:something_random, :customer)
|
154
146
|
```
|
147
|
+
# Then in controller do:
|
148
|
+
```can?(:something_random, :customer)```
|
155
149
|
|
156
150
|
In english the can method is saying:
|
157
151
|
|
@@ -160,12 +154,22 @@ use the CustomerPolicy's can? method to do the checking.
|
|
160
154
|
|
161
155
|
`can?(:something_random, :user)` would use the ... you guessed it UserPolicy's can? method.
|
162
156
|
|
157
|
+
If you want to deny access by default across all model policies you could do something as simple as:
|
158
|
+
|
159
|
+
``` ruby
|
160
|
+
def can?
|
161
|
+
false
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
in your base_policy's `can?` method
|
166
|
+
|
163
167
|
### Force the Use of Policies
|
164
168
|
|
165
169
|
Also like Pundit you can force your app to use policies.
|
166
170
|
I recommend you do this so you don't forget to wrap authorization about some of your resources.
|
167
171
|
|
168
|
-
To make sure your controller actions are using the can? method add this
|
172
|
+
To make sure your controller actions are using the can? method add this near the top of your
|
169
173
|
application_controller.rb
|
170
174
|
|
171
175
|
``` ruby
|
@@ -180,6 +184,15 @@ after_action :ensure_scope, only: :index
|
|
180
184
|
Note the use of only here. You usually won't need the canner_scope on anything except
|
181
185
|
for the index to be strictly enforced.
|
182
186
|
|
187
|
+
If you would like to skip for a particular controller just add
|
188
|
+
``` ruby
|
189
|
+
skip_filter :ensure_scope
|
190
|
+
```
|
191
|
+
And / Or
|
192
|
+
``` ruby
|
193
|
+
skip_filter :ensure_auth
|
194
|
+
```
|
195
|
+
|
183
196
|
### Handle Canner Authorization Failures
|
184
197
|
|
185
198
|
When a user does stumble onto something they don't have access to you'll want to politely
|
@@ -188,18 +201,18 @@ tell them about it and direct the app flow as you see fit.
|
|
188
201
|
To accomplish this in your application_controller.rb add
|
189
202
|
|
190
203
|
``` ruby
|
191
|
-
|
204
|
+
rescue_from Canner::NotAuthorizedError, with: :user_not_authorized
|
192
205
|
```
|
193
206
|
|
194
207
|
You can name your method whatever you want. Mine is user_not_authorized and looks like this:
|
195
208
|
|
196
209
|
``` ruby
|
197
|
-
|
210
|
+
private
|
198
211
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
212
|
+
def user_not_authorized(exception)
|
213
|
+
flash[:error] = exception.message
|
214
|
+
redirect_to(request.referrer || root_path)
|
215
|
+
end
|
203
216
|
```
|
204
217
|
|
205
218
|
### Using can? in views
|
@@ -228,4 +241,7 @@ would only be able to see the create customer link if they had an admin role.
|
|
228
241
|
end
|
229
242
|
```
|
230
243
|
|
244
|
+
## Testing
|
231
245
|
|
246
|
+
See the wiki for some testing tips
|
247
|
+
[Testing](https://github.com/jacklin10/canner/wiki/Testing)
|
data/canner.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.add_dependency "activesupport"
|
21
21
|
gem.add_development_dependency "activemodel"
|
22
22
|
gem.add_development_dependency "bundler", "~> 1.3"
|
23
|
-
gem.add_development_dependency "rspec", "~>
|
23
|
+
gem.add_development_dependency "rspec", "~> 2.1"
|
24
24
|
gem.add_development_dependency "pry"
|
25
25
|
gem.add_development_dependency "rake"
|
26
26
|
gem.add_development_dependency "yard"
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Canner
|
2
|
+
|
3
|
+
class Policy
|
4
|
+
|
5
|
+
def initialize(current_user, method, current_branch=nil)
|
6
|
+
@current_user = current_user
|
7
|
+
@current_branch = current_branch
|
8
|
+
@method = method.to_sym
|
9
|
+
@roles = fetch_roles
|
10
|
+
end
|
11
|
+
|
12
|
+
# if you handle your roles differently you'll need to override.
|
13
|
+
# use: rails g canner:fetch_roles
|
14
|
+
# expects an array or strings or symbols that represent the user roles
|
15
|
+
def fetch_roles
|
16
|
+
@current_user.roles
|
17
|
+
end
|
18
|
+
|
19
|
+
# implement in your policy class to auto scope in an action
|
20
|
+
def canner_scope
|
21
|
+
raise ArgumentError.new("NOT IMPLEMENTED")
|
22
|
+
# ex:
|
23
|
+
# case @method
|
24
|
+
# when :index
|
25
|
+
# User.by_branch(@current_branch)
|
26
|
+
# else
|
27
|
+
# User.none
|
28
|
+
# end
|
29
|
+
end
|
30
|
+
|
31
|
+
# implment in your policy class.
|
32
|
+
# return true when the user can access the action or resource and false when they can't
|
33
|
+
def can?
|
34
|
+
raise ArgumentError.new("NOT IMPLEMENTED")
|
35
|
+
# ex:
|
36
|
+
# case @method
|
37
|
+
# when :index, :show
|
38
|
+
# has_role?(:admin)
|
39
|
+
# else
|
40
|
+
# false
|
41
|
+
# end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def is_method?(methods)
|
47
|
+
prepare(methods).include?(@method)
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_role?(roles)
|
51
|
+
begin
|
52
|
+
@roles.any?{|r| Util.prepare(roles).include?(r.to_sym) }
|
53
|
+
rescue Exception => e
|
54
|
+
raise ArgumentError.new "Canner: Problem fetching user roles. If current_user.roles isn't how you do it see wiki for overriding fetch_roles."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/lib/canner/util.rb
CHANGED
data/lib/canner/version.rb
CHANGED
data/lib/canner.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'active_support/core_ext/string'
|
2
|
+
require "active_support/concern"
|
3
|
+
require 'canner/policy'
|
4
|
+
require 'canner/util'
|
5
|
+
|
3
6
|
module Canner
|
4
7
|
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
5
10
|
# so you don't have to have a helper method in the app_controller
|
6
|
-
|
7
|
-
|
11
|
+
included do
|
12
|
+
if respond_to?(:helper_method)
|
13
|
+
helper_method :canner_policy
|
14
|
+
helper_method :canner_user
|
15
|
+
helper_method :canner_branch
|
16
|
+
end
|
8
17
|
end
|
9
18
|
|
10
19
|
class NotAuthorizedError < StandardError
|
@@ -14,12 +23,21 @@ module Canner
|
|
14
23
|
class AuthNotUsedError < StandardError; end
|
15
24
|
class ScopeNotUsedError < StandardError; end
|
16
25
|
|
26
|
+
def auth_used
|
27
|
+
@auth_used ||= false
|
28
|
+
end
|
29
|
+
|
30
|
+
def scope_used
|
31
|
+
@scope_used ||= false
|
32
|
+
end
|
33
|
+
|
17
34
|
# method_name - The controller action method that you are concerned with access
|
18
35
|
# target_model - Name of the object you are limiting access to. ( :user, :pet, :customer )
|
19
36
|
# target_obj - The instance obj for what you want to test. ( does user 1 have access to company 1?)
|
20
37
|
def instance_can?(method_name, target_model, target_obj)
|
21
38
|
policy = canner_policy(method_name, target_model)
|
22
39
|
raise NotAuthorizedError.new("You do not have access to this #{target_model.capitalize}") unless policy.instance_can?(target_obj)
|
40
|
+
true
|
23
41
|
end
|
24
42
|
|
25
43
|
# method_name - The controller action method that you are concerned with access
|
@@ -27,6 +45,7 @@ module Canner
|
|
27
45
|
def can?(method_name, target_model)
|
28
46
|
@auth_used = true
|
29
47
|
raise NotAuthorizedError.new("You are not authorized to perform this action.") unless canner_policy(method_name, target_model).can?
|
48
|
+
true
|
30
49
|
end
|
31
50
|
|
32
51
|
# method_name - The controller action method that you are concerned with access
|
@@ -36,20 +55,32 @@ module Canner
|
|
36
55
|
canner_policy(method_name, target_model).canner_scope
|
37
56
|
end
|
38
57
|
|
58
|
+
# override this if your method for getting the current user isn't called current_user.
|
59
|
+
def canner_user
|
60
|
+
current_user
|
61
|
+
end
|
62
|
+
|
63
|
+
# override this if your method for getting the current branch isn't called current_branch.
|
64
|
+
def canner_branch
|
65
|
+
current_branch
|
66
|
+
end
|
67
|
+
|
39
68
|
protected
|
40
69
|
|
41
70
|
def ensure_scope
|
42
71
|
return if devise_controller? rescue false
|
43
|
-
raise ScopeNotUsedError.new("Must use a canner_scope or exclude this action from the after_action") unless
|
72
|
+
raise ScopeNotUsedError.new("Must use a canner_scope or exclude this action from the after_action") unless scope_used
|
73
|
+
true
|
44
74
|
end
|
45
75
|
|
46
76
|
def ensure_auth
|
47
77
|
return if devise_controller? rescue false
|
48
|
-
raise AuthNotUsedError.new("Must use can? method or exclude this action from the after_action") unless
|
78
|
+
raise AuthNotUsedError.new("Must use can? method or exclude this action from the after_action") unless auth_used
|
79
|
+
true
|
49
80
|
end
|
50
81
|
|
51
82
|
def canner_policy(method_name, target_model)
|
52
|
-
derive_class_name(target_model).constantize.new(
|
83
|
+
derive_class_name(target_model).constantize.new(canner_user, method_name, canner_branch)
|
53
84
|
end
|
54
85
|
|
55
86
|
def derive_class_name(target_model)
|
@@ -1,8 +1,14 @@
|
|
1
1
|
Description:
|
2
|
-
|
2
|
+
Generates a policy for a model with the given name.
|
3
3
|
|
4
|
-
Example:
|
4
|
+
Example:
|
5
5
|
rails generate canner:policy user
|
6
6
|
|
7
7
|
This will create:
|
8
|
-
|
8
|
+
app/policies/user_policy.rb
|
9
|
+
|
10
|
+
Note:
|
11
|
+
If you have overridden fetch_roles, or created a base policy of your own you'll want to pass
|
12
|
+
the parent option and specify your parent.
|
13
|
+
|
14
|
+
rails generate canner:policy user --parent BasePolicy
|
@@ -2,12 +2,24 @@ module Canner
|
|
2
2
|
module Generators
|
3
3
|
class PolicyGenerator < ::Rails::Generators::NamedBase
|
4
4
|
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
5
|
+
check_class_collision suffix: "Policy"
|
6
|
+
|
7
|
+
class_option :parent, type: :string, desc: "The parent class for the generated policy"
|
5
8
|
|
6
9
|
def create_policy
|
7
10
|
template 'policy.rb', File.join('app/policies', class_path, "#{file_name}_policy.rb")
|
8
11
|
end
|
9
12
|
|
10
13
|
hook_for :test_framework
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def parent_class_name
|
18
|
+
options.fetch("parent") do
|
19
|
+
Canner::Policy
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
11
23
|
end
|
12
24
|
end
|
13
25
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module TestUnit
|
2
|
+
module Generators
|
3
|
+
class PolicyGenerator < ::Rails::Generators::NamedBase
|
4
|
+
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
5
|
+
|
6
|
+
def create_policy_test
|
7
|
+
template 'policy_test.rb', File.join('test/policies', class_path, "#{file_name}_policy_test.rb")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/spec/canner_spec.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "canner"
|
3
|
+
|
4
|
+
class Sample
|
5
|
+
end
|
6
|
+
|
7
|
+
class SamplePolicy
|
8
|
+
|
9
|
+
def initialize(current_user, method, current_branch)
|
10
|
+
@current_user = current_user
|
11
|
+
@current_branch = current_branch
|
12
|
+
@method = method.to_sym
|
13
|
+
@roles = fetch_roles
|
14
|
+
end
|
15
|
+
|
16
|
+
def fetch_roles
|
17
|
+
# ['admin']
|
18
|
+
end
|
19
|
+
|
20
|
+
def canner_scope
|
21
|
+
# [Sample.new]
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class AppController
|
27
|
+
include Canner
|
28
|
+
|
29
|
+
attr_reader :current_user, :current_branch, :params
|
30
|
+
end
|
31
|
+
|
32
|
+
describe Canner do
|
33
|
+
let(:user) { double }
|
34
|
+
let(:branch) { double }
|
35
|
+
let(:app_controller) { AppController.new }
|
36
|
+
let(:sample_policy) {SamplePolicy.new(user, 'index', branch) }
|
37
|
+
|
38
|
+
describe "instance_can?" do
|
39
|
+
|
40
|
+
it "should call the policy's instance_can method" do
|
41
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
42
|
+
expect(sample_policy).to receive(:instance_can?).and_return true
|
43
|
+
|
44
|
+
app_controller.instance_can?('test', 'sample', Sample.new)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should raise a NotAuthorizedError if the policy's instance_can? returns false" do
|
48
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
49
|
+
expect(sample_policy).to receive(:instance_can?).and_return false
|
50
|
+
|
51
|
+
expect { app_controller.instance_can?('test', 'sample', Sample.new) }.to raise_error(Canner::NotAuthorizedError)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should return true if the policy allows access to the instance" do
|
55
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
56
|
+
expect(sample_policy).to receive(:instance_can?).and_return true
|
57
|
+
|
58
|
+
app_controller.instance_can?('test', 'sample', Sample.new).should be_truthy
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "can?" do
|
64
|
+
|
65
|
+
it "should call the policy's can? method" do
|
66
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
67
|
+
expect(sample_policy).to receive(:can?).and_return true
|
68
|
+
|
69
|
+
app_controller.can?('test', 'sample')
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should raise a NotAuthorized error if the policy's can? returns false" do
|
73
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
74
|
+
expect(sample_policy).to receive(:can?).and_return false
|
75
|
+
|
76
|
+
expect { app_controller.can?('test', 'sample') }.to raise_error(Canner::NotAuthorizedError)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should return true if the policy's can? permits access" do
|
80
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
81
|
+
expect(sample_policy).to receive(:can?).and_return true
|
82
|
+
|
83
|
+
expect(app_controller.can?('test', 'sample')).to eq true
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "canner_scope" do
|
89
|
+
|
90
|
+
it "should call the policy's canner_scope" do
|
91
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
92
|
+
expect(sample_policy).to receive(:canner_scope)
|
93
|
+
|
94
|
+
app_controller.canner_scope('test', 'sample')
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "ensure_scope" do
|
100
|
+
|
101
|
+
it "should not raise an error if canner_scope was called" do
|
102
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
103
|
+
expect(sample_policy).to receive(:canner_scope).and_return(true)
|
104
|
+
app_controller.canner_scope('test', 'sample')
|
105
|
+
|
106
|
+
expect(app_controller.send(:ensure_scope)).to be_truthy
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should raise error if canner_scope was not called" do
|
110
|
+
expect { app_controller.send(:ensure_scope) }.to raise_error(Canner::ScopeNotUsedError)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "ensure_auth" do
|
116
|
+
|
117
|
+
it "should not raise an error if can? was called" do
|
118
|
+
expect(app_controller).to receive(:canner_policy).and_return(sample_policy)
|
119
|
+
expect(sample_policy).to receive(:can?).and_return(true)
|
120
|
+
app_controller.can?('test', 'sample')
|
121
|
+
|
122
|
+
expect(app_controller.send(:ensure_auth)).to be_truthy
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should raise error if can? was not called" do
|
126
|
+
expect { app_controller.send(:ensure_auth) }.to raise_error(Canner::AuthNotUsedError)
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "canner_policy" do
|
132
|
+
|
133
|
+
it "should instantiate the proper policy class" do
|
134
|
+
expect(app_controller).to receive(:canner_user).and_return user
|
135
|
+
expect(app_controller).to receive(:canner_branch).and_return branch
|
136
|
+
|
137
|
+
expect(app_controller.send(:canner_policy, 'test', 'sample')).to be_a SamplePolicy
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "derive_class_name" do
|
143
|
+
|
144
|
+
it "should return the proper policy class name from the model" do
|
145
|
+
expect(app_controller.send(:derive_class_name, 'sample')).to eq "SamplePolicy"
|
146
|
+
expect(app_controller.send(:derive_class_name, 'samples')).to eq "SamplePolicy"
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
config.filter_run :focus
|
11
|
+
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
14
|
+
# the seed, which is printed after each run.
|
15
|
+
# --seed 1234
|
16
|
+
config.order = 'random'
|
17
|
+
end
|
metadata
CHANGED
@@ -1,111 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: canner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.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-
|
11
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '2.1'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '2.1'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - '>='
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - '>='
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rake
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - '>='
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - '>='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: yard
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - '>='
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - '>='
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
description: No magic authorization for Rails
|
@@ -115,25 +115,28 @@ executables: []
|
|
115
115
|
extensions: []
|
116
116
|
extra_rdoc_files: []
|
117
117
|
files:
|
118
|
-
-
|
118
|
+
- .gitignore
|
119
119
|
- Gemfile
|
120
120
|
- LICENSE
|
121
121
|
- README.md
|
122
122
|
- Rakefile
|
123
123
|
- canner.gemspec
|
124
124
|
- lib/canner.rb
|
125
|
-
- lib/canner/
|
125
|
+
- lib/canner/policy.rb
|
126
126
|
- lib/canner/util.rb
|
127
127
|
- lib/canner/version.rb
|
128
|
-
- lib/generators/canner/
|
129
|
-
- lib/generators/canner/
|
130
|
-
- lib/generators/canner/
|
128
|
+
- lib/generators/canner/fetch_roles/USAGE
|
129
|
+
- lib/generators/canner/fetch_roles/fetch_roles_generator.rb
|
130
|
+
- lib/generators/canner/fetch_roles/templates/base_policy.rb
|
131
131
|
- lib/generators/canner/policy/USAGE
|
132
132
|
- lib/generators/canner/policy/policy_generator.rb
|
133
133
|
- lib/generators/canner/policy/templates/policy.rb
|
134
134
|
- lib/generators/rspec/policy_generator.rb
|
135
135
|
- lib/generators/rspec/templates/policy_spec.rb
|
136
|
-
-
|
136
|
+
- lib/generators/test_unit/policy_generator.rb
|
137
|
+
- lib/generators/test_unit/templates/policy_test.rb
|
138
|
+
- spec/canner_spec.rb
|
139
|
+
- spec/spec_helper.rb
|
137
140
|
homepage: https://github.com/jacklin10/canner
|
138
141
|
licenses:
|
139
142
|
- MIT
|
@@ -144,19 +147,21 @@ require_paths:
|
|
144
147
|
- lib
|
145
148
|
required_ruby_version: !ruby/object:Gem::Requirement
|
146
149
|
requirements:
|
147
|
-
- -
|
150
|
+
- - '>='
|
148
151
|
- !ruby/object:Gem::Version
|
149
152
|
version: '0'
|
150
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
154
|
requirements:
|
152
|
-
- -
|
155
|
+
- - '>='
|
153
156
|
- !ruby/object:Gem::Version
|
154
157
|
version: '0'
|
155
158
|
requirements: []
|
156
159
|
rubyforge_project:
|
157
|
-
rubygems_version: 2.4.
|
160
|
+
rubygems_version: 2.4.1
|
158
161
|
signing_key:
|
159
162
|
specification_version: 4
|
160
163
|
summary: Rails Auth
|
161
164
|
test_files:
|
162
|
-
- spec/
|
165
|
+
- spec/canner_spec.rb
|
166
|
+
- spec/spec_helper.rb
|
167
|
+
has_rdoc:
|
data/lib/canner/rspec.rb
DELETED
File without changes
|
@@ -1,52 +0,0 @@
|
|
1
|
-
class BasePolicy
|
2
|
-
|
3
|
-
def initialize(current_user, current_branch, method)
|
4
|
-
@current_user = current_user
|
5
|
-
@current_branch = current_branch
|
6
|
-
@method = method.to_sym
|
7
|
-
@roles = fetch_roles
|
8
|
-
end
|
9
|
-
|
10
|
-
# implement this in your policy class
|
11
|
-
# expects an array or strings or symbols that represent the user roles
|
12
|
-
def fetch_roles
|
13
|
-
raise ArgumentError.new("YOU NEED TO IMPLEMENT")
|
14
|
-
# ex. User.roles
|
15
|
-
end
|
16
|
-
|
17
|
-
# implement in your policy class to auto scope in an action
|
18
|
-
def canner_scope
|
19
|
-
raise ArgumentError.new("NOT IMPLEMENTED")
|
20
|
-
# ex:
|
21
|
-
# case @method
|
22
|
-
# when :index
|
23
|
-
# User.by_branch(@current_branch)
|
24
|
-
# else
|
25
|
-
# User.none
|
26
|
-
# end
|
27
|
-
end
|
28
|
-
|
29
|
-
# implment in your policy class.
|
30
|
-
# return true when the user can access the action or resource and false when they can't
|
31
|
-
def can?
|
32
|
-
raise ArgumentError.new("NOT IMPLEMENTED")
|
33
|
-
# ex:
|
34
|
-
# case @method
|
35
|
-
# when :index, :show
|
36
|
-
# has_role?(:admin)
|
37
|
-
# else
|
38
|
-
# false
|
39
|
-
# end
|
40
|
-
end
|
41
|
-
|
42
|
-
protected
|
43
|
-
|
44
|
-
def is_method?(methods)
|
45
|
-
prepare(methods).include?(@method)
|
46
|
-
end
|
47
|
-
|
48
|
-
def has_role?(roles)
|
49
|
-
@roles.any?{|r| prepare(roles).include?(r.to_sym) }
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
data/spec/Gemfile
DELETED