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.
- 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
|
+
[](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
|