active_acl 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +19 -0
- data/LICENSE +504 -0
- data/README +255 -0
- data/Rakefile +97 -0
- data/db/migrate/001_base_table_setup.rb +111 -0
- data/generators/active_acl/active_acl_generator.rb +25 -0
- data/init.rb +1 -0
- data/install.rb +1 -0
- data/lib/active_acl/acl.rb +39 -0
- data/lib/active_acl/acl_section.rb +20 -0
- data/lib/active_acl/acts_as_access_group.rb +64 -0
- data/lib/active_acl/acts_as_access_object.rb +283 -0
- data/lib/active_acl/controller_action.rb +29 -0
- data/lib/active_acl/controller_group.rb +19 -0
- data/lib/active_acl/load_controller_actions.rb +80 -0
- data/lib/active_acl/load_files_from.rb +21 -0
- data/lib/active_acl/options.rb +37 -0
- data/lib/active_acl/privilege.rb +25 -0
- data/lib/active_acl/privilege_const_set.rb +22 -0
- data/lib/active_acl/requester_group_link.rb +10 -0
- data/lib/active_acl/requester_link.rb +10 -0
- data/lib/active_acl/target_group_link.rb +10 -0
- data/lib/active_acl/target_link.rb +11 -0
- metadata +78 -0
@@ -0,0 +1,283 @@
|
|
1
|
+
module ActiveAcl #:nodoc:
|
2
|
+
module Acts #:nodoc:
|
3
|
+
module AccessObject #:nodoc:
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
# Extend self with access object capabilites. See README for details
|
12
|
+
# on usage. Accepts the following options as a hash:
|
13
|
+
# grouped_by:: name of the association acting as a group for access privilege
|
14
|
+
# group_class_name:: class name of group class
|
15
|
+
# join_table:: name of the join table
|
16
|
+
# foreign_key:: foreign key of self in the join table
|
17
|
+
# association_foreign_key:: foreign_key of the group class
|
18
|
+
# habtm:: set to <code>true</code> if the grup is joined with a habtm association. If not specified, the plugin tries to guess if the association is has_and_belongs_to_many or belongs_to by creating the singular form of the :grouped_by option and comparing it to itself: If it matches, it assumes a belongs_to association.
|
19
|
+
def acts_as_access_object(options = {})
|
20
|
+
configuration = {
|
21
|
+
:controller => ActiveAcl::OPTIONS[:default_selector_controller],
|
22
|
+
:action => ActiveAcl::OPTIONS[:default_selector_action]
|
23
|
+
}
|
24
|
+
if options[:grouped_by]
|
25
|
+
configuration[:group_class_name] = options[:grouped_by].to_s.classify
|
26
|
+
configuration[:join_table] = [name.pluralize.underscore, configuration[:group_class_name].pluralize.underscore].sort.join('_')
|
27
|
+
configuration[:foreign_key] = "#{name.underscore}_id"
|
28
|
+
configuration[:association_foreign_key] = "#{configuration[:group_class_name].underscore}_id"
|
29
|
+
configuration[:habtm] = (options[:grouped_by].to_s.demodulize.singularize != options[:grouped_by].to_s.demodulize)
|
30
|
+
end
|
31
|
+
|
32
|
+
configuration.update(options) if options.is_a?(Hash)
|
33
|
+
|
34
|
+
ActiveAcl::ACCESS_CLASSES[self.name] = configuration
|
35
|
+
|
36
|
+
has_many :requester_links, :as => :requester, :dependent => :delete_all, :class_name => 'ActiveAcl::RequesterLink'
|
37
|
+
has_many :requester_acls, :through => :requester_links, :source => :acl, :class_name => 'ActiveAcl::Acl'
|
38
|
+
|
39
|
+
has_many :target_links, :as => :target, :dependent => :delete_all, :class_name => 'ActiveAcl::TargetLink'
|
40
|
+
has_many :target_acls, :through => :target_links, :source => :acl, :class_name => 'ActiveAcl::Acl'
|
41
|
+
|
42
|
+
include InstanceMethods
|
43
|
+
extend SingletonMethods
|
44
|
+
|
45
|
+
from_classes = ActiveAcl::ACCESS_CLASSES.keys.collect do |x|
|
46
|
+
x.split('::').join('/').underscore.pluralize.to_sym
|
47
|
+
end
|
48
|
+
|
49
|
+
ActiveAcl::Acl.instance_eval do
|
50
|
+
has_many_polymorphs :requesters, {:from => from_classes,
|
51
|
+
:through => :"active_acl/requester_links",
|
52
|
+
:join_table_name => ActiveAcl::OPTIONS[:requester_links_table],
|
53
|
+
:rename_individual_collections => true}
|
54
|
+
|
55
|
+
has_many_polymorphs :targets, {:from => from_classes,
|
56
|
+
:through => :"active_acl/target_links",
|
57
|
+
:join_table_name => ActiveAcl::OPTIONS[:target_links_table],
|
58
|
+
:rename_individual_collections => true}
|
59
|
+
end
|
60
|
+
|
61
|
+
self.module_eval do
|
62
|
+
# checks if method is defined to not break tests
|
63
|
+
unless instance_methods.include? "reload_before_gacl"
|
64
|
+
alias :reload_before_gacl :reload
|
65
|
+
|
66
|
+
# Redefines reload, making shure privilege caches are cleared on reload
|
67
|
+
def reload
|
68
|
+
clear_cached_permissions
|
69
|
+
reload_before_gacl
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# build ACL query strings once, so we don't need to do this on every request
|
75
|
+
requester_groups_table = configuration[:group_class_name].constantize.table_name
|
76
|
+
requester_group_type = configuration[:group_class_name].constantize.name
|
77
|
+
requester_join_table = configuration[:join_table]
|
78
|
+
requester_assoc_fk = configuration[:association_foreign_key]
|
79
|
+
requester_fk = configuration[:foreign_key]
|
80
|
+
requester_group_left = ActiveAcl::GROUP_CLASSES[configuration[:group_class_name]][:left_column].to_s
|
81
|
+
requester_group_right = ActiveAcl::GROUP_CLASSES[configuration[:group_class_name]][:right_column].to_s
|
82
|
+
requester_type = self.base_class.name
|
83
|
+
|
84
|
+
# last join is necessary to weed out rules associated with targets groups
|
85
|
+
query = <<-QUERY
|
86
|
+
SELECT acls.id, acls.allow, privileges.id AS privilege_id FROM #{ActiveAcl::OPTIONS[:acls_table]} acls
|
87
|
+
LEFT JOIN #{ActiveAcl::OPTIONS[:acls_privileges_table]} acls_privileges ON acls_privileges.acl_id=acls.id
|
88
|
+
LEFT JOIN #{ActiveAcl::OPTIONS[:privileges_table]} privileges ON privileges.id = acls_privileges.privilege_id
|
89
|
+
LEFT JOIN #{ActiveAcl::OPTIONS[:requester_links_table]} r_links ON r_links.acl_id=acls.id
|
90
|
+
LEFT JOIN #{ActiveAcl::OPTIONS[:requester_group_links_table]} r_g_links ON acls.id = r_g_links.acl_id AND r_g_links.requester_group_type = '#{requester_group_type}'
|
91
|
+
LEFT JOIN #{requester_groups_table} r_groups ON r_g_links.requester_group_id = r_groups.id
|
92
|
+
LEFT JOIN #{ActiveAcl::OPTIONS[:target_group_links_table]} t_g_links ON t_g_links.acl_id=acls.id
|
93
|
+
QUERY
|
94
|
+
|
95
|
+
acl_query_on_target = '' << query
|
96
|
+
acl_query_prefetch = '' << query
|
97
|
+
|
98
|
+
# if there are no target groups, don't bother doing the join
|
99
|
+
# else append type condition
|
100
|
+
acl_query_on_target << " AND t_g_links.target_group_type = '%{target_group_type}' "
|
101
|
+
acl_query_on_target << " LEFT JOIN #{ActiveAcl::OPTIONS[:target_links_table]} t_links ON t_links.acl_id=acls.id"
|
102
|
+
acl_query_on_target << " LEFT JOIN %{target_groups_table} t_groups ON t_groups.id=t_g_links.target_group_id"
|
103
|
+
|
104
|
+
acl_query_on_target << " WHERE acls.enabled = #{connection.quote(true)} AND (privileges.id = %{privilege_id}) "
|
105
|
+
acl_query_prefetch << " WHERE acls.enabled = #{connection.quote(true)} "
|
106
|
+
|
107
|
+
query = " AND (((r_links.requester_id=%{requester_id} ) AND (r_links.requester_type='#{requester_type}')) OR (r_g_links.requester_group_id IN "
|
108
|
+
|
109
|
+
if configuration[:habtm]
|
110
|
+
configuration[:query_group] = <<-QUERY
|
111
|
+
(SELECT DISTINCT g2.id FROM #{requester_join_table} ml
|
112
|
+
LEFT JOIN #{requester_groups_table} g1 ON ml.#{requester_assoc_fk} = g1.id CROSS JOIN #{requester_groups_table} g2
|
113
|
+
WHERE ml.#{requester_fk} = %{requester_id} AND (g2.#{requester_group_left} <= g1.#{requester_group_left} AND g2.#{requester_group_right} >= g1.#{requester_group_right})))
|
114
|
+
QUERY
|
115
|
+
else
|
116
|
+
configuration[:query_group] = <<-QUERY
|
117
|
+
(SELECT DISTINCT g2.id FROM #{requester_groups_table} g1 CROSS JOIN #{requester_groups_table} g2
|
118
|
+
WHERE g1.id = %{requester_group_id} AND (g2.#{requester_group_left} <= g1.#{requester_group_left} AND g2.#{requester_group_right} >= g1.#{requester_group_right})))
|
119
|
+
QUERY
|
120
|
+
end
|
121
|
+
|
122
|
+
query << configuration[:query_group]
|
123
|
+
query << " ) AND ( "
|
124
|
+
|
125
|
+
acl_query_on_target << query
|
126
|
+
acl_query_prefetch << query
|
127
|
+
|
128
|
+
query = "(t_links.target_id=%{target_id} AND t_links.target_type = '%{target_type}' ) OR t_g_links.target_group_id IN %{target_group_query} "
|
129
|
+
|
130
|
+
acl_query_on_target << query
|
131
|
+
acl_query_prefetch << '(t_g_links.acl_id IS NULL)) '
|
132
|
+
|
133
|
+
# The ordering is always very tricky and makes all the difference in the world.
|
134
|
+
# Order (CASE WHEN r_links.requester_type = \'Group\' THEN 1 ELSE 0 END) ASC
|
135
|
+
# should put ACLs given to specific AROs ahead of any ACLs given to groups.
|
136
|
+
# This works well for exceptions to groups.
|
137
|
+
order_by_on_target = ['(CASE WHEN r_g_links.acl_id IS NULL THEN 0 ELSE 1 END) ASC ', "r_groups.#{requester_group_left} - r_groups.#{requester_group_right} ASC",
|
138
|
+
'(CASE WHEN t_g_links.acl_id IS NULL THEN 0 ELSE 1 END) ASC', 't_groups.%{target_group_left} - t_groups.%{target_group_right} ASC', 'acls.updated_at DESC']
|
139
|
+
order_by_prefetch = ['privileges.id', '(CASE WHEN r_g_links.acl_id IS NULL THEN 0 ELSE 1 END) ASC ', "r_groups.#{requester_group_left} - r_groups.#{requester_group_right} ASC", 'acls.updated_at DESC']
|
140
|
+
|
141
|
+
acl_query_on_target << 'ORDER BY ' + order_by_on_target.join(',') + ' LIMIT 1'
|
142
|
+
acl_query_prefetch << 'ORDER BY ' + order_by_prefetch.join(',')
|
143
|
+
|
144
|
+
# save query string to configuration
|
145
|
+
configuration[:query_target] = acl_query_on_target.gsub(/\n+/, "\n")
|
146
|
+
configuration[:query_simple] = acl_query_prefetch.gsub(/\n+/, "\n")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
module SingletonMethods
|
151
|
+
# class description in engine interface
|
152
|
+
def active_acl_description
|
153
|
+
return name
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
module InstanceMethods
|
158
|
+
|
159
|
+
# checks if the user has a certain privilege, optionally on the given object.
|
160
|
+
# Option :on defines the target object.
|
161
|
+
def has_privilege?(privilege, options = {})
|
162
|
+
target = options[:on] #TODO: add error handling if not a hash
|
163
|
+
|
164
|
+
unless (privilege and (privilege.is_a?(Privilege)))
|
165
|
+
# no need to check anything if privilege is not a Privilege
|
166
|
+
return false
|
167
|
+
end
|
168
|
+
|
169
|
+
unless (target.nil? or (target.class.respond_to?(:base_class) and ActiveAcl::ACCESS_CLASSES.has_key?(target.class.base_class.name)))
|
170
|
+
# no need to check anything if target is no Access Object
|
171
|
+
return false
|
172
|
+
end
|
173
|
+
|
174
|
+
query_id = [privilege.id, self.class.base_class.name, id, (target ? target.class.base_class.name : ''), (target ? target.id.to_s : '')].join('-')
|
175
|
+
cache_id = 'gacl_instance-' + self.class.base_class.name + '-' + id.to_s
|
176
|
+
cache = ActiveAcl::OPTIONS[:cache]
|
177
|
+
|
178
|
+
# try to load instance cache from second level cache if not present
|
179
|
+
@gacl_instance_cache = cache.get(cache_id) if @gacl_instance_cache.nil?
|
180
|
+
|
181
|
+
# try to get from instance cache
|
182
|
+
if @gacl_instance_cache
|
183
|
+
if not (value = @gacl_instance_cache[query_id]).nil?
|
184
|
+
logger.debug 'GACL::INSTANCE_CACHE::' + (value ? 'GRANT ' : 'DENY ') + query_id if logger.debug?
|
185
|
+
return value
|
186
|
+
elsif target.nil? and @gacl_instance_cache[:prefetch_done]
|
187
|
+
# we didn't get a simple query from prefetched cache => cache miss
|
188
|
+
logger.debug 'GACL::INSTANCE_CACHE::DENY ' + query_id if logger.debug?
|
189
|
+
return false
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
if value.nil? # still a cache miss?
|
194
|
+
|
195
|
+
value = false
|
196
|
+
|
197
|
+
r_config = ActiveAcl::ACCESS_CLASSES[self.class.base_class.name]
|
198
|
+
|
199
|
+
if target
|
200
|
+
qry = r_config[:query_target].clone
|
201
|
+
|
202
|
+
t_config = ActiveAcl::ACCESS_CLASSES[target.class.base_class.name]
|
203
|
+
|
204
|
+
qry.gsub!('%{target_group_type}', t_config[:group_class_name])
|
205
|
+
qry.gsub!('%{target_groups_table}', t_config[:group_class_name].constantize.table_name)
|
206
|
+
qry.gsub!('%{target_group_left}', ActiveAcl::GROUP_CLASSES[t_config[:group_class_name]][:left_column].to_s)
|
207
|
+
qry.gsub!('%{target_group_right}', ActiveAcl::GROUP_CLASSES[t_config[:group_class_name]][:right_column].to_s)
|
208
|
+
qry.gsub!('%{target_type}', target.class.base_class.name)
|
209
|
+
qry.gsub!('%{target_id}', target.id.to_s)
|
210
|
+
|
211
|
+
group_query = t_config[:query_group].clone
|
212
|
+
group_query.gsub!('%{requester_id}', target.id.to_s)
|
213
|
+
group_query.gsub!('%{requester_group_id}', target.send(t_config[:association_foreign_key]).to_s) unless t_config[:habtm]
|
214
|
+
|
215
|
+
qry.gsub!('%{target_group_query}', group_query)
|
216
|
+
else
|
217
|
+
qry = r_config[:query_simple].clone
|
218
|
+
end
|
219
|
+
|
220
|
+
# substitute variables
|
221
|
+
qry.gsub!('%{requester_id}', self.id.to_s)
|
222
|
+
qry.gsub!('%{privilege_id}', privilege.id.to_s)
|
223
|
+
qry.gsub!('%{requester_group_id}', self.send(r_config[:association_foreign_key]).to_s) unless r_config[:habtm]
|
224
|
+
results = ActiveAcl::OPTIONS[:db].query(qry)
|
225
|
+
|
226
|
+
if target.nil?
|
227
|
+
# prefetch privileges
|
228
|
+
privilegevalue = nil
|
229
|
+
@gacl_instance_cache = {}
|
230
|
+
|
231
|
+
results.each do |row|
|
232
|
+
if row['privilege_id'] != privilegevalue
|
233
|
+
privilegevalue = row['privilege_id']
|
234
|
+
c_id = [privilegevalue, self.class.base_class.name, id, '', ''].join('-')
|
235
|
+
@gacl_instance_cache[c_id] = ((row['allow'] == '1') or (row['allow'] == 't'))
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
value = @gacl_instance_cache[query_id]
|
240
|
+
@gacl_instance_cache[:prefetch_done] = true
|
241
|
+
|
242
|
+
elsif not results.empty?
|
243
|
+
# normal gacl query without prefetching
|
244
|
+
value = ((results[0]['allow'].to_s == '1') or (results[0]['allow'].to_s == 't'))
|
245
|
+
@gacl_instance_cache ||= {} # create if not exists
|
246
|
+
|
247
|
+
@gacl_instance_cache[query_id] = value
|
248
|
+
end
|
249
|
+
|
250
|
+
# nothing found, deny access
|
251
|
+
@gacl_instance_cache[query_id] = value = false if value.nil?
|
252
|
+
|
253
|
+
# save to second level cache
|
254
|
+
cache.set(cache_id, @gacl_instance_cache, ActiveAcl::OPTIONS[:cache_privilege_timeout])
|
255
|
+
|
256
|
+
logger.debug 'GACL::INSTANCE_CACHE::' + (value ? 'GRANT ' : 'DENY ') + query_id if logger.debug?
|
257
|
+
|
258
|
+
end # cache miss
|
259
|
+
return value
|
260
|
+
end
|
261
|
+
|
262
|
+
# override this to customize the description in the interface
|
263
|
+
def active_acl_description
|
264
|
+
to_s
|
265
|
+
end
|
266
|
+
|
267
|
+
# link to model selector
|
268
|
+
def self.model_selector_link params
|
269
|
+
AclsController.url_for(:action => :show_group_members, :clazz => self.class, *params)
|
270
|
+
end
|
271
|
+
|
272
|
+
# clears the permission caches (instance and memory cache)
|
273
|
+
def clear_cached_permissions
|
274
|
+
@gacl_instance_cache = nil
|
275
|
+
ActiveAcl::OPTIONS[:cache].delete('gacl_instance-' + self.class.name + '-' + id.to_s)
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
ActiveRecord::Base.send(:include, ActiveAcl::Acts::AccessObject)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# This model is a DB representation of actions on an ActionController::Base
|
2
|
+
# controller and is grouped by ActiveAcl::ControllerGroup.
|
3
|
+
class ActiveAcl::ControllerAction < ActiveRecord::Base
|
4
|
+
set_table_name ActiveAcl::OPTIONS[:controller_actions_table]
|
5
|
+
privilege_const_set('EXECUTE')
|
6
|
+
|
7
|
+
belongs_to :controller_group
|
8
|
+
acts_as_access_object :grouped_by => :"active_acl/controller_group"
|
9
|
+
|
10
|
+
# Returns the instance representation in the admin screens.
|
11
|
+
def active_acl_description
|
12
|
+
if action
|
13
|
+
if controller
|
14
|
+
return '/' + controller + '/' + action
|
15
|
+
else
|
16
|
+
return action
|
17
|
+
end
|
18
|
+
else
|
19
|
+
return nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the class representation in the admin screens.
|
24
|
+
def self.active_acl_description
|
25
|
+
return 'Action'
|
26
|
+
end
|
27
|
+
|
28
|
+
validates_presence_of :action, :controller, :controller_group
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This model is used for grouping ActiveAcl::ControllerAction models.
|
2
|
+
class ActiveAcl::ControllerGroup < ActiveRecord::Base
|
3
|
+
set_table_name ActiveAcl::OPTIONS[:controller_groups_table]
|
4
|
+
acts_as_nested_set
|
5
|
+
has_many :controller_actions
|
6
|
+
acts_as_access_group
|
7
|
+
|
8
|
+
# Returns the instance representation in the admin screens.
|
9
|
+
def active_acl_description
|
10
|
+
return description
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the class representation in the admin screens.
|
14
|
+
def self.active_acl_description
|
15
|
+
return 'ControllerGroup'
|
16
|
+
end
|
17
|
+
|
18
|
+
validates_presence_of 'description'
|
19
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
require 'action_view'
|
4
|
+
|
5
|
+
class ActionController::Base
|
6
|
+
# Get the access object for the current action.
|
7
|
+
def current_action
|
8
|
+
ActiveAcl::CONTROLLERS[self.class.name][action_name]
|
9
|
+
end
|
10
|
+
|
11
|
+
# alias method_added class method
|
12
|
+
class << self
|
13
|
+
alias :method_added_before_active_acl_controller_action_loading :method_added
|
14
|
+
end
|
15
|
+
|
16
|
+
# Overrides method_added, so the needed ActiveAcl::ControllerAction is loaded/created
|
17
|
+
# when the action gets added to the controller.
|
18
|
+
def self.method_added(action)
|
19
|
+
method_added_before_active_acl_controller_action_loading(action)
|
20
|
+
ActiveAcl::CONTROLLERS[self.name] ||= {}
|
21
|
+
|
22
|
+
if (public_instance_methods.include?(action.to_s))
|
23
|
+
# if no loaded target found
|
24
|
+
unless ActiveAcl::CONTROLLERS[self.name][action.to_s]
|
25
|
+
# load it
|
26
|
+
stripped_name = self.name.underscore.gsub(/_controller/, '')
|
27
|
+
|
28
|
+
begin
|
29
|
+
target = (ActiveAcl::CONTROLLERS[self.name][action.to_s] ||= ActiveAcl::ControllerAction.find_by_action_and_controller(action.to_s, stripped_name))
|
30
|
+
unless target
|
31
|
+
grp_name = stripped_name + ActiveAcl::OPTIONS[:controller_group_name_suffix]
|
32
|
+
|
33
|
+
# find controller group
|
34
|
+
cgroup = ActiveAcl::CONTROLLERS[self.name][:cgroup] ||= ActiveAcl::ControllerGroup.find_by_description(grp_name)
|
35
|
+
|
36
|
+
unless cgroup
|
37
|
+
#try to get main group
|
38
|
+
main_group ||= (ActiveAcl::CONTROLLERS[ActiveAcl::OPTIONS[:controllers_group_name]] ||= ActiveAcl::ControllerGroup.find_by_description(ActiveAcl::OPTIONS[:controllers_group_name]))
|
39
|
+
|
40
|
+
unless main_group
|
41
|
+
# create main group
|
42
|
+
base_group = ActiveAcl::ControllerGroup.find_by_lft(1)
|
43
|
+
main_group = ActiveAcl::ControllerGroup.create(:description => ActiveAcl::OPTIONS[:controllers_group_name])
|
44
|
+
# check if better_nested_set functionality is available
|
45
|
+
if main_group.respond_to?(:move_to_child_of)
|
46
|
+
main_group.move_to_child_of base_group
|
47
|
+
else
|
48
|
+
base_group.add_child main_group
|
49
|
+
end
|
50
|
+
|
51
|
+
ActiveAcl::CONTROLLERS[ActiveAcl::OPTIONS[:controllers_group_name]] = main_group
|
52
|
+
end
|
53
|
+
|
54
|
+
# create controller group
|
55
|
+
cgroup = ActiveAcl::ControllerGroup.create(:description => grp_name)
|
56
|
+
|
57
|
+
# check if better_nested_set functionality is available
|
58
|
+
if cgroup.respond_to?(:move_to_child_of)
|
59
|
+
cgroup.move_to_child_of main_group
|
60
|
+
else
|
61
|
+
main_group.add_child cgroup
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
target = cgroup.controller_actions.create :action => action.to_s, :controller => stripped_name
|
66
|
+
|
67
|
+
# save to collection
|
68
|
+
ActiveAcl::CONTROLLERS[self.name][action.to_s] = target
|
69
|
+
|
70
|
+
end # unless target fetched from db
|
71
|
+
|
72
|
+
# return target
|
73
|
+
return target
|
74
|
+
rescue Exception => e
|
75
|
+
RAILS_DEFAULT_LOGGER.error("error loading target actions in controller #{self.name}: #{e.message}")
|
76
|
+
end
|
77
|
+
end # unless target constant found
|
78
|
+
end # if method is a action
|
79
|
+
end # method_added
|
80
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class ::Object
|
2
|
+
|
3
|
+
# Loads all files it finds at the specified path -
|
4
|
+
# use /path/**/[^.]*.rb to load from sub directories as well
|
5
|
+
#
|
6
|
+
# Silently fails if path is not found or an error occurs
|
7
|
+
def load_files_from(filenames)
|
8
|
+
# don't show files that begin with . and ensure .rb ending
|
9
|
+
cs = Dir["#{filenames}"]
|
10
|
+
for file_name in cs.sort
|
11
|
+
begin
|
12
|
+
# load file_name
|
13
|
+
load(file_name)
|
14
|
+
RAILS_DEFAULT_LOGGER.info "#{file_name} loaded"
|
15
|
+
rescue Exception => e
|
16
|
+
RAILS_DEFAULT_LOGGER.warn("error loading file #{file_name}: #{e.message}")
|
17
|
+
RAILS_DEFAULT_LOGGER.warn(e.backtrace)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ActiveAcl
|
2
|
+
unless const_defined?('OPTIONS')
|
3
|
+
OPTIONS = {}
|
4
|
+
end
|
5
|
+
|
6
|
+
ActiveAcl::ACCESS_CLASSES = {}
|
7
|
+
ActiveAcl::GROUP_CLASSES = {}
|
8
|
+
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
:acl_sections_table => 'acl_sections',
|
11
|
+
:acls_privileges_table => 'acls_privileges',
|
12
|
+
:acls_table => 'acls',
|
13
|
+
:privileges_table => 'privileges',
|
14
|
+
:requester_links_table => 'requester_links',
|
15
|
+
:target_links_table => 'target_links',
|
16
|
+
:requester_group_links_table => 'requester_group_links',
|
17
|
+
:target_group_links_table => 'target_group_links',
|
18
|
+
:controller_actions_table => 'controller_actions',
|
19
|
+
:controller_groups_table => 'controller_groups',
|
20
|
+
|
21
|
+
:controllers_group_name => 'unassigned_controller_actions',
|
22
|
+
:controller_group_name_suffix => '_controller',
|
23
|
+
|
24
|
+
:cache_privilege_timeout => 10,
|
25
|
+
|
26
|
+
:db => ActiveAcl::DB::ActiveRecordAdapter,
|
27
|
+
:cache => ActiveAcl::Cache::NoCacheAdapter,
|
28
|
+
|
29
|
+
:default_selector_controller => 'selector',
|
30
|
+
:default_selector_action => 'show_members',
|
31
|
+
|
32
|
+
:default_group_selector_controller => 'selector',
|
33
|
+
:default_group_selector_action => 'show_group_members'}
|
34
|
+
|
35
|
+
# merge options
|
36
|
+
OPTIONS.replace DEFAULT_OPTIONS.merge(OPTIONS)
|
37
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# The basic "privilege" object, like Forum::VIEW might be the privilege to
|
2
|
+
# view a forum. Check the README for a detailed description on usage.
|
3
|
+
class ActiveAcl::Privilege < ActiveRecord::Base
|
4
|
+
set_table_name ActiveAcl::OPTIONS[:privileges_table]
|
5
|
+
|
6
|
+
has_and_belongs_to_many :acls, :uniq => true, :join_table => ActiveAcl::OPTIONS[:acls_privileges_table]
|
7
|
+
|
8
|
+
validates_presence_of :section, :value
|
9
|
+
|
10
|
+
validates_uniqueness_of :value, :scope => :section
|
11
|
+
|
12
|
+
# Returns the instance representation in the admin screens.
|
13
|
+
# Uses active_acl_description from class if present.
|
14
|
+
def active_acl_description
|
15
|
+
begin
|
16
|
+
section.constantize.active_acl_description
|
17
|
+
rescue
|
18
|
+
section
|
19
|
+
end + '/' + value
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.reloadable? #:nodoc:
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ::Module
|
2
|
+
public
|
3
|
+
# Looks up or creates a privilege object using the caller's name and the constant's name.
|
4
|
+
# Finally sets the privilege object as a constant to the caller.
|
5
|
+
# Accepts a hash of names with descriptions like :name => description or a single string name value.
|
6
|
+
# If force_reload is set to true, the constant will be recreated from the DB.
|
7
|
+
# Returns an array of changed privileges.
|
8
|
+
def privilege_const_set(constant, force_reload = false)
|
9
|
+
result = []
|
10
|
+
constant.is_a?(Hash) ? constant_hash = constant : constant_hash = {constant.to_s => nil}
|
11
|
+
constant_hash.each_pair do |constant_name, description|
|
12
|
+
if !const_defined?(constant_name.to_s) or force_reload
|
13
|
+
remove_const(constant_name.to_s) if const_defined?(constant_name.to_s)
|
14
|
+
privilege = ActiveAcl::Privilege.find_by_section_and_value(self.name, constant_name.to_s)
|
15
|
+
privilege = ActiveAcl::Privilege.create(:section => self.name, :value => constant_name.to_s, :description => description) unless privilege
|
16
|
+
const_set(constant_name.to_s, privilege)
|
17
|
+
result << privilege
|
18
|
+
end
|
19
|
+
end
|
20
|
+
result
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: active_acl
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2006-11-28 00:00:00 +01:00
|
8
|
+
summary: Provides an unintrusive, scalable and very flexible approach to fine grained access control.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: g.melhorn@web.de
|
12
|
+
homepage: http://activeacl.rubyforge.org
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: active_acl
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- Gregor Melhorn
|
30
|
+
files:
|
31
|
+
- lib/active_acl/db
|
32
|
+
- lib/active_acl/cache
|
33
|
+
- lib/active_acl/target_group_link.rb
|
34
|
+
- lib/active_acl/load_files_from.rb
|
35
|
+
- lib/active_acl/requester_link.rb
|
36
|
+
- lib/active_acl/controller_group.rb
|
37
|
+
- lib/active_acl/target_link.rb
|
38
|
+
- lib/active_acl/requester_group_link.rb
|
39
|
+
- lib/active_acl/load_controller_actions.rb
|
40
|
+
- lib/active_acl/privilege_const_set.rb
|
41
|
+
- lib/active_acl/acts_as_access_group.rb
|
42
|
+
- lib/active_acl/controller_action.rb
|
43
|
+
- lib/active_acl/acl_section.rb
|
44
|
+
- lib/active_acl/acts_as_access_object.rb
|
45
|
+
- lib/active_acl/privilege.rb
|
46
|
+
- lib/active_acl/options.rb
|
47
|
+
- lib/active_acl/acl.rb
|
48
|
+
- generators/active_acl/active_acl_generator.rb
|
49
|
+
- generators/active_acl/templates
|
50
|
+
- db/migrate/001_base_table_setup.rb
|
51
|
+
- init.rb
|
52
|
+
- install.rb
|
53
|
+
- LICENSE
|
54
|
+
- Rakefile
|
55
|
+
- README
|
56
|
+
- CHANGELOG
|
57
|
+
test_files: []
|
58
|
+
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
extra_rdoc_files: []
|
62
|
+
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
dependencies:
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rails
|
72
|
+
version_requirement:
|
73
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.1.6
|
78
|
+
version:
|