annotation_security 1.0.2 → 1.3.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 (70) hide show
  1. data/CHANGELOG +22 -0
  2. data/HOW-TO +261 -0
  3. data/{LICENSE → MIT-LICENSE} +1 -1
  4. data/README +39 -0
  5. data/Rakefile +53 -62
  6. data/assets/app/helpers/annotation_security_helper.rb +8 -8
  7. data/assets/config/initializers/annotation_security.rb +11 -11
  8. data/assets/config/security/relations.rb +20 -20
  9. data/assets/vendor/plugins/annotation_security/init.rb +14 -14
  10. data/bin/annotation_security +7 -7
  11. data/lib/annotation_security.rb +94 -103
  12. data/lib/annotation_security/exceptions.rb +124 -124
  13. data/lib/annotation_security/exec.rb +188 -188
  14. data/lib/annotation_security/includes/helper.rb +215 -215
  15. data/lib/annotation_security/includes/resource.rb +84 -84
  16. data/lib/annotation_security/includes/role.rb +30 -30
  17. data/lib/annotation_security/includes/user.rb +26 -26
  18. data/lib/annotation_security/manager/policy_factory.rb +29 -29
  19. data/lib/annotation_security/manager/policy_manager.rb +87 -79
  20. data/lib/annotation_security/manager/relation_loader.rb +272 -272
  21. data/lib/annotation_security/manager/resource_manager.rb +36 -36
  22. data/lib/annotation_security/manager/right_loader.rb +87 -87
  23. data/lib/annotation_security/policy/abstract_policy.rb +344 -344
  24. data/lib/annotation_security/policy/abstract_static_policy.rb +75 -75
  25. data/lib/annotation_security/policy/all_resources_policy.rb +20 -20
  26. data/lib/annotation_security/policy/rule.rb +340 -340
  27. data/lib/annotation_security/policy/rule_set.rb +138 -138
  28. data/lib/annotation_security/rails.rb +22 -39
  29. data/lib/{extensions → annotation_security/rails/2/extensions}/filter.rb +131 -133
  30. data/lib/annotation_security/rails/2/includes/action_controller.rb +144 -0
  31. data/lib/annotation_security/rails/2/includes/active_record.rb +28 -0
  32. data/lib/annotation_security/rails/2/initializer.rb +35 -0
  33. data/lib/annotation_security/{model_observer.rb → rails/2/model_observer.rb} +61 -61
  34. data/lib/annotation_security/rails/3/extensions/filter.rb +28 -0
  35. data/lib/annotation_security/{includes → rails/3/includes}/action_controller.rb +143 -144
  36. data/lib/annotation_security/{includes → rails/3/includes}/active_record.rb +27 -27
  37. data/lib/annotation_security/rails/3/initializer.rb +40 -0
  38. data/lib/annotation_security/rails/3/model_observer.rb +61 -0
  39. data/lib/annotation_security/rails/extensions.rb +21 -0
  40. data/lib/{extensions → annotation_security/rails/extensions}/action_controller.rb +31 -32
  41. data/lib/{extensions → annotation_security/rails/extensions}/active_record.rb +33 -34
  42. data/lib/{extensions → annotation_security/rails/extensions}/object.rb +10 -10
  43. data/lib/annotation_security/{filters.rb → rails/filters.rb} +37 -37
  44. data/lib/annotation_security/user_wrapper.rb +73 -73
  45. data/lib/annotation_security/utils.rb +141 -141
  46. data/lib/security_context.rb +588 -589
  47. data/spec/annotation_security/exceptions_spec.rb +16 -16
  48. data/spec/annotation_security/includes/helper_spec.rb +82 -82
  49. data/spec/annotation_security/manager/policy_manager_spec.rb +15 -15
  50. data/spec/annotation_security/manager/resource_manager_spec.rb +17 -17
  51. data/spec/annotation_security/manager/right_loader_spec.rb +17 -17
  52. data/spec/annotation_security/policy/abstract_policy_spec.rb +16 -16
  53. data/spec/annotation_security/policy/all_resources_policy_spec.rb +24 -24
  54. data/spec/annotation_security/policy/rule_set_spec.rb +112 -112
  55. data/spec/annotation_security/policy/rule_spec.rb +77 -77
  56. data/spec/annotation_security/policy/test_policy_spec.rb +80 -80
  57. data/spec/annotation_security/security_context_spec.rb +129 -78
  58. data/spec/annotation_security/utils_spec.rb +73 -73
  59. data/spec/helper/test_controller.rb +65 -65
  60. data/spec/helper/test_helper.rb +5 -5
  61. data/spec/helper/test_relations.rb +6 -6
  62. data/spec/helper/test_resource.rb +38 -38
  63. data/spec/helper/test_role.rb +21 -21
  64. data/spec/helper/test_user.rb +31 -31
  65. data/spec/rails_stub.rb +44 -37
  66. metadata +110 -96
  67. data/CHANGELOG.md +0 -14
  68. data/HOW-TO.md +0 -275
  69. data/README.md +0 -39
  70. data/lib/annotation_security/version.rb +0 -10
data/CHANGELOG ADDED
@@ -0,0 +1,22 @@
1
+ = 1.3.1
2
+ * Fixed a bug which made the application fail if a routing error occured
3
+ * Refactored code base to make it easier to ensure rails 2 / 3 compatibility
4
+ * braking changes:
5
+ * plugin initializer in vendor/plugins/annotation_security changed to
6
+ config = eval("config", binding)
7
+ before call to AnnotationSecurity.init_rails(config)
8
+
9
+ *
10
+ = 1.3.0
11
+ * slow transition to Rails 3.x
12
+ * Fixed a bug with Ruby 1.9 and Rails 2.x
13
+
14
+ = 1.0.3
15
+ * added possibility to disable security layer inside a block passed to SecurityContext#without_security!
16
+
17
+ = 1.0.2 (unpublished)
18
+ * minor bugfix
19
+ * more tests
20
+
21
+ = 1.0.1
22
+ * 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.
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009, 2010, 2013 Nico Rehwaldt, Arian Treffer
1
+ Copyright (c) 2009 Nico Rehwaldt, Arian Treffer
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of
4
4
  this software and associated documentation files (the "Software"), to deal in
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 CHANGED
@@ -1,63 +1,54 @@
1
- require 'rubygems'
2
- require 'rubygems/package_task'
3
-
4
- require 'rake'
5
- require 'rake/clean'
6
-
7
- require 'rdoc/task'
8
-
9
- require 'rspec/core/rake_task'
10
-
11
- require File.dirname(__FILE__) + '/lib/annotation_security/version'
12
-
13
- module RakeFileUtils
14
- extend Rake::FileUtilsExt
15
- end
16
-
17
- spec = Gem::Specification.new do |s|
18
- s.name = 'annotation_security'
19
- s.version = AnnotationSecurity::Version
20
- s.has_rdoc = true
21
- s.extra_rdoc_files = ['README.md', 'LICENSE', 'CHANGELOG.md', 'HOW-TO.md']
22
- s.summary = 'A role based security model for rails applications with ' +
23
- 'descriptive definitions and automated evaluation.'
24
- s.description =
25
- 'AnnotationSecurity provides a role based security model with automated ' +
26
- 'rule evaluation for Ruby on Rails. It allows you to define user-resource-'+
27
- 'relations and rights in separate files, keeping your controllers and ' +
28
- 'views free from any security logic. See the gem\'s homepage for an ' +
29
- 'example.'
30
- s.author = 'Nico Rehwaldt, Arian Treffer'
31
- s.email = 'ruby@nixis.de'
32
- s.homepage = 'http://github.com/Nikku/annotation_security'
33
- s.add_dependency 'action_annotation', '>= 1.0.1'
34
- s.add_dependency 'activesupport', '>= 2.3.18'
35
- s.add_development_dependency 'rspec', '>= 1.3.2'
36
- s.add_development_dependency 'mocha', '>= 0.9.8'
37
- s.executables = ['annotation_security']
38
- s.files = %w(CHANGELOG.md LICENSE README.md HOW-TO.md Rakefile) + Dir.glob("{bin,lib,spec,assets}/**/*")
39
- s.require_path = "lib"
40
- s.bindir = "bin"
41
- end
42
-
43
- desc "Create rdoc documentation"
44
- Rake::RDocTask.new do |rdoc|
45
- files = ['README.md', 'LICENSE', 'CHANGELOG.md', 'HOW-TO.md', 'lib/**/*.rb']
46
- rdoc.rdoc_files.add(files)
47
- rdoc.main = "README.md" # page to start on
48
- rdoc.title = "Annotation Security Docs"
49
- rdoc.rdoc_dir = 'doc' # rdoc output folder
50
- rdoc.options << '--line-numbers'
51
- end
52
-
53
- desc "Run rspec tests"
54
- RSpec::Core::RakeTask.new do |t|
55
- t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
56
- t.pattern = 'spec/**/*_spec.rb'
57
- end
58
-
59
- desc "Package library as gem"
60
- Gem::PackageTask.new(spec) do |pkg|
61
- pkg.need_zip = true
62
- pkg.need_tar = true
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+
7
+ require 'rspec/core/rake_task'
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.name = 'annotation_security'
11
+ s.version = '1.3.1'
12
+ s.has_rdoc = true
13
+ s.extra_rdoc_files = ['README', 'MIT-LICENSE', 'CHANGELOG', 'HOW-TO']
14
+ s.summary = 'A role based security model for rails applications with ' +
15
+ 'descriptive definitions and automated evaluation.'
16
+ s.description =
17
+ 'AnnotationSecurity provides a role based security model with automated ' +
18
+ 'rule evaluation for Ruby on Rails. It allows you to define user-resource-'+
19
+ 'relations and rights in separate files, keeping your controllers and ' +
20
+ 'views free from any security logic. See the gem\'s homepage for an ' +
21
+ 'example.'
22
+ s.author = 'Nico Rehwaldt, Arian Treffer'
23
+ s.email = 'ruby@nixis.de'
24
+ s.homepage = 'http://tech.lefedt.de/2010/3/annotation-based-security-for-rails'
25
+ s.add_dependency 'action_annotation', '>= 1.0.1'
26
+ s.add_dependency 'activesupport', '>= 2.3.5'
27
+ s.add_development_dependency 'rspec', '>= 1.2.0'
28
+ s.add_development_dependency 'mocha', '>= 0.9.8'
29
+ s.executables = ['annotation_security']
30
+ s.files = %w(CHANGELOG MIT-LICENSE README HOW-TO Rakefile) + Dir.glob("{bin,lib,spec,assets}/**/*")
31
+ s.require_path = "lib"
32
+ s.bindir = "bin"
33
+ end
34
+
35
+ Rake::GemPackageTask.new(spec) do |p|
36
+ p.gem_spec = spec
37
+ p.need_tar = true
38
+ p.need_zip = true
39
+ end
40
+
41
+ Rake::RDocTask.new do |rdoc|
42
+ files = ['README', 'MIT-LICENSE', 'CHANGELOG', 'HOW-TO', 'lib/**/*.rb']
43
+ rdoc.rdoc_files.add(files)
44
+ rdoc.main = "README" # page to start on
45
+ rdoc.title = "Annotation Security Docs"
46
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
47
+ rdoc.options << '--line-numbers'
48
+ end
49
+
50
+ desc "Run specs"
51
+ RSpec::Core::RakeTask.new do |t|
52
+ t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
53
+ t.pattern = './spec/**/*_spec.rb'
63
54
  end