vigilante 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/.document +5 -0
  2. data/.travis.yml +5 -0
  3. data/Gemfile +27 -0
  4. data/Gemfile.lock +107 -0
  5. data/History.md +7 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.markdown +109 -0
  8. data/Rakefile +48 -0
  9. data/VERSION +1 -0
  10. data/app/controllers/abilities_controller.rb +18 -0
  11. data/app/models/ability.rb +6 -0
  12. data/app/models/ability_permission.rb +4 -0
  13. data/app/models/authorization.rb +34 -0
  14. data/app/models/authorization_extent.rb +34 -0
  15. data/app/models/permission.rb +2 -0
  16. data/app/models/permission_hash.rb +131 -0
  17. data/app/views/abilities/index.html.haml +15 -0
  18. data/app/views/abilities/show.html.haml +71 -0
  19. data/lib/config/vigilante_config.yml +19 -0
  20. data/lib/db/migrate/20101028091755_create_permissions.rb +13 -0
  21. data/lib/db/migrate/20101028091859_create_abilities.rb +14 -0
  22. data/lib/db/migrate/20101028091927_create_ability_permissions.rb +14 -0
  23. data/lib/db/migrate/20101028092014_create_authorizations.rb +16 -0
  24. data/lib/db/migrate/20101124131334_add_extent_flag_to_ability.rb +9 -0
  25. data/lib/db/migrate/20101129084538_add_authorization_extent.rb +15 -0
  26. data/lib/db/migrate/20101129084620_remove_extent_from_authorization.rb +11 -0
  27. data/lib/generators/vigilante/install/install_generator.rb +104 -0
  28. data/lib/generators/vigilante/install/templates/create_abilities.rb +14 -0
  29. data/lib/generators/vigilante/install/templates/create_ability_permissions.rb +14 -0
  30. data/lib/generators/vigilante/install/templates/create_authorization_extents.rb +15 -0
  31. data/lib/generators/vigilante/install/templates/create_authorizations.rb +13 -0
  32. data/lib/generators/vigilante/install/templates/create_permissions.rb +13 -0
  33. data/lib/generators/vigilante/install/templates/watchman_config.yml +19 -0
  34. data/lib/vigilante/active_record_extensions.rb +33 -0
  35. data/lib/vigilante/authorization.rb +169 -0
  36. data/lib/vigilante/controller_extension.rb +34 -0
  37. data/lib/vigilante/finder_helper.rb +24 -0
  38. data/lib/vigilante/watched_operator.rb +149 -0
  39. data/lib/vigilante.rb +47 -0
  40. data/spec/controllers/application_controller_spec.rb +8 -0
  41. data/spec/controllers/blogs_controller_spec.rb +8 -0
  42. data/spec/dummy/Rakefile +7 -0
  43. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  44. data/spec/dummy/app/controllers/blogs_controller.rb +6 -0
  45. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  46. data/spec/dummy/app/models/author.rb +3 -0
  47. data/spec/dummy/app/models/blog.rb +3 -0
  48. data/spec/dummy/app/models/post.rb +3 -0
  49. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  50. data/spec/dummy/config/application.rb +45 -0
  51. data/spec/dummy/config/boot.rb +10 -0
  52. data/spec/dummy/config/database.yml +22 -0
  53. data/spec/dummy/config/environment.rb +5 -0
  54. data/spec/dummy/config/environments/development.rb +26 -0
  55. data/spec/dummy/config/environments/production.rb +49 -0
  56. data/spec/dummy/config/environments/test.rb +35 -0
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  58. data/spec/dummy/config/initializers/inflections.rb +10 -0
  59. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  60. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  61. data/spec/dummy/config/initializers/session_store.rb +8 -0
  62. data/spec/dummy/config/locales/en.yml +5 -0
  63. data/spec/dummy/config/routes.rb +58 -0
  64. data/spec/dummy/config/vigilante_config.yml +18 -0
  65. data/spec/dummy/config.ru +4 -0
  66. data/spec/dummy/db/migrate/20101028091755_create_permissions.rb +13 -0
  67. data/spec/dummy/db/migrate/20101028091859_create_abilities.rb +14 -0
  68. data/spec/dummy/db/migrate/20101028091927_create_ability_permissions.rb +14 -0
  69. data/spec/dummy/db/migrate/20101028092014_create_authorizations.rb +16 -0
  70. data/spec/dummy/db/migrate/20101124131334_add_extent_flag_to_ability.rb +9 -0
  71. data/spec/dummy/db/migrate/20101129084538_add_authorization_extent.rb +15 -0
  72. data/spec/dummy/db/migrate/20101129084620_remove_extent_from_authorization.rb +11 -0
  73. data/spec/dummy/db/migrate/20110118120344_create_blogs.rb +14 -0
  74. data/spec/dummy/db/migrate/20110118120421_create_posts.rb +16 -0
  75. data/spec/dummy/db/migrate/20110118120448_create_authors.rb +15 -0
  76. data/spec/dummy/db/schema.rb +75 -0
  77. data/spec/dummy/db/seeds/initial_watchman_permissions.rb +37 -0
  78. data/spec/dummy/db/seeds.rb +6 -0
  79. data/spec/dummy/public/404.html +26 -0
  80. data/spec/dummy/public/422.html +26 -0
  81. data/spec/dummy/public/500.html +26 -0
  82. data/spec/dummy/public/favicon.ico +0 -0
  83. data/spec/dummy/public/javascripts/application.js +2 -0
  84. data/spec/dummy/public/javascripts/controls.js +965 -0
  85. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  86. data/spec/dummy/public/javascripts/effects.js +1123 -0
  87. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  88. data/spec/dummy/public/javascripts/rails.js +175 -0
  89. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  90. data/spec/dummy/script/rails +6 -0
  91. data/spec/models/ability_permission_spec.rb +6 -0
  92. data/spec/models/ability_spec.rb +20 -0
  93. data/spec/models/author_spec.rb +7 -0
  94. data/spec/models/authorization_extent_spec.rb +94 -0
  95. data/spec/models/authorization_spec.rb +104 -0
  96. data/spec/models/permission_hash_spec.rb +162 -0
  97. data/spec/models/permission_spec.rb +5 -0
  98. data/spec/spec_helper.rb +49 -0
  99. data/spec/vigilante_spec.rb +5 -0
  100. metadata +236 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - rbx
5
+ - ree
data/Gemfile ADDED
@@ -0,0 +1,27 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rails", "3.0.3"
4
+
5
+ group :development, :test do
6
+ gem "jeweler"
7
+ gem "rspec-rails", ">= 2.4.0"
8
+ end
9
+
10
+
11
+ # test-environment gems
12
+ group :test, :spec, :cucumber do
13
+ gem 'sqlite3-ruby', :require => 'sqlite3' # needed for the rails-3-app : not really needed, but not sure how to avoid it
14
+ gem "rspec", ">= 2.4.0"
15
+ gem "remarkable", ">=4.0.0.alpha4"
16
+ gem "remarkable_activemodel", ">=4.0.0.alpha4"
17
+ gem "remarkable_activerecord", ">=4.0.0.alpha4"
18
+ # gem "capybara"
19
+ # gem "cucumber"
20
+ # gem "database_cleaner"
21
+ # gem "cucumber-rails"
22
+ end
23
+
24
+
25
+ # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
26
+ # gem 'ruby-debug'
27
+ # gem 'ruby-debug19'
data/Gemfile.lock ADDED
@@ -0,0 +1,107 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.3)
6
+ actionpack (= 3.0.3)
7
+ mail (~> 2.2.9)
8
+ actionpack (3.0.3)
9
+ activemodel (= 3.0.3)
10
+ activesupport (= 3.0.3)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.4)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.13)
16
+ rack-test (~> 0.5.6)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.3)
19
+ activesupport (= 3.0.3)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.4)
22
+ activerecord (3.0.3)
23
+ activemodel (= 3.0.3)
24
+ activesupport (= 3.0.3)
25
+ arel (~> 2.0.2)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.3)
28
+ activemodel (= 3.0.3)
29
+ activesupport (= 3.0.3)
30
+ activesupport (3.0.3)
31
+ arel (2.0.6)
32
+ builder (2.1.2)
33
+ diff-lcs (1.1.2)
34
+ erubis (2.6.6)
35
+ abstract (>= 1.0.0)
36
+ git (1.2.5)
37
+ i18n (0.5.0)
38
+ jeweler (1.5.2)
39
+ bundler (~> 1.0.0)
40
+ git (>= 1.2.5)
41
+ rake
42
+ mail (2.2.14)
43
+ activesupport (>= 2.3.6)
44
+ i18n (>= 0.4.0)
45
+ mime-types (~> 1.16)
46
+ treetop (~> 1.4.8)
47
+ mime-types (1.16)
48
+ polyglot (0.3.1)
49
+ rack (1.2.1)
50
+ rack-mount (0.6.13)
51
+ rack (>= 1.0.0)
52
+ rack-test (0.5.7)
53
+ rack (>= 1.0)
54
+ rails (3.0.3)
55
+ actionmailer (= 3.0.3)
56
+ actionpack (= 3.0.3)
57
+ activerecord (= 3.0.3)
58
+ activeresource (= 3.0.3)
59
+ activesupport (= 3.0.3)
60
+ bundler (~> 1.0)
61
+ railties (= 3.0.3)
62
+ railties (3.0.3)
63
+ actionpack (= 3.0.3)
64
+ activesupport (= 3.0.3)
65
+ rake (>= 0.8.7)
66
+ thor (~> 0.14.4)
67
+ rake (0.8.7)
68
+ remarkable (4.0.0.alpha4)
69
+ rspec (>= 2.0.0.alpha11)
70
+ remarkable_activemodel (4.0.0.alpha4)
71
+ remarkable (~> 4.0.0.alpha4)
72
+ rspec (>= 2.0.0.alpha11)
73
+ remarkable_activerecord (4.0.0.alpha4)
74
+ remarkable (~> 4.0.0.alpha4)
75
+ remarkable_activemodel (~> 4.0.0.alpha4)
76
+ rspec (>= 2.0.0.alpha11)
77
+ rspec (2.4.0)
78
+ rspec-core (~> 2.4.0)
79
+ rspec-expectations (~> 2.4.0)
80
+ rspec-mocks (~> 2.4.0)
81
+ rspec-core (2.4.0)
82
+ rspec-expectations (2.4.0)
83
+ diff-lcs (~> 1.1.2)
84
+ rspec-mocks (2.4.0)
85
+ rspec-rails (2.4.1)
86
+ actionpack (~> 3.0)
87
+ activesupport (~> 3.0)
88
+ railties (~> 3.0)
89
+ rspec (~> 2.4.0)
90
+ sqlite3-ruby (1.3.2)
91
+ thor (0.14.6)
92
+ treetop (1.4.9)
93
+ polyglot (>= 0.3.1)
94
+ tzinfo (0.3.23)
95
+
96
+ PLATFORMS
97
+ ruby
98
+
99
+ DEPENDENCIES
100
+ jeweler
101
+ rails (= 3.0.3)
102
+ remarkable (>= 4.0.0.alpha4)
103
+ remarkable_activemodel (>= 4.0.0.alpha4)
104
+ remarkable_activerecord (>= 4.0.0.alpha4)
105
+ rspec (>= 2.4.0)
106
+ rspec-rails (>= 2.4.0)
107
+ sqlite3-ruby
data/History.md ADDED
@@ -0,0 +1,7 @@
1
+ # Change History / Release Notes
2
+
3
+ ## Version 1.0.0 (17/07/2011)
4
+
5
+ * first public release of the Vigilante gem. This gem will allow you to dynamically manage the
6
+ authorisations of our users. Authorisations can even be scoped/limited, e.g. a multi-blog site
7
+ where authors only are allowed to write/edit on one or more blogs.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,109 @@
1
+ # Vigilante
2
+ ========
3
+
4
+ [![Build Status](http://travis-ci.org/nathanvda/vigilante.png)](http://travis-ci.org/nathanvda/vigilante)
5
+
6
+ Vigilante is a plugin that will offer database stored authorisation, and offers the ability
7
+ that certain permissions have a limited scope/extent.
8
+
9
+ All permissions can be managed from an admin-interface.
10
+ If permissions are changed, they will be used on the next login.
11
+
12
+ ## Terminology
13
+
14
+ - context: the current context, the object(s) we want to see/visit
15
+ - scope : term from activerecord, to allow scoping a query (adding conditions).
16
+ - extent : permissions have an extent; permissions are only valid in a certain context.
17
+
18
+ ## Example
19
+
20
+ Suppose we have a site like blogger -> multiple blogs, a blog can have multiple author, a blog can have limited access.
21
+
22
+ So we have something like
23
+
24
+ class User
25
+ has_many :posts
26
+ end
27
+
28
+ class Post
29
+ belongs_to :author, :class_name => User
30
+ belongs_to :blog
31
+ end
32
+
33
+ class Comment
34
+ belongs_to :post
35
+ belongs_to :commentor, :class_name => User
36
+ end
37
+
38
+ class Blog
39
+ has_many :posts
40
+ end
41
+
42
+ What we want to be able to express is that certain users are
43
+
44
+ * blog-admins: they can add authors, and can manage the entirety of the blog
45
+ * authors: they can manage their own posts (which they wrote), and they can manage the comments on their own posts
46
+ * commentators: they can read a blog, and create comments. They can only edit the comments they created
47
+
48
+ This should be expressable in our system ...
49
+
50
+ Therefore there are two concepts we introduce:
51
+
52
+ * the extent: which scopes the permission to certain contexts. A context is user-defined, in our case a blog.
53
+ Permissions are only valid on certain blogs.
54
+
55
+ ## Installation
56
+
57
+ First, add the `Vigilante` gem to your `Gemfile`:
58
+
59
+ gem 'vigilante'
60
+
61
+ Then, do `bundle install`, and run the generator:
62
+
63
+ rails g vigilante:install
64
+
65
+ This will add a configuration-file (so you edit it) and will add example glue code to the ApplicationController.
66
+ This will also add a number of needed migrations.
67
+
68
+
69
+
70
+ ### What needs to be configured
71
+
72
+ For starters we need some kind of user-model. You can call it User, Operator, ...
73
+ But because the permissions will be specified (in the database), we need only one model (and no models based on
74
+ a role or permissions for the user). A user (operator, ...) just needs to be able to log on. Use Devise, Authlogic, or
75
+ roll your own. The Vigilante needs to know how the user model is called, and it needs to be able to reach the currently
76
+ logged on user.
77
+
78
+ Inside that class, you have to add a single line:
79
+
80
+ authorisations_handled_by_vigilante
81
+
82
+ This will add extra methods and properties to your User/Operator model.
83
+
84
+
85
+ Next up, we need some extra glue code, which is configured inside the `vigilante_config.yml`.
86
+ You will need to set the following values:
87
+
88
+ - *current_user_method*: the method that needs to be called from within the controller context to retrieve the current user.
89
+ If you are using Devise, this would be something like `current_<devise-model>`, e.g. `current_user` or `current_operator`.
90
+ - *current_user_class*: the class of the user/operator
91
+ - application_context: what method will give us the current context (e.g. current blog)
92
+ - application_extent_id_from_object : get_context_id_from_context_object
93
+ - application_context_from_nested_resources: find_context_by_context_id
94
+
95
+ I will give an example later to make this more clear.
96
+
97
+
98
+ ###
99
+
100
+
101
+ ### To DO
102
+
103
+ - improve documentation
104
+
105
+
106
+ ## Copyright
107
+
108
+ Based on original code written by Bart Duchesne.
109
+ Copyright &copy; 2011 Nathan Van der Auwera, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rake/rdoctask'
11
+
12
+ Rake::RDocTask.new(:rdoc) do |rdoc|
13
+ rdoc.rdoc_dir = 'rdoc'
14
+ rdoc.title = 'Vigilante'
15
+ rdoc.options << '--line-numbers' << '--inline-source'
16
+ rdoc.rdoc_files.include('README.rdoc')
17
+ rdoc.rdoc_files.include('lib/**/*.rb')
18
+ end
19
+
20
+
21
+ begin
22
+ require 'jeweler'
23
+ Jeweler::Tasks.new do |gem|
24
+ gem.name = "vigilante"
25
+ gem.summary = %Q{Context-based, db-backed authorisation for your rails3 apps}
26
+ gem.description = %Q{Vigilante is a db-backed authorisation, completely configurable and dynamic; where permissions can be limited to extents.}
27
+ gem.email = "nathan@dixis.com"
28
+ gem.homepage = "http://github.com/vigilante"
29
+ gem.authors = ["Nathan Van der Auwera"]
30
+ gem.add_development_dependency "rails", ">= 3.0.0"
31
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
32
+ end
33
+ Jeweler::GemcutterTasks.new
34
+ rescue LoadError
35
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
36
+ end
37
+
38
+
39
+ require "rspec/core/rake_task"
40
+ RSpec::Core::RakeTask.new(:spec)
41
+
42
+ desc "Run all specs with rcov"
43
+ RSpec::Core::RakeTask.new("test_cov") do |t|
44
+ t.rcov = true
45
+ t.rcov_opts = %w{--rails --include views -Ispec --exclude gems\/,spec\/,features\/,seeds\/}
46
+ end
47
+
48
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,18 @@
1
+ class AbilitiesController < ApplicationController
2
+
3
+ before_filter :check_permissions
4
+
5
+ def index
6
+ @abilities = Ability.order(:name)
7
+ end
8
+
9
+ def show
10
+ @ability = Ability.find(params[:id])
11
+ end
12
+
13
+
14
+ private
15
+
16
+
17
+
18
+ end
@@ -0,0 +1,6 @@
1
+ class Ability < ActiveRecord::Base
2
+ has_many :ability_permissions
3
+ has_many :permissions, :through => :ability_permissions
4
+
5
+ scope :that_need_extent, lambda { where('needs_extent=?', true)}
6
+ end
@@ -0,0 +1,4 @@
1
+ class AbilityPermission < ActiveRecord::Base
2
+ belongs_to :permission
3
+ belongs_to :ability
4
+ end
@@ -0,0 +1,34 @@
1
+ class Authorization < ActiveRecord::Base
2
+ belongs_to :operator, :class_name => ::VIGILANTE_CONFIG['current_user_class'].to_s
3
+ belongs_to :ability
4
+
5
+ has_many :authorization_extents, :dependent => :delete_all
6
+ accepts_nested_attributes_for :authorization_extents, :reject_if => proc { |x| x[:extent].blank? }, :allow_destroy => true
7
+
8
+
9
+ def match_extent(extent_object)
10
+ extents_count = authorization_extents.count
11
+ return true if extents_count == 0 && extent_object.blank?
12
+
13
+ return false if ((extents_count == 0 && extent_object.present?) ||
14
+ (extents_count > 0 && extent_object.blank?))
15
+
16
+ authorization_extents.each do |extent|
17
+ return true if extent.match_extent(extent_object)
18
+ end
19
+ false
20
+ end
21
+
22
+
23
+ def add_extent(extent_object)
24
+ unless extent_object.nil? || match_extent(extent_object)
25
+ new_extent = authorization_extents.build
26
+ new_extent.set_extent(extent_object)
27
+ new_extent.save
28
+ end
29
+ end
30
+
31
+ def has_extent?
32
+ authorization_extents.count > 0
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ class AuthorizationExtent < ActiveRecord::Base
2
+ belongs_to :authorization
3
+
4
+ def extent
5
+ if extent_objid
6
+ default_extent_class.find_by_id(extent_objid)
7
+ end
8
+ end
9
+
10
+ def extent=(ext_label)
11
+ # find asp
12
+ extent_obj = default_extent_class.find_by_id(ext_label)
13
+ if new_record?
14
+ self.extent_objid = extent_obj.id
15
+ self.extent_type = extent_obj.class.name
16
+ else
17
+ set_extent(extent_obj)
18
+ end
19
+ end
20
+
21
+ def match_extent(extent_object)
22
+ extent_type == extent_object.class.name && extent_objid == extent_object.id
23
+ end
24
+
25
+ def set_extent(extent_object)
26
+ update_attributes(:extent_objid => extent_object.id, :extent_type => extent_object.class.name)
27
+ end
28
+
29
+ private
30
+
31
+ def default_extent_class
32
+ @@default_extent_class ||= Kernel.const_get(::VIGILANTE_CONFIG['default_extent_class'])
33
+ end
34
+ end
@@ -0,0 +1,2 @@
1
+ class Permission < ActiveRecord::Base
2
+ end
@@ -0,0 +1,131 @@
1
+ class PermissionHash < HashWithIndifferentAccess
2
+
3
+ DEFAULT_PERMISSIONS = HashWithIndifferentAccess.new({'*' => {
4
+ :homepage => {:index => 1, :show => 1}
5
+ }
6
+ })
7
+
8
+ # default initialization
9
+ def initialize(default_start = DEFAULT_PERMISSIONS)
10
+ super( default_start )
11
+ end
12
+
13
+ # add extra allowed actions
14
+ def add(extent, path, allowed_actions)
15
+ self[extent] ||= {}
16
+ self[extent][path] ||= {}
17
+
18
+ allowed_actions = [:index, :show] if allowed_actions.nil? || allowed_actions.empty?
19
+ allowed_actions.push(:update) if allowed_actions.include?(:edit) && !allowed_actions.include?(:update)
20
+ allowed_actions.push(:create) if allowed_actions.include?(:new) && !allowed_actions.include?(:create)
21
+
22
+ allowed_actions.each do |a|
23
+ self[extent][path][a] = 1
24
+ end
25
+ self
26
+ end
27
+
28
+ # get_extent_of calculates the extent of a
29
+ # given controller/action for this permissionhash
30
+ # this returns either
31
+ # - [] : no extent, nothing is allowed
32
+ # - [extent_objid, ..] : the extent
33
+ # Note: if the extent of the permission is global the returned array will include '*'
34
+ def get_extent_of(controller_name, action)
35
+ controller_name = to_controller_name(controller_name) unless controller_name.instance_of?(String)
36
+
37
+ permission_extent = []
38
+ self.keys.each do |extent|
39
+ if is_allowed_by_permissions(controller_name, action, self[extent])
40
+ permission_extent << extent.to_s
41
+ end
42
+ end
43
+ permission_extent
44
+ end
45
+
46
+
47
+ # does this permission-hash only has global permissions (without extent)
48
+ def are_only_global?
49
+ self.keys.size == 1 && self.keys[0] == '*'
50
+ end
51
+
52
+ # convenience method
53
+ def is_global?
54
+ are_only_global?
55
+ end
56
+
57
+ def is_allowed_by_context(controller_name, action_name, extents)
58
+ controller_name = to_controller_name(controller_name) unless controller_name.instance_of?(String)
59
+
60
+ is_allowed_by_permissions(controller_name, action_name, get_permissions_by_context(extents))
61
+ end
62
+
63
+
64
+ #####################################################
65
+ #
66
+ # Protected methods
67
+ #
68
+ #####################################################
69
+
70
+ protected
71
+
72
+
73
+ def model_name
74
+ controller_name.singularize.camelize
75
+ end
76
+
77
+
78
+ def to_controller_name(klass)
79
+ klass_str = klass.is_a?(Class) ? klass.name :
80
+ klass.is_a?(String) ? klass :
81
+ klass.class.name
82
+ "#{klass_str.underscore.pluralize}"
83
+ end
84
+
85
+ def get_permissions_by_context(extents)
86
+ # start from the empty permissions
87
+ Rails.logger.debug "get_permissions_by_context received #{extents.inspect}"
88
+ result = {}
89
+ # add specific extents
90
+ unless extents.nil? || self.is_global?
91
+ extents.each do |ctx_id|
92
+ Rails.logger.debug "get_permissions_by_context add extent #{ctx_id.inspect}"
93
+ permissions_for_ctx = self[ctx_id]
94
+ result.merge!(permissions_for_ctx) unless permissions_for_ctx.nil?
95
+ end
96
+ end
97
+ Rails.logger.debug "get_permissions_by_context after extents built #{result.inspect}"
98
+
99
+ # add general extent only if we have nothing specific
100
+ result = {}.merge(self['*']) if result == {}
101
+
102
+ Rails.logger.debug "get_permissions_by_context built #{result.inspect}"
103
+
104
+ result
105
+ end
106
+
107
+ def is_allowed_by_permissions(controller_name, action, extent_permissions)
108
+ action = action || 'index'
109
+ action = action.to_sym
110
+ controller_name = 'homepage' if controller_name == '/'
111
+ controller_name = controller_name[1..-1] if controller_name.starts_with?('/')
112
+
113
+ p = ''
114
+ path_parts = controller_name.split('/').collect() { |e| p = p+'/' unless p.empty?; p = p + e; p }.sort { |a, b| b.length <=> a.length }
115
+
116
+ result = false
117
+ [path_parts, '*'].flatten!.each do |path|
118
+ allowed = extent_permissions[path]
119
+ unless allowed.nil?
120
+ result = (allowed[action] != nil) || (allowed[:all] != nil || allowed[:'*'] != nil)
121
+ break if result
122
+ end
123
+ end
124
+ result
125
+ end
126
+
127
+
128
+
129
+
130
+
131
+ end
@@ -0,0 +1,15 @@
1
+
2
+ %table{:class => 'overview'}
3
+ %thead
4
+ %tr
5
+ %th Name
6
+ %th Description
7
+ %th
8
+
9
+ %tbody#groups
10
+ - @abilities.each do |ab|
11
+ %tr
12
+ %td=h ab.name
13
+ %td=h ab.description
14
+ %td
15
+ = link_to 'Show', ab
@@ -0,0 +1,71 @@
1
+ %table.resource_attributes
2
+ %tr
3
+ %th Name
4
+ %td= @ability.name
5
+ %tr
6
+ %th Description
7
+ %td= @ability.description
8
+
9
+
10
+ %h2 Allowed actions
11
+
12
+
13
+
14
+ %table{:class => 'overview'}
15
+ - @ability.permissions.each do |perm|
16
+ %tr
17
+ %td= perm.allowed_action
18
+
19
+ #abilities_explanation.help_text
20
+ %p
21
+ Allowed actions are specified as follows:
22
+
23
+ %ul
24
+ %li
25
+ %pre
26
+ posts[index, show]
27
+ %ul
28
+ %li
29
+ Only the things that are explicitly specified are allowed.
30
+ This declares that on the
31
+ %tt
32
+ PostsController
33
+ only
34
+ %tt
35
+ index
36
+ and
37
+ %tt
38
+ show
39
+ are allowed.
40
+ %li
41
+ %pre
42
+ *[index, show, report]
43
+ %ul
44
+ %li
45
+ We also allow wild-cards. Instead of a controller-name, we could write
46
+ %tt
47
+ *
48
+ which would mean the specified actions would apply to all controllers.
49
+ %li
50
+ %pre
51
+ posts[all]
52
+ %ul
53
+ %li
54
+ If we write
55
+ %tt
56
+ all
57
+ instead of a specific action or list of actions, then all actions are allowed for a given controller.
58
+ In this case a user has the ability to access all actions inside the posts_controller.
59
+ %li
60
+ %pre
61
+ *[all]
62
+ %ul
63
+ %li
64
+ By extension, this means a user has the ability to access all actions from all controllers.
65
+ %p
66
+ When abilities are assigned to operators (authorisation), it is possible to specify the extent of the ability.
67
+ So an
68
+ %tt
69
+ asp_admin
70
+ 's permissions could only be valid on a few asps.
71
+
@@ -0,0 +1,19 @@
1
+ development: &common
2
+ current_user_method: current_operator
3
+ current_user_class: Author
4
+ default_extent_class: Blog
5
+
6
+ # delegate extent handling to owner application
7
+ application_context: current_context
8
+ application_extent_id_from_object : get_blog_id_from_context_object
9
+ application_context_from_nested_resources: find_blog_by_blog_id
10
+
11
+
12
+ test:
13
+ <<: *common # merges key:value pairs defined in development anchor
14
+
15
+ cucumber:
16
+ <<: *common # merges key:value pairs defined in development anchor
17
+
18
+ production:
19
+ <<: *common # merges key:value pairs defined in development anchor