strongbolt 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +33 -0
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +22 -0
- data/README.md +182 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/strongbolt.js +1 -0
- data/app/assets/javascripts/strongbolt/role-capabilities.js +80 -0
- data/app/controllers/strongbolt/capabilities_controller.rb +77 -0
- data/app/controllers/strongbolt/roles_controller.rb +92 -0
- data/app/controllers/strongbolt/security_controller.rb +8 -0
- data/app/controllers/strongbolt/user_groups_controller.rb +76 -0
- data/app/controllers/strongbolt/user_groups_users_controller.rb +35 -0
- data/app/controllers/strongbolt_controller.rb +2 -0
- data/app/views/strongbolt/_menu.html.erb +13 -0
- data/app/views/strongbolt/capabilities/index.html.erb +53 -0
- data/app/views/strongbolt/capabilities/show.html.erb +53 -0
- data/app/views/strongbolt/roles/_capabilities.html.erb +47 -0
- data/app/views/strongbolt/roles/_capability.html.erb +21 -0
- data/app/views/strongbolt/roles/_form.html.erb +12 -0
- data/app/views/strongbolt/roles/edit.html.erb +14 -0
- data/app/views/strongbolt/roles/index.html.erb +54 -0
- data/app/views/strongbolt/roles/new.html.erb +11 -0
- data/app/views/strongbolt/roles/show.html.erb +52 -0
- data/app/views/strongbolt/user_groups/_form.html.erb +12 -0
- data/app/views/strongbolt/user_groups/edit.html.erb +14 -0
- data/app/views/strongbolt/user_groups/index.html.erb +46 -0
- data/app/views/strongbolt/user_groups/new.html.erb +13 -0
- data/app/views/strongbolt/user_groups/show.html.erb +88 -0
- data/lib/generators/strongbolt/fix_generator.rb +23 -0
- data/lib/generators/strongbolt/indexes_generator.rb +19 -0
- data/lib/generators/strongbolt/install_generator.rb +29 -0
- data/lib/generators/strongbolt/templates/fix.rb +5 -0
- data/lib/generators/strongbolt/templates/indexes.rb +21 -0
- data/lib/generators/strongbolt/templates/migration.rb +73 -0
- data/lib/generators/strongbolt/templates/strongbolt.rb +45 -0
- data/lib/generators/strongbolt/views_generator.rb +26 -0
- data/lib/strongbolt.rb +219 -0
- data/lib/strongbolt/base.rb +7 -0
- data/lib/strongbolt/bolted.rb +125 -0
- data/lib/strongbolt/bolted_controller.rb +297 -0
- data/lib/strongbolt/capabilities_role.rb +15 -0
- data/lib/strongbolt/capability.rb +165 -0
- data/lib/strongbolt/configuration.rb +111 -0
- data/lib/strongbolt/controllers/url_helpers.rb +37 -0
- data/lib/strongbolt/engine.rb +44 -0
- data/lib/strongbolt/errors.rb +38 -0
- data/lib/strongbolt/generators/migration.rb +35 -0
- data/lib/strongbolt/helpers.rb +18 -0
- data/lib/strongbolt/rails/routes.rb +20 -0
- data/lib/strongbolt/role.rb +46 -0
- data/lib/strongbolt/roles_user_group.rb +15 -0
- data/lib/strongbolt/rspec.rb +29 -0
- data/lib/strongbolt/rspec/user.rb +90 -0
- data/lib/strongbolt/tenantable.rb +304 -0
- data/lib/strongbolt/user_abilities.rb +292 -0
- data/lib/strongbolt/user_group.rb +24 -0
- data/lib/strongbolt/user_groups_user.rb +16 -0
- data/lib/strongbolt/users_tenant.rb +12 -0
- data/lib/strongbolt/version.rb +3 -0
- data/lib/tasks/strongbolt_tasks.rake +29 -0
- data/spec/controllers/strongbolt/capabilities_controller_spec.rb +254 -0
- data/spec/controllers/strongbolt/roles_controller_spec.rb +228 -0
- data/spec/controllers/strongbolt/user_groups_controller_spec.rb +216 -0
- data/spec/controllers/strongbolt/user_groups_users_controller_spec.rb +69 -0
- data/spec/controllers/without_authorization_controller_spec.rb +20 -0
- data/spec/dummy/.rspec +2 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/controllers/posts_controller.rb +18 -0
- data/spec/dummy/app/controllers/test_controller.rb +3 -0
- data/spec/dummy/app/controllers/without_authorization_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +29 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +78 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/strongbolt.rb +32 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +12 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20150630212236_create_strongbolt_tables.rb +54 -0
- data/spec/dummy/db/migrate/20150630212251_create_strongbolt_tables_indexes.rb +21 -0
- data/spec/dummy/db/schema.rb +84 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/fabricators/capability_fabricator.rb +4 -0
- data/spec/fabricators/role_fabricator.rb +9 -0
- data/spec/fabricators/user_fabricator.rb +3 -0
- data/spec/fabricators/user_group_fabricator.rb +9 -0
- data/spec/fixtures/application.rb +28 -0
- data/spec/fixtures/controllers.rb +5 -0
- data/spec/spec_helper.rb +89 -0
- data/spec/strongbolt/bolted_controller_spec.rb +706 -0
- data/spec/strongbolt/bolted_spec.rb +136 -0
- data/spec/strongbolt/capability_spec.rb +251 -0
- data/spec/strongbolt/configuration_spec.rb +119 -0
- data/spec/strongbolt/controllers/url_helpers_spec.rb +34 -0
- data/spec/strongbolt/helpers_spec.rb +43 -0
- data/spec/strongbolt/role_spec.rb +90 -0
- data/spec/strongbolt/tenantable_spec.rb +281 -0
- data/spec/strongbolt/user_abilities_spec.rb +509 -0
- data/spec/strongbolt/user_group_spec.rb +37 -0
- data/spec/strongbolt/users_tenant_spec.rb +36 -0
- data/spec/strongbolt_spec.rb +274 -0
- data/spec/support/controller_macros.rb +11 -0
- data/spec/support/db_setup.rb +134 -0
- data/spec/support/helpers.rb +62 -0
- data/spec/support/transactional_specs.rb +17 -0
- data/strongbolt.gemspec +32 -0
- metadata +407 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b2be7a6357fe3a1bac22a246b34013f1c5109c5e
|
4
|
+
data.tar.gz: 145bb831919b70d9e9165328f097f77249c83726
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a4612a54b4b84c47381bae52e9e8aca1a2992a23c6d7c48981beab4da8beaebbd5f45084c6ca4427d3513a491b530de9efebf5ca595cf7b0087a59aff5c35c6
|
7
|
+
data.tar.gz: f933dd404243f00ed6a081619b997aa04b10af0924cf82c42504b331dfe7c1b33851ab352da04ee9a7c0a64d1ac47ebb01ab4dad0c1cbe6bb79c316d71539d6a
|
data/.editorconfig
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
root = true
|
2
|
+
|
3
|
+
# defaults over all files
|
4
|
+
[*]
|
5
|
+
charset = utf-8
|
6
|
+
end_of_line = lf
|
7
|
+
insert_final_newline = true
|
8
|
+
trim_trailing_whitespace = true
|
9
|
+
|
10
|
+
# documentation
|
11
|
+
[*.md]
|
12
|
+
indent_style = space
|
13
|
+
indent_size = 4
|
14
|
+
|
15
|
+
# ruby files
|
16
|
+
[{*.rb,*.ru,Gemfile,Capfile,Rakefile,Guardfile}]
|
17
|
+
indent_style = space
|
18
|
+
indent_size = 2
|
19
|
+
|
20
|
+
# config files
|
21
|
+
[*.yml]
|
22
|
+
indent_style = space
|
23
|
+
indent_size = 2
|
24
|
+
|
25
|
+
# javascript files
|
26
|
+
[*.{js,coffee}]
|
27
|
+
indent_style = space
|
28
|
+
indent_size = 2
|
29
|
+
|
30
|
+
# stylesheets
|
31
|
+
[*.{css,scss}]
|
32
|
+
indent_style = space
|
33
|
+
indent_size = 2
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
strongbolt
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.3
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
strongbolt (0.3.6)
|
5
|
+
awesome_nested_set (~> 3.0.0)
|
6
|
+
grant (~> 3.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionmailer (4.1.6)
|
12
|
+
actionpack (= 4.1.6)
|
13
|
+
actionview (= 4.1.6)
|
14
|
+
mail (~> 2.5, >= 2.5.4)
|
15
|
+
actionpack (4.1.6)
|
16
|
+
actionview (= 4.1.6)
|
17
|
+
activesupport (= 4.1.6)
|
18
|
+
rack (~> 1.5.2)
|
19
|
+
rack-test (~> 0.6.2)
|
20
|
+
actionview (4.1.6)
|
21
|
+
activesupport (= 4.1.6)
|
22
|
+
builder (~> 3.1)
|
23
|
+
erubis (~> 2.7.0)
|
24
|
+
activemodel (4.1.6)
|
25
|
+
activesupport (= 4.1.6)
|
26
|
+
builder (~> 3.1)
|
27
|
+
activerecord (4.1.6)
|
28
|
+
activemodel (= 4.1.6)
|
29
|
+
activesupport (= 4.1.6)
|
30
|
+
arel (~> 5.0.0)
|
31
|
+
activesupport (4.1.6)
|
32
|
+
i18n (~> 0.6, >= 0.6.9)
|
33
|
+
json (~> 1.7, >= 1.7.7)
|
34
|
+
minitest (~> 5.1)
|
35
|
+
thread_safe (~> 0.1)
|
36
|
+
tzinfo (~> 1.1)
|
37
|
+
arel (5.0.1.20140414130214)
|
38
|
+
awesome_nested_set (3.0.3)
|
39
|
+
activerecord (>= 4.0.0, < 5)
|
40
|
+
builder (3.2.2)
|
41
|
+
diff-lcs (1.2.5)
|
42
|
+
erubis (2.7.0)
|
43
|
+
fabrication (2.11.3)
|
44
|
+
fuubar (2.0.0)
|
45
|
+
rspec (~> 3.0)
|
46
|
+
ruby-progressbar (~> 1.4)
|
47
|
+
grant (3.0.0)
|
48
|
+
activerecord (>= 4.0.0)
|
49
|
+
hike (1.2.3)
|
50
|
+
i18n (0.6.11)
|
51
|
+
json (1.8.1)
|
52
|
+
mail (2.6.3)
|
53
|
+
mime-types (>= 1.16, < 3)
|
54
|
+
mime-types (2.4.3)
|
55
|
+
minitest (5.4.2)
|
56
|
+
multi_json (1.10.1)
|
57
|
+
rack (1.5.2)
|
58
|
+
rack-test (0.6.2)
|
59
|
+
rack (>= 1.0)
|
60
|
+
rails (4.1.6)
|
61
|
+
actionmailer (= 4.1.6)
|
62
|
+
actionpack (= 4.1.6)
|
63
|
+
actionview (= 4.1.6)
|
64
|
+
activemodel (= 4.1.6)
|
65
|
+
activerecord (= 4.1.6)
|
66
|
+
activesupport (= 4.1.6)
|
67
|
+
bundler (>= 1.3.0, < 2.0)
|
68
|
+
railties (= 4.1.6)
|
69
|
+
sprockets-rails (~> 2.0)
|
70
|
+
railties (4.1.6)
|
71
|
+
actionpack (= 4.1.6)
|
72
|
+
activesupport (= 4.1.6)
|
73
|
+
rake (>= 0.8.7)
|
74
|
+
thor (>= 0.18.1, < 2.0)
|
75
|
+
rake (10.3.2)
|
76
|
+
rspec (3.1.0)
|
77
|
+
rspec-core (~> 3.1.0)
|
78
|
+
rspec-expectations (~> 3.1.0)
|
79
|
+
rspec-mocks (~> 3.1.0)
|
80
|
+
rspec-core (3.1.5)
|
81
|
+
rspec-support (~> 3.1.0)
|
82
|
+
rspec-expectations (3.1.2)
|
83
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
84
|
+
rspec-support (~> 3.1.0)
|
85
|
+
rspec-mocks (3.1.2)
|
86
|
+
rspec-support (~> 3.1.0)
|
87
|
+
rspec-rails (3.1.0)
|
88
|
+
actionpack (>= 3.0)
|
89
|
+
activesupport (>= 3.0)
|
90
|
+
railties (>= 3.0)
|
91
|
+
rspec-core (~> 3.1.0)
|
92
|
+
rspec-expectations (~> 3.1.0)
|
93
|
+
rspec-mocks (~> 3.1.0)
|
94
|
+
rspec-support (~> 3.1.0)
|
95
|
+
rspec-support (3.1.1)
|
96
|
+
ruby-progressbar (1.6.0)
|
97
|
+
shoulda-matchers (2.7.0)
|
98
|
+
activesupport (>= 3.0.0)
|
99
|
+
sprockets (2.12.3)
|
100
|
+
hike (~> 1.2)
|
101
|
+
multi_json (~> 1.0)
|
102
|
+
rack (~> 1.0)
|
103
|
+
tilt (~> 1.1, != 1.3.0)
|
104
|
+
sprockets-rails (2.2.2)
|
105
|
+
actionpack (>= 3.0)
|
106
|
+
activesupport (>= 3.0)
|
107
|
+
sprockets (>= 2.8, < 4.0)
|
108
|
+
sqlite3 (1.3.9)
|
109
|
+
thor (0.19.1)
|
110
|
+
thread_safe (0.3.4)
|
111
|
+
tilt (1.4.1)
|
112
|
+
tzinfo (1.2.2)
|
113
|
+
thread_safe (~> 0.1)
|
114
|
+
|
115
|
+
PLATFORMS
|
116
|
+
ruby
|
117
|
+
|
118
|
+
DEPENDENCIES
|
119
|
+
bundler (> 1.7.0)
|
120
|
+
fabrication
|
121
|
+
fuubar
|
122
|
+
rails (~> 4.1.0)
|
123
|
+
rake
|
124
|
+
rspec-rails (~> 3.1.0)
|
125
|
+
shoulda-matchers
|
126
|
+
sqlite3 (= 1.3.9)
|
127
|
+
strongbolt!
|
128
|
+
|
129
|
+
BUNDLED WITH
|
130
|
+
1.11.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Thomas Césaré-Herriau
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
# Strongbolt
|
2
|
+
|
3
|
+
RBAC framework for model-level authorization gem with very granular control on permissions, using Capabilities, Roles and UserGroups.
|
4
|
+
|
5
|
+
Only works with Rails 4.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'grant', '>= 2.2', git: "git@github.com:AnalyticsMediaGroup/grant.git"
|
12
|
+
gem 'strongbolt', git: "git@github.com:AnalyticsMediaGroup/strongbolt.git"
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
## Getting Started
|
19
|
+
|
20
|
+
To creates the required migrations, run:
|
21
|
+
|
22
|
+
$ rails g strongbolt:install && rake db:migrate
|
23
|
+
|
24
|
+
To create a Role and User Group that has full access and assign the group to all users (this allow to get started using StrongBolt), run:
|
25
|
+
|
26
|
+
$ rake strongbolt:seed
|
27
|
+
|
28
|
+
If you plan on using the built-in view to manage user groups, roles and permissions, also add to your application.js:
|
29
|
+
|
30
|
+
//= require strongbolt
|
31
|
+
|
32
|
+
You will need to have jQuery or a similar library with Ajax to make it work
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
### Configuration
|
37
|
+
|
38
|
+
The initializer of strongbolt, `config/initializers/strongbolt.rb` has some included documentation to help you with configuring the little you need to for Strongbolt to work.
|
39
|
+
|
40
|
+
By default, the user class is `User` and there is no tenant set.
|
41
|
+
|
42
|
+
#### A note on the list of models
|
43
|
+
|
44
|
+
Strongbolt has been made to be used with the least configuration possible. If given a tenant, it will traverse the graph of dependencies on this tenant to try to configure all the tenant dependent models authorization check ups. However, some models may be totally independant or not belong to (directly or indirectly) to a tenant. You may also have no tenant at all. In these cases, some or all of your models won't be discovered by Strongbolt when running your app.
|
45
|
+
To avoid eager loading the whole application to automatically get the list of models, you can specify in the initializer the models of your application.
|
46
|
+
This list is prefilled when running the install generator.
|
47
|
+
|
48
|
+
### Controllers
|
49
|
+
|
50
|
+
Strongbolt perform high level authorization on controllers, to avoid testing more granular authorization and increase the performance. For instance, if an user cannot find any Movies, he certainly won't be able to find the movie with the specific id 5.
|
51
|
+
|
52
|
+
#### Custom controller actions
|
53
|
+
|
54
|
+
Strongbolt relies on the usual Rails restful actions to guess the corresponding model action (edit requires update authorization, new requires create authorization, etc.). However, you will sometimes create other custom actions. In that case, you must specify in the controller how to map these custom controller actions to one of the 4 model actions using:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
authorize_as_find :action1, :action2
|
58
|
+
authorize_as_create :action, :action2
|
59
|
+
authorize_as_update :action, :action2
|
60
|
+
authorize_as_destroy :action, :action2
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Skipping authorization
|
64
|
+
|
65
|
+
You can disable the controller-level authorization checks by using in the controllers:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
skip_controller_authorization,
|
69
|
+
skip_controller_authorization, only: [:index]
|
70
|
+
skip_controller_authorization, except: [:update]
|
71
|
+
```
|
72
|
+
|
73
|
+
You can also specify a list of controllers in the initializer `config/initializers/strongbolt.rb`. It is useful for third-party controllers, like devise for instance. The syntax is:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
config.skip_controller_authorization_for "Devise::SessionsController", "Devise::RegistrationsController"
|
77
|
+
```
|
78
|
+
|
79
|
+
You can also skip ALL authorization checks (BAD IDEA) using:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
skip_all_authorization
|
83
|
+
skip_all_authorization, only: [:index]
|
84
|
+
skip_all_authorization, except: [:update]
|
85
|
+
```
|
86
|
+
|
87
|
+
Sometimes you may want to render the views without checking again every single instance you're displaying (for the list of movies for instance, if the user can find ALL movies no need to test separatly each of them). You can skip the authorization checks when rendering pages by using:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
render_without_authorization :index, :show
|
91
|
+
```
|
92
|
+
|
93
|
+
Be careful when using one of this skipping authorization check as it may result in leaked data.
|
94
|
+
|
95
|
+
#### Controller not derived from a Model
|
96
|
+
|
97
|
+
Usually most of your controllers, in a RestFUL design, are backed by a specific model, derived from the name of the controller. In that case Strongbolt will know what model authorization it should test against. Otherwise, it will raise an error unless you specify the model for authorization:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
self.model_for_authorization = "Movie"
|
101
|
+
```
|
102
|
+
|
103
|
+
### Models
|
104
|
+
|
105
|
+
Usually you will never need to configure anything on the models. In some cases though, to simplify the roles and permissions, you may want to authorize some models as if they were other models (in nested models, sometimes it is safe to assume that the lower level model should have the same permissions than its parent)>
|
106
|
+
To achieve this, use the following within your model:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
authorize_as "Movie"
|
110
|
+
```
|
111
|
+
|
112
|
+
### Tenants
|
113
|
+
|
114
|
+
Strongbolt allows the utilization of _tenants_. Tenants are vertical scopes within your application.
|
115
|
+
|
116
|
+
> Let's take an example. A project tracking application (like Pivotal) can have several companies as clients, but each company's users can see only what concern them. _Company_ is a tenant of the application.
|
117
|
+
|
118
|
+
The initializer let you define the model(s) that should be considered tenants.
|
119
|
+
|
120
|
+
#### How to set what tenants a user has access to
|
121
|
+
|
122
|
+
Strongbolt comes with a table, `strongbolt_users_tenants`, that will store what tenants users have access to.
|
123
|
+
|
124
|
+
When a tenant is declared, it will add some features to the _User class_ that has been defined in the initializer.
|
125
|
+
|
126
|
+
First, an association between the _User class_ and the _Tenant class_ will be created, named after the _Tenant class_ name. It is a `has_many :trough => :users_tenants_` association.
|
127
|
+
|
128
|
+
> For instance, a `Company` tenant will generate a `companies` association.
|
129
|
+
|
130
|
+
A convenient instance method will also be created on the _User class_ to directly access the list of _Tenant class_ a _User_ can access. It is name `accessible_{tenants}` where `{tenants}` is the pluralize version of the _Tenant class_ name.
|
131
|
+
|
132
|
+
> `Company` will create an `accessible_companies` instance method
|
133
|
+
|
134
|
+
#### Tenanted models
|
135
|
+
|
136
|
+
A tenanted model is a model that belongs indirectly to a _Tenant class_.
|
137
|
+
|
138
|
+
> For instance, `Project` is a tenanted model of `Company`. Now, let's consider a `belong_to` association that links `Project` to a `Country`. The list of countries is stored in the table `countries` and does not belong to `Company`: `Country` is not a tenanted model.
|
139
|
+
|
140
|
+
Strongbolt will traverse your schema and automatically determine what models in your application is linked to your _Tenant class_.
|
141
|
+
|
142
|
+
> In our example, where `Project` belongs to `Company` and `Country`, but `Country` does not belong to `Company`, Strongbolt will automatically determine that `Project` is a tenanted model and `Country` is not.
|
143
|
+
|
144
|
+
Strongbolt will then create a `has_one` association on every tenanted model, so you can access directly the dependent _Tenant_
|
145
|
+
|
146
|
+
> For instance, every `Task` of a `Project` will have a `has_one :company, :through => :project` association automatically created (if not already existing).
|
147
|
+
|
148
|
+
#### Restricting permissions to accessible tenanted models
|
149
|
+
|
150
|
+
Strongbolt's capabilites have a boolean attribute, `require_tenant_access`, that specify whether the user can access all _tenanted models_ or only the ones that belong to the _Tenants_ he has access to.
|
151
|
+
|
152
|
+
> Let's look back at the example. Each companies has several _projects_. The normal user, belonging to a company, would only have access to his company's projects. You would then define for normal user a capability *requiring tenant access*
|
153
|
+
|
154
|
+
> An admin user, on the other hand, like an engineer of the application, could have access to all the companies' projects. An engineer's projects' permissions would then *not require tenant access*
|
155
|
+
|
156
|
+
It will then perform the right permission check based on this requirement and the relationship of the model being checked and the _Tenant class_. If the model being checked is not linked to any of the _Tenant classes_, it won't check any dependency.
|
157
|
+
|
158
|
+
|
159
|
+
### Troubleshooting
|
160
|
+
|
161
|
+
#### Strongbolt::ModelNotFound
|
162
|
+
|
163
|
+
This means Strongbolt is trying to perform some controller-level authorizations but cannot infer the model from the controller name. In that case you must use in this controller:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
self.model_for_authorization = "Movie"
|
167
|
+
```
|
168
|
+
|
169
|
+
Or skip controller authorizations when it cannot be related to a model or it is not useful (like for Devise controllers), using either one of the methods described in *Skipping Authorization*.
|
170
|
+
|
171
|
+
#### Strongbolt::ActionNotConfigured
|
172
|
+
|
173
|
+
This happens when a controller is using a custom action which is not one of the 6 usual restful Rails actions (index, new, create, sho, edit, update, destroy). Refer to *Custom controller actions* to fix this.
|
174
|
+
|
175
|
+
|
176
|
+
## Contributing
|
177
|
+
|
178
|
+
1. Fork it ( http://github.com/<my-github-username>/strongbolt/fork )
|
179
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
180
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
181
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
182
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require strongbolt/role-capabilities
|
@@ -0,0 +1,80 @@
|
|
1
|
+
(function() {
|
2
|
+
var RoleCapabilities;
|
3
|
+
|
4
|
+
RoleCapabilities = (function() {
|
5
|
+
function RoleCapabilities(table) {
|
6
|
+
this.table = table;
|
7
|
+
this.url = this.table.data('url');
|
8
|
+
this.setup();
|
9
|
+
}
|
10
|
+
|
11
|
+
RoleCapabilities.prototype.toggleAction = function(button) {
|
12
|
+
var granted, params, parent;
|
13
|
+
granted = !button.data('granted');
|
14
|
+
button.blur();
|
15
|
+
button.data("granted", granted);
|
16
|
+
parent = button.parent();
|
17
|
+
params = {
|
18
|
+
model: parent.data('model'),
|
19
|
+
require_ownership: parent.data('require-ownership'),
|
20
|
+
require_tenant_access: parent.data('require-tenant-access'),
|
21
|
+
action: button.data('action')
|
22
|
+
};
|
23
|
+
return this[granted ? 'addAction' : 'destroyAction'](params, function() {
|
24
|
+
if (granted) {
|
25
|
+
button.addClass('btn-success');
|
26
|
+
return button.removeClass('btn-danger');
|
27
|
+
} else {
|
28
|
+
button.addClass('btn-danger');
|
29
|
+
return button.removeClass('btn-success');
|
30
|
+
}
|
31
|
+
});
|
32
|
+
};
|
33
|
+
|
34
|
+
RoleCapabilities.prototype.destroyAction = function(params, callback) {
|
35
|
+
var options;
|
36
|
+
options = {
|
37
|
+
data: {
|
38
|
+
capability: params
|
39
|
+
},
|
40
|
+
type: "DELETE",
|
41
|
+
complete: callback
|
42
|
+
};
|
43
|
+
return this.request(options);
|
44
|
+
};
|
45
|
+
|
46
|
+
RoleCapabilities.prototype.addAction = function(params, callback) {
|
47
|
+
var options;
|
48
|
+
options = {
|
49
|
+
data: {
|
50
|
+
capability: params
|
51
|
+
},
|
52
|
+
type: "POST",
|
53
|
+
complete: callback
|
54
|
+
};
|
55
|
+
return this.request(options);
|
56
|
+
};
|
57
|
+
|
58
|
+
RoleCapabilities.prototype.request = function(options) {
|
59
|
+
options.url = this.url;
|
60
|
+
options.dataType = 'json';
|
61
|
+
return $.ajax(options);
|
62
|
+
};
|
63
|
+
|
64
|
+
RoleCapabilities.prototype.setup = function() {
|
65
|
+
return this.table.on('click', 'button[data-action]', (function(_this) {
|
66
|
+
return function(event) {
|
67
|
+
return _this.toggleAction($(event.currentTarget));
|
68
|
+
};
|
69
|
+
})(this));
|
70
|
+
};
|
71
|
+
|
72
|
+
return RoleCapabilities;
|
73
|
+
|
74
|
+
})();
|
75
|
+
|
76
|
+
$(document).ready(function() {
|
77
|
+
return new RoleCapabilities($("#role-capabilities"));
|
78
|
+
});
|
79
|
+
|
80
|
+
}).call(this);
|