graylog2-declarative_authorization 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGELOG +153 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +529 -0
  4. data/Rakefile +35 -0
  5. data/app/controllers/authorization_rules_controller.rb +259 -0
  6. data/app/controllers/authorization_usages_controller.rb +23 -0
  7. data/app/helpers/authorization_rules_helper.rb +218 -0
  8. data/app/views/authorization_rules/_change.erb +58 -0
  9. data/app/views/authorization_rules/_show_graph.erb +44 -0
  10. data/app/views/authorization_rules/_suggestions.erb +48 -0
  11. data/app/views/authorization_rules/change.html.erb +169 -0
  12. data/app/views/authorization_rules/graph.dot.erb +68 -0
  13. data/app/views/authorization_rules/graph.html.erb +47 -0
  14. data/app/views/authorization_rules/index.html.erb +17 -0
  15. data/app/views/authorization_usages/index.html.erb +36 -0
  16. data/authorization_rules.dist.rb +20 -0
  17. data/config/routes.rb +20 -0
  18. data/garlic_example.rb +20 -0
  19. data/init.rb +5 -0
  20. data/lib/declarative_authorization.rb +17 -0
  21. data/lib/declarative_authorization/authorization.rb +705 -0
  22. data/lib/declarative_authorization/development_support/analyzer.rb +252 -0
  23. data/lib/declarative_authorization/development_support/change_analyzer.rb +253 -0
  24. data/lib/declarative_authorization/development_support/change_supporter.rb +620 -0
  25. data/lib/declarative_authorization/development_support/development_support.rb +243 -0
  26. data/lib/declarative_authorization/helper.rb +68 -0
  27. data/lib/declarative_authorization/in_controller.rb +645 -0
  28. data/lib/declarative_authorization/in_model.rb +162 -0
  29. data/lib/declarative_authorization/maintenance.rb +212 -0
  30. data/lib/declarative_authorization/obligation_scope.rb +354 -0
  31. data/lib/declarative_authorization/rails_legacy.rb +22 -0
  32. data/lib/declarative_authorization/railsengine.rb +6 -0
  33. data/lib/declarative_authorization/reader.rb +521 -0
  34. data/lib/tasks/authorization_tasks.rake +82 -0
  35. data/test/authorization_test.rb +1104 -0
  36. data/test/controller_filter_resource_access_test.rb +511 -0
  37. data/test/controller_test.rb +480 -0
  38. data/test/dsl_reader_test.rb +178 -0
  39. data/test/helper_test.rb +247 -0
  40. data/test/maintenance_test.rb +46 -0
  41. data/test/model_test.rb +1883 -0
  42. data/test/schema.sql +55 -0
  43. data/test/test_helper.rb +152 -0
  44. metadata +112 -0
@@ -0,0 +1,35 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the authorization plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the authorization plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Authorization'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.options << '--charset' << 'utf-8'
21
+ rdoc.rdoc_files.include('README.rdoc')
22
+ rdoc.rdoc_files.include('CHANGELOG')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+ # load up garlic if it's here
27
+ if File.directory?(File.join(File.dirname(__FILE__), 'garlic'))
28
+ require File.join(File.dirname(__FILE__), 'garlic/lib/garlic_tasks')
29
+ require File.join(File.dirname(__FILE__), 'garlic')
30
+ end
31
+
32
+ desc "clone the garlic repo (for running ci tasks)"
33
+ task :get_garlic do
34
+ sh "git clone git://github.com/ianwhite/garlic.git garlic"
35
+ end
@@ -0,0 +1,259 @@
1
+ if Authorization::activate_authorization_rules_browser?
2
+
3
+ require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support analyzer})
4
+ require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support change_supporter})
5
+ require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support development_support})
6
+
7
+ begin
8
+ # for nice auth_rules output:
9
+ require "parse_tree"
10
+ require "parse_tree_extensions"
11
+ require "ruby2ruby"
12
+ rescue LoadError; end
13
+
14
+ class AuthorizationRulesController < ApplicationController
15
+ unloadable
16
+
17
+ filter_access_to :all, :require => :read
18
+ def index
19
+ respond_to do |format|
20
+ format.html do
21
+ @auth_rules_script = File.read("#{::Rails.root}/config/authorization_rules.rb")
22
+ end
23
+ end
24
+ end
25
+
26
+ def graph
27
+ if params[:format] == "svg"
28
+ render :text => dot_to_svg(auth_to_dot(graph_options)),
29
+ :content_type => "image/svg+xml"
30
+ end
31
+ end
32
+
33
+ def change
34
+ @users = find_all_users
35
+ @users.sort! {|a, b| a.login <=> b.login }
36
+
37
+ @privileges = authorization_engine.auth_rules.collect {|rule| rule.privileges.to_a}.flatten.uniq
38
+ @privileges = @privileges.collect do |priv|
39
+ priv = Authorization::DevelopmentSupport::AnalyzerEngine::Privilege.for_sym(priv, authorization_engine)
40
+ ([priv] + priv.descendants + priv.ancestors).map(&:to_sym)
41
+ end.flatten.uniq
42
+ @privileges.sort_by {|priv| priv.to_s}
43
+ @privilege = params[:privilege].to_sym rescue @privileges.first
44
+ @contexts = authorization_engine.auth_rules.collect {|rule| rule.contexts.to_a}.flatten.uniq
45
+ @context = params[:context].to_sym rescue @contexts.first
46
+
47
+ respond_to do |format|
48
+ format.html
49
+ format.js do
50
+ render :partial => 'change'
51
+ end
52
+ end
53
+ end
54
+
55
+ def suggest_change
56
+ users_permission = params[:user].inject({}) do |memo, (user_id, data)|
57
+ if data[:permission] != "undetermined"
58
+ begin
59
+ memo[find_user_by_id(user_id)] = (data[:permission] == 'yes')
60
+ rescue ActiveRecord::NotFound
61
+ end
62
+ end
63
+ memo
64
+ end
65
+
66
+ prohibited_actions = (params[:prohibited_action] || []).collect do |spec|
67
+ deserialize_changes(spec).flatten
68
+ end
69
+
70
+ analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(authorization_engine)
71
+
72
+ privilege = params[:privilege].to_sym
73
+ context = params[:context].to_sym
74
+ all_users = User.all
75
+ @context = context
76
+ @approaches = analyzer.find_approaches_for(:users => all_users, :prohibited_actions => prohibited_actions) do
77
+ users.each_with_index do |user, idx|
78
+ unless users_permission[all_users[idx]].nil?
79
+ args = [privilege, {:context => context, :user => user}]
80
+ assert(users_permission[all_users[idx]] ? permit?(*args) : !permit?(*args))
81
+ end
82
+ end
83
+ end
84
+
85
+ @affected_users = @approaches.each_with_object({}) do |approach, memo|
86
+ memo[approach] = approach.affected_users(authorization_engine, all_users, privilege, context).length
87
+ end
88
+ max_affected_users = @affected_users.values.max
89
+ if params[:affected_users]
90
+ @approaches = @approaches.sort_by do |approach|
91
+ affected_users_count = @affected_users[approach]
92
+ if params[:affected_users] == "many"
93
+ #approach.weight.to_f / [affected_users_count, 0.1].min
94
+ approach.weight + (max_affected_users - affected_users_count) * 10
95
+ else
96
+ #approach.weight * affected_users_count
97
+ approach.weight + affected_users_count * 10
98
+ end
99
+ end
100
+ end
101
+
102
+ @grouped_approaches = analyzer.group_approaches(@approaches)
103
+
104
+ respond_to do |format|
105
+ format.js do
106
+ render :partial => 'suggestions'
107
+ end
108
+ end
109
+ end
110
+
111
+ private
112
+ def auth_to_dot (options = {})
113
+ options = {
114
+ :effective_role_privs => true,
115
+ :privilege_hierarchy => false,
116
+ :stacked_roles => false,
117
+ :only_relevant_contexts => true,
118
+ :only_relevant_roles => false,
119
+ :filter_roles => nil,
120
+ :filter_contexts => nil,
121
+ :highlight_privilege => nil,
122
+ :changes => nil,
123
+ :users => nil
124
+ }.merge(options)
125
+
126
+ @has_changes = options[:changes] && !options[:changes].empty?
127
+ @highlight_privilege = options[:highlight_privilege]
128
+ @stacked_roles = options[:stacked_roles]
129
+
130
+ @users = options[:users]
131
+
132
+ engine = authorization_engine.clone
133
+ @changes = replay_changes(engine, @users, options[:changes]) if options[:changes]
134
+
135
+ options[:filter_roles] ||= @users.collect {|user| user.role_symbols}.flatten.uniq if options[:only_relevant_roles] and @users
136
+
137
+ filter_roles_flattened = nil
138
+ if options[:filter_roles]
139
+ filter_roles_flattened = options[:filter_roles].collect do |role_sym|
140
+ Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role_sym, engine).
141
+ ancestors.map(&:to_sym) + [role_sym]
142
+ end.flatten.uniq
143
+ end
144
+
145
+ @roles = engine.roles
146
+ @roles = @roles.select {|r| filter_roles_flattened.include?(r) } if options[:filter_roles]
147
+ @role_hierarchy = engine.role_hierarchy
148
+ @privilege_hierarchy = engine.privilege_hierarchy
149
+
150
+ @contexts = engine.auth_rules.
151
+ collect {|ar| ar.contexts.to_a}.flatten.uniq
152
+ @contexts = @contexts.select {|c| c == options[:filter_contexts] } if options[:filter_contexts]
153
+ @context_privs = {}
154
+ @role_privs = {}
155
+ engine.auth_rules.each do |auth_rule|
156
+ @role_privs[auth_rule.role] ||= []
157
+ auth_rule.contexts.
158
+ select {|c| options[:filter_contexts].nil? or c == options[:filter_contexts]}.
159
+ each do |context|
160
+ @context_privs[context] ||= []
161
+ @context_privs[context] += auth_rule.privileges.to_a
162
+ @context_privs[context].uniq!
163
+ @role_privs[auth_rule.role] += auth_rule.privileges.collect {|p| [context, p, auth_rule.attributes.empty?, auth_rule.to_long_s]}
164
+ end
165
+ end
166
+
167
+ if options[:effective_role_privs]
168
+ @roles.each do |role|
169
+ role = Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role, engine)
170
+ @role_privs[role.to_sym] ||= []
171
+ role.ancestors.each do |lower_role|
172
+ @role_privs[role.to_sym].concat(@role_privs[lower_role.to_sym]).uniq!
173
+ end
174
+ end
175
+ end
176
+
177
+ @roles.delete_if do |role|
178
+ role = Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role, engine)
179
+ ([role] + role.ancestors).all? {|inner_role| @role_privs[inner_role.to_sym].blank? }
180
+ end
181
+
182
+ if options[:only_relevant_contexts]
183
+ @contexts.delete_if do |context|
184
+ @roles.all? {|role| !@role_privs[role] || !@role_privs[role].any? {|info| info[0] == context}}
185
+ end
186
+ end
187
+
188
+ if options[:privilege_hierarchy]
189
+ @context_privs.each do |context, privs|
190
+ privs.each do |priv|
191
+ context_lower_privs = (@privilege_hierarchy[priv] || []).
192
+ select {|p,c| c.nil? or c == context}.
193
+ collect {|p,c| p}
194
+ privs.concat(context_lower_privs).uniq!
195
+ end
196
+ end
197
+ end
198
+
199
+ render_to_string :template => 'authorization_rules/graph.dot.erb', :layout => false
200
+ end
201
+
202
+ def replay_changes (engine, users, changes)
203
+ changes.inject({}) do |memo, info|
204
+ case info[0]
205
+ when :add_privilege, :add_role
206
+ Authorization::DevelopmentSupport::AnalyzerEngine.apply_change(engine, info)
207
+ when :assign_role_to_user
208
+ user = users.find {|u| u.login == info[2]}
209
+ user.role_symbols << info[1] if user
210
+ end
211
+ (memo[info[0]] ||= Set.new) << info[1..-1]
212
+ memo
213
+ end
214
+ end
215
+
216
+ def dot_to_svg (dot_data)
217
+ gv = IO.popen("#{Authorization.dot_path} -q -Tsvg", "w+")
218
+ gv.puts dot_data
219
+ gv.close_write
220
+ gv.read
221
+ rescue IOError, Errno::EPIPE => e
222
+ raise Exception, "Error in call to graphviz: #{e}"
223
+ end
224
+
225
+ def graph_options
226
+ {
227
+ :effective_role_privs => !params[:effective_role_privs].blank?,
228
+ :privilege_hierarchy => !params[:privilege_hierarchy].blank?,
229
+ :stacked_roles => !params[:stacked_roles].blank?,
230
+ :only_relevant_roles => !params[:only_relevant_roles].blank?,
231
+ :filter_roles => params[:filter_roles].blank? ? nil : (params[:filter_roles].is_a?(Array) ? params[:filter_roles].map(&:to_sym) : [params[:filter_roles].to_sym]),
232
+ :filter_contexts => params[:filter_contexts].blank? ? nil : params[:filter_contexts].to_sym,
233
+ :highlight_privilege => params[:highlight_privilege].blank? ? nil : params[:highlight_privilege].to_sym,
234
+ :changes => deserialize_changes(params[:changes]),
235
+ :users => params[:user_ids] && params[:user_ids].collect {|user_id| find_user_by_id(user_id)}
236
+ }
237
+ end
238
+
239
+ def deserialize_changes (changes)
240
+ if changes
241
+ changes.split(';').collect do |info|
242
+ info.split(',').collect do |info_part|
243
+ info_part[0,1] == ':' ? info_part[1..-1].to_sym : info_part
244
+ end
245
+ end
246
+ end
247
+ end
248
+
249
+ def find_user_by_id (id)
250
+ User.find(id)
251
+ end
252
+ def find_all_users
253
+ User.all.select {|user| !user.login.blank?}
254
+ end
255
+ end
256
+
257
+ else
258
+ class AuthorizationRulesController < ApplicationController; end
259
+ end # activate_authorization_rules_browser?
@@ -0,0 +1,23 @@
1
+ if Authorization::activate_authorization_rules_browser?
2
+
3
+ require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization maintenance})
4
+
5
+ class AuthorizationUsagesController < ApplicationController
6
+ unloadable
7
+
8
+ helper :authorization_rules
9
+ filter_access_to :all, :require => :read
10
+ # TODO set context?
11
+
12
+ def index
13
+ respond_to do |format|
14
+ format.html do
15
+ @auth_usages_by_controller = Authorization::Maintenance::Usage.usages_by_controller
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ else
22
+ class AuthorizationUsagesController < ApplicationController; end
23
+ end # activate_authorization_rules_browser?
@@ -0,0 +1,218 @@
1
+ module AuthorizationRulesHelper
2
+ def syntax_highlight (rules)
3
+ regexps = {
4
+ :constant => [/(:)(\w+)/],
5
+ :proc => ['role', 'authorization', 'privileges'],
6
+ :statement => ['has_permission_on', 'if_attribute', 'if_permitted_to', 'includes', 'privilege', 'to'],
7
+ :operator => ['is', 'contains', 'is_in', 'is_not', 'is_not_in', 'intersects'],
8
+ :special => ['user', 'true', 'false'],
9
+ :preproc => ['do', 'end', /()(=&gt;)/, /()(\{)/, /()(\})/, /()(\[)/, /()(\])/],
10
+ :comment => [/()(#.*$)/]#,
11
+ #:privilege => [:read],
12
+ #:context => [:conferences]
13
+ }
14
+ regexps.each do |name, res|
15
+ res.each do |re|
16
+ rules.gsub!(
17
+ re.is_a?(String) ? Regexp.new("(^|[^:])\\b(#{Regexp.escape(re)})\\b") :
18
+ (re.is_a?(Symbol) ? Regexp.new("()(:#{Regexp.escape(re.to_s)})\\b") : re),
19
+ "\\1<span class=\"#{name}\">\\2</span>")
20
+ end
21
+ end
22
+ rules
23
+ end
24
+
25
+ def policy_analysis_hints (marked_up, policy_data)
26
+ analyzer = Authorization::DevelopmentSupport::Analyzer.new(controller.authorization_engine)
27
+ analyzer.analyze(policy_data)
28
+ marked_up_by_line = marked_up.split("\n")
29
+ reports_by_line = analyzer.reports.inject({}) do |memo, report|
30
+ memo[report.line || 1] ||= []
31
+ memo[report.line || 1] << report
32
+ memo
33
+ end
34
+ reports_by_line.each do |line, reports|
35
+ text = reports.collect {|report| "#{report.type}: #{report.message}"} * " "
36
+ note = %Q{<span class="note" title="#{h text}">[i]</span>}
37
+ marked_up_by_line[line - 1] = note + marked_up_by_line[line - 1]
38
+ end
39
+ (marked_up_by_line * "\n").html_safe
40
+ end
41
+
42
+ def link_to_graph (title, options = {})
43
+ type = options[:type] || ''
44
+ link_to_function title, "$$('object')[0].data = '#{url_for :action => 'index', :format => 'svg', :type => type}'"
45
+ end
46
+
47
+ def navigation
48
+ link_to("Rules", authorization_rules_path) << ' | ' <<
49
+ link_to("Change Support", change_authorization_rules_path) << ' | ' <<
50
+ link_to("Graphical view", graph_authorization_rules_path) << ' | ' <<
51
+ link_to("Usages", authorization_usages_path) #<< ' | ' <<
52
+ # 'Edit | ' <<
53
+ # link_to("XACML export", :action => 'index', :format => 'xacml')
54
+ end
55
+
56
+ def role_color (role, fill = false)
57
+ if @has_changes
58
+ if has_changed(:add_role, role)
59
+ fill ? '#ddffdd' : '#000000'
60
+ elsif has_changed(:remove_role, role)
61
+ fill ? '#ffdddd' : '#000000'
62
+ else
63
+ fill ? '#ddddff' : '#000000'
64
+ end
65
+ else
66
+ fill_colors = %w{#ffdddd #ddffdd #ddddff #ffffdd #ffddff #ddffff}
67
+ colors = %w{#dd0000 #00dd00 #0000dd #dddd00 #dd00dd #00dddd}
68
+ @@role_colors ||= {}
69
+ @@role_colors[role] ||= begin
70
+ idx = @@role_colors.length % colors.length
71
+ [colors[idx], fill_colors[idx]]
72
+ end
73
+ @@role_colors[role][fill ? 1 : 0]
74
+ end
75
+ end
76
+
77
+ def role_fill_color (role)
78
+ role_color(role, true)
79
+ end
80
+
81
+ def privilege_color (privilege, context, role)
82
+ has_changed(:add_privilege, privilege, context, role) ? '#00dd00' :
83
+ (has_changed(:remove_privilege, privilege, context, role) ? '#dd0000' :
84
+ role_color(role))
85
+ end
86
+
87
+ def human_privilege (privilege)
88
+ begin
89
+ I18n.t(privilege, :scope => [:declarative_authorization, :privilege], :raise => true)
90
+ rescue
91
+ privilege.to_s
92
+ end
93
+ end
94
+
95
+ def human_context (context)
96
+ begin
97
+ context.to_s.classify.constantize.human_name
98
+ rescue
99
+ context.to_s
100
+ end
101
+ end
102
+
103
+ def human_privilege_context (privilege, context)
104
+ human = [human_privilege(privilege), human_context(context)]
105
+ begin
106
+ unless I18n.t(:verb_in_front_of_object, :scope => :declarative_authorization, :raise => true)
107
+ human.reverse!
108
+ end
109
+ rescue
110
+ end
111
+ human * " "
112
+ end
113
+
114
+ def human_role (role)
115
+ Authorization::Engine.instance.title_for(role) or role.to_s
116
+ end
117
+
118
+ def describe_step (step, options = {})
119
+ options = {:with_removal => false}.merge(options)
120
+
121
+ case step[0]
122
+ when :add_privilege
123
+ dont_assign = prohibit_link(step[0,3],
124
+ "Add privilege <strong>#{h human_privilege_context(step[1], step[2])}</strong> to any role",
125
+ "Don't suggest adding #{h human_privilege_context(step[1], step[2])}.", options)
126
+ "Add privilege <strong>#{h human_privilege_context(step[1], step[2])}</strong>#{dont_assign} to role <strong>#{h human_role(step[3].to_sym)}</strong>"
127
+ when :remove_privilege
128
+ dont_remove = prohibit_link(step[0,3],
129
+ "Remove privilege <strong>#{h human_privilege_context(step[1], step[2])}</strong> from any role",
130
+ "Don't suggest removing #{h human_privilege_context(step[1], step[2])}.", options)
131
+ "Remove privilege <strong>#{h human_privilege_context(step[1], step[2])}</strong>#{dont_remove} from role <strong>#{h human_role(step[3].to_sym)}</strong>"
132
+ when :add_role
133
+ "New role <strong>#{h human_role(step[1].to_sym)}</strong>"
134
+ when :assign_role_to_user
135
+ dont_assign = prohibit_link(step[0,2],
136
+ "Assign role <strong>#{h human_role(step[1].to_sym)}</strong> to any user",
137
+ "Don't suggest assigning #{h human_role(step[1].to_sym)}.", options)
138
+ "Assign role <strong>#{h human_role(step[1].to_sym)}</strong>#{dont_assign} to <strong>#{h readable_step_info(step[2])}</strong>"
139
+ when :remove_role_from_user
140
+ dont_remove = prohibit_link(step[0,2],
141
+ "Remove role <strong>#{h human_role(step[1].to_sym)}</strong> from any user",
142
+ "Don't suggest removing #{h human_role(step[1].to_sym)}.", options)
143
+ "Remove role <strong>#{h human_role(step[1].to_sym)}</strong>#{dont_remove} from <strong>#{h readable_step_info(step[2])}</strong>"
144
+ else
145
+ step.collect {|info| readable_step_info(info) }.map {|str| h str } * ', '
146
+ end + prohibit_link(step, options[:with_removal] ? "#{escape_javascript(describe_step(step))}" : '',
147
+ "Don't suggest this action.", options)
148
+ end
149
+
150
+ def prohibit_link (step, text, title, options)
151
+ options[:with_removal] ?
152
+ link_to_function("[x]", "prohibit_action('#{serialize_action(step)}', '#{text}')",
153
+ :class => 'prohibit', :title => title) :
154
+ ''
155
+ end
156
+
157
+ def readable_step_info (info)
158
+ case info
159
+ when Symbol then info.inspect
160
+ when User then info.login
161
+ else info.to_sym.inspect
162
+ end
163
+ end
164
+
165
+ def serialize_changes (approach)
166
+ changes = approach.changes.collect {|step| step.to_a.first.is_a?(Enumerable) ? step.to_a : [step.to_a]}
167
+ changes.collect {|multi_step| multi_step.collect {|step| serialize_action(step) }}.flatten * ';'
168
+ end
169
+
170
+ def serialize_action (step)
171
+ step.collect {|info| readable_step_info(info) } * ','
172
+ end
173
+
174
+ def serialize_relevant_roles (approach)
175
+ {:filter_roles => (Authorization::DevelopmentSupport::AnalyzerEngine.relevant_roles(approach.engine, approach.users).
176
+ map(&:to_sym) + [:new_role_for_change_analyzer]).uniq}.to_param
177
+ end
178
+
179
+ def has_changed (*args)
180
+ @changes && @changes[args[0]] && @changes[args[0]].include?(args[1..-1])
181
+ end
182
+
183
+ def affected_users_count (approach)
184
+ @affected_users[approach]
185
+ end
186
+
187
+ def auth_usage_info_classes (auth_info)
188
+ classes = []
189
+ if auth_info[:controller_permissions]
190
+ if auth_info[:controller_permissions][0]
191
+ classes << "catch-all" if auth_info[:controller_permissions][0].actions.include?(:all)
192
+ classes << "default-privilege" unless auth_info[:controller_permissions][0].privilege
193
+ classes << "default-context" unless auth_info[:controller_permissions][0].context
194
+ classes << "no-attribute-check" unless auth_info[:controller_permissions][0].attribute_check
195
+ end
196
+ else
197
+ classes << "unprotected"
198
+ end
199
+ classes * " "
200
+ end
201
+
202
+ def auth_usage_info_title (auth_info)
203
+ titles = []
204
+ if auth_usage_info_classes(auth_info) =~ /unprotected/
205
+ titles << "No filter_access_to call protects this action"
206
+ end
207
+ if auth_usage_info_classes(auth_info) =~ /no-attribute-check/
208
+ titles << "Action is not protected with attribute check"
209
+ end
210
+ if auth_usage_info_classes(auth_info) =~ /default-privilege/
211
+ titles << "Privilege set automatically from action name by :all rule"
212
+ end
213
+ if auth_usage_info_classes(auth_info) =~ /default-context/
214
+ titles << "Context set automatically from controller name by filter_access_to call without :context option"
215
+ end
216
+ titles * ". "
217
+ end
218
+ end