annotation_security 1.0.2 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
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