rubycs-declarative_authorization 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/CHANGELOG +70 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +9 -0
  4. data/Rakefile +43 -0
  5. data/app/controllers/authorization_rules_controller.rb +114 -0
  6. data/app/controllers/authorization_usages_controller.rb +23 -0
  7. data/app/helpers/authorization_rules_helper.rb +100 -0
  8. data/app/views/authorization_rules/graph.dot.erb +49 -0
  9. data/app/views/authorization_rules/graph.html.erb +39 -0
  10. data/app/views/authorization_rules/index.html.erb +16 -0
  11. data/app/views/authorization_usages/index.html.erb +45 -0
  12. data/authorization_rules.dist.rb +20 -0
  13. data/config/locales/en.declarative_authorization.yml +35 -0
  14. data/config/locales/ro.declarative_authorization.yml +35 -0
  15. data/config/routes.rb +6 -0
  16. data/garlic_example.rb +20 -0
  17. data/init.rb +5 -0
  18. data/lib/declarative_authorization.rb +15 -0
  19. data/lib/declarative_authorization/authorization.rb +578 -0
  20. data/lib/declarative_authorization/authorization_rules_analyzer.rb +138 -0
  21. data/lib/declarative_authorization/helper.rb +56 -0
  22. data/lib/declarative_authorization/in_controller.rb +343 -0
  23. data/lib/declarative_authorization/in_model.rb +125 -0
  24. data/lib/declarative_authorization/maintenance.rb +174 -0
  25. data/lib/declarative_authorization/obligation_scope.rb +292 -0
  26. data/lib/declarative_authorization/rails_legacy.rb +14 -0
  27. data/lib/declarative_authorization/reader.rb +430 -0
  28. data/test/authorization_rules_analyzer_test.rb +123 -0
  29. data/test/authorization_test.rb +779 -0
  30. data/test/controller_test.rb +361 -0
  31. data/test/dsl_reader_test.rb +157 -0
  32. data/test/helper_test.rb +133 -0
  33. data/test/maintenance_test.rb +15 -0
  34. data/test/model_test.rb +1143 -0
  35. data/test/schema.sql +53 -0
  36. data/test/test_helper.rb +99 -0
  37. metadata +97 -0
data/CHANGELOG ADDED
@@ -0,0 +1,70 @@
1
+
2
+ ** RELEASE 0.3 (April 20, 2009) **
3
+
4
+ * New option :join_by for has_permission_on to allow AND'ing of statements in one has_permission_on block [sb]
5
+
6
+ * Allow using_access_control to be called directly on ActiveRecord::Base, globally enabling model security [sb]
7
+
8
+ * New operator: intersects_with, comparing two Enumerables in if_attribute [sb]
9
+
10
+ * Improved if_permitted_to syntax: if the attribute is left out, permissions are checked on for the current object [sb]
11
+
12
+ * Added #has_role_with_hierarchy? method to retrieve explicit and calculated roles [jeremyf]
13
+
14
+ * Added a simple rules analyzer to help improve authorization rules [sb]
15
+
16
+ * Gemified plugin. Needed to restructure the lib path contents [sb]
17
+
18
+ * Added handling of Authorization::AuthorizationInController::ClassMethods.filter_access_to parameters that are of the form [:show, :update] instead of just :show, :update. [jeremyf]
19
+
20
+ * Added authorization usage helper for checking filter_access_to usage in controllers [sb]
21
+
22
+ * Added a authorization rules browser. See README for more information [sb]
23
+
24
+ * Added Model.using_access_control? to check if a model has model security activated [sb]
25
+
26
+ * Changed Authorization::ObligationScope#map_table_alias_for [Brian Langenfeld]
27
+ * Fixed to prevent bad aliases from being produced.
28
+
29
+ * Changed Authorization::Attribute#validate? [Brian Langenfeld]
30
+ * Encountering a nil value when evaluating an attribute now raises a NilAttributeValueError, instead of an AuthorizationError. We leave it to the caller to decide what to do about it.
31
+
32
+ * Changed Authorization::Engine#permit! [Brian Langenfeld]
33
+ * We now convert incoming privileges to symbols (e.g. 'read' is made equivalent to :read). This ensures the privileges will match those defined in the authorization rules file.
34
+ * The method now properly infers context when checking against an association (e.g. user.posts). We do this by leveraging ActiveRecord builder method 'new' to instantiate a proper object we can work with.
35
+ * When testing rules for positive results (via Authorization::Attribute#validate?), we now rescue NilAttributeValueError exceptions, simply causing the rule to return a negative result (instead of barfing).
36
+
37
+ * Changed Authorization::ObligationScope#rebuild_join_options! [Brian Langenfeld]
38
+ * If we're dealing with multiple obligations we have to check (i.e. ones that result in OR'd conditions), we now use :include instead of :joins for our generated scope. This does seem like a kludge, but until ActiveRecord scopes support unions (for checking obligations individually and consolidating the results), we don't have much choice. Something to revisit later, for sure.
39
+
40
+ ** RELEASE 0.2 (February 2, 2009) **
41
+
42
+ * added negative operators: is_not, not_in, does_not_contain [sb]
43
+
44
+ * changed user.roles to user.role_symbols to reduce interferance with associations [sb]
45
+
46
+ * Ruby 1.9 and Rails 2.3 compatibility [sb]
47
+
48
+ * if_permitted_to for has_permission_on blocks for DRYer auth rules [sb]
49
+
50
+ * ObligationScope rewrite of query rewriting [Brian Langenfeld]
51
+
52
+ * changed exception hierarchy to begin at StandardError [sb]
53
+
54
+ * :is_in operator [sb]
55
+
56
+ * added has_role? helper [sb]
57
+
58
+ * made plugin thread-safe [sb]
59
+
60
+ * added maintenance and test helpers [sb]
61
+
62
+ * changed default permission denied response to 403 Forbidden [sb]
63
+
64
+ * descriptions for titles and roles [sb]
65
+
66
+ * fixed for PostgreSQL [Mark Mansour]
67
+
68
+ * improved DSL syntax: allow for array of contexts in has_permission_on [sb]
69
+
70
+ ** RELEASE 0.1 (August 22, 2008) **
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,9 @@
1
+ = Declarative Authorization with I18n support
2
+
3
+ This is a fork of Steffen Bartsch's declarative_authorization[http://github.com/stffn/declarative_authorization/tree] equipped with localization
4
+ based on Rails default I18n.
5
+
6
+
7
+ = Usage
8
+
9
+
data/Rakefile ADDED
@@ -0,0 +1,43 @@
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
36
+
37
+ desc "Expand filelist in src gemspec"
38
+ task :build_gemspec do
39
+ gemspec_data = File.read("declarative_authorization.gemspec.src")
40
+ gemspec_data.gsub!(/\.files = (.*)/) {|m| ".files = #{eval($1).inspect}"}
41
+ File.open("declarative_authorization.gemspec", "w") {|f| f.write(gemspec_data)}
42
+ end
43
+
@@ -0,0 +1,114 @@
1
+ if Authorization::activate_authorization_rules_browser?
2
+
3
+ require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization authorization_rules_analyzer})
4
+
5
+ begin
6
+ # for nice auth_rules output:
7
+ require "parse_tree"
8
+ require "parse_tree_extensions"
9
+ require "ruby2ruby"
10
+ rescue LoadError; end
11
+
12
+ class AuthorizationRulesController < ApplicationController
13
+ unloadable
14
+
15
+ filter_access_to :all, :require => :read
16
+ def index
17
+ respond_to do |format|
18
+ format.html do
19
+ @auth_rules_script = File.read("#{RAILS_ROOT}/config/authorization_rules.rb")
20
+ end
21
+ end
22
+ end
23
+
24
+ def graph
25
+ if params[:format] == "svg"
26
+ render :text => dot_to_svg(auth_to_dot(graph_options)),
27
+ :content_type => "image/svg+xml"
28
+ end
29
+ end
30
+
31
+ private
32
+ def auth_to_dot (options = {})
33
+ options = {
34
+ :effective_role_privs => true,
35
+ :privilege_hierarchy => false,
36
+ :only_relevant_contexts => true,
37
+ :filter_roles => nil,
38
+ :filter_contexts => nil,
39
+ :highlight_privilege => nil
40
+ }.merge(options)
41
+
42
+ @highlight_privilege = options[:highlight_privilege]
43
+ @roles = authorization_engine.roles
44
+ @roles = @roles.select {|r| r == options[:filter_roles] } if options[:filter_roles]
45
+ @role_hierarchy = authorization_engine.role_hierarchy
46
+ @privilege_hierarchy = authorization_engine.privilege_hierarchy
47
+
48
+ @contexts = authorization_engine.auth_rules.
49
+ collect {|ar| ar.contexts.to_a}.flatten.uniq
50
+ @contexts = @contexts.select {|c| c == options[:filter_contexts] } if options[:filter_contexts]
51
+ @context_privs = {}
52
+ @role_privs = {}
53
+ authorization_engine.auth_rules.each do |auth_rule|
54
+ @role_privs[auth_rule.role] ||= []
55
+ auth_rule.contexts.
56
+ select {|c| options[:filter_contexts].nil? or c == options[:filter_contexts]}.
57
+ each do |context|
58
+ @context_privs[context] ||= []
59
+ @context_privs[context] += auth_rule.privileges.to_a
60
+ @context_privs[context].uniq!
61
+ @role_privs[auth_rule.role] += auth_rule.privileges.collect {|p| [context, p, auth_rule.attributes.empty?, auth_rule.to_long_s]}
62
+ end
63
+ end
64
+
65
+ if options[:effective_role_privs]
66
+ @roles.each do |role|
67
+ @role_privs[role] ||= []
68
+ (@role_hierarchy[role] || []).each do |lower_role|
69
+ @role_privs[role].concat(@role_privs[lower_role]).uniq!
70
+ end
71
+ end
72
+ end
73
+
74
+ if options[:only_relevant_contexts]
75
+ @contexts.delete_if {|context| @roles.all? {|role| !@role_privs[role] || !@role_privs[role].any? {|info| info[0] == context}}}
76
+ end
77
+
78
+ if options[:privilege_hierarchy]
79
+ @context_privs.each do |context, privs|
80
+ privs.each do |priv|
81
+ context_lower_privs = (@privilege_hierarchy[priv] || []).
82
+ select {|p,c| c.nil? or c == context}.
83
+ collect {|p,c| p}
84
+ privs.concat(context_lower_privs).uniq!
85
+ end
86
+ end
87
+ end
88
+
89
+ render_to_string :template => 'authorization_rules/graph.dot.erb', :layout => false
90
+ end
91
+
92
+ def dot_to_svg (dot_data)
93
+ gv = IO.popen("#{Authorization.dot_path} -q -Tsvg", "w+")
94
+ gv.puts dot_data
95
+ gv.close_write
96
+ gv.read
97
+ rescue IOError, Errno::EPIPE => e
98
+ raise Exception, "#{I18n.t(:error_in_call_to_graphviz, :scope => [:declarative_authorization])}: #{e}"
99
+ end
100
+
101
+ def graph_options
102
+ {
103
+ :effective_role_privs => !params[:effective_role_privs].blank?,
104
+ :privilege_hierarchy => !params[:privilege_hierarchy].blank?,
105
+ :filter_roles => params[:filter_roles].blank? ? nil : params[:filter_roles].to_sym,
106
+ :filter_contexts => params[:filter_contexts].blank? ? nil : params[:filter_contexts].to_sym,
107
+ :highlight_privilege => params[:highlight_privilege].blank? ? nil : params[:highlight_privilege].to_sym
108
+ }
109
+ end
110
+ end
111
+
112
+ else
113
+ class AuthorizationRulesController < ApplicationController; end
114
+ 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,100 @@
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', 'includes', 'privilege', 'to'],
7
+ :operator => ['is', 'contains'],
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::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] ||= []
31
+ memo[report.line] << report
32
+ memo
33
+ end
34
+ reports_by_line.each do |line, reports|
35
+ note = %Q{<span class="note" title="#{reports.first.type}: #{reports.first.message}">[i]</span>}
36
+ marked_up_by_line[line - 1] = note + marked_up_by_line[line - 1]
37
+ end
38
+ marked_up_by_line * "\n"
39
+ end
40
+
41
+ def link_to_graph (title, options = {})
42
+ type = options[:type] || ''
43
+ link_to_function title, "$$('object')[0].data = '#{url_for :action => 'index', :format => 'svg', :type => type}'"
44
+ end
45
+
46
+ def navigation
47
+ link_to(I18n.t(:rules, :scope => [:declarative_authorization]), authorization_rules_path) << ' | ' <<
48
+ link_to(I18n.t(:graphical_view, :scope => [:declarative_authorization]), graph_authorization_rules_path) << ' | ' <<
49
+ link_to(I18n.t(:usages, :scope => [:declarative_authorization]), authorization_usages_path) #<< ' | ' <<
50
+ # 'Edit | ' <<
51
+ # link_to("XACML export", :action => 'index', :format => 'xacml')
52
+ end
53
+
54
+ def role_color (role, fill = false)
55
+ fill_colors = %w{#ffdddd #ddffdd #ddddff #ffffdd #ffddff #ddffff}
56
+ colors = %w{#dd0000 #00dd00 #0000dd #dddd00 #dd00dd #00dddd}
57
+ @@role_colors ||= {}
58
+ @@role_colors[role] ||= begin
59
+ idx = @@role_colors.length % colors.length
60
+ [colors[idx], fill_colors[idx]]
61
+ end
62
+ @@role_colors[role][fill ? 1 : 0]
63
+ end
64
+
65
+ def role_fill_color (role)
66
+ role_color(role, true)
67
+ end
68
+
69
+ def auth_usage_info_classes (auth_info)
70
+ classes = []
71
+ if auth_info[:controller_permissions]
72
+ if auth_info[:controller_permissions][0]
73
+ classes << "catch-all" if auth_info[:controller_permissions][0].actions.include?(:all)
74
+ classes << "default-privilege" unless auth_info[:controller_permissions][0].privilege
75
+ classes << "default-context" unless auth_info[:controller_permissions][0].context
76
+ classes << "no-attribute-check" unless auth_info[:controller_permissions][0].attribute_check
77
+ end
78
+ else
79
+ classes << "unprotected"
80
+ end
81
+ classes * " "
82
+ end
83
+
84
+ def auth_usage_info_title (auth_info)
85
+ titles = []
86
+ if auth_usage_info_classes(auth_info) =~ /unprotected/
87
+ titles << I18n.t(:no_filter_access_to_call_protects_this_action, :scope => [:declarative_authorization])
88
+ end
89
+ if auth_usage_info_classes(auth_info) =~ /no-attribute-check/
90
+ titles << I18n.t(:action_is_not_protected_with_attribute_check, :scope => [:declarative_authorization])
91
+ end
92
+ if auth_usage_info_classes(auth_info) =~ /default-privilege/
93
+ titles << I18n.t(:privilege_set_automatically_from_action_name_by_all_rule, :scope => [:declarative_authorization])
94
+ end
95
+ if auth_usage_info_classes(auth_info) =~ /default-context/
96
+ titles << I18n.t(:context_set_automatically_from_controller_name_by_filter_access_to_call_without_context_option, :scope => [:declarative_authorization])
97
+ end
98
+ titles * ". "
99
+ end
100
+ end
@@ -0,0 +1,49 @@
1
+
2
+ digraph rules {
3
+ compound = true
4
+ edge [arrowhead=open]
5
+ node [shape=box,fontname="sans-serif",fontsize="16"]
6
+ fontname="sans-serif";fontsize="16"
7
+ ranksep = "0.3"
8
+ //concentrate = true
9
+ rankdir = TB
10
+ {
11
+ node [shape=ellipse,style=filled]
12
+ //rank = source
13
+ <% @roles.each do |role| %>
14
+ "<%= role.inspect %>" [fillcolor="<%= role_fill_color(role) %>"]
15
+ // ,URL="javascript:set_filter({roles: '<%= role %>'})"
16
+ <% end %>
17
+ <% @roles.each do |role| %>
18
+ <% (@role_hierarchy[role] || []).each do |lower_role| %>
19
+ "<%= role.inspect %>" -> "<%= lower_role.inspect %>" [constraint=false,arrowhead=empty]
20
+ <% end %>
21
+ <% end %>
22
+ }
23
+
24
+ <% @contexts.each do |context| %>
25
+ subgraph cluster_<%= context %> {
26
+ label = "<%= context.inspect %>"
27
+ style=filled; fillcolor="#eeeeee"
28
+ node[fillcolor=white,style=filled]
29
+ <% (@context_privs[context] || []).each do |priv| %>
30
+ <%= priv %>_<%= context %> [label="<%= priv.inspect %>"<%= ',fontcolor="#ff0000"' if @highlight_privilege == priv %>]
31
+ <% end %>
32
+ <% (@context_privs[context] || []).each do |priv| %>
33
+ <% (@privilege_hierarchy[priv] || []).
34
+ select {|p,c| (c.nil? or c == context) and @context_privs[context].include?(p)}.
35
+ each do |lower_priv, c| %>
36
+ <%= priv %>_<%= context %> -> <%= lower_priv %>_<%= context %> [arrowhead=empty]
37
+ <% end %>
38
+ <% end %>
39
+ //read_conferences -> update_conferences [style=invis]
40
+ //create_conferences -> delete_conferences [style=invis]
41
+ }
42
+ <% end %>
43
+
44
+ <% @roles.each do |role| %>
45
+ <% (@role_privs[role] || []).each do |context, privilege, unconditionally, attribute_string| %>
46
+ "<%= role.inspect %>" -> <%= privilege %>_<%= context %> [color="<%= role_color(role) %>", minlen=3<%= ", arrowhead=opendot, URL=\"javascript:\", edgetooltip=\"#{attribute_string.gsub('"','')}\"" unless unconditionally %>]
47
+ <% end %>
48
+ <% end %>
49
+ }
@@ -0,0 +1,39 @@
1
+ <h1><%= I18n.t(:authorization_rules_graph, :scope => [:declarative_authorization]) %></h1>
2
+ <p><%= I18n.t(:currently_active_rules_in_this_application, :scope => [:declarative_authorization]) %></p>
3
+ <p><%= navigation %></p>
4
+
5
+ <% javascript_tag do %>
6
+ function update_graph (form) {
7
+ base_url = "<%= url_for :format => 'svg' %>";
8
+ $('graph').data = base_url + '?' + form.serialize();
9
+ }
10
+
11
+ function set_filter (filter) {
12
+ for (f in filter) {
13
+ var select = $("filter_" + f);
14
+ if (select) {
15
+ var opt = select.down("option[value='"+ filter[f] + "']");
16
+ if (opt) {
17
+ opt.selected = true;
18
+ update_graph(select.form);
19
+ }
20
+ }
21
+ }
22
+ }
23
+ <% end %>
24
+ <p>
25
+ <% form_tag do %>
26
+ <%#= link_to_graph I18n.t(:rules, :scope => [:declarative_authorization]) %>
27
+ <%#= link_to_graph I18n.t(:privilege_hierarchy, :scope => [:declarative_authorization]), :type => 'priv_hierarchy' %>
28
+
29
+ <%= select_tag "filter_roles", options_for_select([[I18n.t(:all_rules, :scope => [:declarative_authorization]),'']] + controller.authorization_engine.roles.map(&:to_s).sort), :onchange => 'update_graph(this.form)' %>
30
+ <%= select_tag "filter_contexts", options_for_select([[I18n.t(:all_contexts, :scope => [:declarative_authorization]),'']] + controller.authorization_engine.auth_rules.collect {|ar| ar.contexts.to_a}.flatten.uniq.map(&:to_s).sort), :onchange => 'update_graph(this.form)' %>
31
+ <%= check_box_tag "effective_role_privs", "1", false, :onclick => 'update_graph(this.form)' %> <%= label_tag "effective_role_privs", I18n.t(:effective_privileges, :scope => [:declarative_authorization]) %>
32
+ <%= check_box_tag "privilege_hierarchy", "1", false, :onclick => 'update_graph(this.form)' %> <%= label_tag "privilege_hierarchy", I18n.t(:show_full_privilege_hierarchy, :scope => [:declarative_authorization]) %>
33
+ <% end %>
34
+ </p>
35
+ <div style="margin: 1em;border:1px solid #ccc;max-width:95%">
36
+ <object id="graph" data="<%= url_for :format => 'svg' %>" type="image/svg+xml" style="max-width:100%"/>
37
+ </div>
38
+ <%= button_to_function I18n.t(:zoom_in, :scope => [:declarative_authorization]), '$("graph").style.maxWidth = "";$(this).toggle();$(this).next().toggle()' %>
39
+ <%= button_to_function I18n.t(:zoom_out, :scope => [:declarative_authorization]), '$("graph").style.maxWidth = "100%";$(this).toggle();$(this).previous().toggle()', :style => 'display:none' %>