action_access 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/CONTRIBUTING.md +23 -0
  4. data/Gemfile +14 -0
  5. data/Gemfile.lock +87 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.md +283 -0
  8. data/Rakefile +28 -0
  9. data/action_access.gemspec +24 -0
  10. data/lib/action_access.rb +14 -0
  11. data/lib/action_access/controller_additions.rb +75 -0
  12. data/lib/action_access/keeper.rb +90 -0
  13. data/lib/action_access/model_additions.rb +14 -0
  14. data/lib/action_access/railtie.rb +19 -0
  15. data/lib/action_access/user_utilities.rb +39 -0
  16. data/lib/action_access/version.rb +3 -0
  17. data/test/action_access_test.rb +21 -0
  18. data/test/controllers/articles_controller_test.rb +41 -0
  19. data/test/controllers/secrets_controller_test.rb +10 -0
  20. data/test/controllers/static_controller_test.rb +15 -0
  21. data/test/dummy/README.rdoc +28 -0
  22. data/test/dummy/Rakefile +6 -0
  23. data/test/dummy/app/assets/images/.keep +0 -0
  24. data/test/dummy/app/assets/javascripts/application.js +13 -0
  25. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  26. data/test/dummy/app/controllers/application_controller.rb +15 -0
  27. data/test/dummy/app/controllers/articles_controller.rb +36 -0
  28. data/test/dummy/app/controllers/concerns/.keep +0 -0
  29. data/test/dummy/app/controllers/secrets_controller.rb +4 -0
  30. data/test/dummy/app/controllers/static_controller.rb +6 -0
  31. data/test/dummy/app/helpers/application_helper.rb +2 -0
  32. data/test/dummy/app/mailers/.keep +0 -0
  33. data/test/dummy/app/models/.keep +0 -0
  34. data/test/dummy/app/models/concerns/.keep +0 -0
  35. data/test/dummy/app/models/user.rb +7 -0
  36. data/test/dummy/app/views/articles/edit.html.erb +1 -0
  37. data/test/dummy/app/views/articles/index.html.erb +1 -0
  38. data/test/dummy/app/views/articles/new.html.erb +1 -0
  39. data/test/dummy/app/views/articles/show.html.erb +3 -0
  40. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/test/dummy/app/views/static/home.html.erb +1 -0
  42. data/test/dummy/bin/bundle +3 -0
  43. data/test/dummy/bin/rails +4 -0
  44. data/test/dummy/bin/rake +4 -0
  45. data/test/dummy/config.ru +4 -0
  46. data/test/dummy/config/application.rb +23 -0
  47. data/test/dummy/config/boot.rb +5 -0
  48. data/test/dummy/config/database.yml +25 -0
  49. data/test/dummy/config/environment.rb +5 -0
  50. data/test/dummy/config/environments/development.rb +37 -0
  51. data/test/dummy/config/environments/production.rb +78 -0
  52. data/test/dummy/config/environments/test.rb +39 -0
  53. data/test/dummy/config/initializers/assets.rb +8 -0
  54. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  55. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  56. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  57. data/test/dummy/config/initializers/inflections.rb +16 -0
  58. data/test/dummy/config/initializers/mime_types.rb +4 -0
  59. data/test/dummy/config/initializers/session_store.rb +3 -0
  60. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  61. data/test/dummy/config/locales/en.yml +23 -0
  62. data/test/dummy/config/routes.rb +6 -0
  63. data/test/dummy/config/secrets.yml +22 -0
  64. data/test/dummy/db/migrate/20140926071026_create_users.rb +10 -0
  65. data/test/dummy/db/schema.rb +23 -0
  66. data/test/dummy/lib/assets/.keep +0 -0
  67. data/test/dummy/log/.keep +0 -0
  68. data/test/dummy/public/404.html +67 -0
  69. data/test/dummy/public/422.html +67 -0
  70. data/test/dummy/public/500.html +66 -0
  71. data/test/dummy/public/favicon.ico +0 -0
  72. data/test/models/user_test.rb +22 -0
  73. data/test/support/compact_environment.rb +9 -0
  74. data/test/test_helper.rb +8 -0
  75. metadata +203 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c3a922a62dc47428db03349b5ab4381c32d669ea
4
+ data.tar.gz: 639f7cf2ce63e3783f7d33970ea874624f8c7981
5
+ SHA512:
6
+ metadata.gz: 10c2835e378462860b56b636431ebb26ac196acd179c82703a72bb77cb61745352b97ed668d28f2999dc88a4deec16f0ac32d3c10794a42be1489dd103b37d94
7
+ data.tar.gz: 8a1b64c08c10887c41e55a1e8f16d2ed8677cd68a7f7ef42f050f8e04a7d517727e2651e7841c0cc8bfa84b195768ae7c43d99c168eaa0f6a6d61e2b96bf797a
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/db/*.sqlite3-journal
6
+ test/dummy/log/*.log
7
+ test/dummy/tmp/
8
+ test/dummy/.sass-cache
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,23 @@
1
+ ## Please read before contributing
2
+
3
+ 1. If you have questions about Action Access, use the
4
+ [Mailing List](https://groups.google.com/d/forum/action_access) or
5
+ [Stack Overflow](https://stackoverflow.com/questions/tagged/action_access).
6
+ Do not post questions here.
7
+
8
+ 2. If you find a security bug, **DO NOT** submit an issue here.
9
+ Please send an e-mail to [mgag.issues@gmail.com](mailto:mgag.issues@gmail.com)
10
+ instead.
11
+
12
+ 3. Do a small search on the issues tracker before submitting your issue to
13
+ see if it was already reported or fixed. In case it was not, create your report
14
+ with a **clear description** of the issue and a **code sample** that
15
+ demonstrates it. Include Rails and Action Access versions, and as much relevant
16
+ information as possible. Tests or a sample application showing how the
17
+ expected behavior is not occurring will be much appreciated.
18
+
19
+ The more information you give, the easier it becomes to track the issue and fix
20
+ it. Your goal should be to make it easy for yourself and others to replicate
21
+ the bug and figure out a fix.
22
+
23
+ Thanks for your time and support!
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in action_access.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # Declare any dependencies that are still in development here instead of in
9
+ # your gemspec. These might include edge Rails or gems from your path or
10
+ # Git. Remember to move these dependencies to your gemspec before releasing
11
+ # your gem to rubygems.org.
12
+
13
+ # To use debugger
14
+ # gem 'debugger'
data/Gemfile.lock ADDED
@@ -0,0 +1,87 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ action_access (0.0.1)
5
+ rails (~> 4.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actionmailer (4.1.6)
11
+ actionpack (= 4.1.6)
12
+ actionview (= 4.1.6)
13
+ mail (~> 2.5, >= 2.5.4)
14
+ actionpack (4.1.6)
15
+ actionview (= 4.1.6)
16
+ activesupport (= 4.1.6)
17
+ rack (~> 1.5.2)
18
+ rack-test (~> 0.6.2)
19
+ actionview (4.1.6)
20
+ activesupport (= 4.1.6)
21
+ builder (~> 3.1)
22
+ erubis (~> 2.7.0)
23
+ activemodel (4.1.6)
24
+ activesupport (= 4.1.6)
25
+ builder (~> 3.1)
26
+ activerecord (4.1.6)
27
+ activemodel (= 4.1.6)
28
+ activesupport (= 4.1.6)
29
+ arel (~> 5.0.0)
30
+ activesupport (4.1.6)
31
+ i18n (~> 0.6, >= 0.6.9)
32
+ json (~> 1.7, >= 1.7.7)
33
+ minitest (~> 5.1)
34
+ thread_safe (~> 0.1)
35
+ tzinfo (~> 1.1)
36
+ arel (5.0.1.20140414130214)
37
+ builder (3.2.2)
38
+ erubis (2.7.0)
39
+ hike (1.2.3)
40
+ i18n (0.6.11)
41
+ json (1.8.1)
42
+ mail (2.6.1)
43
+ mime-types (>= 1.16, < 3)
44
+ mime-types (2.3)
45
+ minitest (5.4.1)
46
+ multi_json (1.10.1)
47
+ rack (1.5.2)
48
+ rack-test (0.6.2)
49
+ rack (>= 1.0)
50
+ rails (4.1.6)
51
+ actionmailer (= 4.1.6)
52
+ actionpack (= 4.1.6)
53
+ actionview (= 4.1.6)
54
+ activemodel (= 4.1.6)
55
+ activerecord (= 4.1.6)
56
+ activesupport (= 4.1.6)
57
+ bundler (>= 1.3.0, < 2.0)
58
+ railties (= 4.1.6)
59
+ sprockets-rails (~> 2.0)
60
+ railties (4.1.6)
61
+ actionpack (= 4.1.6)
62
+ activesupport (= 4.1.6)
63
+ rake (>= 0.8.7)
64
+ thor (>= 0.18.1, < 2.0)
65
+ rake (10.3.2)
66
+ sprockets (2.12.2)
67
+ hike (~> 1.2)
68
+ multi_json (~> 1.0)
69
+ rack (~> 1.0)
70
+ tilt (~> 1.1, != 1.3.0)
71
+ sprockets-rails (2.1.4)
72
+ actionpack (>= 3.0)
73
+ activesupport (>= 3.0)
74
+ sprockets (~> 2.8)
75
+ sqlite3 (1.3.9)
76
+ thor (0.19.1)
77
+ thread_safe (0.3.4)
78
+ tilt (1.4.1)
79
+ tzinfo (1.2.2)
80
+ thread_safe (~> 0.1)
81
+
82
+ PLATFORMS
83
+ ruby
84
+
85
+ DEPENDENCIES
86
+ action_access!
87
+ sqlite3
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Matías A. Gagliano
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.md ADDED
@@ -0,0 +1,283 @@
1
+ # Action Access
2
+
3
+ Action Access is an access control system for Ruby on Rails. It provides a
4
+ modular and easy way to secure applications and handle permissions.
5
+
6
+ It works at controller level focusing on what **actions** are accessible for
7
+ the current user instead of handling models and their attributes.
8
+
9
+ It also provides utilities for thorough control and some useful view helpers.
10
+
11
+
12
+ ## Installation
13
+
14
+ Add `action_access` to the app's Gemfile, run the `bundle` command and restart
15
+ any running server.
16
+
17
+ ```ruby
18
+ # Gemfile
19
+ gem 'action_access'
20
+ ```
21
+
22
+
23
+ ## Basic configuration
24
+
25
+ The most important setting is the way to get the **clearance level** (role,
26
+ user group, etc.), other than that it works out of the box.
27
+
28
+ Action Access doesn't require users or authentication at all to function so
29
+ you can get creative with the way you set and identify clearance levels.
30
+
31
+ It only needs a `current_clearance_level` method that returns the proper
32
+ clearance level for the current request. It can be a string or symbol and
33
+ it doesn't matter if it's singular or plural, it'll be singularized.
34
+
35
+ * With `current_user`:
36
+
37
+ The default `current_clearance_level` method tests if it can get
38
+ `current_user.clearance_level` and defaults to `:guest` if not.
39
+
40
+ So, if you already have a `current_user` method you just need to add a
41
+ `clearance_level` method to the user. With a role based authorization you
42
+ may add the following to your `User` model:
43
+
44
+ ```ruby
45
+ class User < ActiveRecord::Base
46
+ belongs_to :role
47
+
48
+ def clearance_level
49
+ role.name
50
+ end
51
+ end
52
+ ```
53
+
54
+ * No `current_user`:
55
+
56
+ If there's no `current_user` you need to override `current_clearance_level`
57
+ with whatever logic that applies to your application.
58
+
59
+ Continuing with the role based example, you might do something like this:
60
+
61
+ ```ruby
62
+ class ApplicationController < ActionController::Base
63
+ def current_clearance_level
64
+ session[:role] || :guest
65
+ end
66
+ end
67
+ ```
68
+
69
+
70
+ ## Setting permissions
71
+
72
+ Permissions are set through authorization statements using the **let** class
73
+ method available in every controller. The first parameter is the clearance
74
+ level (plural or singular) and the second is the action or list of actions.
75
+
76
+ As a simple example, to allow administrators (and only administrators in this
77
+ case) to delete articles you'd add the following to `ArticlesController`:
78
+
79
+ ```ruby
80
+ class ArticlesController < ApplicationController
81
+ let :admins, :destroy
82
+
83
+ def destroy
84
+ # ...
85
+ end
86
+
87
+ # ...
88
+ end
89
+ ```
90
+
91
+ This will automatically **lock** the controller and only allow administrators
92
+ accessing the destroy action. **Every other request** pointing to the controller
93
+ **will be rejected** and redirected with an alert.
94
+
95
+ ### Real-life example:
96
+
97
+ ```ruby
98
+ class ArticlesController < ApplicationController
99
+ let :admins, :all
100
+ let :editors, [:index, :show, :edit, :update]
101
+ let :all, [:index, :show]
102
+
103
+ def index
104
+ # ...
105
+ end
106
+
107
+ # ...
108
+ end
109
+ ```
110
+
111
+ These statements lock the controller and set the following:
112
+ * _Administrators_ (admins) are authorized to access any action.
113
+ * _Editors_ can list, view and edit articles.
114
+ * _Anyone else_ can **only** list and view articles.
115
+
116
+ This case uses the special keyword `:all`, it means everyone if passed as the
117
+ first argument or every action if passed as the second one.
118
+
119
+ Again, any unauthorized request will be rejected and redirected with an alert.
120
+
121
+ ### Note about clearance levels
122
+
123
+ Notice that in the previous examples we didn't need to define clearance levels
124
+ or roles anywhere else in the application. With the authorization statement you
125
+ both **define** them and **set their permissions**. The only requirement is
126
+ that the clearance levels from the authorizations match the one returned by
127
+ `current_clearance_level`.
128
+
129
+
130
+ ## Advanced configuration
131
+
132
+ ### Locked by default
133
+
134
+ The `lock_access` class method forces controllers to be locked even if no
135
+ permissions are defined, in such case every request will be redirected.
136
+
137
+ This allows to ensure that an entire application or scope (e.g. `Admin`) is
138
+ **locked by default**. Simply call `lock_access` inside `ApplicationController`
139
+ or from a scope's base controller.
140
+
141
+ ```ruby
142
+ class ApplicationController < ActionController::Base
143
+ lock_access
144
+
145
+ # ...
146
+ end
147
+ ```
148
+
149
+ To **unlock** a single controller (to make it "public") add `let :all, :all`,
150
+ this will allow anyone to access any action in the controller.
151
+
152
+ ### Redirection path
153
+
154
+ By default any unauthorized (or not explicitly authorized) access will be
155
+ redirected to the **root path**.
156
+
157
+ You can set or choose a different path by overriding the somewhat long but
158
+ very clear `unauthorized_access_redirection_path` method.
159
+
160
+ ```ruby
161
+ class ApplicationController < ActionController::Base
162
+
163
+ def unathorized_access_redirection_path
164
+ case current_user.clearance_level.to_sym
165
+ when :admin then admin_root_path
166
+ when :user then user_root_path
167
+ else root_path
168
+ end
169
+ end
170
+
171
+ # ...
172
+ end
173
+ ```
174
+
175
+ ### Alert message
176
+
177
+ Redirections have a default alert message of "Not authorized.". To customize it
178
+ or use translations set `action_access.redirection_message` in your locales.
179
+
180
+ ```yml
181
+ # config/locales/en.yml
182
+ en:
183
+ action_access:
184
+ redirection_message: "You are not allowed to do this!"
185
+ ```
186
+
187
+
188
+ ## Utilities
189
+
190
+ ### Fine Grained Access Control
191
+
192
+ If further control is required, possibly because access depends on request
193
+ parameters or some result from the database, you can use the `not_authorized!`
194
+ method inside actions to reject the request and issue a redirection. It
195
+ optionally takes a redirection path and a custom alert message.
196
+
197
+ ```ruby
198
+ class ProfilesController < ApplicationController
199
+ let :user, [:edit, :update]
200
+
201
+ def update
202
+ unless params[:id] == current_user.profile_id
203
+ not_authorized! path: profile_path, message: "That's not your profile!"
204
+ end
205
+
206
+ # ...
207
+ end
208
+
209
+ # ...
210
+ end
211
+ ```
212
+
213
+ There are better ways to handle this particular case but it serves to outline
214
+ the use of `not_authorized!` inside actions.
215
+
216
+ ### Model additions
217
+
218
+ Action Access is bundled with some model utilities too. By calling
219
+ `add_access_utilities` in any model it will extend it with a `can?` instance
220
+ method that checks if the entity (commonly a user) is authorized to perform a
221
+ given action on a resource.
222
+
223
+ `can?` takes two arguments, the action and the resource, and a namespace option
224
+ if needed. The resource can be a string, symbol, controller class or model
225
+ instance. Action Access will do the possible to get the right controller out
226
+ of the resource and the namespace (optional). In the end it returns a boolean.
227
+
228
+ **Some examples:**
229
+
230
+ ```ruby
231
+ @user.can? :edit, :articles, namespace: :admin
232
+ @user.can? :edit, @admin_article # Admin::Article instance
233
+ @user.can? :edit, Admin::ArticlesController
234
+ # True if the user's clearance level allows her to access 'admin/articles#edit'.
235
+ ```
236
+
237
+ `can?` depends on a `clearance_level` method in the model so don't forget it.
238
+ Continuing with the `User` model from before:
239
+
240
+ ```ruby
241
+ class User < ActiveRecord::Base
242
+ add_access_utilities
243
+
244
+ belongs_to :role
245
+
246
+ def clearance_level
247
+ role.name
248
+ end
249
+ end
250
+ ```
251
+
252
+ ```erb
253
+ <% if current_user.can? :edit, :articles %>
254
+ <%= link_to 'Edit article', edit_article_path(@article) %>
255
+ <% end %>
256
+ ```
257
+
258
+ ### The keeper
259
+
260
+ The **keeper** is the core of Action Access, it's the one that registers
261
+ permissions and who decides if a clearance level grants access or not.
262
+
263
+ It's available as `keeper` within controllers and views and as
264
+ `ActionAccess::Keeper.instance` anywhere else. You can use it check permissions
265
+ with the `lets?` method that takes the clearance level as the first argument,
266
+ the rest are the same as `can?`.
267
+
268
+ ```ruby
269
+ # Filter a list of users to only those allowed to edit articles.
270
+ @users.select { |user| keeper.lets? user.role.name, :edit, :articles }
271
+ ```
272
+
273
+
274
+ ## License
275
+
276
+ Action Access is released under the [MIT License](http://opensource.org/licenses/MIT).
277
+
278
+ Copyright (c) 2014 Matías A. Gagliano.
279
+
280
+
281
+ ## Contributing
282
+
283
+ See [CONTRIBUTING.md](CONTRIBUTING.md).