active_acl 0.2.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.
- 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:
|