erbac 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -4
- data/README.md +126 -0
- data/build.bat +4 -0
- data/build.sh +3 -0
- data/erbac.gemspec +1 -1
- data/lib/erbac/active_record_support.rb +1 -7
- data/lib/erbac/auth_manage.rb +5 -22
- data/lib/erbac/version.rb +1 -1
- data/spec/erbac/user_instance_spec.rb +22 -6
- data/spec/support/adapters/active_record.rb +4 -4
- data/spec/support/data.rb +12 -6
- metadata +5 -2
data/.gitignore
CHANGED
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# Erbac
|
2
|
+
|
3
|
+
Q: First things first, you might ask, why the name?
|
4
|
+
|
5
|
+
A: Well, it is actually a transplantation of [yiiframework][yii]'s [Role Based Access Control][yii-rbac] system.
|
6
|
+
|
7
|
+
[yii]: http://www.yiiframework.com/
|
8
|
+
[yii-rbac]: http://www.yiiframework.com/doc/guide/1.1/en/topics.auth#role-based-access-control
|
9
|
+
|
10
|
+
## How to Use
|
11
|
+
1. Installation
|
12
|
+
> Put it in the Gemfile:
|
13
|
+
> ```gem 'erbac'```
|
14
|
+
> then run
|
15
|
+
> ```bundle install```.
|
16
|
+
|
17
|
+
2. Generation
|
18
|
+
> In your command line tools, try to input
|
19
|
+
> ```rails generate erbac```
|
20
|
+
> here is the options for the gem:
|
21
|
+
|
22
|
+
Usage:
|
23
|
+
rails generate erbac User [options]
|
24
|
+
|
25
|
+
Options:
|
26
|
+
-i, [--auth-item=auth_item AuthItem auth_items] # auth item, model and table
|
27
|
+
# Default: ["auth_item", "AuthItem", "auth_items"]
|
28
|
+
-c, [--auth-item-child=auth_item_child auth_item_children] # auth item child and the join table
|
29
|
+
# Default: ["auth_item_child", "auth_item_children"]
|
30
|
+
-a, [--auth-assignment=auth_assignment AuthAssignment auth_assignments] # auth assignment and the join table
|
31
|
+
# Default: ["auth_assignment", "AuthAssignment", "auth_assignments"]
|
32
|
+
-o, [--orm=NAME] # Orm to be invoked
|
33
|
+
# Default: active_record
|
34
|
+
|
35
|
+
Generates RBAC(role base access control) models and migration files according to the USER
|
36
|
+
|
37
|
+
Here, the 'User' is the Model from your project's 'User' model:
|
38
|
+
> ``` rails g erbac User ```
|
39
|
+
> or
|
40
|
+
> ``` rails g erbac Account ```
|
41
|
+
> or
|
42
|
+
> ``` rails g erbac Admin ```
|
43
|
+
> or whatever is suitable for your system.
|
44
|
+
|
45
|
+
And an example of customization with 'auth\_item':
|
46
|
+
> ``` rails g erbac User --i my_auth_item ```
|
47
|
+
> equals
|
48
|
+
> ``` rails g erbac User --i my_auth_item MyAuthItem my_auth_items ```
|
49
|
+
>
|
50
|
+
> ``` rails g erbac User --i my_auth_item YourAuthItem ```
|
51
|
+
> equals
|
52
|
+
> ``` rails g erbac User --i my_auth_item YourAuthItem my_auth_items ```
|
53
|
+
>
|
54
|
+
> ``` rails g erbac User --i my_auth_item YourAuthItem their_auth_items ```
|
55
|
+
|
56
|
+
The same holds true for option -c and -a.
|
57
|
+
You don't change -o option for it only support active record right now...
|
58
|
+
|
59
|
+
3. Configuration
|
60
|
+
A file name erbac.rb will be generated in "rails_root/config/initializer/erbac.rb", you can see many of the options commented out as default value, and there are two points worth noting:
|
61
|
+
* strict\_check\_mode
|
62
|
+
* __NB: first of all, if bizrule.nil? or bizrule.empty? holds, it will pass.__
|
63
|
+
* set to true: if bizrule evaluates to be true, it will pass, or else, won't pass.
|
64
|
+
* set to false: if bizrule evaluates to be false, it won't pass, or else, will pass.
|
65
|
+
|
66
|
+
* default roles
|
67
|
+
roles in this array will be checked first, if none of them passed, a normal check will be carried on.
|
68
|
+
|
69
|
+
4. Role/Task/Operation creation and assignment
|
70
|
+
Just the same as yii, but in a Object Oriented way(with the help of Erbac helper module), example will be found at spec/support/data.rb file of this project.
|
71
|
+
|
72
|
+
5. Use
|
73
|
+
Use ``` check_access? ``` of Erbac or the 'User' model, find the sample codes from spec/user\_instance\_spec.rb file.
|
74
|
+
You can also use the raw execute\_biz\_rule? to find out whether it hold only for _ONLY This_ item, whilst check\_access? checks it RECURSIVELY.
|
75
|
+
|
76
|
+
|
77
|
+
## Inside the Erbac ##
|
78
|
+
the model we use is defined here:
|
79
|
+
|
80
|
+
authorA = User.new(name: "authorA")
|
81
|
+
authorB = User.new(name: "authorB")
|
82
|
+
|
83
|
+
oper_create_post = Erbac.create_operation "createPost", description: "create a post"
|
84
|
+
oper_read_post = Erbac.create_operation 'readPost', description: 'read a post'
|
85
|
+
oper_update_post = Erbac.create_operation 'updatePost', description: 'update a post'
|
86
|
+
oper_delete_post = Erbac.create_operation 'deletePost', description: 'delete a post'
|
87
|
+
|
88
|
+
task_update_own_post = Erbac.create_task "updateOwnPost", description: "update a post by author himself", bizrule: "self == params[:post].author"
|
89
|
+
task_update_own_post.add_child oper_update_post
|
90
|
+
|
91
|
+
role_reader = Erbac.create_role "reader"
|
92
|
+
role_reader.add_child oper_read_post
|
93
|
+
|
94
|
+
role_author = Erbac.create_role "author"
|
95
|
+
role_author.add_child role_reader
|
96
|
+
role_author.add_child oper_create_post
|
97
|
+
role_author.add_child task_update_own_post
|
98
|
+
|
99
|
+
Erbac.assign role_author, authorA
|
100
|
+
Erbac.assign role_author, authorB
|
101
|
+
|
102
|
+
first_post = Post.create! header: "first post", author_id: @authorA.id
|
103
|
+
|
104
|
+
authorA.check_access?(oper_update_post, post: first_post)
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
check_access? will check the privileges RECURSIVELY, in a top down sequence:
|
109
|
+
|
110
|
+
* check the item and if it passes
|
111
|
+
* check if this item is a default role, if so, return true
|
112
|
+
* check assignment, if it passes, find all the parents items and do the check again, return true if any of them return true
|
113
|
+
|
114
|
+
So in the code above, erbac will check oper_update_post first, then task\_update\_own\_post, then role\_author, bingo, it is passing the check.
|
115
|
+
|
116
|
+
Now you know why an nil or empty string bizrule will cause a pass, if not, the check_access? will not work properly RECURSIVELY.
|
117
|
+
|
118
|
+
## Cautions ##
|
119
|
+
|
120
|
+
* When you define your bizrule, either do it with in an empty string, or not assign to it at all, space string will not work preperly, thus break the check link and cause an logic error. (" ".empty? == false)
|
121
|
+
* 'bizrule's will be check in two cases: auth\_assignment and auth\_item, so you can customize your auth_assignment to micro control your access.
|
122
|
+
|
123
|
+
## TODOs ##
|
124
|
+
* It only support Active Record, in the model layer.
|
125
|
+
|
126
|
+
|
data/build.bat
ADDED
data/build.sh
ADDED
data/erbac.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
|
12
12
|
s.authors = ["dx"]
|
13
13
|
s.email = 'bitcheap@gmail.com'
|
14
|
-
s.homepage = '
|
14
|
+
s.homepage = 'https://github.com/douxing/erbac'
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -11,9 +11,6 @@ module Erbac
|
|
11
11
|
class_name: Erbac.auth_assignment_class,
|
12
12
|
foreign_key: "user_id"
|
13
13
|
|
14
|
-
accepts_nested_attributes_for Erbac.auth_assignment.pluralize.to_sym, allow_destroy: true
|
15
|
-
attr_accessible (Erbac.auth_assignment.pluralize + "_attributes").to_sym
|
16
|
-
|
17
14
|
has_many Erbac.auth_item.pluralize.to_sym,
|
18
15
|
through: Erbac.auth_assignment.pluralize.to_sym,
|
19
16
|
source: Erbac.auth_item.pluralize.to_sym
|
@@ -92,9 +89,6 @@ module Erbac
|
|
92
89
|
class_name: Erbac.auth_assignment_class,
|
93
90
|
foreign_key: "item_id"
|
94
91
|
|
95
|
-
accepts_nested_attributes_for Erbac.auth_assignment.pluralize.to_sym, allow_destroy: true
|
96
|
-
attr_accessible (Erbac.auth_assignment.pluralize + "_attributes").to_sym
|
97
|
-
|
98
92
|
has_many Erbac.user_class.underscore.pluralize.to_sym,
|
99
93
|
through: Erbac.auth_assignment.pluralize.to_sym,
|
100
94
|
source: Erbac.user_class.underscore.pluralize.to_sym
|
@@ -133,7 +127,7 @@ module Erbac
|
|
133
127
|
end
|
134
128
|
|
135
129
|
define_method :has_child? do |item|
|
136
|
-
self.children.include?
|
130
|
+
self.children.include? item
|
137
131
|
end
|
138
132
|
|
139
133
|
define_method :assign do |user, bizrule=nil, data=nil|
|
data/lib/erbac/auth_manage.rb
CHANGED
@@ -11,7 +11,9 @@ module Erbac
|
|
11
11
|
define_method ("create_" + type) do |name, options={}|
|
12
12
|
options[:name] = name
|
13
13
|
options[:auth_type] = Erbac.auth_item_class.constantize.const_get("TYPE_" + type.upcase)
|
14
|
-
Erbac.auth_item_class.constantize.
|
14
|
+
item = Erbac.auth_item_class.constantize.new options
|
15
|
+
item.save!
|
16
|
+
item
|
15
17
|
end
|
16
18
|
|
17
19
|
define_method ("get_" + type.pluralize) do |user|
|
@@ -19,11 +21,6 @@ module Erbac
|
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
|
-
def check_access(*args)
|
23
|
-
user = args[1].is_a? Erbac.user_class.constantize ? args[1] : Erbac.user_class.constantize.anonymous
|
24
|
-
user.check_access? args.first, args.extract_options!
|
25
|
-
end
|
26
|
-
|
27
24
|
def add_item_child(parent, child)
|
28
25
|
parent.add_child child
|
29
26
|
end
|
@@ -79,24 +76,10 @@ module Erbac
|
|
79
76
|
raise TypeError, "Should pass in #{Erbac.auth_item_class} instance as the first parameter. Got #{args.first.to_s}", caller
|
80
77
|
end
|
81
78
|
|
82
|
-
|
83
|
-
|
84
|
-
else
|
85
|
-
bizrule_sandbox args.first.bizrule, args.extract_options!, args.first.data
|
86
|
-
end
|
79
|
+
user = (args[1].is_a? Erbac.user_class.constantize) ? args[1] : Erbac.user_class.constantize.anonymous
|
80
|
+
user.check_access? args.first, args.extract_options!
|
87
81
|
end
|
88
82
|
|
89
|
-
protected
|
90
|
-
def bizrule_sandbox(bizrule, params={}, data=nil)
|
91
|
-
if (bizrule.nil? or bizrule.empty?)
|
92
|
-
true
|
93
|
-
else
|
94
|
-
proc do
|
95
|
-
$SAFE = 4 # here is a military area
|
96
|
-
Erbac.restrict_check_mode ? (eval bizrule) == true : (eval bizrule) != false
|
97
|
-
end.call
|
98
|
-
end
|
99
|
-
end
|
100
83
|
end
|
101
84
|
end
|
102
85
|
end
|
data/lib/erbac/version.rb
CHANGED
@@ -24,8 +24,10 @@ describe Erbac do
|
|
24
24
|
describe User do
|
25
25
|
subject {nil}
|
26
26
|
|
27
|
-
it "can not
|
28
|
-
|
27
|
+
it "can not do any thing" do
|
28
|
+
AuthItem.find_each do |auth|
|
29
|
+
Erbac.check_access?(auth, subject, post: @first_post).should be_false
|
30
|
+
end
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
@@ -95,9 +97,9 @@ describe Erbac do
|
|
95
97
|
|
96
98
|
it "can edit as editor" do
|
97
99
|
subject.check_access?(@role_editor).should be_true
|
98
|
-
Erbac.check_access?(@role_editor, subject).should
|
100
|
+
Erbac.check_access?(@role_editor, subject).should be_true
|
99
101
|
subject.check_access?(@oper_update_post, post: @first_post).should be_true
|
100
|
-
Erbac.check_access?(@oper_update_post, subject, post: @first_post).should
|
102
|
+
Erbac.check_access?(@oper_update_post, subject, post: @first_post).should be_true
|
101
103
|
end
|
102
104
|
|
103
105
|
it "can not delete" do
|
@@ -111,50 +113,64 @@ describe Erbac do
|
|
111
113
|
|
112
114
|
it "can read" do
|
113
115
|
subject.check_access?(@role_reader).should be_true
|
116
|
+
Erbac.check_access?(@role_reader, subject).should be_true
|
114
117
|
end
|
115
118
|
|
116
119
|
it "can edit self post as task" do
|
117
120
|
subject.check_access?(@task_update_own_post, post: @first_post).should be_true
|
121
|
+
Erbac.check_access?(@task_update_own_post, subject, post: @first_post).should be_true
|
118
122
|
subject.check_access?(@task_update_own_post, post: @second_post).should be_false
|
123
|
+
Erbac.check_access?(@task_update_own_post, subject, post: @first_post).should be_true
|
119
124
|
end
|
120
125
|
|
121
126
|
it "can edit self post as update operation" do
|
122
127
|
subject.check_access?(@oper_update_post, post: @first_post).should be_true
|
128
|
+
Erbac.check_access?(@oper_update_post, subject, post: @first_post).should be_true
|
123
129
|
subject.check_access?(@oper_update_post, post: @second_post).should be_false
|
130
|
+
Erbac.check_access?(@oper_update_post, subject, post: @second_post).should be_false
|
124
131
|
end
|
125
132
|
|
126
133
|
it "can not edit as editor" do
|
127
134
|
subject.check_access?(@role_editor).should be_false
|
135
|
+
Erbac.check_access?(@role_editor, subject).should be_false
|
128
136
|
end
|
129
137
|
|
130
138
|
it "can not delete" do
|
131
|
-
subject.check_access?(@
|
139
|
+
subject.check_access?(@oper_delete_post).should be_false
|
140
|
+
Erbac.check_access?(@oper_delete_post, subject).should be_false
|
132
141
|
end
|
133
142
|
end
|
134
143
|
|
135
144
|
describe User do
|
136
|
-
subject { User.where(name: "
|
145
|
+
subject { User.where(name: "admin").first }
|
137
146
|
|
138
147
|
it "can read" do
|
139
148
|
subject.check_access?(@role_reader).should be_true
|
149
|
+
Erbac.check_access?(@role_reader, subject).should be_true
|
140
150
|
end
|
141
151
|
|
142
152
|
it "can edit self post as task" do
|
143
153
|
subject.check_access?(@task_update_own_post, post: @first_post).should be_false
|
154
|
+
Erbac.check_access?(@task_update_own_post, subject, post: @first_post).should be_false
|
144
155
|
subject.check_access?(@task_update_own_post, post: @second_post).should be_false
|
156
|
+
Erbac.check_access?(@task_update_own_post, subject, post: @second_post).should be_false
|
145
157
|
end
|
146
158
|
|
147
159
|
it "can edit self post as update operation" do
|
148
160
|
subject.check_access?(@oper_update_post, post: @first_post).should be_true
|
161
|
+
Erbac.check_access?(@oper_update_post, subject, post: @first_post).should be_true
|
149
162
|
subject.check_access?(@oper_update_post, post: @second_post).should be_true
|
163
|
+
Erbac.check_access?(@oper_update_post, subject, post: @second_post).should be_true
|
150
164
|
end
|
151
165
|
|
152
166
|
it "can not edit as editor" do
|
153
167
|
subject.check_access?(@role_editor).should be_true
|
168
|
+
Erbac.check_access?(@role_editor, subject).should be_true
|
154
169
|
end
|
155
170
|
|
156
171
|
it "can not delete" do
|
157
172
|
subject.check_access?(@oper_delete_post).should be_true
|
173
|
+
Erbac.check_access?(@role_editor, subject).should be_true
|
158
174
|
end
|
159
175
|
end
|
160
176
|
end
|
@@ -8,7 +8,7 @@ load File.dirname(__FILE__) + '/../schema.rb'
|
|
8
8
|
|
9
9
|
# ActiveRecord models
|
10
10
|
class User < ActiveRecord::Base
|
11
|
-
attr_accessible :name
|
11
|
+
# attr_accessible :name
|
12
12
|
control_access
|
13
13
|
|
14
14
|
has_many :my_posts, class_name: "Post", inverse_of: :author
|
@@ -17,17 +17,17 @@ class User < ActiveRecord::Base
|
|
17
17
|
end
|
18
18
|
|
19
19
|
class AuthItem < ActiveRecord::Base
|
20
|
-
attr_accessible :name, :auth_type, :description, :bizrule, :data
|
20
|
+
# attr_accessible :name, :auth_type, :description, :bizrule, :data
|
21
21
|
control_auth_item
|
22
22
|
end
|
23
23
|
|
24
24
|
class AuthAssignment < ActiveRecord::Base
|
25
|
-
attr_accessible :item_id, :user_id, :bizrule, :data
|
25
|
+
# attr_accessible :item_id, :user_id, :bizrule, :data
|
26
26
|
control_auth_assignment
|
27
27
|
end
|
28
28
|
|
29
29
|
class Post < ActiveRecord::Base
|
30
|
-
attr_accessible :header, :author_id
|
30
|
+
# attr_accessible :header, :author_id
|
31
31
|
belongs_to :author, class_name: "User", inverse_of: :my_posts
|
32
32
|
belongs_to :co_workers, class_name: "User", inverse_of: :co_posts
|
33
33
|
end
|
data/spec/support/data.rb
CHANGED
@@ -2,12 +2,18 @@ User.destroy_all
|
|
2
2
|
AuthItem.destroy_all
|
3
3
|
|
4
4
|
# users
|
5
|
-
visitor = User.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
visitor = User.new(name: "visitor")
|
6
|
+
visitor.save!
|
7
|
+
reader = User.new(name: "reader")
|
8
|
+
reader.save!
|
9
|
+
authorA = User.new(name: "authorA")
|
10
|
+
authorA.save!
|
11
|
+
authorB = User.new(name: "authorB")
|
12
|
+
authorB.save!
|
13
|
+
editor = User.new(name: "editor")
|
14
|
+
editor.save!
|
15
|
+
admin = User.new(name: "admin")
|
16
|
+
admin.save!
|
11
17
|
|
12
18
|
oper_create_post = Erbac.create_operation "createPost", description: "create a post"
|
13
19
|
oper_read_post = Erbac.create_operation 'readPost', description: 'read a post'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erbac
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -116,7 +116,10 @@ files:
|
|
116
116
|
- .gitignore
|
117
117
|
- Gemfile
|
118
118
|
- Gemfile.lock
|
119
|
+
- README.md
|
119
120
|
- Rakefile
|
121
|
+
- build.bat
|
122
|
+
- build.sh
|
120
123
|
- erbac.gemspec
|
121
124
|
- lib/erbac.rb
|
122
125
|
- lib/erbac/action_controller_support.rb
|
@@ -139,7 +142,7 @@ files:
|
|
139
142
|
- spec/support/adapters/active_record.rb
|
140
143
|
- spec/support/data.rb
|
141
144
|
- spec/support/schema.rb
|
142
|
-
homepage:
|
145
|
+
homepage: https://github.com/douxing/erbac
|
143
146
|
licenses: []
|
144
147
|
post_install_message:
|
145
148
|
rdoc_options: []
|