annotation_security 1.0.1

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 (62) hide show
  1. data/CHANGELOG +2 -0
  2. data/HOW-TO +261 -0
  3. data/MIT-LICENSE +18 -0
  4. data/README +39 -0
  5. data/Rakefile +56 -0
  6. data/assets/app/helpers/annotation_security_helper.rb +9 -0
  7. data/assets/config/initializers/annotation_security.rb +12 -0
  8. data/assets/config/security/relations.rb +20 -0
  9. data/assets/config/security/rights.yml +16 -0
  10. data/assets/vendor/plugins/annotation_security/init.rb +14 -0
  11. data/bin/annotation_security +8 -0
  12. data/lib/annotation_security/exceptions.rb +125 -0
  13. data/lib/annotation_security/exec.rb +189 -0
  14. data/lib/annotation_security/filters.rb +38 -0
  15. data/lib/annotation_security/includes/action_controller.rb +144 -0
  16. data/lib/annotation_security/includes/active_record.rb +28 -0
  17. data/lib/annotation_security/includes/helper.rb +215 -0
  18. data/lib/annotation_security/includes/resource.rb +85 -0
  19. data/lib/annotation_security/includes/role.rb +31 -0
  20. data/lib/annotation_security/includes/user.rb +27 -0
  21. data/lib/annotation_security/manager/policy_factory.rb +30 -0
  22. data/lib/annotation_security/manager/policy_manager.rb +80 -0
  23. data/lib/annotation_security/manager/relation_loader.rb +273 -0
  24. data/lib/annotation_security/manager/resource_manager.rb +36 -0
  25. data/lib/annotation_security/manager/right_loader.rb +88 -0
  26. data/lib/annotation_security/model_observer.rb +61 -0
  27. data/lib/annotation_security/policy/abstract_policy.rb +345 -0
  28. data/lib/annotation_security/policy/abstract_static_policy.rb +76 -0
  29. data/lib/annotation_security/policy/all_resources_policy.rb +21 -0
  30. data/lib/annotation_security/policy/rule.rb +340 -0
  31. data/lib/annotation_security/policy/rule_set.rb +139 -0
  32. data/lib/annotation_security/rails.rb +39 -0
  33. data/lib/annotation_security/user_wrapper.rb +74 -0
  34. data/lib/annotation_security/utils.rb +142 -0
  35. data/lib/annotation_security.rb +98 -0
  36. data/lib/extensions/action_controller.rb +33 -0
  37. data/lib/extensions/active_record.rb +35 -0
  38. data/lib/extensions/filter.rb +134 -0
  39. data/lib/extensions/object.rb +11 -0
  40. data/lib/security_context.rb +551 -0
  41. data/spec/annotation_security/exceptions_spec.rb +17 -0
  42. data/spec/annotation_security/includes/helper_spec.rb +82 -0
  43. data/spec/annotation_security/manager/policy_manager_spec.rb +15 -0
  44. data/spec/annotation_security/manager/resource_manager_spec.rb +17 -0
  45. data/spec/annotation_security/manager/right_loader_spec.rb +17 -0
  46. data/spec/annotation_security/policy/abstract_policy_spec.rb +17 -0
  47. data/spec/annotation_security/policy/all_resources_policy_spec.rb +24 -0
  48. data/spec/annotation_security/policy/rule_set_spec.rb +112 -0
  49. data/spec/annotation_security/policy/rule_spec.rb +78 -0
  50. data/spec/annotation_security/policy/test_policy_spec.rb +81 -0
  51. data/spec/annotation_security/security_context_spec.rb +78 -0
  52. data/spec/annotation_security/utils_spec.rb +74 -0
  53. data/spec/helper/test_controller.rb +66 -0
  54. data/spec/helper/test_helper.rb +5 -0
  55. data/spec/helper/test_relations.rb +7 -0
  56. data/spec/helper/test_resource.rb +39 -0
  57. data/spec/helper/test_rights.yml +5 -0
  58. data/spec/helper/test_role.rb +22 -0
  59. data/spec/helper/test_user.rb +32 -0
  60. data/spec/rails_stub.rb +38 -0
  61. data/spec/spec_helper.rb +43 -0
  62. metadata +157 -0
@@ -0,0 +1,189 @@
1
+ require 'optparse'
2
+ require 'fileutils'
3
+
4
+ # = lib/annotation_security/exec.rb
5
+ # This file is borrowed heavily from HAML
6
+ #
7
+
8
+ module AnnotationSecurity
9
+ module Exec # :nodoc:
10
+
11
+ # An abstract class that encapsulates the executable
12
+ # code for all executables.
13
+ class Generic # :nodoc:
14
+
15
+ # Parsed options
16
+ def options
17
+ @options ||= {}
18
+ end
19
+
20
+ # @param args [Array<String>] The command-line arguments
21
+ def initialize(args)
22
+ @args = args
23
+ end
24
+
25
+ # Parses the command-line arguments and runs the executable.
26
+ # Calls `Kernel#exit` at the end, so it never returns.
27
+ def parse!
28
+ begin
29
+ @opts = OptionParser.new(&method(:set_opts))
30
+ @opts.parse!(@args)
31
+
32
+ process_result
33
+
34
+ options
35
+ rescue Exception => e
36
+ raise e if e.is_a?(SystemExit) || options[:trace]
37
+
38
+ $stderr.puts e.message
39
+ exit 1
40
+ end
41
+ exit 0
42
+ end
43
+
44
+ # @return [String] A description of the executable
45
+ def to_s
46
+ @opts.to_s
47
+ end
48
+
49
+ protected
50
+
51
+ # Tells optparse how to parse the arguments
52
+ # available for all executables.
53
+ #
54
+ # This is meant to be overridden by subclasses
55
+ # so they can add their own options.
56
+ #
57
+ # @param opts [OptionParser]
58
+ def set_opts(opts)
59
+ opts.on("--force", "Force command execution, override assets without asking") do
60
+ options[:force] = true
61
+ end
62
+
63
+ opts.on("--trace", "Shows full stack trace in case of errors") do
64
+ options[:trace] = true
65
+ end
66
+
67
+ opts.on_tail("-?", "-h", "--help", "Show this message") do
68
+ puts opts
69
+ exit
70
+ end
71
+
72
+ opts.on_tail("-v", "--version", "Print version") do
73
+ puts("AnnotationSecurity 0.01")
74
+ exit
75
+ end
76
+ end
77
+
78
+ # Processes the options set by the command-line arguments.
79
+ #
80
+ # This is meant to be overridden by subclasses
81
+ # so they can run their respective programs.
82
+ def process_result; end
83
+ end
84
+
85
+ # An abstrac class that encapsulates the code
86
+ # specific to executables.
87
+ class RailsInstaller < Generic # :nodoc:
88
+
89
+ ASSET_FILES = %w{
90
+ config/initializers/annotation_security.rb
91
+ config/security/relations.rb
92
+ config/security/rights.yml
93
+ app/helpers/annotation_security_helper.rb
94
+ vendor/plugins/annotation_security/init.rb
95
+ }
96
+
97
+ # @param args [Array<String>] The command-line arguments
98
+ def initialize(args)
99
+ super
100
+ @name = "annosec"
101
+ end
102
+
103
+ protected
104
+
105
+ # Tells optparse how to parse the arguments.
106
+ #
107
+ # This is meant to be overridden by subclasses
108
+ # so they can add their own options.
109
+ #
110
+ # @param opts [OptionParser]
111
+ def set_opts(opts)
112
+ opts.banner = <<END
113
+ Usage: #{@name.downcase} [options]
114
+
115
+ Description:
116
+ Installs the AnnotationSecurity layer into a rails app
117
+
118
+ Options:
119
+ END
120
+
121
+ opts.on('--rails RAILS_DIR', "Install AnnotationSecurity layer from the Gem to a Rails project") do |dir|
122
+ options[:rails_dir] = dir
123
+ end
124
+
125
+ super
126
+ end
127
+
128
+ # Processes the options set by the command-line arguments.
129
+ # In particular, sets `@options[:for_engine][:filename]` to the input filename
130
+ # and requires the appropriate file.
131
+ #
132
+ # This is meant to be overridden by subclasses
133
+ # so they can run their respective programs.
134
+ def process_result
135
+
136
+ unless options[:rails_dir]
137
+ puts @opts
138
+ exit
139
+ end
140
+
141
+ options[:cur_dir] = File.dirname(__FILE__)
142
+ options[:assets_dir] = File.join(options[:cur_dir], '..', '..', 'assets')
143
+
144
+ assert_exists('config')
145
+ assert_exists('vendor')
146
+ assert_exists('app/helpers')
147
+
148
+ ASSET_FILES.each { |f| install_file(f) }
149
+
150
+ puts "AnnotationSecurity plugin added to #{options[:rails_dir]}"
151
+ exit
152
+ end
153
+
154
+ private
155
+
156
+ def assert_exists(dir)
157
+ dir = File.join(options[:rails_dir], dir)
158
+ unless File.exists?(dir)
159
+ if options[:force]
160
+ puts "Creating #{dir}"
161
+ FileUtils.mkdir_p dir
162
+ else
163
+ puts "Directory #{dir} does not exist"
164
+ exit
165
+ end
166
+ end
167
+ end
168
+
169
+ def install_file(f)
170
+ orign = File.join(options[:assets_dir], f)
171
+ dest = File.join(options[:rails_dir], f)
172
+
173
+ if File.exists?(dest) && !options[:force]
174
+ print "File #{dest} already exists, overwrite [y/N]? "
175
+ return if gets !~ /y/i
176
+ end
177
+
178
+ dir = File.dirname(dest)
179
+ unless File.exists?(dir)
180
+ puts "Creating #{dir}"
181
+ FileUtils.mkdir_p(dir)
182
+ end
183
+
184
+ FileUtils.install(orign, dest)
185
+ puts "Installed #{dest}"
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,38 @@
1
+ #
2
+ # = lib/annotation_security/filters.rb
3
+ #
4
+
5
+ require "active_record"
6
+
7
+ module AnnotationSecurity # :nodoc:
8
+
9
+ # Contains filters of the security layer which filter current requests,
10
+ # set up security context and apply security rules.
11
+ module Filters
12
+ # This filter is a before filter and is executed as the first filter in the
13
+ # filter chain. It initializes the security layer.
14
+ class InitializeSecurity
15
+
16
+ # Initialize current security context depending on logged_in user
17
+ def self.filter(controller)
18
+ SecurityContext.initialize(controller)
19
+ yield
20
+ end
21
+ end
22
+
23
+ # This filter is an around filter and is executed as the last filter before
24
+ # execution of action. It applies the security mechanisms.
25
+ class ApplySecurity
26
+ # Applies security policies based on current user.
27
+ def self.filter(controller)
28
+ ::ActiveRecord::Base.transaction do
29
+ rules = controller.class.descriptions_of(controller.action_name)
30
+ SecurityContext.current.eval_with_security(rules){ yield }
31
+ end
32
+ rescue AnnotationSecurity::SecurityError
33
+ SecurityContext.security_exception = $!
34
+ raise $!
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,144 @@
1
+ #
2
+ # = lib/annotation_security/includes/action_controller.rb
3
+ #
4
+
5
+ # Provides security extensions for rails controllers.
6
+ # Is included in ActionController::Base.
7
+ #
8
+ # See AnnotationSecurity::ActionController::ClassMethods.
9
+ #
10
+ module AnnotationSecurity::ActionController
11
+
12
+ def self.included(base) # :nodoc:
13
+ base.extend(ClassMethods)
14
+ base.send :include, InstanceMethods
15
+ end
16
+
17
+ # Provides security extensions for rails controllers on the class side.
18
+ #
19
+ module ClassMethods
20
+
21
+ # Filters are not affected by the security settings of the action.
22
+ # If you want security checkings in your filters, activate them with
23
+ # +apply_security+.
24
+ #
25
+ # apply_security :get_user
26
+ #
27
+ # private
28
+ #
29
+ # desc "shows a user"
30
+ # def get_user
31
+ # @user = User.find params[:id]
32
+ # end
33
+ #
34
+ # You can use +apply_security+ to secure any methods, not only filters.
35
+ # Notice that these rules are *not* taken into account when evaluating
36
+ # AnnotationSecurity::Helper#link_to_if_allowed and similar methods.
37
+ #
38
+ def apply_security(*symbols)
39
+ symbols.each { |s| pending_security_wrappers << s.to_sym }
40
+ end
41
+
42
+ # Filters are not affected by the security settings of the action.
43
+ # If you want the security settings of the action applied to your filter,
44
+ # use this method. It can be combined with #apply_security
45
+ def apply_action_security(*symbols)
46
+ symbols.each { |s| pending_action_security_wrappers << s.to_sym }
47
+ end
48
+
49
+ # AnnotationSecurity is using the +method_added+ callback. If this method
50
+ # is overwritten without calling +super+, +apply_security+ will not work.
51
+ #
52
+ def method_added(method)
53
+ super(method)
54
+ if pending_security_wrappers.delete method
55
+ build_security_wrapper(method)
56
+ end
57
+ if pending_action_security_wrappers.delete method
58
+ build_action_security_wrapper(method)
59
+ end
60
+ end
61
+
62
+ # If no resource type is provided in a description, the default resource
63
+ # will be used. Once set the value cannot be changed.
64
+ #
65
+ # This is still experimental. You should not use it unless you have a
66
+ # reason. It might be usefull for inheritance.
67
+ #
68
+ def default_resource(value=nil)
69
+ @default_resource ||= value || compute_default_resource
70
+ end
71
+
72
+ # Creates a new security filter.
73
+ #
74
+ # Security filters are around filters that are evaluated before the first
75
+ # before filter. Use security filters to set the credentials and to react
76
+ # to security violations.
77
+ # class ApplicationController < ActionController::Base
78
+ #
79
+ # security_filter :security_filter
80
+ #
81
+ # private
82
+ #
83
+ # def security_filter
84
+ # SecurityContext.current_credential = session[:user]
85
+ # yield
86
+ # rescue SecurityViolationError
87
+ # if SecurityContext.is? :logged_in
88
+ # render :template => "welcome/not_allowed"
89
+ # else
90
+ # render :template => "welcome/please_login"
91
+ # end
92
+ # end
93
+ #
94
+ # See SecurityContext#current_credential= and SecurityViolationError.
95
+ #
96
+ def security_filter(symbol, &block)
97
+ filter_chain.append_filter_to_chain([symbol], :security, &block)
98
+ end
99
+
100
+ private
101
+
102
+ def pending_security_wrappers
103
+ @pending_security_wrappers ||= []
104
+ end
105
+
106
+ def pending_action_security_wrappers
107
+ @pending_action_security_wrappers ||= []
108
+ end
109
+
110
+ def build_security_wrapper(method)
111
+ no_security = "#{method}_without_security".to_sym
112
+ class_eval %{
113
+ alias :#{no_security} :#{method}
114
+ def #{method}(*args, &proc)
115
+ rules = self.class.descriptions_of(:#{method})
116
+ SecurityContext.current.send_with_security(rules, self, :#{no_security}, *args, &proc)
117
+ end
118
+ }
119
+ end
120
+
121
+ def build_action_security_wrapper(method)
122
+ no_security = "#{method}_without_action_security".to_sym
123
+ class_eval %{
124
+ alias :#{no_security} :#{method}
125
+ def #{method}(*args, &proc)
126
+ rules = self.class.descriptions_of(action_name)
127
+ SecurityContext.current.send_with_security(rules, self, :#{no_security}, *args, &proc)
128
+ end
129
+ }
130
+ end
131
+
132
+ def compute_default_resource
133
+ name.first(-"Controller".length).singularize.underscore.to_sym
134
+ end
135
+
136
+ end
137
+
138
+ module InstanceMethods # :nodoc:
139
+
140
+ def security_exception=(ex)
141
+ @security_exception = ex
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,28 @@
1
+ #
2
+ # = lib/annotation_security/includes/active_record.rb
3
+ #
4
+
5
+ # = AnnotationSecurity::ActiveRecord
6
+ #
7
+ # Included by model classes if they are used as resources.
8
+ # Includes AnnotationSecurity::Resource and sets up the model observer.
9
+ #
10
+ module AnnotationSecurity::ActiveRecord # :nodoc:
11
+
12
+ def self.included(base)
13
+ base.class_eval do
14
+ include ::AnnotationSecurity::Resource
15
+ end
16
+ base.extend(ClassMethods)
17
+ AnnotationSecurity::ModelObserver.observe base.name.underscore.to_sym
18
+ AnnotationSecurity::ModelObserver.instance.reload_model_observer
19
+ end
20
+
21
+ module ClassMethods # :nodoc:
22
+ def get_resource(object)
23
+ return object if object.is_a? self
24
+ # Object.const_get(name) needed because of a bug in Rails
25
+ Object.const_get(name).find(object)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,215 @@
1
+ #
2
+ # = lib/annotation_security/includes/helper.rb
3
+ #
4
+
5
+ # = AnnotationSecurity::Helper
6
+ #
7
+ # This module adds some useful helper methods to your templates.
8
+ #
9
+ module AnnotationSecurity::Helper
10
+
11
+ # Returns true if the operation defined by +policy_args+ is allowed.
12
+ #
13
+ # The following calls to #allowed? are possible:
14
+ #
15
+ # allowed? :show, :resource, @resource
16
+ # # => true if the current user has the right to show @resource,
17
+ # # which belongs to the :resource resource-class
18
+ #
19
+ # In case of model objects or other classes which implement a #resource_type
20
+ # method the the second argument may be ommited
21
+ #
22
+ # allowed? :show, @resource
23
+ # # equivalent to the above call if @resource.resource_type == :resource
24
+ #
25
+ # A policy description used as a controller annotation may also be used
26
+ # to check a right
27
+ #
28
+ # allowed? "show resource", @resource
29
+ # # => true if the current user has the right "show resource" for @resource
30
+ #
31
+ # A policy may also be applied without an object representing the context:
32
+ #
33
+ # allowed? :show, :resource
34
+ # # => true if the current may show resources.
35
+ #
36
+ # This will only check system and pretest rules. The result +true+ does not
37
+ # mean that the user may show all resources. However, a +false+ indicates
38
+ # that the user is not allowed to show any resources.
39
+ #
40
+ # If the resource class is omitted as well, only rules defined for all
41
+ # resources can be tested. See RelationLoader#all_resources for details.
42
+ #
43
+ # allowed? :administrate
44
+ # # => true if the user is allowed to administrate all resources.
45
+ #
46
+ # See SecurityContext#allowed?.
47
+ #
48
+ def allowed?(*args)
49
+ SecurityContext.allowed?(*args)
50
+ end
51
+
52
+ alias a? allowed?
53
+
54
+ # Equivalent to allowed?; is? is provided for better readability.
55
+ #
56
+ # allowed? :logged_in
57
+ # vs
58
+ # is? :logged_in
59
+ #
60
+ def is?(*args)
61
+ SecurityContext.is?(*args)
62
+ end
63
+
64
+ # Checks whether the user is allowed to access the action.
65
+ #
66
+ # Expects arguments like #link_to_if_allowed, just without name and block.
67
+ #
68
+ # Returns true if the action is allowed.
69
+ #
70
+ def action_allowed?(options, objects=nil, params=nil, html_options=nil)
71
+
72
+ options, objects, params, html_options =
73
+ parse_allow_action_args(options, objects, params, html_options)
74
+
75
+ controller = params.delete :controller
76
+ action = params.delete :action
77
+ SecurityContext.allow_action?(controller, action, objects, params)
78
+ end
79
+
80
+ # Returns a link tag with the specified name to the specified resource if
81
+ # the user is allowed to access it. See #link_to_unless and
82
+ # SecurityContext#action_allowed? for more documentation.
83
+ #
84
+ # There are two ways of using #link_to_if_allowed
85
+ #
86
+ # === As #link_to with alternative
87
+ # (or as #link_to_unless without explicit condition)
88
+ # link_to_if_allowed(name, options={}, html_options=nil) { 'alternative' }
89
+ # +options+ either is a hash, like
90
+ # { :controller => :comments, :action => edit, :id => @comment }
91
+ # a string, like
92
+ # "comments/1/edit"
93
+ # or
94
+ # edit_comment_path(@comment)
95
+ # or a single resource object.
96
+ #
97
+ # Notice that when providing a string, controller, action and parameters will
98
+ # be parsed. After that, the resource types of the parameters are *guessed*,
99
+ # the resources are retrieved and the rules of the action are evaluated.
100
+ #
101
+ # The block will be evaluated if the action is not allowed,
102
+ # like in #link_to_unless.
103
+ #
104
+ # === As #link_to with alternative and explicit objects
105
+ # link_to_if_allowed(name, options={}, objects=[], params={}, html_options=nil) { 'alternative' }
106
+ # In this case, controller and action will be derived from +options+ unless
107
+ # they are specified in +params+.
108
+ # All items in +objects+ and all remaining items in +params+ will be used
109
+ # for evaluating the rules of the action.
110
+ #
111
+ # If you want to specify +html_options+, provide at least an empty hash
112
+ # for +params+.
113
+ #
114
+ # Unlike to #link_to, you can also provide a symbol as +options+ value.
115
+ # In this case, the target url will be determined by sending symbol as
116
+ # message, providing +objects+ and +params+ as arguments, e.g.
117
+ # link_to_if_allowed("Show comment", :comment_path, [@article, @comment], {:details => true})
118
+ # will call
119
+ # comment_path(@article, @comment, {:details => true})
120
+ #
121
+ # === Examples
122
+ # <%= link_to_if_allowed("Show", @course) { } %>
123
+ # <%= link_to_if_allowed("New", new_course_path) { "You may not create a new course." } %>
124
+ #
125
+ # These two are equivalent, however, the second approach is more efficient:
126
+ # <%= link_to_if_allowed("Edit", edit_course_path(@course)) { } %>
127
+ # <%= link_to_if_allowed("Edit", :edit_course_path, @course) { } %>
128
+ #
129
+ # The HTML-options are taken into account when choosing the action.
130
+ # <%= link_to_if_allowed("Delete", @course, {:method => :delete}) { } %>
131
+ #
132
+ # You can also define all values explicitly
133
+ # <%= link_to_if_allowed("Edit comment", "articles/1/comments/5/edit", [@comment], {:article => @comment.article, :action => :edit, :controller => :comments}) { } %>
134
+ #
135
+ # === Parameters
136
+ # - +name+ Text of the link
137
+ # - +options+
138
+ # - +objects+
139
+ # - +params+
140
+ # - +html_options+
141
+ #
142
+ def link_to_if_allowed(name, options, objects=nil, params=nil, html_options=nil, &block)
143
+
144
+ options, objects, params, html_options =
145
+ parse_allow_action_args(options, objects, params, html_options)
146
+
147
+ controller = params.delete :controller
148
+ action = params.delete :action
149
+ allowed = SecurityContext.allow_action?(controller, action, objects, params)
150
+
151
+ link_to_if(allowed, name, options, html_options, &block)
152
+ end
153
+
154
+ alias link_if_a link_to_if_allowed
155
+
156
+ private
157
+
158
+ def parse_allow_action_args(*args)
159
+ if args.second && !(args.second.is_a? Hash)
160
+ # objects and params are specified
161
+ options, objects, params, html_options = args
162
+ objects = [objects] unless objects.is_a? Array
163
+ params ||= {}
164
+ html_options ||= {}
165
+ if options.is_a? Symbol
166
+ # options is a symbol, send the message to get the link path
167
+ path_args = objects + [params]
168
+ options = send(options, *path_args)
169
+ end
170
+ else
171
+ # retrieve objects and params from options
172
+ options = args.first
173
+ html_options = args.second || {}
174
+ objects = [] # everything will be in the params
175
+ if options.is_a? Hash
176
+ params = options.dup
177
+ else
178
+ params = parse_action_params(options, html_options)
179
+ end
180
+ end
181
+
182
+ unless params[:controller] && params[:action]
183
+ # if controller and action are not given, parse from options
184
+ params = parse_controller_action(options, params, html_options)
185
+ end
186
+
187
+ [options, objects, params, html_options]
188
+ end
189
+
190
+ # uses options and html_options to retrieve controller and action,
191
+ # adds these values to params hash
192
+ def parse_controller_action(options, params, html_options)
193
+ path_info = get_path_info(options, html_options)
194
+ params[:controller] ||= path_info[:controller]
195
+ params[:action] ||= path_info[:action]
196
+ params
197
+ end
198
+
199
+ # uses options and html_options to retrieve controller, action
200
+ # and params
201
+ def parse_action_params(options, html_options)
202
+ get_path_info(options, html_options)
203
+ end
204
+
205
+ def get_path_info(options, html_options)
206
+ if options.is_a? String
207
+ path = options
208
+ else
209
+ path = url_for(options)
210
+ end
211
+ env = { :method => (html_options[:method] || :get ) }
212
+ ActionController::Routing::Routes.recognize_path(path, env)
213
+ end
214
+
215
+ end
@@ -0,0 +1,85 @@
1
+ #
2
+ # = lib/annotation_security/includes/resource.rb
3
+ #
4
+
5
+ # Must be included by all classes that are resource classes and do not extend
6
+ # ActiveRecord::Base.
7
+ #
8
+ # class MailDispatcher
9
+ # include AnnotationSecurity::Resource
10
+ # resource_type = :email
11
+ # ...
12
+ #
13
+ # See AnnotationSecurity::Resource::ClassMethods.
14
+ #
15
+ module AnnotationSecurity::Resource
16
+
17
+ def self.included(base) # :nodoc:
18
+ base.extend(ClassMethods)
19
+ base.class_eval do
20
+ include InstanceMethods
21
+ end
22
+ end
23
+
24
+ # Provides class side methods for resource classes.
25
+ module ClassMethods
26
+
27
+ # Registers the class as a resource.
28
+ #
29
+ def resource_type=(symbol)
30
+ @resource_type = symbol
31
+ AnnotationSecurity::ResourceManager.add_resource_class(symbol,self)
32
+ symbol
33
+ end
34
+
35
+ def resource_type # :nodoc:
36
+ @resource_type || (self.resource_type = name.underscore.to_sym)
37
+ end
38
+
39
+ def policy_for(user,obj=nil) # :nodoc:
40
+ policy_factory.create_policy(user,obj)
41
+ end
42
+
43
+ # If required, overwrite this method to return a resource object identified
44
+ # by the argument.
45
+ #
46
+ # This might be necessary if you change the to_param method of an
47
+ # ActiveRecord class.
48
+ #
49
+ # class Course < ActiveRecord::Base
50
+ # ...
51
+ # # each course has a unique name --> make better urls
52
+ # def to_param
53
+ # name
54
+ # end
55
+ #
56
+ # def self.get_resource(name)
57
+ # find_by_name(name)
58
+ # end
59
+ #
60
+ def get_resource(arg)
61
+ raise NoMethodError, "#{self} does not implement #get_resource"
62
+ end
63
+
64
+ private
65
+
66
+ def policy_factory # :nodoc:
67
+ @policy_factory ||= AnnotationSecurity::PolicyManager.policy_factory(resource_type)
68
+ end
69
+
70
+ end
71
+
72
+ module InstanceMethods # :nodoc:
73
+ def resource_type
74
+ self.class.resource_type
75
+ end
76
+
77
+ def __is_resource?
78
+ true
79
+ end
80
+
81
+ def policy_for(user)
82
+ self.class.policy_for(user,self)
83
+ end
84
+ end
85
+ end