zeiv-declarative_authorization 1.0.0.pre

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +189 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +632 -0
  5. data/Rakefile +53 -0
  6. data/app/controllers/authorization_rules_controller.rb +258 -0
  7. data/app/controllers/authorization_usages_controller.rb +22 -0
  8. data/app/helpers/authorization_rules_helper.rb +218 -0
  9. data/app/views/authorization_rules/_change.erb +58 -0
  10. data/app/views/authorization_rules/_show_graph.erb +44 -0
  11. data/app/views/authorization_rules/_suggestions.erb +48 -0
  12. data/app/views/authorization_rules/change.html.erb +169 -0
  13. data/app/views/authorization_rules/graph.dot.erb +68 -0
  14. data/app/views/authorization_rules/graph.html.erb +47 -0
  15. data/app/views/authorization_rules/index.html.erb +17 -0
  16. data/app/views/authorization_usages/index.html.erb +36 -0
  17. data/authorization_rules.dist.rb +20 -0
  18. data/config/routes.rb +20 -0
  19. data/garlic_example.rb +20 -0
  20. data/init.rb +5 -0
  21. data/lib/declarative_authorization.rb +19 -0
  22. data/lib/declarative_authorization/adapters/active_record.rb +13 -0
  23. data/lib/declarative_authorization/adapters/active_record/base_extensions.rb +0 -0
  24. data/lib/declarative_authorization/adapters/active_record/obligation_scope_builder.rb +0 -0
  25. data/lib/declarative_authorization/authorization.rb +798 -0
  26. data/lib/declarative_authorization/development_support/analyzer.rb +261 -0
  27. data/lib/declarative_authorization/development_support/change_analyzer.rb +253 -0
  28. data/lib/declarative_authorization/development_support/change_supporter.rb +620 -0
  29. data/lib/declarative_authorization/development_support/development_support.rb +243 -0
  30. data/lib/declarative_authorization/helper.rb +68 -0
  31. data/lib/declarative_authorization/in_controller.rb +703 -0
  32. data/lib/declarative_authorization/in_model.rb +188 -0
  33. data/lib/declarative_authorization/maintenance.rb +210 -0
  34. data/lib/declarative_authorization/obligation_scope.rb +361 -0
  35. data/lib/declarative_authorization/rails_legacy.rb +22 -0
  36. data/lib/declarative_authorization/railsengine.rb +6 -0
  37. data/lib/declarative_authorization/reader.rb +546 -0
  38. data/lib/generators/authorization/install/install_generator.rb +77 -0
  39. data/lib/generators/authorization/rules/rules_generator.rb +14 -0
  40. data/lib/generators/authorization/rules/templates/authorization_rules.rb +27 -0
  41. data/lib/tasks/authorization_tasks.rake +89 -0
  42. data/test/authorization_test.rb +1124 -0
  43. data/test/controller_filter_resource_access_test.rb +575 -0
  44. data/test/controller_test.rb +480 -0
  45. data/test/database.yml +3 -0
  46. data/test/dsl_reader_test.rb +178 -0
  47. data/test/helper_test.rb +247 -0
  48. data/test/maintenance_test.rb +46 -0
  49. data/test/model_test.rb +2008 -0
  50. data/test/schema.sql +56 -0
  51. data/test/test_helper.rb +255 -0
  52. metadata +95 -0
@@ -0,0 +1,53 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rdoc/task'
4
+
5
+ desc 'Default: run unit tests against all versions.'
6
+ task :default => 'bundles:test'
7
+
8
+ def run_for_bundles cmd
9
+ Dir['gemfiles/*.gemfile'].each do |gemfile|
10
+ puts "\n#{gemfile}: #{cmd}"
11
+ ENV['BUNDLE_GEMFILE'] = gemfile
12
+ system(cmd)
13
+ end
14
+ end
15
+
16
+ task 'bundles:install' do
17
+ run_for_bundles 'bundle install'
18
+ end
19
+ task 'bundles:update' do
20
+ run_for_bundles 'bundle update'
21
+ end
22
+ task 'bundles:test' do
23
+ run_for_bundles 'bundle exec rake test'
24
+ end
25
+
26
+ desc 'Test the authorization plugin.'
27
+ Rake::TestTask.new(:test) do |t|
28
+ t.libs << 'lib' << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = true
31
+ end
32
+
33
+ desc 'Generate documentation for the authorization plugin.'
34
+ Rake::RDocTask.new(:rdoc) do |rdoc|
35
+ rdoc.rdoc_dir = 'rdoc'
36
+ rdoc.title = 'Authorization'
37
+ rdoc.options << '--line-numbers' << '--inline-source'
38
+ rdoc.options << '--charset' << 'utf-8'
39
+ rdoc.rdoc_files.include('README.rdoc')
40
+ rdoc.rdoc_files.include('CHANGELOG')
41
+ rdoc.rdoc_files.include('lib/**/*.rb')
42
+ end
43
+
44
+ # load up garlic if it's here
45
+ if File.directory?(File.join(File.dirname(__FILE__), 'garlic'))
46
+ require File.join(File.dirname(__FILE__), 'garlic/lib/garlic_tasks')
47
+ require File.join(File.dirname(__FILE__), 'garlic')
48
+ end
49
+
50
+ desc "clone the garlic repo (for running ci tasks)"
51
+ task :get_garlic do
52
+ sh "git clone git://github.com/ianwhite/garlic.git garlic"
53
+ end
@@ -0,0 +1,258 @@
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
+
16
+ filter_access_to :all, :require => :read
17
+ def index
18
+ respond_to do |format|
19
+ format.html do
20
+ @auth_rules_script = File.read("#{::Rails.root}/config/authorization_rules.rb")
21
+ end
22
+ end
23
+ end
24
+
25
+ def graph
26
+ if params[:format] == "svg"
27
+ render :text => dot_to_svg(auth_to_dot(graph_options)),
28
+ :content_type => "image/svg+xml"
29
+ end
30
+ end
31
+
32
+ def change
33
+ @users = find_all_users
34
+ @users.sort! {|a, b| a.login <=> b.login }
35
+
36
+ @privileges = authorization_engine.auth_rules.collect {|rule| rule.privileges.to_a}.flatten.uniq
37
+ @privileges = @privileges.collect do |priv|
38
+ priv = Authorization::DevelopmentSupport::AnalyzerEngine::Privilege.for_sym(priv, authorization_engine)
39
+ ([priv] + priv.descendants + priv.ancestors).map(&:to_sym)
40
+ end.flatten.uniq
41
+ @privileges.sort_by {|priv| priv.to_s}
42
+ @privilege = params[:privilege].to_sym rescue @privileges.first
43
+ @contexts = authorization_engine.auth_rules.collect {|rule| rule.contexts.to_a}.flatten.uniq
44
+ @context = params[:context].to_sym rescue @contexts.first
45
+
46
+ respond_to do |format|
47
+ format.html
48
+ format.js do
49
+ render :partial => 'change'
50
+ end
51
+ end
52
+ end
53
+
54
+ def suggest_change
55
+ users_permission = params[:user].inject({}) do |memo, (user_id, data)|
56
+ if data[:permission] != "undetermined"
57
+ begin
58
+ memo[find_user_by_id(user_id)] = (data[:permission] == 'yes')
59
+ rescue ActiveRecord::NotFound
60
+ end
61
+ end
62
+ memo
63
+ end
64
+
65
+ prohibited_actions = (params[:prohibited_action] || []).collect do |spec|
66
+ deserialize_changes(spec).flatten
67
+ end
68
+
69
+ analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(authorization_engine)
70
+
71
+ privilege = params[:privilege].to_sym
72
+ context = params[:context].to_sym
73
+ all_users = User.all
74
+ @context = context
75
+ @approaches = analyzer.find_approaches_for(:users => all_users, :prohibited_actions => prohibited_actions) do
76
+ users.each_with_index do |user, idx|
77
+ unless users_permission[all_users[idx]].nil?
78
+ args = [privilege, {:context => context, :user => user}]
79
+ assert(users_permission[all_users[idx]] ? permit?(*args) : !permit?(*args))
80
+ end
81
+ end
82
+ end
83
+
84
+ @affected_users = @approaches.each_with_object({}) do |approach, memo|
85
+ memo[approach] = approach.affected_users(authorization_engine, all_users, privilege, context).length
86
+ end
87
+ max_affected_users = @affected_users.values.max
88
+ if params[:affected_users]
89
+ @approaches = @approaches.sort_by do |approach|
90
+ affected_users_count = @affected_users[approach]
91
+ if params[:affected_users] == "many"
92
+ #approach.weight.to_f / [affected_users_count, 0.1].min
93
+ approach.weight + (max_affected_users - affected_users_count) * 10
94
+ else
95
+ #approach.weight * affected_users_count
96
+ approach.weight + affected_users_count * 10
97
+ end
98
+ end
99
+ end
100
+
101
+ @grouped_approaches = analyzer.group_approaches(@approaches)
102
+
103
+ respond_to do |format|
104
+ format.js do
105
+ render :partial => 'suggestions'
106
+ end
107
+ end
108
+ end
109
+
110
+ private
111
+ def auth_to_dot (options = {})
112
+ options = {
113
+ :effective_role_privs => true,
114
+ :privilege_hierarchy => false,
115
+ :stacked_roles => false,
116
+ :only_relevant_contexts => true,
117
+ :only_relevant_roles => false,
118
+ :filter_roles => nil,
119
+ :filter_contexts => nil,
120
+ :highlight_privilege => nil,
121
+ :changes => nil,
122
+ :users => nil
123
+ }.merge(options)
124
+
125
+ @has_changes = options[:changes] && !options[:changes].empty?
126
+ @highlight_privilege = options[:highlight_privilege]
127
+ @stacked_roles = options[:stacked_roles]
128
+
129
+ @users = options[:users]
130
+
131
+ engine = authorization_engine.clone
132
+ @changes = replay_changes(engine, @users, options[:changes]) if options[:changes]
133
+
134
+ options[:filter_roles] ||= @users.collect {|user| user.role_symbols}.flatten.uniq if options[:only_relevant_roles] and @users
135
+
136
+ filter_roles_flattened = nil
137
+ if options[:filter_roles]
138
+ filter_roles_flattened = options[:filter_roles].collect do |role_sym|
139
+ Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role_sym, engine).
140
+ ancestors.map(&:to_sym) + [role_sym]
141
+ end.flatten.uniq
142
+ end
143
+
144
+ @roles = engine.roles
145
+ @roles = @roles.select {|r| filter_roles_flattened.include?(r) } if options[:filter_roles]
146
+ @role_hierarchy = engine.role_hierarchy
147
+ @privilege_hierarchy = engine.privilege_hierarchy
148
+
149
+ @contexts = engine.auth_rules.
150
+ collect {|ar| ar.contexts.to_a}.flatten.uniq
151
+ @contexts = @contexts.select {|c| c == options[:filter_contexts] } if options[:filter_contexts]
152
+ @context_privs = {}
153
+ @role_privs = {}
154
+ engine.auth_rules.each do |auth_rule|
155
+ @role_privs[auth_rule.role] ||= []
156
+ auth_rule.contexts.
157
+ select {|c| options[:filter_contexts].nil? or c == options[:filter_contexts]}.
158
+ each do |context|
159
+ @context_privs[context] ||= []
160
+ @context_privs[context] += auth_rule.privileges.to_a
161
+ @context_privs[context].uniq!
162
+ @role_privs[auth_rule.role] += auth_rule.privileges.collect {|p| [context, p, auth_rule.attributes.empty?, auth_rule.to_long_s]}
163
+ end
164
+ end
165
+
166
+ if options[:effective_role_privs]
167
+ @roles.each do |role|
168
+ role = Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role, engine)
169
+ @role_privs[role.to_sym] ||= []
170
+ role.ancestors.each do |lower_role|
171
+ @role_privs[role.to_sym].concat(@role_privs[lower_role.to_sym]).uniq!
172
+ end
173
+ end
174
+ end
175
+
176
+ @roles.delete_if do |role|
177
+ role = Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role, engine)
178
+ ([role] + role.ancestors).all? {|inner_role| @role_privs[inner_role.to_sym].blank? }
179
+ end
180
+
181
+ if options[:only_relevant_contexts]
182
+ @contexts.delete_if do |context|
183
+ @roles.all? {|role| !@role_privs[role] || !@role_privs[role].any? {|info| info[0] == context}}
184
+ end
185
+ end
186
+
187
+ if options[:privilege_hierarchy]
188
+ @context_privs.each do |context, privs|
189
+ privs.each do |priv|
190
+ context_lower_privs = (@privilege_hierarchy[priv] || []).
191
+ select {|p,c| c.nil? or c == context}.
192
+ collect {|p,c| p}
193
+ privs.concat(context_lower_privs).uniq!
194
+ end
195
+ end
196
+ end
197
+
198
+ render_to_string :template => 'authorization_rules/graph.dot.erb', :layout => false
199
+ end
200
+
201
+ def replay_changes (engine, users, changes)
202
+ changes.inject({}) do |memo, info|
203
+ case info[0]
204
+ when :add_privilege, :add_role
205
+ Authorization::DevelopmentSupport::AnalyzerEngine.apply_change(engine, info)
206
+ when :assign_role_to_user
207
+ user = users.find {|u| u.login == info[2]}
208
+ user.role_symbols << info[1] if user
209
+ end
210
+ (memo[info[0]] ||= Set.new) << info[1..-1]
211
+ memo
212
+ end
213
+ end
214
+
215
+ def dot_to_svg (dot_data)
216
+ gv = IO.popen("#{Authorization.dot_path} -q -Tsvg", "w+")
217
+ gv.puts dot_data
218
+ gv.close_write
219
+ gv.read
220
+ rescue IOError, Errno::EPIPE => e
221
+ raise Exception, "Error in call to graphviz: #{e}"
222
+ end
223
+
224
+ def graph_options
225
+ {
226
+ :effective_role_privs => !params[:effective_role_privs].blank?,
227
+ :privilege_hierarchy => !params[:privilege_hierarchy].blank?,
228
+ :stacked_roles => !params[:stacked_roles].blank?,
229
+ :only_relevant_roles => !params[:only_relevant_roles].blank?,
230
+ :filter_roles => params[:filter_roles].blank? ? nil : (params[:filter_roles].is_a?(Array) ? params[:filter_roles].map(&:to_sym) : [params[:filter_roles].to_sym]),
231
+ :filter_contexts => params[:filter_contexts].blank? ? nil : params[:filter_contexts].to_sym,
232
+ :highlight_privilege => params[:highlight_privilege].blank? ? nil : params[:highlight_privilege].to_sym,
233
+ :changes => deserialize_changes(params[:changes]),
234
+ :users => params[:user_ids] && params[:user_ids].collect {|user_id| find_user_by_id(user_id)}
235
+ }
236
+ end
237
+
238
+ def deserialize_changes (changes)
239
+ if changes
240
+ changes.split(';').collect do |info|
241
+ info.split(',').collect do |info_part|
242
+ info_part[0,1] == ':' ? info_part[1..-1].to_sym : info_part
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+ def find_user_by_id (id)
249
+ User.find(id)
250
+ end
251
+ def find_all_users
252
+ User.all.select {|user| !user.login.blank?}
253
+ end
254
+ end
255
+
256
+ else
257
+ class AuthorizationRulesController < ApplicationController; end
258
+ end # activate_authorization_rules_browser?
@@ -0,0 +1,22 @@
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
+
7
+ helper :authorization_rules
8
+ filter_access_to :all, :require => :read
9
+ # TODO set context?
10
+
11
+ def index
12
+ respond_to do |format|
13
+ format.html do
14
+ @auth_usages_by_controller = Authorization::Maintenance::Usage.usages_by_controller
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ else
21
+ class AuthorizationUsagesController < ApplicationController; end
22
+ 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 = 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