access-granted 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/.travis.yml +6 -0
- data/Gemfile +7 -1
- data/README.md +30 -14
- data/access-granted.gemspec +1 -4
- data/lib/access-granted/controller_methods.rb +1 -1
- data/lib/access-granted/permission.rb +3 -3
- data/lib/access-granted/role.rb +3 -8
- data/lib/access-granted/version.rb +1 -1
- data/spec/controller_methods_spec.rb +1 -1
- data/spec/policy_spec.rb +42 -14
- data/spec/role_spec.rb +4 -4
- data/spec/spec_helper.rb +7 -2
- metadata +4 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e569e46f4095287086e980979eb59cb48bb8d671
|
4
|
+
data.tar.gz: 12579f6c1242101c5dfdab73bda111170fd719be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3bdef4853790d402a621cc1eae254d4fed2dc12a2273c704379bb84d7dce6f4a03d6c7b071a6b1a74d27bdf319cc98b0372490b164dd8ef3eaaa7edc2af3fe8
|
7
|
+
data.tar.gz: 4baac040d13e99a97aae7c3e160a3dc6e506350195b148e6c2737c8ee5b51c141b45e6e6f1e4b791a07e077abdf7552cfda87eab22c1a9c2b162fd14f7e6a2c2
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -3,7 +3,13 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in access-granted.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
group :test do
|
6
|
+
group :test, :development do
|
7
|
+
gem 'rb-readline'
|
7
8
|
gem 'simplecov', require: false
|
8
9
|
gem 'rake'
|
10
|
+
gem 'pry'
|
11
|
+
end
|
12
|
+
|
13
|
+
platforms :rbx do
|
14
|
+
gem 'rubysl', '~> 2.0'
|
9
15
|
end
|
data/README.md
CHANGED
@@ -2,14 +2,18 @@
|
|
2
2
|
|
3
3
|
Multi-role and whitelist based authorization gem for Rails. And it's lightweight (~300 lines of code)!
|
4
4
|
|
5
|
+
### Supported Ruby versions
|
6
|
+
|
7
|
+
Guaranteed to work on MRI 1.9.3/2.0/2.1, Rubinius >= 2.1.1 and JRuby >= 1.7.6.
|
8
|
+
|
5
9
|
# Summary
|
6
10
|
|
7
11
|
AccessGranted is meant as replacement for CanCan to solve three major problems:
|
8
12
|
|
9
13
|
1. built-in support for roles
|
10
14
|
|
11
|
-
Easy to read
|
12
|
-
Additionally permissions are forced to be unique in the scope a role greatly simplifying the
|
15
|
+
Easy to read access policy code where permissions are cleanly grouped into roles which may or may not apply to a user.
|
16
|
+
Additionally permissions are forced to be unique in the scope a role. Thus greatly simplifying the
|
13
17
|
permission resolving and extremely reducing the code-base.
|
14
18
|
|
15
19
|
2. white-list based
|
@@ -17,23 +21,34 @@ AccessGranted is meant as replacement for CanCan to solve three major problems:
|
|
17
21
|
This means that you define what a role **can** do,
|
18
22
|
not overidding permissions with `cannot` in a specific order which results in an ugly and unmaintainable code.
|
19
23
|
|
24
|
+
**Note**: `cannot` is still possible, but has a specifc use. See [Usage](#usage) below.
|
25
|
+
|
20
26
|
3. Permissions can work on basically any object and AccessGranted is framework-agnostic,
|
21
|
-
(the
|
27
|
+
(the Rails-specific methods are `can?`/`cannot?`/`authorize!` helpers injected
|
22
28
|
into the framework only when it's present).
|
23
29
|
|
24
30
|
See [Usage](#usage) for an example of a complete AccessPolicy file.
|
25
31
|
|
26
|
-
## Compatibility
|
32
|
+
## Compatibility with CanCan
|
27
33
|
|
28
34
|
This gem was created as a replacement for CanCan and therefore it requires minimum work to switch.
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
36
|
+
### Main differences
|
37
|
+
|
38
|
+
1. AccessGranted does not extend ActiveRecord in any way, so it does not have the `accessible_by?`
|
39
|
+
method which could be used for querying objects available to current user.
|
40
|
+
This was very complex and only worked with permissions defined using hash conditions, so
|
41
|
+
I decided to not implement this functionality as it was mostly ignored by CanCan users.
|
42
|
+
|
43
|
+
2. Both `can?`/`cannot?` and `authorize!` methods work in Rails controllers and views, just like in CanCan.
|
44
|
+
The only change you have to make is replace all `can? :manage, Class` with precise action.
|
45
|
+
`can :manage` is stil available for **defining** methods and serves as a shortcut for defining `:read`, `:create`, `:update`, `:destroy`
|
46
|
+
in one line.
|
47
|
+
|
48
|
+
Due to introduction of Roles checking for generic `:manage` permission is very complicated and also confusing for developers.
|
49
|
+
|
50
|
+
3. Syntax for defining permissions in AccessPolicy file (Ability in CanCan) is exactly the same,
|
33
51
|
with added roles on top. See [Usage](#usage) below.
|
34
|
-
3. **Main difference**: AccessGranted does not extend ActiveRecord in any way, so it does not have the `accessible_by?`
|
35
|
-
method to keep the code as simple as possible.
|
36
|
-
That is because `accessible_by?` was very limited making it useless in most cases (complex permissions with lambdas).
|
37
52
|
|
38
53
|
|
39
54
|
## Installation
|
@@ -70,12 +85,12 @@ class Policy
|
|
70
85
|
cannot [:create, :update, :destroy], Post
|
71
86
|
|
72
87
|
# same as above, :manage is just a shortcut for
|
73
|
-
# `[:create, :update, :destroy]`
|
88
|
+
# `[:read, :create, :update, :destroy]`
|
74
89
|
cannot :manage, Comment
|
75
90
|
end
|
76
91
|
|
77
92
|
# Takes precedences over roles placed lower
|
78
|
-
# and explicitly lets admin
|
93
|
+
# and explicitly lets admin manage everything.
|
79
94
|
role :admin, { is_admin: true } do
|
80
95
|
can :manage, Post
|
81
96
|
can :manage, Comment
|
@@ -84,7 +99,8 @@ class Policy
|
|
84
99
|
# You can also use Procs to determine
|
85
100
|
# if the role should apply to a given user.
|
86
101
|
role :moderator, proc {|u| u.moderator? } do
|
87
|
-
#
|
102
|
+
# takes precedence over :update/:destroy
|
103
|
+
# permissions defined in member role below
|
88
104
|
# and lets moderators edit and delete all posts
|
89
105
|
can [:update, :destroy], Post
|
90
106
|
|
@@ -93,8 +109,8 @@ class Policy
|
|
93
109
|
can :update, User
|
94
110
|
end
|
95
111
|
|
96
|
-
# Applies to everyone logged in.
|
97
112
|
# The basic role.
|
113
|
+
# Applies to everyone logged in.
|
98
114
|
role :member do
|
99
115
|
can :create, Post
|
100
116
|
|
data/access-granted.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = AccessGranted::VERSION
|
9
9
|
spec.authors = ["Piotrek Okoński"]
|
10
10
|
spec.email = ["piotrek@okonski.org"]
|
11
|
-
spec.description = %q{
|
11
|
+
spec.description = %q{Role based authorization gem}
|
12
12
|
spec.summary = %q{Elegant whitelist and role based authorization with ability to prioritize roles.}
|
13
13
|
spec.homepage = "https://github.com/pokonski/access-granted"
|
14
14
|
spec.license = "MIT"
|
@@ -19,8 +19,5 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
-
spec.add_development_dependency "rake"
|
23
22
|
spec.add_development_dependency "rspec"
|
24
|
-
spec.add_development_dependency "pry"
|
25
|
-
spec.add_development_dependency "text-table"
|
26
23
|
end
|
@@ -35,9 +35,9 @@ module AccessGranted
|
|
35
35
|
|
36
36
|
def eql?(other)
|
37
37
|
other.class == self.class &&
|
38
|
-
@action
|
39
|
-
@subject
|
40
|
-
@granted
|
38
|
+
@action == other.action &&
|
39
|
+
@subject == other.subject &&
|
40
|
+
@granted == other.granted
|
41
41
|
end
|
42
42
|
|
43
43
|
def ==(other)
|
data/lib/access-granted/role.rb
CHANGED
@@ -28,11 +28,6 @@ module AccessGranted
|
|
28
28
|
add_permission(false, action, subject, conditions, block)
|
29
29
|
end
|
30
30
|
|
31
|
-
def can?(action, subject)
|
32
|
-
permission = find_permission(action, subject)
|
33
|
-
permission ? permission.granted : false
|
34
|
-
end
|
35
|
-
|
36
31
|
def find_permission(action, subject)
|
37
32
|
relevant_permissions(action, subject).detect do |permission|
|
38
33
|
permission.matches_conditions?(subject)
|
@@ -42,7 +37,7 @@ module AccessGranted
|
|
42
37
|
def applies_to?(user)
|
43
38
|
case @conditions
|
44
39
|
when Hash
|
45
|
-
matches_hash(user, @conditions)
|
40
|
+
matches_hash?(user, @conditions)
|
46
41
|
when Proc
|
47
42
|
@conditions.call(user)
|
48
43
|
else
|
@@ -57,7 +52,7 @@ module AccessGranted
|
|
57
52
|
end
|
58
53
|
end
|
59
54
|
|
60
|
-
def matches_hash(user, conditions = {})
|
55
|
+
def matches_hash?(user, conditions = {})
|
61
56
|
conditions.all? do |name, value|
|
62
57
|
user.send(name) == value
|
63
58
|
end
|
@@ -76,7 +71,7 @@ module AccessGranted
|
|
76
71
|
|
77
72
|
def prepare_actions(action)
|
78
73
|
if action == :manage
|
79
|
-
actions = [:create, :update, :destroy]
|
74
|
+
actions = [:read, :create, :update, :destroy]
|
80
75
|
else
|
81
76
|
actions = [action].flatten
|
82
77
|
end
|
@@ -5,7 +5,7 @@ describe AccessGranted::ControllerMethods do
|
|
5
5
|
@current_user = double("User")
|
6
6
|
@controller_class = Class.new
|
7
7
|
@controller = @controller_class.new
|
8
|
-
@controller_class.stub(:helper_method).with(:can?, :cannot?, :
|
8
|
+
@controller_class.stub(:helper_method).with(:can?, :cannot?, :current_policy)
|
9
9
|
@controller_class.send(:include, AccessGranted::ControllerMethods)
|
10
10
|
@controller.stub(:current_user).and_return(@current_user)
|
11
11
|
end
|
data/spec/policy_spec.rb
CHANGED
@@ -9,10 +9,10 @@ describe AccessGranted::Policy do
|
|
9
9
|
|
10
10
|
describe "#configure" do
|
11
11
|
before :each do
|
12
|
-
@member = double("member", is_moderator: false, is_admin: false, is_banned: false)
|
13
|
-
@mod = double("moderator", is_moderator: true, is_admin: false, is_banned: false)
|
14
|
-
@admin = double("administrator", is_moderator: false, is_admin: true, is_banned: false)
|
15
|
-
@banned = double("banned", is_moderator: false, is_admin: true, is_banned: true)
|
12
|
+
@member = double("member", id: 1, is_moderator: false, is_admin: false, is_banned: false)
|
13
|
+
@mod = double("moderator", id: 2, is_moderator: true, is_admin: false, is_banned: false)
|
14
|
+
@admin = double("administrator", id: 3, is_moderator: false, is_admin: true, is_banned: false)
|
15
|
+
@banned = double("banned", id: 4, is_moderator: false, is_admin: true, is_banned: true)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "selects permission based on role priority" do
|
@@ -20,27 +20,55 @@ describe AccessGranted::Policy do
|
|
20
20
|
include AccessGranted::Policy
|
21
21
|
|
22
22
|
def configure(user)
|
23
|
-
role :
|
24
|
-
can :
|
23
|
+
role :administrator, { is_admin: true } do
|
24
|
+
can :destroy, String
|
25
25
|
end
|
26
26
|
|
27
27
|
role :moderator, { is_moderator: true } do
|
28
|
-
can :
|
28
|
+
can :update, String
|
29
29
|
end
|
30
30
|
|
31
|
-
role :
|
32
|
-
can :
|
31
|
+
role :member do
|
32
|
+
can :read, String
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
klass.new(@member).cannot?(:destroy, String).should be_true
|
37
36
|
klass.new(@admin).can?(:destroy, String).should be_true
|
38
37
|
klass.new(@admin).can?(:read, String).should be_true
|
38
|
+
|
39
|
+
klass.new(@member).cannot?(:destroy, String).should be_true
|
40
|
+
klass.new(@member).can?(:read, String).should be_true
|
41
|
+
|
42
|
+
klass.new(@mod).can?(:read, String).should be_true
|
39
43
|
klass.new(@mod).cannot?(:destroy, String).should be_true
|
40
44
|
end
|
41
45
|
|
46
|
+
context "when multiple roles define the same permission" do
|
47
|
+
it "checks all roles until conditions are met" do
|
48
|
+
user_post = FakePost.new(@member.id)
|
49
|
+
other_post = FakePost.new(66)
|
50
|
+
|
51
|
+
klass = Class.new do
|
52
|
+
include AccessGranted::Policy
|
53
|
+
|
54
|
+
def configure(user)
|
55
|
+
role :administrator, { is_admin: true } do
|
56
|
+
can :destroy, FakePost
|
57
|
+
end
|
58
|
+
|
59
|
+
role :member do
|
60
|
+
can :destroy, FakePost, user_id: user.id
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
klass.new(@admin).can?(:destroy, user_post).should be_true
|
66
|
+
klass.new(@member).can?(:destroy, user_post).should be_true
|
67
|
+
klass.new(@member).cannot?(:destroy, other_post).should be_true
|
68
|
+
end
|
69
|
+
end
|
42
70
|
describe "#cannot" do
|
43
|
-
it "forbids action when used in
|
71
|
+
it "forbids action when used in superior role" do
|
44
72
|
klass = Class.new do
|
45
73
|
include AccessGranted::Policy
|
46
74
|
|
@@ -54,8 +82,8 @@ describe AccessGranted::Policy do
|
|
54
82
|
end
|
55
83
|
end
|
56
84
|
end
|
57
|
-
klass.new(@member).can?(:create, String).should
|
58
|
-
klass.new(@banned).
|
85
|
+
klass.new(@member).can?(:create, String).should be_true
|
86
|
+
klass.new(@banned).cannot?(:create, String).should be_true
|
59
87
|
end
|
60
88
|
end
|
61
89
|
end
|
@@ -86,7 +114,7 @@ describe AccessGranted::Policy do
|
|
86
114
|
can :read, String
|
87
115
|
end
|
88
116
|
|
89
|
-
role.
|
117
|
+
role.find_permission(:read, String).granted.should be_true
|
90
118
|
end
|
91
119
|
end
|
92
120
|
|
data/spec/role_spec.rb
CHANGED
@@ -62,7 +62,7 @@ describe AccessGranted::Role do
|
|
62
62
|
|
63
63
|
it "accepts :manage shortcut for CRUD actions" do
|
64
64
|
@role.can :manage, String
|
65
|
-
@role.permissions.map(&:action).should include(:create, :update, :destroy)
|
65
|
+
@role.permissions.map(&:action).should include(:read, :create, :update, :destroy)
|
66
66
|
end
|
67
67
|
|
68
68
|
describe "when action is an Array" do
|
@@ -75,12 +75,12 @@ describe AccessGranted::Role do
|
|
75
75
|
describe "when no conditions given" do
|
76
76
|
it "should be able to read a class" do
|
77
77
|
@role.can :read, String
|
78
|
-
@role.
|
78
|
+
@role.find_permission(:read, String).should be_true
|
79
79
|
end
|
80
80
|
|
81
81
|
it "should be able to read instance of class" do
|
82
82
|
@role.can :read, String
|
83
|
-
@role.
|
83
|
+
@role.find_permission(:read, "text").should be_true
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -88,7 +88,7 @@ describe AccessGranted::Role do
|
|
88
88
|
it "should be able to read when conditions match" do
|
89
89
|
sub = double("Element", published: true)
|
90
90
|
@role.can :read, sub.class, { published: true }
|
91
|
-
@role.
|
91
|
+
@role.find_permission(:read, sub).should be_true
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler/setup'
|
3
|
-
|
4
|
-
|
3
|
+
if ENV["COV"]
|
4
|
+
require 'simplecov'
|
5
|
+
SimpleCov.start
|
6
|
+
end
|
5
7
|
require 'pry'
|
6
8
|
|
7
9
|
RSpec.configure do |config|
|
@@ -20,6 +22,9 @@ module ActionController
|
|
20
22
|
end
|
21
23
|
require 'access-granted'
|
22
24
|
|
25
|
+
class FakePost < Struct.new(:user_id)
|
26
|
+
end
|
27
|
+
|
23
28
|
class Policy
|
24
29
|
include AccessGranted::Policy
|
25
30
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: access-granted
|
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
|
- Piotrek Okoński
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '>='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '>='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: rspec
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,35 +38,7 @@ dependencies:
|
|
52
38
|
- - '>='
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: '0'
|
55
|
-
|
56
|
-
name: pry
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - '>='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - '>='
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: text-table
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - '>='
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - '>='
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
description: Whitelist and role based authorization gem
|
41
|
+
description: Role based authorization gem
|
84
42
|
email:
|
85
43
|
- piotrek@okonski.org
|
86
44
|
executables: []
|
@@ -127,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
85
|
version: '0'
|
128
86
|
requirements: []
|
129
87
|
rubyforge_project:
|
130
|
-
rubygems_version: 2.
|
88
|
+
rubygems_version: 2.1.11
|
131
89
|
signing_key:
|
132
90
|
specification_version: 4
|
133
91
|
summary: Elegant whitelist and role based authorization with ability to prioritize
|