vigilante 1.0.0

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 (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