annotation_security 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ = 1.0.1
2
+ * first public release
data/HOW-TO ADDED
@@ -0,0 +1,261 @@
1
+ = How to secure your Rails application with Annotation Security
2
+
3
+ == Step 0: Installing Annotation Security
4
+
5
+ Annotation Security comes as a gem hosted on rubygems.org. You can install it
6
+ via <tt>gem install annotation_security</tt>.
7
+ The gem contains a binary called <tt>annotation_security</tt>. It can be used to
8
+ install the security layer into a rails app via
9
+ <tt>annotation_security --rails RAILS_HOME</tt>. This will make your app ready to be
10
+ secured.
11
+
12
+ == Step 1: Defining user and roles
13
+
14
+ Annotation Security assumes that there is a user class, representing the user,
15
+ and some role classes containing additional information if the user has a
16
+ certain role in the application.
17
+
18
+ If you don't have user or role classes in your application,
19
+ continue with step 2.
20
+
21
+ === User
22
+
23
+ In most cases the user class will be a subclass of ActiveRecord::Base,
24
+ but this is not necessary.
25
+
26
+ Include the module AnnotationSecurity::User into this class.
27
+
28
+ class User < ActiveRecord::Base
29
+ include AnnotationSecurity::User
30
+ ...
31
+
32
+ === Roles
33
+
34
+ Include the module AnnotationSecurity::Role into these classes. If you are
35
+ having a hierachy of role classes, only include the module in the topmost class.
36
+
37
+ class Role < ActiveRecord::Base
38
+ belongs_to :user
39
+ include AnnotationSecurity::Role
40
+ ...
41
+
42
+ class Student < Role
43
+ # no include here
44
+ ...
45
+
46
+ A role object should respond to +user+ with returning the user object
47
+ it belongs to.
48
+
49
+ Do not include both modules in one class!
50
+
51
+ === Connecting user and roles
52
+
53
+ As next, you should provide some default methods for accessing the roles
54
+ of a user. You can skip this step, but it will be helpfull later on.
55
+
56
+ There are two types of access methods: <tt>is_ROLE?</tt> and +as_ROLE+.
57
+
58
+ IS-methods return true or false whether a user has a role or not.
59
+ class User < ActiveRecord::Base
60
+ def is_administrator?
61
+ self.admin_flag == 1
62
+ end
63
+ def is_student?
64
+ self.roles.any? { |role| role.is_a? Student }
65
+ end
66
+ ...
67
+
68
+ AS-methods return a single object or an array of objects representing the role.
69
+ If the user does not have the role, the result should be an empty array or nil.
70
+ class User < ActiveRecord::Base
71
+ def as_administrator
72
+ # there is no administrator class, just return the user
73
+ is_administrator? ? self : nil
74
+ end
75
+ def as_student
76
+ # assuming a user can only be student once
77
+ self.roles.detect { |role| role.is_a? Student }
78
+ end
79
+ def as_corrector
80
+ # assuming a user can be a corrector several times
81
+ self.roles.select { |role| role.is_a? Corrector }
82
+ end
83
+
84
+ == Step 2: Providing the current credential
85
+
86
+ To evaluate the security policies, for each request the current credential has
87
+ to be provided. Therefore, a new filter type was introduced: security filters
88
+ are around filters that are always the first in the filter chain. You can also
89
+ use these filters to react to security violations.
90
+
91
+ In this example, the user is simply fetched from the session. However, you
92
+ could also pass a symbol or a string (e.g. if you are using API-keys).
93
+
94
+ Passing +nil+ will be interpreted as not being authenticated in any way.
95
+
96
+ class ApplicationController < ActionController::Base
97
+
98
+ security_filter :security_filter
99
+
100
+ private
101
+
102
+ def security_filter
103
+ SecurityContext.current_credential = session[:user]
104
+ yield
105
+ rescue SecurityViolationError
106
+ if SecurityContext.is? :logged_in
107
+ render :template => "welcome/not_allowed"
108
+ else
109
+ render :template => "welcome/please_login"
110
+ end
111
+ end
112
+
113
+ Please notice that once set, the credential cannot be changed.
114
+
115
+ == Step 3: Defining your resources
116
+
117
+ Another wild assumption we made is that your application contains some resources
118
+ you want to protect. In most cases, this will be your ActiveRecord classes.
119
+ To turn them into resources, just call <tt>resource(symbol)</tt> in the class
120
+ definition.
121
+ class Course < ActiveRecord::Base
122
+ resource :course
123
+ ...
124
+ The symbol is used to further identify this class and should be unique.
125
+
126
+ It is possible (and likely) that the users and roles are resources as well.
127
+
128
+ If you want to restrict access to other resource classes, see
129
+ AnnotationSecurity::Resource for more information.
130
+
131
+ == Step 4: Defining relations and rights
132
+
133
+ in <tt>config/security</tt> you will find the files <tt>relations.rb</tt> and
134
+ <tt>rights.yml</tt>.
135
+
136
+ === Relations
137
+
138
+ The relations between the user (or the roles) and the resources are defined
139
+ as code blocks, that evaluate to true or false.
140
+
141
+ The <tt>:as</tt>-flag causes that instead of the user object, a role object
142
+ will be passed into the block (using the +as_ROLE+-method from above).
143
+ Similar, the <tt>:is</tt>-flag can be used as precondition.
144
+
145
+ AnnotationSecurity.define_relations do
146
+ resource :course do
147
+ enrolled :as => :student { |student,course| course.students.include? student }
148
+ corrector :as => :corrector { |corrector,course| corrector.corrects? course }
149
+ lecturer :as => :lecturer { |lecturer,course| lecturer.lectures? course }
150
+ end
151
+ ...
152
+
153
+ You can also define relations that are valid for all resources.
154
+ all_resources do
155
+ # corrector and lecturer are defined by the resource
156
+ responsible { corrector or lecturer }
157
+ # no block required here
158
+ administrator :is => :administrator
159
+ end
160
+
161
+ For more details and features on defining relations,
162
+ see AnnotationSecurity::RelationLoader.
163
+
164
+ === Rights
165
+
166
+ The rights of application are specified in a YAML-file, they correspond to the
167
+ actions(not necessarily the controller actions) that can be performed on a
168
+ resource. For instance, to edit a course object, you will need the edit-right
169
+ for the course resource. If you are not sure which rights your application
170
+ needs, just skip this now and return after step 5.
171
+
172
+ Rights should be valid ruby conditional statements.
173
+
174
+ course:
175
+ create: if lecturer
176
+ show: if enrolled or responsible
177
+ edit: if responsible
178
+
179
+ AnnotationSecurity provides two default relations: +logged_in+, that is true
180
+ if there is a user at all, and +self+, that can be used to determine if a user
181
+ or role resource belongs to the current user.
182
+
183
+ user:
184
+ register: unless logged_in
185
+ show: if logged_in
186
+ edit: if self or administrator
187
+ student:
188
+ show_results: if self
189
+
190
+ To improve readability, you can append 'may', 'is', 'can' or 'has' as prefix and
191
+ 'for', 'in', 'of' or 'to' as suffix to the relation name.
192
+ This is especially recommended if you are defining rights that depend on
193
+ other rights of the resource.
194
+
195
+ assignment:
196
+ edit: if responsible
197
+ delete: if may_edit
198
+
199
+ Another example can be found at AnnotationSecurity::RightLoader.
200
+
201
+ == Step 5: Securing your actions
202
+
203
+ The main goal of AnnotationSecurity was to remove security logic from
204
+ controller actions. Now you only have to define the abstract effects of an
205
+ action.
206
+
207
+ An action performs one or more tasks on different resources. You have to provide
208
+ this information as a descriptions, using the
209
+ {Action Annotation Gem}[http://comasy.nixis.de].
210
+ A description always has the form 'ACTION on RESOURCE'.
211
+
212
+ desc 'shows a course'
213
+ def show
214
+ @course = Course.find(params[:id])
215
+ end
216
+
217
+ To perform a task, the user must have the right for it. Thus, when a course is
218
+ fetched from the database during the show-action, the right course/show will be
219
+ evaluated for the current user and the course instance.
220
+
221
+ In our example, the user has to be responsible or enrolled. If both relations
222
+ evaluate to false, the right is not given and access will be denied by raising
223
+ a SecurityViolationError, which will then be catched in the security filter.
224
+
225
+ Congratulations, you Rails application is secured now.
226
+
227
+ == Step 6: Securing your views
228
+
229
+ However, actions aren't the only place with security code. Links to the actions
230
+ are shown in the view and very often, the view itself depends on the
231
+ user's rights.
232
+
233
+ When setting up Annotation Security in your Rails project, a helper will be
234
+ included automatically. The most important functions this helper provides are
235
+ <tt>allowed?</tt> and +link_to_if_allowed+.
236
+
237
+ The method <tt>allowed?</tt> expects a right and a resource and returns true iif
238
+ the current user has that right.
239
+
240
+ <% unless allowed? :edit, @course %>
241
+ <p>You may not edit this course!</p>
242
+ <% end %>
243
+
244
+ +link_to_if_allowed+ expects the same arguments as +link_to+, except it also
245
+ expects a block like +link_to_if+ (which will be called internally).
246
+
247
+ <%= link_to_if_allowed("New", new_course_path) { "You may not create a new course." } %>
248
+ <%= link_to_if_allowed("Edit", edit_course_path(@course)) { } %>
249
+ <%= link_to_if_allowed("Delete", @course, {:method => :delete}) { } %>
250
+
251
+ +link_to_if_allowed+ tries to automatically detect the accessed resources.
252
+ In case this should not work for you, see AnnotationSecurity::Helper for more
253
+ features.
254
+
255
+ == Step 7: Live long and prosper
256
+
257
+ Well, that's it. Here are some additional notes:
258
+ * in development mode, the rights and relations are reloaded with every request.
259
+ * See AnnotationSecurity::RelationLoader and AnnotationSecurity::RightLoader
260
+ for more examples and features for defining relations and rights.
261
+ * See AnnotationSecurity::Helper for more methods for securing your views.
data/MIT-LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2009 Nico Rehwaldt, Arian Treffer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,39 @@
1
+ == AnnotationSecurity plugin for Ruby on Rails
2
+
3
+ This plugin provides a security layer for rails applications. It performs access
4
+ checks based on a behavioural description of controller actions. Security rules
5
+ are defined cleanly separated from your models and controllers.
6
+
7
+ == Installation steps
8
+
9
+ The security layer is a gem and may be installed using
10
+ <tt>gem install annotation_security</tt>.
11
+
12
+ After installing the gem, run <tt>annotation_security --rails RAILS_HOME</tt> to
13
+ integrate the security layer in your rails app. Along with the
14
+ annotation_security plugin this will add
15
+
16
+ * the AnnotationSecurity::Helper in the <tt>app/helpers</tt> folder of your
17
+ rails-app. It provides some useful methods to create links and query the
18
+ security layer from views.
19
+ * example configuration files to setup the security layer under <tt>config/security</tt>
20
+ * an initializer for the security layer under <tt>config/initializer</tt>
21
+
22
+ == Where to start
23
+
24
+ You can find a basic introduction how to secure your application {here}[link:files/HOW-TO.html].
25
+ In order to get a detailed idea about how things work, have a deeper look
26
+ inside AnnotationSecurity::ActionController (how to secure your application),
27
+ AnnotationSecurity::RightLoader (how to setup rights) and
28
+ AnnotationSecurity::RelationLoader (how to setup relations).
29
+
30
+ Have a look at the view methods provided by the AnnotationSecurity::Helper as
31
+ well and at the SecurityContext which is the main entry-point for security related
32
+ functionality in the layer.
33
+
34
+ == License
35
+
36
+ Copyright Nico Rehwaldt, Arian Treffer 2009, 2010
37
+
38
+ You may use, copy and redistribute this library under the same terms as
39
+ {Ruby itself}[http://www.ruby-lang.org/en/LICENSE.txt] or under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ #
2
+ # To change this template, choose Tools | Templates
3
+ # and open the template in the editor.
4
+
5
+
6
+ require 'rubygems'
7
+ require 'rake'
8
+ require 'rake/clean'
9
+ require 'rake/gempackagetask'
10
+ require 'rake/rdoctask'
11
+ require 'spec/rake/spectask'
12
+
13
+ spec = Gem::Specification.new do |s|
14
+ s.name = 'annotation_security'
15
+ s.version = '1.0.1'
16
+ s.has_rdoc = true
17
+ s.extra_rdoc_files = ['README', 'MIT-LICENSE', 'CHANGELOG', 'HOW-TO']
18
+ s.summary = 'A role based security model for rails applications with ' +
19
+ 'descriptive definitions and automated evaluation.'
20
+ s.description =
21
+ 'AnnotationSecurity provides a role based security model with automated ' +
22
+ 'rule evaluation for Ruby on Rails. It allows you to define user-resource-'+
23
+ 'relations and rights in separate files, keeping your controllers and ' +
24
+ 'views free from any security logic. See the gem\'s homepage for an ' +
25
+ 'example.'
26
+ s.author = 'Nico Rehwaldt, Arian Treffer'
27
+ s.email = 'ruby@nixis.de'
28
+ s.homepage = 'http://tech.lefedt.de/2010/3/annotation-based-security-for-rails'
29
+ s.add_dependency 'action_annotation', '>= 1.0.1'
30
+ s.add_dependency 'activesupport', '>= 2.3.5'
31
+ s.add_development_dependency 'rspec', '>= 1.2.0'
32
+ s.add_development_dependency 'mocha', '>= 0.9.8'
33
+ s.executables = ['annotation_security']
34
+ s.files = %w(CHANGELOG MIT-LICENSE README HOW-TO Rakefile) + Dir.glob("{bin,lib,spec,assets}/**/*")
35
+ s.require_path = "lib"
36
+ s.bindir = "bin"
37
+ end
38
+
39
+ Rake::GemPackageTask.new(spec) do |p|
40
+ p.gem_spec = spec
41
+ p.need_tar = true
42
+ p.need_zip = true
43
+ end
44
+
45
+ Rake::RDocTask.new do |rdoc|
46
+ files = ['README', 'MIT-LICENSE', 'CHANGELOG', 'HOW-TO', 'lib/**/*.rb']
47
+ rdoc.rdoc_files.add(files)
48
+ rdoc.main = "README" # page to start on
49
+ rdoc.title = "Annotation Security Docs"
50
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
51
+ rdoc.options << '--line-numbers'
52
+ end
53
+
54
+ Spec::Rake::SpecTask.new do |t|
55
+ t.spec_files = FileList['spec/**/*_spec.rb']
56
+ end
@@ -0,0 +1,9 @@
1
+ #
2
+ # = app/helpers/annotation_security_helper.rb
3
+ #
4
+ # This helper provides some useful view methods to be used in conjunction with
5
+ # the plugin. See AnnotationSecurity::Helper for documentation.
6
+ #
7
+ module AnnotationSecurityHelper
8
+ include AnnotationSecurity::Helper
9
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # = config/initializers/annotation_security.rb
3
+ #
4
+ # Sets up files under <tt>config/security</tt> which hold
5
+ # the security configuration.
6
+
7
+ #
8
+ # Add your own files here if they should also be loaded.
9
+ #
10
+ AnnotationSecurity.load_relations('relations')
11
+ AnnotationSecurity.load_rights('rights')
12
+ # AnnotationSecurity.load_rights('rights', 'rb) # loads rights from a ruby file
@@ -0,0 +1,20 @@
1
+ AnnotationSecurity.define_relations do
2
+
3
+ # All relations are defined in the context of a resource.
4
+ # The block should return true iif the user has this relations.
5
+
6
+ # all_resources do
7
+ # administrator(:system, :is => :administrator)
8
+ # owner_or_admin(:pretest){ owner or administrator }
9
+ # owner(:system) { |user| user.status == :registered }
10
+ # end
11
+
12
+ # resource :album do
13
+ # owner { |user, album| album.owner == user }
14
+ # end
15
+
16
+ # resource :picture do
17
+ # owner "if owner: album"
18
+ # end
19
+
20
+ end
@@ -0,0 +1,16 @@
1
+ #all_resources:
2
+ # show: if logged_in
3
+ # edit: if may_show
4
+ # delete: if may_edit
5
+ #
6
+ #welcome:
7
+ # show: if logged_in
8
+ # register: unless logged_in
9
+ #
10
+ #picture:
11
+ # show: if owner or friend
12
+ #
13
+ #user_content:
14
+ # applies_to: picture, comment
15
+ # create: if logged_in
16
+ # edit: if owner
@@ -0,0 +1,14 @@
1
+ #
2
+ # = init.rb
3
+ #
4
+ # This file will be copied to a rails apps `vendors/plugins/annotation_security`
5
+ # directory if the annotation_security gem is installed into a rails app
6
+ # via `annosec --rails`. It will be invoked by the rails app during startup an
7
+ # loads the security layer.
8
+ #
9
+
10
+ require "annotation_security"
11
+
12
+ # Initialize security layer for rails root
13
+ puts "Initializing AnnotationSecurity security layer"
14
+ AnnotationSecurity::init_rails(binding)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # The command line to install .
3
+
4
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
5
+
6
+ require "annotation_security/exec"
7
+
8
+ AnnotationSecurity::Exec::RailsInstaller.new(ARGV).parse!
@@ -0,0 +1,125 @@
1
+ #
2
+ # = lib/annotation_security/exceptions.rb
3
+ #
4
+ # Provides some Exceptions used within AnnotationSecurity
5
+
6
+ module AnnotationSecurity
7
+
8
+ # Superclass of all security related errors thrown by anno sec
9
+ class SecurityError < StandardError # :nodoc:
10
+ end
11
+
12
+ end
13
+
14
+ # Exception indicating that some rights were violated.
15
+ #
16
+ class SecurityViolationError < AnnotationSecurity::SecurityError
17
+
18
+ def self.access_denied(user,*args) # :nodoc:
19
+ new(user,*args)
20
+ end
21
+
22
+ def initialize(user=nil,*args) # :nodoc:
23
+ if user == nil || args.empty?
24
+ super "Access denied"
25
+ else
26
+ super load_args(user,args)
27
+ end
28
+ end
29
+
30
+ def load_args(user,args) # :nodoc:
31
+ @user = user
32
+ @action,@resclass,@res = AnnotationSecurity::Utils.parse_policy_arguments(args)
33
+ "You (#@user) are missing the right '#@action' for #@resclass" +
34
+ (@res.blank? ? '' : " '#@res'")
35
+ end
36
+
37
+ # user that violated the right
38
+ #
39
+ def user
40
+ @user
41
+ end
42
+
43
+ # the action that should have been performed on the resource object
44
+ #
45
+ def action
46
+ @action
47
+ end
48
+
49
+ # the resource type
50
+ #
51
+ def resource_class
52
+ @resclass
53
+ end
54
+
55
+ # the resource that was accessed
56
+ #
57
+ def resource
58
+ @res
59
+ end
60
+ end
61
+
62
+ module AnnotationSecurity
63
+
64
+ # = AnnotationSecurity::RuleError
65
+ #
66
+ # Will be raised if a right or relation is defined twice
67
+ # or has an invalid name.
68
+ #
69
+ class RuleError < SecurityError
70
+ def self.defined_twice(type,rule) # :nodoc:
71
+ new "The #{type} #{rule} is defined twice"
72
+ end
73
+
74
+ def self.forbidden_name(type,rule) # :nodoc:
75
+ new "#{rule} is not allowed as #{type} name"
76
+ end
77
+ end
78
+
79
+ # = AnnotationSecurity::RuleExecutionError
80
+ #
81
+ # Will be raised if an error occured while evaluation a right or relation.
82
+ #
83
+ class RuleExecutionError < RuleError
84
+
85
+ def initialize(rule, proc=false, ex = nil) # :nodoc:
86
+ if ex
87
+ log_backtrace(proc,ex)
88
+ super("An error occured while evaluating #{rule}: \n" +
89
+ ex.class.name + ": " + ex.message)
90
+ else
91
+ super("An error occured while evaluating #{rule}")
92
+ end
93
+ end
94
+
95
+ def set_backtrace(array) # :nodoc:
96
+ super((@bt || []) + array[1..-1])
97
+ end
98
+
99
+ private
100
+
101
+ # Select all lines of the backtrace above "rule.rb evaluate".
102
+ # so they can be appended to the backtrace
103
+ def log_backtrace(proc,ex)
104
+ return unless proc
105
+ backtrace = ex.backtrace
106
+ stop = backtrace.find { |l| l =~ /rule\.rb(.*)`evaluate'/ }
107
+ stop = backtrace.index(stop) || 5
108
+ backtrace = backtrace.first(stop)
109
+ @bt = backtrace.reject { |l| l =~ /annotation_security|active_support/ }
110
+ end
111
+
112
+ end
113
+
114
+ # = AnnotationSecurity::RuleNotFoundError
115
+ #
116
+ # Will be raised when attempting to acces a right or relation that was not
117
+ # defined.
118
+ #
119
+ class RuleNotFoundError < RuleError
120
+ def self.for_rule(rname,policy_class)
121
+ new("Unknown #{policy_class.static? ? 'static' : 'dynamic'} " +
122
+ "rule '#{rname}' for #{policy_class.name}")
123
+ end
124
+ end
125
+ end