allowy 0.2.4 → 0.2.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +42 -37
- data/lib/allowy/access_control.rb +34 -0
- data/lib/allowy/context.rb +4 -4
- data/lib/allowy/version.rb +1 -1
- metadata +14 -14
data/README.md
CHANGED
@@ -14,10 +14,10 @@ CanCan doesn't work very well for me when Ability definitions grow above 20 line
|
|
14
14
|
|
15
15
|
- it becomes **really hard to track down** why something was (or not) allowed.
|
16
16
|
- **DSL enforces** you to use ActiveRecord-like scopes or blocks. It gets harder to maintain.
|
17
|
-
- The Ability class contains **all the definitions for everything**. Hard to test, hard to maintain unless carefully refactor it.
|
18
|
-
- Implicit permission - CanCan tries to be very smart (and is indeed) using aliases such as `:manage` but it makes even harder to
|
17
|
+
- The Ability class contains **all the definitions for everything**. Hard to test, hard to maintain unless you carefully refactor it.
|
18
|
+
- Implicit permission - CanCan tries to be very smart (and is indeed) using aliases such as `:manage` but it makes even harder to understand it.
|
19
19
|
- Implicit permission - you can use any symbol to check permissions. `:love_people` will do, even if you never defined it.
|
20
|
-
- A little bit **tight to ORM**. When using with database such as neo4j, some
|
20
|
+
- A little bit **tight to ORM**. When using with database such as neo4j, some small-ish things don't work. So I prefer to be explicit.
|
21
21
|
- **Testing** an ability for a single class often depends on too many others.
|
22
22
|
- **Refacoring** of the abilities feels like rolling your own authorization library.
|
23
23
|
|
@@ -36,7 +36,7 @@ gem 'allowy'
|
|
36
36
|
|
37
37
|
Then `bundle install`.
|
38
38
|
|
39
|
-
Or use `allowy` gem
|
39
|
+
Or use `allowy` gem as usually.
|
40
40
|
|
41
41
|
# Usage
|
42
42
|
|
@@ -53,7 +53,7 @@ If you want to safeguard `Page` class then define `PageAccess` class:
|
|
53
53
|
class PageAccess
|
54
54
|
include Allowy::AccessControl
|
55
55
|
|
56
|
-
# This will allow you to ask: can? :view, page
|
56
|
+
# This will allow you to ask: `can? :view, page`
|
57
57
|
# The truthy result of this function will grant access, otherwise not.
|
58
58
|
def view?(page)
|
59
59
|
page and page.published?
|
@@ -64,11 +64,11 @@ class PageAccess
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
# Then, in rails, you would use it:
|
67
|
+
# Then, in rails controller/view, you would use it:
|
68
68
|
can? :view, page
|
69
69
|
cannot? :edit, page
|
70
70
|
authorize! :view, page # raises Allowy::AccessDenied if can?(:view, page) returns false
|
71
|
-
can? :love_people, page # Will raise
|
71
|
+
can? :love_people, page # Will raise NoMethodError because `love_people` is not defined on the Access Control class
|
72
72
|
```
|
73
73
|
|
74
74
|
## Context
|
@@ -82,18 +82,23 @@ class PageAccess
|
|
82
82
|
include Allowy::AccessControl
|
83
83
|
|
84
84
|
def view?(page)
|
85
|
-
return true if context.params[:
|
85
|
+
return true if context.params[:hidden_hack_for_admin]
|
86
86
|
context.user_signed_in? and page.published?
|
87
87
|
end
|
88
88
|
end
|
89
89
|
```
|
90
90
|
|
91
|
-
If you want to change the context in Rails then just override it in the controller or globally in the `ApplicationController
|
91
|
+
If you want to change the context in Rails then just override it in the controller or globally in the `ApplicationController`.
|
92
|
+
The only requirement for the context is that it should mix-in the `Allowy::Context` module.
|
92
93
|
|
93
94
|
```ruby
|
95
|
+
class CmsContext < Hash
|
96
|
+
include Allowy::Context
|
97
|
+
end
|
98
|
+
|
94
99
|
class PagesController < ApplicationController
|
95
100
|
def allowy_context
|
96
|
-
{realy: 'anything', can_be: 'here', even: params}
|
101
|
+
CmsContext.new {realy: 'anything', can_be: 'here', even: params}
|
97
102
|
end
|
98
103
|
end
|
99
104
|
```
|
@@ -101,7 +106,7 @@ end
|
|
101
106
|
## More comprehensive example
|
102
107
|
|
103
108
|
You probably have multiple classes that you want to protect.
|
104
|
-
I recommend creating your own base class to provide common context and maybe some utility methods:
|
109
|
+
I recommend creating your own base class or module to provide common context and maybe some utility methods:
|
105
110
|
|
106
111
|
```ruby
|
107
112
|
class DefaultAccess
|
@@ -179,7 +184,11 @@ To test the access control classes you can just instantiate those passing contex
|
|
179
184
|
Most of the time you will stub out the context, so the test isolation is a piece of cake.
|
180
185
|
|
181
186
|
You need to `require 'allowy/rspec'`.
|
182
|
-
It will give you
|
187
|
+
It will give you:
|
188
|
+
|
189
|
+
- `be_able_to` RSpec matcher;
|
190
|
+
- `ignore_authorization!` macro for controller specs;
|
191
|
+
- `should_authorize_for!` macro for controller specs (can **only** be used with `ignore_authorization!`).
|
183
192
|
|
184
193
|
|
185
194
|
```ruby
|
@@ -197,17 +206,32 @@ describe PageAccess do
|
|
197
206
|
subject.view?(page).should be_false
|
198
207
|
end
|
199
208
|
|
200
|
-
context "
|
201
|
-
|
202
|
-
|
209
|
+
context "I prefer RSpec contexts" do
|
210
|
+
subject { PageAccess.new(stub(:current_user: user)).view?(page) }
|
211
|
+
|
212
|
+
context "when logged in" do
|
213
|
+
let(:user) { stub 'User' }
|
214
|
+
context "and page is wiki" do
|
215
|
+
before { page.stub(wiki?: true) }
|
216
|
+
it { should be_true }
|
217
|
+
end
|
218
|
+
context "and page is not wiki" do
|
219
|
+
before { page.stub(wiki?: false) }
|
220
|
+
it { should be_false }
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context "when anonim" do
|
225
|
+
let(:user) { nil }
|
226
|
+
it { should be_false }
|
227
|
+
end
|
203
228
|
end
|
204
|
-
end
|
205
229
|
|
206
|
-
|
230
|
+
end
|
207
231
|
end
|
208
232
|
|
209
233
|
|
210
|
-
# Example of a controller
|
234
|
+
# Example of a controller spec
|
211
235
|
describe PagesController do
|
212
236
|
# This will always grant access, so you don't have to create too many objects
|
213
237
|
# But make sure you test PageAccess separately as in the example above
|
@@ -225,25 +249,6 @@ end
|
|
225
249
|
|
226
250
|
```
|
227
251
|
|
228
|
-
But if you don't want to stub the context because you access its `can?`, `cannot?` or `authorize!` methods
|
229
|
-
(allwing permission delegation) then you can simply mix the `Allowy::Context` in:
|
230
|
-
|
231
|
-
```ruby
|
232
|
-
class ControllerLikeContext
|
233
|
-
include Alllowy::Context
|
234
|
-
attr_accessor :current_user
|
235
|
-
|
236
|
-
def initialize(user)
|
237
|
-
@current_user = user
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
# Then you can simply instantiate it to check the permissions:
|
242
|
-
ControllerLikeContext.new(that_user).should be_able_to :edit, Blog
|
243
|
-
ControllerLikeContext.new(this_user).should_not be_able_to :edit, Blog
|
244
|
-
```
|
245
|
-
|
246
|
-
|
247
252
|
# Development
|
248
253
|
|
249
254
|
|
@@ -1,4 +1,38 @@
|
|
1
1
|
module Allowy
|
2
|
+
# This module provides the interface for implementing the access control actions.
|
3
|
+
# In order to use it, mix it into a poor Ruby class and define methods ending with `?`.
|
4
|
+
# For example:
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class PageAccess
|
8
|
+
# include Allowy::AccessControl
|
9
|
+
#
|
10
|
+
# def view?(page)
|
11
|
+
# page and page.wiki? and context.user_signed_in?
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# And then you can check the permissions from a controller:
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# def show
|
18
|
+
# @page = Page.find params[:id]
|
19
|
+
# authorize! :view, @page
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# You can also check the permissions outside of the controller, but you need a similar `Allowy::Context` class:
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# class CucumberContext
|
27
|
+
# include Allowy::Context
|
28
|
+
# attr_accessor :current_user
|
29
|
+
# def initialize(user)
|
30
|
+
# @current_user = user
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# CucumberContext.new(that_user).should be_able_to :create, Blog
|
35
|
+
#
|
2
36
|
module AccessControl
|
3
37
|
extend ActiveSupport::Concern
|
4
38
|
included do
|
data/lib/allowy/context.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Allowy
|
2
2
|
|
3
|
-
# This module provides the default and common context
|
4
|
-
# It is mixed into
|
5
|
-
# in other parts of the application (in RSpec or Cucumber) without
|
3
|
+
# This module provides the default and common context for checking the permissions.
|
4
|
+
# It is mixed into controllers in Rails by default and provides an easy way to reuse it
|
5
|
+
# in other parts of the application (in RSpec or Cucumber) without needing a controller.
|
6
6
|
# For example, you can use this code in your Cucumber features:
|
7
7
|
#
|
8
8
|
# @example
|
@@ -14,7 +14,7 @@ module Allowy
|
|
14
14
|
# @current_user = user
|
15
15
|
# end
|
16
16
|
#
|
17
|
-
# And the you can easily check the permissions
|
17
|
+
# And the you can easily check the permissions like so:
|
18
18
|
#
|
19
19
|
# @example
|
20
20
|
# CustomContext.new(that_user).should be_able_to :create, Blog
|
data/lib/allowy/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: allowy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.4
|
4
|
+
version: 0.2.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: i18n
|
16
|
-
requirement: &
|
16
|
+
requirement: &70101345958680 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70101345958680
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activesupport
|
27
|
-
requirement: &
|
27
|
+
requirement: &70101345957600 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '3.2'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70101345957600
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &70101345946120 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70101345946120
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: pry
|
49
|
-
requirement: &
|
49
|
+
requirement: &70101345945020 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70101345945020
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: guard
|
60
|
-
requirement: &
|
60
|
+
requirement: &70101345944200 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70101345944200
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: guard-rspec
|
71
|
-
requirement: &
|
71
|
+
requirement: &70101345943120 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70101345943120
|
80
80
|
description: Allowy provides CanCan-like way of checking permission but doesn't enforce
|
81
81
|
a tight DSL giving you more control
|
82
82
|
email:
|