erbac 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +16 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +114 -0
- data/Rakefile +11 -0
- data/erbac.gemspec +28 -0
- data/lib/erbac/action_controller_support.rb +15 -0
- data/lib/erbac/active_record_support.rb +241 -0
- data/lib/erbac/auth_manage.rb +102 -0
- data/lib/erbac/configure.rb +44 -0
- data/lib/erbac/errors.rb +5 -0
- data/lib/erbac/railtie.rb +16 -0
- data/lib/erbac/utils.rb +10 -0
- data/lib/erbac/version.rb +3 -0
- data/lib/erbac.rb +12 -0
- data/lib/generators/active_record/erbac_generator.rb +54 -0
- data/lib/generators/active_record/templates/README +0 -0
- data/lib/generators/active_record/templates/migration.rb +27 -0
- data/lib/generators/erbac/erbac_generator.rb +65 -0
- data/lib/generators/erbac/templates/README +13 -0
- data/lib/generators/erbac/templates/initializer.rb +27 -0
- data/lib/generators/erbac/user_generator.rb +27 -0
- data/spec/erbac/user_instance_spec.rb +160 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/adapters/active_record.rb +33 -0
- data/spec/support/data.rb +43 -0
- data/spec/support/schema.rb +44 -0
- metadata +166 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
erbac (0.0.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
actionmailer (3.2.13)
|
10
|
+
actionpack (= 3.2.13)
|
11
|
+
mail (~> 2.5.3)
|
12
|
+
actionpack (3.2.13)
|
13
|
+
activemodel (= 3.2.13)
|
14
|
+
activesupport (= 3.2.13)
|
15
|
+
builder (~> 3.0.0)
|
16
|
+
erubis (~> 2.7.0)
|
17
|
+
journey (~> 1.0.4)
|
18
|
+
rack (~> 1.4.5)
|
19
|
+
rack-cache (~> 1.2)
|
20
|
+
rack-test (~> 0.6.1)
|
21
|
+
sprockets (~> 2.2.1)
|
22
|
+
activemodel (3.2.13)
|
23
|
+
activesupport (= 3.2.13)
|
24
|
+
builder (~> 3.0.0)
|
25
|
+
activerecord (3.2.13)
|
26
|
+
activemodel (= 3.2.13)
|
27
|
+
activesupport (= 3.2.13)
|
28
|
+
arel (~> 3.0.2)
|
29
|
+
tzinfo (~> 0.3.29)
|
30
|
+
activeresource (3.2.13)
|
31
|
+
activemodel (= 3.2.13)
|
32
|
+
activesupport (= 3.2.13)
|
33
|
+
activesupport (3.2.13)
|
34
|
+
i18n (= 0.6.1)
|
35
|
+
multi_json (~> 1.0)
|
36
|
+
arel (3.0.2)
|
37
|
+
builder (3.0.4)
|
38
|
+
diff-lcs (1.2.4)
|
39
|
+
erubis (2.7.0)
|
40
|
+
hike (1.2.3)
|
41
|
+
i18n (0.6.1)
|
42
|
+
journey (1.0.4)
|
43
|
+
json (1.8.0)
|
44
|
+
mail (2.5.4)
|
45
|
+
mime-types (~> 1.16)
|
46
|
+
treetop (~> 1.4.8)
|
47
|
+
mime-types (1.23)
|
48
|
+
multi_json (1.7.8)
|
49
|
+
polyglot (0.3.3)
|
50
|
+
rack (1.4.5)
|
51
|
+
rack-cache (1.2)
|
52
|
+
rack (>= 0.4)
|
53
|
+
rack-ssl (1.3.3)
|
54
|
+
rack
|
55
|
+
rack-test (0.6.2)
|
56
|
+
rack (>= 1.0)
|
57
|
+
rails (3.2.13)
|
58
|
+
actionmailer (= 3.2.13)
|
59
|
+
actionpack (= 3.2.13)
|
60
|
+
activerecord (= 3.2.13)
|
61
|
+
activeresource (= 3.2.13)
|
62
|
+
activesupport (= 3.2.13)
|
63
|
+
bundler (~> 1.0)
|
64
|
+
railties (= 3.2.13)
|
65
|
+
railties (3.2.13)
|
66
|
+
actionpack (= 3.2.13)
|
67
|
+
activesupport (= 3.2.13)
|
68
|
+
rack-ssl (~> 1.3.2)
|
69
|
+
rake (>= 0.8.7)
|
70
|
+
rdoc (~> 3.4)
|
71
|
+
thor (>= 0.14.6, < 2.0)
|
72
|
+
rake (10.1.0)
|
73
|
+
rdoc (3.12.2)
|
74
|
+
json (~> 1.4)
|
75
|
+
rspec (2.14.1)
|
76
|
+
rspec-core (~> 2.14.0)
|
77
|
+
rspec-expectations (~> 2.14.0)
|
78
|
+
rspec-mocks (~> 2.14.0)
|
79
|
+
rspec-core (2.14.4)
|
80
|
+
rspec-expectations (2.14.0)
|
81
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
82
|
+
rspec-mocks (2.14.2)
|
83
|
+
rspec-rails (2.14.0)
|
84
|
+
actionpack (>= 3.0)
|
85
|
+
activesupport (>= 3.0)
|
86
|
+
railties (>= 3.0)
|
87
|
+
rspec-core (~> 2.14.0)
|
88
|
+
rspec-expectations (~> 2.14.0)
|
89
|
+
rspec-mocks (~> 2.14.0)
|
90
|
+
sprockets (2.2.2)
|
91
|
+
hike (~> 1.2)
|
92
|
+
multi_json (~> 1.0)
|
93
|
+
rack (~> 1.0)
|
94
|
+
tilt (~> 1.1, != 1.3.0)
|
95
|
+
sqlite3 (1.3.7-x86-mingw32)
|
96
|
+
thor (0.18.1)
|
97
|
+
tilt (1.4.1)
|
98
|
+
treetop (1.4.14)
|
99
|
+
polyglot
|
100
|
+
polyglot (>= 0.3.1)
|
101
|
+
tzinfo (0.3.37)
|
102
|
+
|
103
|
+
PLATFORMS
|
104
|
+
x86-mingw32
|
105
|
+
|
106
|
+
DEPENDENCIES
|
107
|
+
activerecord (>= 3.0.0)
|
108
|
+
bundler
|
109
|
+
erbac!
|
110
|
+
rails (= 3.2.13)
|
111
|
+
rake
|
112
|
+
rspec (>= 2.0)
|
113
|
+
rspec-rails (>= 2.0)
|
114
|
+
sqlite3
|
data/Rakefile
ADDED
data/erbac.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "erbac/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'erbac'
|
7
|
+
s.version = Erbac::VERSION.dup
|
8
|
+
s.date = '2013-07-16'
|
9
|
+
s.summary = "Yii rbac transplatation!"
|
10
|
+
s.description = "A simple hello world gem"
|
11
|
+
|
12
|
+
s.authors = ["dx"]
|
13
|
+
s.email = 'bitcheap@gmail.com'
|
14
|
+
s.homepage = 'http://utocity.com'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_development_dependency "sqlite3"
|
21
|
+
s.add_development_dependency 'rake'
|
22
|
+
s.add_development_dependency 'rspec', ">= 2.0"
|
23
|
+
s.add_development_dependency "rspec-rails", ">= 2.0"
|
24
|
+
s.add_development_dependency "bundler"
|
25
|
+
s.add_development_dependency "activerecord", ">= 3.0.0"
|
26
|
+
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
module Erbac
|
2
|
+
module ActiveRecordSupport
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def control_access
|
9
|
+
has_many Erbac.auth_assignment.pluralize.to_sym,
|
10
|
+
dependent: :delete_all,
|
11
|
+
class_name: Erbac.auth_assignment_class,
|
12
|
+
foreign_key: "user_id"
|
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
|
+
has_many Erbac.auth_item.pluralize.to_sym,
|
18
|
+
through: Erbac.auth_assignment.pluralize.to_sym,
|
19
|
+
source: Erbac.auth_item.pluralize.to_sym
|
20
|
+
|
21
|
+
define_method :check_access? do |*args|
|
22
|
+
unless (args.first.is_a? Erbac.auth_item_class.constantize)
|
23
|
+
raise TypeError, "Should pass in #{Erbac.auth_item_class} instance as the first parameter. Got #{args.first.to_s}", caller
|
24
|
+
end
|
25
|
+
|
26
|
+
check_access_recursive? args.first, args.extract_options!
|
27
|
+
end
|
28
|
+
|
29
|
+
define_method :execute_biz_rule? do |*args|
|
30
|
+
item = args.first
|
31
|
+
params = args.extract_options!
|
32
|
+
if (item.is_a? Erbac.auth_item_class.constantize or item.is_a? Erbac.auth_assignment_class.constantize)
|
33
|
+
bizrule_sandbox(item.bizrule, params, item.data)
|
34
|
+
else
|
35
|
+
raise TypeError, "Argument type not supported, should pass in #{Erbac.auth_item_class} or #{Erbac.auth_assignment_class} instance as the first parameter. Got #{item.class.to_s}", caller
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method :check_access_recursive? do |item, params={}|
|
40
|
+
if bizrule_sandbox(item.bizrule, params, item.data)
|
41
|
+
return true if Erbac.default_roles.include? item.name
|
42
|
+
assignment = Erbac.auth_assignment_class.constantize.where(user_id: self, item_id: item).first
|
43
|
+
if assignment
|
44
|
+
return true if bizrule_sandbox(item.bizrule, params, item.data)
|
45
|
+
end
|
46
|
+
item.parents.each do |p|
|
47
|
+
return true if check_access_recursive?(p, params)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
define_method :bizrule_sandbox do |bizrule, params={}, data=nil|
|
54
|
+
if (bizrule.nil? or bizrule.empty?)
|
55
|
+
true
|
56
|
+
else
|
57
|
+
proc do
|
58
|
+
# $SAFE = 3 how to change this ?
|
59
|
+
Erbac.strict_check_mode ? (self.instance_eval bizrule) == true : (self.instance_eval bizrule) != false
|
60
|
+
end.call
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
send :protected, :check_access_recursive?, :bizrule_sandbox
|
65
|
+
|
66
|
+
# add an anonymous singleton instance
|
67
|
+
@anonymous = self.new
|
68
|
+
class << self
|
69
|
+
define_method :anonymous do
|
70
|
+
@anonymous
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
define_method :anonymous_should_not_be_saved do
|
75
|
+
raise NoMethodError, "Anonymous object should not be saved!", caller if self.equal? self.class.anonymous
|
76
|
+
end
|
77
|
+
|
78
|
+
before_save :anonymous_should_not_be_saved
|
79
|
+
|
80
|
+
define_method :anonymous? do
|
81
|
+
self.equal? @anonymous
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
def control_auth_item
|
87
|
+
attr_accessible :name, :auth_type, :description, :bizrule, :data
|
88
|
+
validates :name, uniqueness: true
|
89
|
+
|
90
|
+
has_many Erbac.auth_assignment.pluralize.to_sym,
|
91
|
+
dependent: :delete_all,
|
92
|
+
class_name: Erbac.auth_assignment_class,
|
93
|
+
foreign_key: "item_id"
|
94
|
+
|
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
|
+
has_many Erbac.user_class.underscore.pluralize.to_sym,
|
99
|
+
through: Erbac.auth_assignment.pluralize.to_sym,
|
100
|
+
source: Erbac.user_class.underscore.pluralize.to_sym
|
101
|
+
|
102
|
+
has_and_belongs_to_many :parents,
|
103
|
+
join_table: Erbac.auth_item_child_table,
|
104
|
+
class_name: Erbac.auth_item_class,
|
105
|
+
foreign_key: "child_id", association_foreign_key: "parent_id"
|
106
|
+
|
107
|
+
has_and_belongs_to_many :children,
|
108
|
+
join_table: Erbac.auth_item_child_table,
|
109
|
+
class_name: Erbac.auth_item_class,
|
110
|
+
foreign_key: "parent_id", association_foreign_key: "child_id"
|
111
|
+
|
112
|
+
const_set("TYPE_OPERATION", 0)
|
113
|
+
const_set("TYPE_TASK", 1)
|
114
|
+
const_set("TYPE_ROLE", 2)
|
115
|
+
|
116
|
+
|
117
|
+
define_method :add_child do |item|
|
118
|
+
if self.name == item.name
|
119
|
+
raise AuthItemRelationError, "Cannot add #{self.name} as a child of itself.", caller
|
120
|
+
end
|
121
|
+
|
122
|
+
check_item_child_type(item)
|
123
|
+
|
124
|
+
if detect_loop?(item)
|
125
|
+
raise AuthItemRelationError, "Cannot add #{child.name} as a child of #{self.name}. A loop has been detected.", caller
|
126
|
+
end
|
127
|
+
|
128
|
+
self.children << item
|
129
|
+
end
|
130
|
+
|
131
|
+
define_method :remove_child do |item|
|
132
|
+
self.children.delete item
|
133
|
+
end
|
134
|
+
|
135
|
+
define_method :has_child? do |item|
|
136
|
+
self.children.include? child
|
137
|
+
end
|
138
|
+
|
139
|
+
define_method :assign do |user, bizrule=nil, data=nil|
|
140
|
+
assignment = Erbac.auth_assignment_class.constantize.where({item_id: self, user_id: user}).first_or_create
|
141
|
+
assignment.bizrule = bizrule
|
142
|
+
assignment.data = data
|
143
|
+
assignment
|
144
|
+
end
|
145
|
+
|
146
|
+
define_method :revoke do |user|
|
147
|
+
Erbac.auth_assignment_class.constantize.delete({item_id: self, user_id: user})
|
148
|
+
end
|
149
|
+
|
150
|
+
define_method :is_assigned? do |user|
|
151
|
+
Erbac.auth_assignment_class.constantize.where({item_id: self, user_id: user}).any?
|
152
|
+
end
|
153
|
+
|
154
|
+
define_method :get_auth_assignment? do |user|
|
155
|
+
Erbac.auth_assignment_class.constantize.where({item_id: self, user_id: user}).first
|
156
|
+
end
|
157
|
+
|
158
|
+
define_method :detect_loop? do |child|
|
159
|
+
return true if (self.name == child.name)
|
160
|
+
child.children.each do |g|
|
161
|
+
return true if self.detect_loop?(g)
|
162
|
+
end
|
163
|
+
false
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
define_method :check_item_child_type do |child|
|
168
|
+
unless (self.is_a? Erbac.auth_item_class.constantize)
|
169
|
+
raise TypeError, "Should pass in #{Erbac.auth_item_class} instance as the first parameter. Got #{self.to_s}", caller
|
170
|
+
end
|
171
|
+
|
172
|
+
unless (child.is_a? Erbac.auth_item_class.constantize)
|
173
|
+
raise TypeError, "Should pass in #{Erbac.auth_item_class} instance as the second parameter. Got #{child.to_s}", caller
|
174
|
+
end
|
175
|
+
|
176
|
+
if self.auth_type < child.auth_type
|
177
|
+
raise Erbac::AuthItemRelationError, "Cannot add an itme of type #{AUTH_TYPES[child.auth_type]} to an item of type #{AUTH_TYPES[self.auth_type]}.", caller
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# should marshal the data when it comes to database
|
182
|
+
# make it transparent with the user
|
183
|
+
define_method :marshal_around_save do |*args, &block|
|
184
|
+
data = self.data
|
185
|
+
self.data = Marshal.dump data
|
186
|
+
block.call # it is a trick, search it!
|
187
|
+
self.data = data
|
188
|
+
end
|
189
|
+
around_save :marshal_around_save
|
190
|
+
|
191
|
+
define_method :marshal_after_find do
|
192
|
+
begin # rescue marshal error and replace with nil
|
193
|
+
self.data = Marshal.restore self.data
|
194
|
+
rescue ArgumentError
|
195
|
+
self.data = nil
|
196
|
+
end
|
197
|
+
end
|
198
|
+
after_find :marshal_after_find
|
199
|
+
|
200
|
+
send :protected, :detect_loop?, :check_item_child_type
|
201
|
+
send :private, :marshal_around_save, :marshal_after_find
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
def control_auth_assignment
|
206
|
+
attr_accessible :item_id, :user_id, :bizrule, :data
|
207
|
+
|
208
|
+
belongs_to Erbac.user_class.underscore.pluralize.to_sym,
|
209
|
+
class_name: Erbac.user_class,
|
210
|
+
foreign_key: "user_id"
|
211
|
+
|
212
|
+
belongs_to Erbac.auth_item.pluralize.to_sym,
|
213
|
+
class_name: Erbac.auth_item_class,
|
214
|
+
foreign_key: "item_id"
|
215
|
+
|
216
|
+
protected
|
217
|
+
|
218
|
+
# should marshal the data when it comes to database
|
219
|
+
# make it transparent with the user
|
220
|
+
define_method :marshal_around_save do |*args, &block|
|
221
|
+
data = self.data
|
222
|
+
self.data = Marshal.dump data
|
223
|
+
block.call # it is a trick, search it!
|
224
|
+
self.data = data
|
225
|
+
end
|
226
|
+
around_save :marshal_around_save
|
227
|
+
|
228
|
+
define_method :marshal_after_find do
|
229
|
+
begin # rescue marshal error and replace with nil
|
230
|
+
self.data = Marshal.restore self.data
|
231
|
+
rescue ArgumentError
|
232
|
+
self.data = nil
|
233
|
+
end
|
234
|
+
end
|
235
|
+
after_find :marshal_after_find
|
236
|
+
|
237
|
+
send :private, :marshal_around_save, :marshal_after_find
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Erbac
|
2
|
+
module AuthManage
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
AUTH_TYPES = ["operation", "task", "role"]
|
9
|
+
|
10
|
+
AUTH_TYPES.each do |type|
|
11
|
+
define_method ("create_" + type) do |name, options={}|
|
12
|
+
options[:name] = name
|
13
|
+
options[:auth_type] = Erbac.auth_item_class.constantize.const_get("TYPE_" + type.upcase)
|
14
|
+
Erbac.auth_item_class.constantize.create options
|
15
|
+
end
|
16
|
+
|
17
|
+
define_method ("get_" + type.pluralize) do |user|
|
18
|
+
user.send Erbac.auth_item.pluralize.to_sym
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
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
|
+
def add_item_child(parent, child)
|
28
|
+
parent.add_child child
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove_item_child(parent, child)
|
32
|
+
parent.remove_child child
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_item_child?(parent, child)
|
36
|
+
parent.has_child? child
|
37
|
+
end
|
38
|
+
|
39
|
+
def assign(item, user, bizrule=nil, data=nil)
|
40
|
+
item.assign user, bizrule, data
|
41
|
+
end
|
42
|
+
|
43
|
+
def revoke(item, user)
|
44
|
+
item.revoke user
|
45
|
+
end
|
46
|
+
|
47
|
+
def is_assigned?(item, user)
|
48
|
+
item.is_assigned? user
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_auth_assignment(item, user)
|
52
|
+
item.get_auth_assignment user
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear_all
|
56
|
+
Erbac.auth_item_class.constantize.delete_all
|
57
|
+
end
|
58
|
+
|
59
|
+
def clear_auth_assignments(*args)
|
60
|
+
Erbac.auth_assignment_class.constantize.delete_all args
|
61
|
+
end
|
62
|
+
|
63
|
+
def execute_biz_rule?(*args)
|
64
|
+
item = args.first
|
65
|
+
params = args.extract_options!
|
66
|
+
unless (item.is_a? Erbac.auth_item_class.constantize or item.is_a? Erbac.auth_assignment_class.constantize)
|
67
|
+
raise TypeError, "Argument type not supported, should pass in #{Erbac.auth_item_class} or #{Erbac.auth_assignment_class} instance as the first parameter. Got #{item.class.to_s}", caller
|
68
|
+
end
|
69
|
+
|
70
|
+
if (args[1].is_a? Erbac.user_class.constantize)
|
71
|
+
args[1].execute_biz_rule? item, params
|
72
|
+
else
|
73
|
+
bizrule_sandbox(item.bizrule, params, item.data)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_access?(*args)
|
78
|
+
unless (args.first.is_a? Erbac.auth_item_class.constantize)
|
79
|
+
raise TypeError, "Should pass in #{Erbac.auth_item_class} instance as the first parameter. Got #{args.first.to_s}", caller
|
80
|
+
end
|
81
|
+
|
82
|
+
if (args[1].is_a? Erbac.user_class.constantize)
|
83
|
+
args[1].check_access? args.first, args.extract_options!
|
84
|
+
else
|
85
|
+
bizrule_sandbox args.first.bizrule, args.extract_options!, args.first.data
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
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
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Erbac
|
2
|
+
module Configure
|
3
|
+
attr_accessor :strict_check_mode
|
4
|
+
attr_accessor :default_roles
|
5
|
+
|
6
|
+
USER_CLASS = "User"
|
7
|
+
attr_accessor :user_class
|
8
|
+
|
9
|
+
AUTH_ITEM = "auth_item"
|
10
|
+
AUTH_ITEM_CLASS = AUTH_ITEM.dup.classify
|
11
|
+
AUTH_ITEM_TABLE = AUTH_ITEM.dup.tableize
|
12
|
+
attr_accessor :auth_item, :auth_item_class, :auth_item_table
|
13
|
+
|
14
|
+
AUTH_ITEM_CHILD = "auth_item_child"
|
15
|
+
AUTH_ITEM_CHILD_TABLE = AUTH_ITEM_CHILD.dup.tableize
|
16
|
+
attr_accessor :auth_item_child, :auth_item_child_table
|
17
|
+
|
18
|
+
AUTH_ASSIGNMENT = "auth_assignment"
|
19
|
+
AUTH_ASSIGNMENT_CLASS = AUTH_ASSIGNMENT.dup.classify
|
20
|
+
AUTH_ASSIGNMENT_TABLE = AUTH_ASSIGNMENT.dup.tableize
|
21
|
+
attr_accessor :auth_assignment, :auth_assignment_class, :auth_assignment_table
|
22
|
+
|
23
|
+
def configure
|
24
|
+
yield self if block_given?
|
25
|
+
|
26
|
+
self.strict_check_mode ||= true
|
27
|
+
self.default_roles ||= []
|
28
|
+
|
29
|
+
self.user_class ||= USER_CLASS
|
30
|
+
|
31
|
+
self.auth_item ||= AUTH_ITEM
|
32
|
+
self.auth_item_class ||= self.auth_item.classify
|
33
|
+
self.auth_item_table ||= self.auth_item.tableize
|
34
|
+
|
35
|
+
self.auth_item_child ||= AUTH_ITEM_CHILD
|
36
|
+
self.auth_item_child_table ||= self.auth_item_child.tableize
|
37
|
+
|
38
|
+
self.auth_assignment ||= AUTH_ASSIGNMENT
|
39
|
+
self.auth_assignment_class ||= self.auth_assignment.classify
|
40
|
+
self.auth_assignment_table ||= self.auth_assignment.tableize
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/lib/erbac/errors.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'erbac'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module Erbac
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
initializer 'erbac.initialize' do
|
7
|
+
ActiveSupport.on_load(:active_record) do
|
8
|
+
ActiveRecord::Base.send :include, Erbac::ActiveRecordSupport
|
9
|
+
end
|
10
|
+
|
11
|
+
ActiveSupport.on_load(:action_controller) do
|
12
|
+
ActionController::Base.send :include, Erbac::ActionControllerSupport
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/erbac/utils.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Erbac
|
2
|
+
module Utils
|
3
|
+
def deprecate(old_method, new_method)
|
4
|
+
define_method(old_method) do |*args|
|
5
|
+
warn "[DEPRECATION] #{caller.first}: `#{old_method}` is deprecated. Please use `#{new_method}` instead."
|
6
|
+
send(new_method, *args)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/erbac.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'erbac/railtie' if defined?(Rails)
|
2
|
+
require 'erbac/configure'
|
3
|
+
require 'erbac/auth_manage'
|
4
|
+
require 'erbac/errors'
|
5
|
+
require 'erbac/active_record_support'
|
6
|
+
require 'erbac/action_controller_support'
|
7
|
+
|
8
|
+
module Erbac
|
9
|
+
include AuthManage
|
10
|
+
include Error
|
11
|
+
extend Configure
|
12
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
require 'erbac/configure'
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module Generators
|
7
|
+
class ErbacGenerator < ActiveRecord::Generators::Base
|
8
|
+
source_root File.expand_path("../templates", __FILE__)
|
9
|
+
|
10
|
+
class_option :auth_item, type: :array, aliases: "-i",
|
11
|
+
default: [Erbac::Configure::AUTH_ITEM, Erbac::Configure::AUTH_ITEM_CLASS, Erbac::Configure::AUTH_ITEM_TABLE]
|
12
|
+
class_option :auth_item_child, type: :array, aliases: "-c",
|
13
|
+
default: [Erbac::Configure::AUTH_ITEM_CHILD, Erbac::Configure::AUTH_ITEM_CHILD_TABLE]
|
14
|
+
class_option :auth_assignment, type: :array, aliases: "-a",
|
15
|
+
default: [Erbac::Configure::AUTH_ASSIGNMENT, Erbac::Configure::AUTH_ASSIGNMENT_CLASS, Erbac::Configure::AUTH_ASSIGNMENT_TABLE]
|
16
|
+
|
17
|
+
def init_erbac_options
|
18
|
+
# assert options.auth_item[0]
|
19
|
+
options.auth_item[1] ||= options.auth_item[0].classify || Erbac::Configure::AUTH_ITEM_CLASS
|
20
|
+
options.auth_item[2] ||= options.auth_item[0].tableize || Erbac::Configure::AUTH_ITEM_TABLE
|
21
|
+
|
22
|
+
# assert options.auth_item_child[0]
|
23
|
+
options.auth_item_child[1] || options.auth_item_child[0].tableize || Erbac::Configure::AUTH_ITEM_CHILD_TABLE
|
24
|
+
|
25
|
+
# assert options.auth_assignment[0]
|
26
|
+
options.auth_assignment[1] || options.auth_assignment[0].classify || Erbac::Configure::AUTH_ASSIGNMENT_CLASS
|
27
|
+
options.auth_assignment[2] || options.auth_assignment[0].tableize || Erbac::Configure::AUTH_ASSIGNMENT_TABLE
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_auth_item_model
|
31
|
+
Rails::Generators.invoke("active_record:model", [options.auth_item[0], "--no-migration"], behavior: behavior)
|
32
|
+
Rails::Generators.invoke("active_record:model", [options.auth_assignment[0], "--no-migration"], behavior: behavior)
|
33
|
+
end
|
34
|
+
|
35
|
+
def inject_auth_item_model
|
36
|
+
if behavior == :invoke
|
37
|
+
inject_into_class(model_path(options.auth_item[0]), options.auth_item[1], " control_auth_item\n")
|
38
|
+
inject_into_class(model_path(options.auth_assignment[0]), options.auth_assignment[1], " control_auth_assignment\n")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def copy_erbac_migration
|
43
|
+
migration_template "migration.rb", "db/migrate/erbac_create_auth"
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def model_path(filename)
|
49
|
+
File.join("app", "models", "#{filename}.rb")
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class ErbacCreateAuth < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table(:<%= options.auth_item[2] %>) do |t|
|
4
|
+
t.string :name, null: false
|
5
|
+
t.integer :auth_type
|
6
|
+
t.text :description
|
7
|
+
t.text :bizrule
|
8
|
+
t.text :data
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table(:<%= options.auth_item_child[1] %>, id: false) do |t|
|
12
|
+
t.integer :parent_id, null: false
|
13
|
+
t.integer :child_id, null: false
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table(:<%= options.auth_assignment[2] %>) do |t|
|
17
|
+
t.integer :item_id, null: false
|
18
|
+
t.integer :user_id, null: false
|
19
|
+
t.text :bizrule
|
20
|
+
t.text :data
|
21
|
+
end
|
22
|
+
|
23
|
+
add_index(:<%= options.auth_item[2] %>, :name, unique: true)
|
24
|
+
add_index(:<%= options.auth_item_child[1] %>, [:parent_id, :child_id], unique: true)
|
25
|
+
add_index(:<%= options.auth_assignment[2] %>, [:item_id, :user_id], unique: true)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'erbac/configure'
|
2
|
+
|
3
|
+
module Erbac
|
4
|
+
module Generators
|
5
|
+
class ErbacGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
argument :user_class, type: :string, banner: "User", desc: "User class for the system, maybe User, Account or Admin etc. in your case."
|
8
|
+
|
9
|
+
class_option :auth_item, type: :array,
|
10
|
+
default: [Configure::AUTH_ITEM, Configure::AUTH_ITEM_CLASS, Configure::AUTH_ITEM_TABLE],
|
11
|
+
banner: "#{Configure::AUTH_ITEM} #{Configure::AUTH_ITEM_CLASS} #{Configure::AUTH_ITEM_TABLE}",
|
12
|
+
aliases: "-i", desc: "auth item, model and table"
|
13
|
+
class_option :auth_item_child, type: :array,
|
14
|
+
default: [Configure::AUTH_ITEM_CHILD, Configure::AUTH_ITEM_CHILD_TABLE],
|
15
|
+
banner: "#{Configure::AUTH_ITEM_CHILD} #{Configure::AUTH_ITEM_CHILD_TABLE}",
|
16
|
+
aliases: "-c", desc: "auth item child and the join table"
|
17
|
+
class_option :auth_assignment, type: :array,
|
18
|
+
default: [Configure::AUTH_ASSIGNMENT, Configure::AUTH_ASSIGNMENT_CLASS, Configure::AUTH_ASSIGNMENT_TABLE],
|
19
|
+
banner: "#{Configure::AUTH_ASSIGNMENT} #{Configure::AUTH_ASSIGNMENT_CLASS} #{Configure::AUTH_ASSIGNMENT_TABLE}",
|
20
|
+
aliases: "-a", desc: "auth assignment and the join table"
|
21
|
+
|
22
|
+
hook_for :orm
|
23
|
+
namespace :erbac
|
24
|
+
|
25
|
+
desc "Generates RBAC(role base access control) models and migration files according to the USER"
|
26
|
+
# def show_parameters
|
27
|
+
# puts "user: " + self.user
|
28
|
+
# puts "auth_item: " + self.options[:auth_item].inspect
|
29
|
+
# puts "auth_item_child: " + self.options[:auth_item_child].inspect
|
30
|
+
# puts "auth_assignment: " + self.options[:auth_assignment].inspect
|
31
|
+
# puts "options: " + options.inspect
|
32
|
+
# end
|
33
|
+
|
34
|
+
def init_erbac_options
|
35
|
+
# TODO: check the validity of the name
|
36
|
+
|
37
|
+
# assert options.auth_item[0]
|
38
|
+
options.auth_item[1] ||= options.auth_item[0].classify || Configure::AUTH_ITEM_CLASS
|
39
|
+
options.auth_item[2] ||= options.auth_item[0].tableize || Configure::AUTH_ITEM_TABLE
|
40
|
+
|
41
|
+
# assert options.auth_item_child[0]
|
42
|
+
options.auth_item_child[1] || options.auth_item_child[0].tableize || Configure::AUTH_ITEM_CHILD_TABLE
|
43
|
+
|
44
|
+
# assert options.auth_assignment[0]
|
45
|
+
options.auth_assignment[1] || options.auth_assignment[0].classify || Configure::AUTH_ASSIGNMENT_CLASS
|
46
|
+
options.auth_assignment[2] || options.auth_assignment[0].tableize || Configure::AUTH_ASSIGNMENT_TABLE
|
47
|
+
end
|
48
|
+
|
49
|
+
def copy_initializer_file
|
50
|
+
template "initializer.rb", "config/initializers/erbac.rb"
|
51
|
+
end
|
52
|
+
|
53
|
+
def inject_user_class
|
54
|
+
invoke "erbac:user", [ self.user_class ]
|
55
|
+
end
|
56
|
+
|
57
|
+
def show_readme
|
58
|
+
if behavior == :invoke
|
59
|
+
readme "README"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
===============================================================================
|
2
|
+
|
3
|
+
An initializer file has been created here: config/initializers/erbac.rb, you
|
4
|
+
can change erbac settings to match your needs.
|
5
|
+
Defaults values are commented out.
|
6
|
+
|
7
|
+
A Role class has been created in app/models (with the name you gave as
|
8
|
+
argument otherwise the default is auth_item.rb), you can add your own business logic
|
9
|
+
inside.
|
10
|
+
|
11
|
+
Inside your User class (or the name you gave as argument otherwise the default
|
12
|
+
is user.rb), erbac method has been inserted to provide erbac methods.
|
13
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Erbac.configure do |config|
|
2
|
+
# For the time being, maybe in the long term, it only support ActiveRecord...
|
3
|
+
|
4
|
+
# Uncomment the item to override the default
|
5
|
+
|
6
|
+
# if this is set to true, bizrule should return true restrictly
|
7
|
+
# else bizrule will pass if they don't return false
|
8
|
+
# NB in ruby 0 != false and 1 != true
|
9
|
+
# config.strict_check_mode = true
|
10
|
+
|
11
|
+
# check these roles first
|
12
|
+
# config.default_roles = []
|
13
|
+
|
14
|
+
# models and database tables
|
15
|
+
<%= "# " if user_class == Erbac::Configure::USER_CLASS %>config.user_class = <%= %Q("#{user_class}") %>
|
16
|
+
|
17
|
+
<%= "# " if options.auth_item[0] == Erbac::Configure::AUTH_ITEM %>config.auth_item = <%= %Q("#{options.auth_item[0]}") %>
|
18
|
+
<%= "# " if options.auth_item[1] == Erbac::Configure::AUTH_ITEM_CLASS %>config.auth_item_class = <%= %Q("#{options.auth_item[1]}") %>
|
19
|
+
<%= "# " if options.auth_item[2] == Erbac::Configure::AUTH_ITEM_TABLE %>config.auth_item_table = <%= %Q("#{options.auth_item[2]}") %>
|
20
|
+
|
21
|
+
<%= "# " if options.auth_item_child[0] == Erbac::Configure::AUTH_ITEM_CHILD %>config.auth_item_child = <%= %Q("#{options.auth_item_child[0]}") %>
|
22
|
+
<%= "# " if options.auth_item_child[1] == Erbac::Configure::AUTH_ITEM_CHILD_TABLE %>config.auth_item_child_table = <%= %Q("#{options.auth_item_child[1]}") %>
|
23
|
+
|
24
|
+
<%= "# " if options.auth_assignment[0] == Erbac::Configure::AUTH_ASSIGNMENT %>config.auth_assignment = <%= %Q("#{options.auth_assignment[0]}") %>
|
25
|
+
<%= "# " if options.auth_assignment[1] == Erbac::Configure::AUTH_ASSIGNMENT_CLASS %>config.auth_assignment = <%= %Q("#{options.auth_assignment[1]}") %>
|
26
|
+
<%= "# " if options.auth_assignment[2] == Erbac::Configure::AUTH_ASSIGNMENT_TABLE %>config.auth_assignment_table = <%= %Q("#{options.auth_assignment[2]}") %>
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rails/generators/migration'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
|
4
|
+
module Erbac
|
5
|
+
module Generators
|
6
|
+
class UserGenerator < Rails::Generators::Base
|
7
|
+
argument :user_class, type: :string, default: "User"
|
8
|
+
|
9
|
+
desc "Inject erbac method in the User|Account|Admin|* class."
|
10
|
+
|
11
|
+
def inject_user_content
|
12
|
+
inject_into_file(model_path, " control_access\n", :after => inject_erbac_method)
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def inject_erbac_method
|
18
|
+
/class[ |\t]+#{user_class}\n|class[ |\t]+#{user_class}.*\n|class[ |\t]+#{user_class.demodulize}\n|class[ |\t]+#{user_class.demodulize}.*\n/
|
19
|
+
end
|
20
|
+
|
21
|
+
def model_path
|
22
|
+
File.join("app", "models", "#{self.user_class.underscore}.rb")
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Erbac do
|
4
|
+
before(:all) do
|
5
|
+
@authorA = User.where(name: "authorA").first
|
6
|
+
@authorB = User.where(name: "authorB").first
|
7
|
+
@editor = User.where(name: "editor").first
|
8
|
+
@admin = User.where(name: "administrator").first
|
9
|
+
|
10
|
+
@first_post = Post.create! header: "first post", author_id: @authorA.id
|
11
|
+
@second_post = Post.create! header: "second post", author_id: @authorB.id
|
12
|
+
|
13
|
+
@role_reader = AuthItem.where(name: "reader").first
|
14
|
+
@role_author = AuthItem.where(name: "author").first
|
15
|
+
@role_editor = AuthItem.where(name: "editor").first
|
16
|
+
@role_admin = AuthItem.where(name: "admin").first
|
17
|
+
|
18
|
+
@task_update_own_post = AuthItem.where(name: "updateOwnPost").first
|
19
|
+
|
20
|
+
@oper_update_post = AuthItem.where(name: "updatePost").first
|
21
|
+
@oper_delete_post = AuthItem.where(name: "deletePost").first
|
22
|
+
end
|
23
|
+
|
24
|
+
describe User do
|
25
|
+
subject {nil}
|
26
|
+
|
27
|
+
it "can not read" do
|
28
|
+
Erbac.check_access?(@role_reader, subject).should be_false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe User do
|
33
|
+
subject { User.where(name: "visitor").first }
|
34
|
+
|
35
|
+
it "can not read" do
|
36
|
+
subject.check_access?(@role_reader).should be_false
|
37
|
+
Erbac.check_access?(@role_reader, subject).should be_false
|
38
|
+
end
|
39
|
+
|
40
|
+
it "can not edit as author" do
|
41
|
+
subject.check_access?(@role_author).should be_false
|
42
|
+
Erbac.check_access?(@role_author, subject).should be_false
|
43
|
+
end
|
44
|
+
|
45
|
+
it "can not edit as editor" do
|
46
|
+
subject.check_access?(@role_editor).should be_false
|
47
|
+
Erbac.check_access?(@role_editor, subject).should be_false
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can not delete" do
|
51
|
+
subject.check_access?(@oper_delete_post).should be_false
|
52
|
+
Erbac.check_access?(@oper_delete_post, subject).should be_false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
describe User do
|
58
|
+
subject { User.where(name: "reader").first }
|
59
|
+
|
60
|
+
it "can read" do
|
61
|
+
subject.check_access?(@role_reader).should be_true
|
62
|
+
Erbac.check_access?(@role_reader, subject).should be_true
|
63
|
+
end
|
64
|
+
|
65
|
+
it "can not edit as author" do
|
66
|
+
subject.check_access?(@role_author).should be_false
|
67
|
+
Erbac.check_access?(@role_author, subject).should be_false
|
68
|
+
end
|
69
|
+
|
70
|
+
it "can not edit as editor" do
|
71
|
+
subject.check_access?(@role_editor).should be_false
|
72
|
+
Erbac.check_access?(@role_editor, subject).should be_false
|
73
|
+
end
|
74
|
+
|
75
|
+
it "can not delete" do
|
76
|
+
subject.check_access?(@oper_delete_post).should be_false
|
77
|
+
Erbac.check_access?(@oper_delete_post, subject).should be_false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe User do
|
82
|
+
subject { User.where(name: "editor").first }
|
83
|
+
|
84
|
+
it "can read" do
|
85
|
+
subject.check_access?(@role_reader).should be_true
|
86
|
+
Erbac.check_access?(@role_reader, subject).should be_true
|
87
|
+
end
|
88
|
+
|
89
|
+
it "can not edit as author" do
|
90
|
+
subject.check_access?(@role_author).should be_false
|
91
|
+
Erbac.check_access?(@role_author, subject).should be_false
|
92
|
+
subject.check_access?(@task_update_own_post, post: @first_post).should be_false
|
93
|
+
Erbac.check_access?(@task_update_own_post, subject, post: @first_post).should be_false
|
94
|
+
end
|
95
|
+
|
96
|
+
it "can edit as editor" do
|
97
|
+
subject.check_access?(@role_editor).should be_true
|
98
|
+
Erbac.check_access?(@role_editor, subject).should be_false
|
99
|
+
subject.check_access?(@oper_update_post, post: @first_post).should be_true
|
100
|
+
Erbac.check_access?(@oper_update_post, subject, post: @first_post).should be_false
|
101
|
+
end
|
102
|
+
|
103
|
+
it "can not delete" do
|
104
|
+
subject.check_access?(@oper_delete_post).should be_false
|
105
|
+
Erbac.check_access?(@oper_delete_post, subject).should be_false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe User do
|
110
|
+
subject { User.where(name: "authorA").first }
|
111
|
+
|
112
|
+
it "can read" do
|
113
|
+
subject.check_access?(@role_reader).should be_true
|
114
|
+
end
|
115
|
+
|
116
|
+
it "can edit self post as task" do
|
117
|
+
subject.check_access?(@task_update_own_post, post: @first_post).should be_true
|
118
|
+
subject.check_access?(@task_update_own_post, post: @second_post).should be_false
|
119
|
+
end
|
120
|
+
|
121
|
+
it "can edit self post as update operation" do
|
122
|
+
subject.check_access?(@oper_update_post, post: @first_post).should be_true
|
123
|
+
subject.check_access?(@oper_update_post, post: @second_post).should be_false
|
124
|
+
end
|
125
|
+
|
126
|
+
it "can not edit as editor" do
|
127
|
+
subject.check_access?(@role_editor).should be_false
|
128
|
+
end
|
129
|
+
|
130
|
+
it "can not delete" do
|
131
|
+
subject.check_access?(@role_admin).should be_false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe User do
|
136
|
+
subject { User.where(name: "administrator").first }
|
137
|
+
|
138
|
+
it "can read" do
|
139
|
+
subject.check_access?(@role_reader).should be_true
|
140
|
+
end
|
141
|
+
|
142
|
+
it "can edit self post as task" do
|
143
|
+
subject.check_access?(@task_update_own_post, post: @first_post).should be_false
|
144
|
+
subject.check_access?(@task_update_own_post, post: @second_post).should be_false
|
145
|
+
end
|
146
|
+
|
147
|
+
it "can edit self post as update operation" do
|
148
|
+
subject.check_access?(@oper_update_post, post: @first_post).should be_true
|
149
|
+
subject.check_access?(@oper_update_post, post: @second_post).should be_true
|
150
|
+
end
|
151
|
+
|
152
|
+
it "can not edit as editor" do
|
153
|
+
subject.check_access?(@role_editor).should be_true
|
154
|
+
end
|
155
|
+
|
156
|
+
it "can not delete" do
|
157
|
+
subject.check_access?(@oper_delete_post).should be_true
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
RSpec::Matchers::OperatorMatcher.register(ActiveRecord::Relation, '=~', RSpec::Matchers::BuiltIn::MatchArray)
|
4
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
5
|
+
ActiveRecord::Base.send :include, Erbac::ActiveRecordSupport
|
6
|
+
|
7
|
+
load File.dirname(__FILE__) + '/../schema.rb'
|
8
|
+
|
9
|
+
# ActiveRecord models
|
10
|
+
class User < ActiveRecord::Base
|
11
|
+
attr_accessible :name
|
12
|
+
control_access
|
13
|
+
|
14
|
+
has_many :my_posts, class_name: "Post", inverse_of: :author
|
15
|
+
has_many :co_posts, class_name: "Post", inverse_of: :co_workers
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
class AuthItem < ActiveRecord::Base
|
20
|
+
attr_accessible :name, :auth_type, :description, :bizrule, :data
|
21
|
+
control_auth_item
|
22
|
+
end
|
23
|
+
|
24
|
+
class AuthAssignment < ActiveRecord::Base
|
25
|
+
attr_accessible :item_id, :user_id, :bizrule, :data
|
26
|
+
control_auth_assignment
|
27
|
+
end
|
28
|
+
|
29
|
+
class Post < ActiveRecord::Base
|
30
|
+
attr_accessible :header, :author_id
|
31
|
+
belongs_to :author, class_name: "User", inverse_of: :my_posts
|
32
|
+
belongs_to :co_workers, class_name: "User", inverse_of: :co_posts
|
33
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
User.destroy_all
|
2
|
+
AuthItem.destroy_all
|
3
|
+
|
4
|
+
# users
|
5
|
+
visitor = User.create! name: "visitor"
|
6
|
+
reader = User.create! name: "reader"
|
7
|
+
authorA = User.create! name: "authorA"
|
8
|
+
authorB = User.create! name: "authorB"
|
9
|
+
editor = User.create! name: "editor"
|
10
|
+
admin = User.create! name: "administrator"
|
11
|
+
|
12
|
+
oper_create_post = Erbac.create_operation "createPost", description: "create a post"
|
13
|
+
oper_read_post = Erbac.create_operation 'readPost', description: 'read a post'
|
14
|
+
oper_update_post = Erbac.create_operation 'updatePost', description: 'update a post'
|
15
|
+
oper_delete_post = Erbac.create_operation 'deletePost', description: 'delete a post'
|
16
|
+
|
17
|
+
task_update_own_post = Erbac.create_task "updateOwnPost", description: "update a post by author himself", bizrule: "self == params[:post].author"
|
18
|
+
task_update_own_post.add_child oper_update_post
|
19
|
+
|
20
|
+
role_reader = Erbac.create_role "reader"
|
21
|
+
role_reader.add_child oper_read_post
|
22
|
+
|
23
|
+
role_author = Erbac.create_role "author"
|
24
|
+
role_author.add_child role_reader
|
25
|
+
role_author.add_child oper_create_post
|
26
|
+
role_author.add_child task_update_own_post
|
27
|
+
|
28
|
+
role_editor = Erbac.create_role "editor"
|
29
|
+
role_editor.add_child role_reader
|
30
|
+
role_editor.add_child oper_update_post
|
31
|
+
|
32
|
+
role_admin = Erbac.create_role "admin"
|
33
|
+
role_admin.add_child role_editor
|
34
|
+
role_admin.add_child role_author
|
35
|
+
role_admin.add_child oper_delete_post
|
36
|
+
|
37
|
+
Erbac.assign role_reader, reader
|
38
|
+
Erbac.assign role_author, authorA
|
39
|
+
Erbac.assign role_author, authorB
|
40
|
+
Erbac.assign role_editor, editor
|
41
|
+
Erbac.assign role_admin, admin
|
42
|
+
|
43
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
self.verbose = false
|
3
|
+
|
4
|
+
create_table(:users) do |t|
|
5
|
+
t.string :name, null: false
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table(:auth_items) do |t|
|
9
|
+
t.string :name, null: false
|
10
|
+
t.integer :auth_type
|
11
|
+
t.text :description
|
12
|
+
t.text :bizrule
|
13
|
+
t.text :data
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table(:auth_item_children, id: false) do |t|
|
17
|
+
t.integer :parent_id, null: false
|
18
|
+
t.integer :child_id, null: false
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table(:auth_assignments) do |t|
|
22
|
+
t.integer :item_id, null: false
|
23
|
+
t.integer :user_id, null: false
|
24
|
+
t.text :bizrule
|
25
|
+
t.text :data
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table(:posts) do |t|
|
29
|
+
t.string :header
|
30
|
+
t.integer :author_id
|
31
|
+
end
|
32
|
+
|
33
|
+
create_table(:posts_users, id: false) do |t|
|
34
|
+
t.integer :user_id, null: false
|
35
|
+
t.integer :post_id, null: false
|
36
|
+
end
|
37
|
+
|
38
|
+
add_index(:auth_items, :name, unique: true)
|
39
|
+
add_index(:auth_item_children, [:parent_id, :child_id], unique: true)
|
40
|
+
add_index(:auth_assignments, [:item_id, :user_id], unique: true)
|
41
|
+
add_index(:posts, :author_id)
|
42
|
+
add_index(:posts_users, [:user_id, :post_id], unique: true)
|
43
|
+
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: erbac
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- dx
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sqlite3
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec-rails
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: activerecord
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 3.0.0
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 3.0.0
|
110
|
+
description: A simple hello world gem
|
111
|
+
email: bitcheap@gmail.com
|
112
|
+
executables: []
|
113
|
+
extensions: []
|
114
|
+
extra_rdoc_files: []
|
115
|
+
files:
|
116
|
+
- .gitignore
|
117
|
+
- Gemfile
|
118
|
+
- Gemfile.lock
|
119
|
+
- Rakefile
|
120
|
+
- erbac.gemspec
|
121
|
+
- lib/erbac.rb
|
122
|
+
- lib/erbac/action_controller_support.rb
|
123
|
+
- lib/erbac/active_record_support.rb
|
124
|
+
- lib/erbac/auth_manage.rb
|
125
|
+
- lib/erbac/configure.rb
|
126
|
+
- lib/erbac/errors.rb
|
127
|
+
- lib/erbac/railtie.rb
|
128
|
+
- lib/erbac/utils.rb
|
129
|
+
- lib/erbac/version.rb
|
130
|
+
- lib/generators/active_record/erbac_generator.rb
|
131
|
+
- lib/generators/active_record/templates/README
|
132
|
+
- lib/generators/active_record/templates/migration.rb
|
133
|
+
- lib/generators/erbac/erbac_generator.rb
|
134
|
+
- lib/generators/erbac/templates/README
|
135
|
+
- lib/generators/erbac/templates/initializer.rb
|
136
|
+
- lib/generators/erbac/user_generator.rb
|
137
|
+
- spec/erbac/user_instance_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
139
|
+
- spec/support/adapters/active_record.rb
|
140
|
+
- spec/support/data.rb
|
141
|
+
- spec/support/schema.rb
|
142
|
+
homepage: http://utocity.com
|
143
|
+
licenses: []
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
+
none: false
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
requirements: []
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 1.8.24
|
163
|
+
signing_key:
|
164
|
+
specification_version: 3
|
165
|
+
summary: Yii rbac transplatation!
|
166
|
+
test_files: []
|