vigilante 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.travis.yml +5 -0
- data/Gemfile +27 -0
- data/Gemfile.lock +107 -0
- data/History.md +7 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +109 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/app/controllers/abilities_controller.rb +18 -0
- data/app/models/ability.rb +6 -0
- data/app/models/ability_permission.rb +4 -0
- data/app/models/authorization.rb +34 -0
- data/app/models/authorization_extent.rb +34 -0
- data/app/models/permission.rb +2 -0
- data/app/models/permission_hash.rb +131 -0
- data/app/views/abilities/index.html.haml +15 -0
- data/app/views/abilities/show.html.haml +71 -0
- data/lib/config/vigilante_config.yml +19 -0
- data/lib/db/migrate/20101028091755_create_permissions.rb +13 -0
- data/lib/db/migrate/20101028091859_create_abilities.rb +14 -0
- data/lib/db/migrate/20101028091927_create_ability_permissions.rb +14 -0
- data/lib/db/migrate/20101028092014_create_authorizations.rb +16 -0
- data/lib/db/migrate/20101124131334_add_extent_flag_to_ability.rb +9 -0
- data/lib/db/migrate/20101129084538_add_authorization_extent.rb +15 -0
- data/lib/db/migrate/20101129084620_remove_extent_from_authorization.rb +11 -0
- data/lib/generators/vigilante/install/install_generator.rb +104 -0
- data/lib/generators/vigilante/install/templates/create_abilities.rb +14 -0
- data/lib/generators/vigilante/install/templates/create_ability_permissions.rb +14 -0
- data/lib/generators/vigilante/install/templates/create_authorization_extents.rb +15 -0
- data/lib/generators/vigilante/install/templates/create_authorizations.rb +13 -0
- data/lib/generators/vigilante/install/templates/create_permissions.rb +13 -0
- data/lib/generators/vigilante/install/templates/watchman_config.yml +19 -0
- data/lib/vigilante/active_record_extensions.rb +33 -0
- data/lib/vigilante/authorization.rb +169 -0
- data/lib/vigilante/controller_extension.rb +34 -0
- data/lib/vigilante/finder_helper.rb +24 -0
- data/lib/vigilante/watched_operator.rb +149 -0
- data/lib/vigilante.rb +47 -0
- data/spec/controllers/application_controller_spec.rb +8 -0
- data/spec/controllers/blogs_controller_spec.rb +8 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/blogs_controller.rb +6 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/author.rb +3 -0
- data/spec/dummy/app/models/blog.rb +3 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +45 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +22 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +26 -0
- data/spec/dummy/config/environments/production.rb +49 -0
- data/spec/dummy/config/environments/test.rb +35 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/config/vigilante_config.yml +18 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20101028091755_create_permissions.rb +13 -0
- data/spec/dummy/db/migrate/20101028091859_create_abilities.rb +14 -0
- data/spec/dummy/db/migrate/20101028091927_create_ability_permissions.rb +14 -0
- data/spec/dummy/db/migrate/20101028092014_create_authorizations.rb +16 -0
- data/spec/dummy/db/migrate/20101124131334_add_extent_flag_to_ability.rb +9 -0
- data/spec/dummy/db/migrate/20101129084538_add_authorization_extent.rb +15 -0
- data/spec/dummy/db/migrate/20101129084620_remove_extent_from_authorization.rb +11 -0
- data/spec/dummy/db/migrate/20110118120344_create_blogs.rb +14 -0
- data/spec/dummy/db/migrate/20110118120421_create_posts.rb +16 -0
- data/spec/dummy/db/migrate/20110118120448_create_authors.rb +15 -0
- data/spec/dummy/db/schema.rb +75 -0
- data/spec/dummy/db/seeds/initial_watchman_permissions.rb +37 -0
- data/spec/dummy/db/seeds.rb +6 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/javascripts/application.js +2 -0
- data/spec/dummy/public/javascripts/controls.js +965 -0
- data/spec/dummy/public/javascripts/dragdrop.js +974 -0
- data/spec/dummy/public/javascripts/effects.js +1123 -0
- data/spec/dummy/public/javascripts/prototype.js +6001 -0
- data/spec/dummy/public/javascripts/rails.js +175 -0
- data/spec/dummy/public/stylesheets/.gitkeep +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/models/ability_permission_spec.rb +6 -0
- data/spec/models/ability_spec.rb +20 -0
- data/spec/models/author_spec.rb +7 -0
- data/spec/models/authorization_extent_spec.rb +94 -0
- data/spec/models/authorization_spec.rb +104 -0
- data/spec/models/permission_hash_spec.rb +162 -0
- data/spec/models/permission_spec.rb +5 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/vigilante_spec.rb +5 -0
- metadata +236 -0
data/.document
ADDED
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 © 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,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,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,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
|