allowy 0.2.4 → 0.2.4.1
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.
- 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:
|