action_bouncer 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +94 -0
  3. data/Rakefile +0 -5
  4. data/lib/action_bouncer.rb +4 -2
  5. data/lib/action_bouncer/allowance.rb +32 -0
  6. data/lib/action_bouncer/authorization.rb +7 -28
  7. data/lib/action_bouncer/version.rb +1 -1
  8. data/spec/controllers/all_param_controller_spec.rb +52 -0
  9. data/spec/controllers/array_params_controller_spec.rb +39 -0
  10. data/spec/controllers/multiple_allowances_controller_spec.rb +64 -0
  11. data/spec/controllers/no_setup_controller_spec.rb +22 -0
  12. data/spec/controllers/symbol_params_controller_spec.rb +34 -0
  13. data/spec/dummy/README.rdoc +28 -0
  14. data/spec/dummy/Rakefile +6 -0
  15. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  16. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  17. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  18. data/spec/dummy/app/controllers/dummy_controller.rb +4 -0
  19. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  20. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  21. data/spec/dummy/bin/bundle +3 -0
  22. data/spec/dummy/bin/rails +4 -0
  23. data/spec/dummy/bin/rake +4 -0
  24. data/spec/dummy/bin/setup +29 -0
  25. data/spec/dummy/config.ru +4 -0
  26. data/spec/dummy/config/application.rb +26 -0
  27. data/spec/dummy/config/boot.rb +5 -0
  28. data/spec/dummy/config/database.yml +25 -0
  29. data/spec/dummy/config/environment.rb +5 -0
  30. data/spec/dummy/config/environments/development.rb +41 -0
  31. data/spec/dummy/config/environments/production.rb +79 -0
  32. data/spec/dummy/config/environments/test.rb +42 -0
  33. data/spec/dummy/config/initializers/assets.rb +11 -0
  34. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  36. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  37. data/spec/dummy/config/initializers/inflections.rb +16 -0
  38. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  39. data/spec/dummy/config/initializers/session_store.rb +3 -0
  40. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  41. data/spec/dummy/config/locales/en.yml +23 -0
  42. data/spec/dummy/config/routes.rb +3 -0
  43. data/spec/dummy/config/secrets.yml +22 -0
  44. data/spec/dummy/db/test.sqlite3 +0 -0
  45. data/spec/dummy/log/development.log +0 -0
  46. data/spec/dummy/log/test.log +2711 -0
  47. data/spec/dummy/public/404.html +67 -0
  48. data/spec/dummy/public/422.html +67 -0
  49. data/spec/dummy/public/500.html +66 -0
  50. data/spec/dummy/public/favicon.ico +0 -0
  51. data/spec/spec_helper.rb +21 -0
  52. metadata +94 -5
  53. data/README.rdoc +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 737c58734c45cfd9ea3b705412d84a0674952509
4
- data.tar.gz: 428e63fc796799241ced68c3a3f12b3d74886e12
3
+ metadata.gz: ea988351cd9b96ae83cfcb77a9523a6012d87eac
4
+ data.tar.gz: 9a7046bfc38c1f086854076f45a80a5535ceb621
5
5
  SHA512:
6
- metadata.gz: 7a2a51d32a80c19f0c6d859581bdc3965b07eec6537c9e92b340e2212725208b274fe8f3ff8923e1b918f0344a4f023616449159ce76d48ff51449dde57cc3e6
7
- data.tar.gz: 899deb6408b2523f08b70259375c9b95cdc7002379c08a573aef05c5200e2da0e903fb96110f2b179ee9d1bb939364a03733d911b4f04149fa45bc450d340806
6
+ metadata.gz: 44b598c4812fb59bc9ba1758ee9d59e76119bc89347537771cf50f9ff85abcb252582f741f594f3e7f7512a0b0873e4accbfcae243d61a1286037e68317545fd
7
+ data.tar.gz: 800b74c749214f02d234e9c7787b61205b2ad2be53720e5b2cb4332c67518575a43d28f4f9fb09d2dc7d34ea8faf5ca434e99d48139d89f3ea37f84745af4d7c
data/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # ActionBouncer
2
+
3
+ [![Circle CI](https://circleci.com/gh/oswaldoferreira/action_bouncer/tree/master.svg?style=svg)](https://circleci.com/gh/oswaldoferreira/action_bouncer/tree/master)
4
+
5
+ It's a dead simple Rails authorization lib for well defined authorization objects interfaces.
6
+
7
+ ## Installing
8
+
9
+ Add it to your gemfile:
10
+
11
+ `gem 'action_bouncer'`
12
+
13
+ Or manually install it:
14
+
15
+ `gem install action_bouncer`
16
+
17
+ ## Examples
18
+
19
+ Allowing user to access specific actions:
20
+
21
+ ```ruby
22
+ class UsersController < ApplicationController
23
+ allow :current_user, to: [:index, :new], if: :admin?
24
+
25
+ def index
26
+ end
27
+
28
+ def new
29
+ end
30
+
31
+ def edit
32
+ end
33
+ end
34
+ ```
35
+
36
+ Allowing user to access all actions:
37
+
38
+ ```ruby
39
+ class UsersController < ApplicationController
40
+ allow :current_user, to: :all, if: :admin?
41
+
42
+ def index
43
+ end
44
+
45
+ def new
46
+ end
47
+
48
+ def edit
49
+ end
50
+ end
51
+ ```
52
+
53
+ Also, you can pass multiple methods that your authorizable object responds to:
54
+
55
+ ```ruby
56
+ allow :current_user, to: [:index, :new], if: [:admin?, :leader?]
57
+ ```
58
+
59
+ And allow users with different authorizations to access different actions:
60
+
61
+ ```ruby
62
+ allow :current_user, to: :index, if: :leader?
63
+ allow :current_user, to: :all, if: :admin?
64
+ ```
65
+
66
+ When not authorized, `ActionBouncer` raises an exception that can be rescued on your `ApplicationController`:
67
+
68
+ ```ruby
69
+ class ApplicationController < ActionController::Base
70
+ protect_from_forgery with: :exception
71
+
72
+ before_action :authenticate_user!
73
+
74
+ include ActionBouncer
75
+
76
+ rescue_from ActionBouncer::Unauthorized,
77
+ with: :user_not_authorized
78
+
79
+ private
80
+
81
+ def user_not_authorized
82
+ render nothing: true, status: :unauthorized
83
+ end
84
+ end
85
+ ```
86
+
87
+ ## Development
88
+
89
+ ```
90
+ bundle install
91
+ bundle exec rspec spec
92
+ ```
93
+
94
+ Feel free to create issues and submit pull requests.
data/Rakefile CHANGED
@@ -14,11 +14,6 @@ RDoc::Task.new(:rdoc) do |rdoc|
14
14
  rdoc.rdoc_files.include('lib/**/*.rb')
15
15
  end
16
16
 
17
-
18
-
19
-
20
-
21
-
22
17
  Bundler::GemHelper.install_tasks
23
18
 
24
19
  require 'rake/testtask'
@@ -1,14 +1,16 @@
1
+ require 'action_bouncer/allowance'
1
2
  require 'action_bouncer/authorization'
2
3
 
3
4
  module ActionBouncer
4
5
  def self.included(klass)
5
6
  klass.class_eval do
6
7
  def self.allow(resource, options)
7
- @_authorization = Authorization.new(resource, options)
8
+ @_allowances ||= []
9
+ @_allowances << Allowance.new(resource, options)
8
10
  end
9
11
 
10
12
  def self._authorization
11
- @_authorization
13
+ Authorization.new(@_allowances)
12
14
  end
13
15
 
14
16
  before_action { self.class._authorization.try(:authorize!, self) }
@@ -0,0 +1,32 @@
1
+ module ActionBouncer
2
+ class Allowance
3
+ attr_reader :resource_sym
4
+
5
+ def initialize(resource_sym, options)
6
+ @resource_sym, @options = resource_sym, options
7
+ end
8
+
9
+ def not_allowed?(controller, action)
10
+ resource = controller.send(@resource_sym)
11
+ !allowed_action?(action) || !matches_resource_condition?(resource)
12
+ end
13
+
14
+ private
15
+
16
+ def allowed_action?(action)
17
+ allowed_actions.include?(action.to_sym) || allowed_actions.include?(:all)
18
+ end
19
+
20
+ def matches_resource_condition?(resource)
21
+ conditions.any? { |condition| resource.send(condition).present? }
22
+ end
23
+
24
+ def allowed_actions
25
+ Array.wrap(@options[:to])
26
+ end
27
+
28
+ def conditions
29
+ Array.wrap(@options[:if])
30
+ end
31
+ end
32
+ end
@@ -2,41 +2,20 @@ module ActionBouncer
2
2
  class Unauthorized < StandardError; end
3
3
 
4
4
  class Authorization
5
- attr_reader :resource_sym
6
-
7
- def initialize(resource_sym, options)
8
- @resource_sym, @options = resource_sym, options
5
+ def initialize(allowances)
6
+ @allowances = allowances
9
7
  end
10
8
 
11
9
  def authorize!(controller)
12
- action = controller.send(:params).fetch(:action)
13
- resource = controller.send(@resource_sym)
14
-
15
- fail Unauthorized if unauthorized?(action, resource)
10
+ return if @allowances.nil?
11
+ fail Unauthorized if unauthorized?(controller)
16
12
  end
17
13
 
18
14
  private
19
15
 
20
- def unauthorized?(action, resource)
21
- !authorized_action?(action) || !matches_resource_condition?(resource)
22
- end
23
-
24
- def authorized_action?(action)
25
- allowed_actions.include?(action.to_sym) || allowed_actions.include?(:all)
26
- end
27
-
28
- def matches_resource_condition?(resource)
29
- conditions.any? { |condition| resource.send(condition).present? }
30
- end
31
-
32
- def allowed_actions
33
- allowed_actions = @options[:to]
34
- allowed_actions.is_a?(Array) ? allowed_actions : [allowed_actions]
35
- end
36
-
37
- def conditions
38
- conditions = @options[:if]
39
- conditions.is_a?(Array) ? conditions : [conditions]
16
+ def unauthorized?(controller)
17
+ action = controller.send(:params).fetch(:action)
18
+ @allowances.all? { |allowance| allowance.not_allowed?(controller, action) }
40
19
  end
41
20
  end
42
21
  end
@@ -1,3 +1,3 @@
1
1
  module ActionBouncer
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ class AllParamController < ActionController::Base
4
+ helper_method :current_user
5
+
6
+ include ActionBouncer
7
+
8
+ allow :current_user, to: :all, if: :admin?
9
+
10
+ def index
11
+ render nothing: true, status: :success
12
+ end
13
+
14
+ def new
15
+ render nothing: true, status: :success
16
+ end
17
+
18
+ def edit
19
+ render nothing: true, status: :success
20
+ end
21
+ end
22
+
23
+ describe AllParamController do
24
+ before do
25
+ Rails.application.routes.draw do
26
+ get '/index' => 'all_param#index'
27
+ get '/new' => 'all_param#new'
28
+ get '/edit' => 'all_param#edit'
29
+ end
30
+ end
31
+
32
+ context 'when authorized' do
33
+ before do
34
+ allow(subject).to receive(:current_user) { OpenStruct.new(admin?: true) }
35
+ end
36
+
37
+ it { expect{ get :edit }.not_to raise_error }
38
+ it { expect{ get :index }.not_to raise_error }
39
+ it { expect{ get :new }.not_to raise_error }
40
+ end
41
+
42
+ context 'when not authorized' do
43
+ before do
44
+ allow(subject).to receive(:current_user) { OpenStruct.new(admin?: false) }
45
+ end
46
+
47
+ it { expect{ get :edit }.to raise_error{ ActionBouncer::Unauthorized } }
48
+ it { expect{ get :index }.to raise_error{ ActionBouncer::Unauthorized } }
49
+ it { expect{ get :new }.to raise_error{ ActionBouncer::Unauthorized } }
50
+ end
51
+ end
52
+
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ class ArrayParamsController < ActionController::Base
4
+ helper_method :current_user
5
+
6
+ def current_user
7
+ OpenStruct.new(admin?: false, leader?: true)
8
+ end
9
+
10
+ include ActionBouncer
11
+
12
+ allow :current_user, to: [:index, :new], if: [:admin?, :leader?]
13
+
14
+ def index
15
+ render nothing: true, status: :success
16
+ end
17
+
18
+ def new
19
+ render nothing: true, status: :success
20
+ end
21
+
22
+ def edit
23
+ render nothing: true, status: :success
24
+ end
25
+ end
26
+
27
+ describe ArrayParamsController do
28
+ before do
29
+ Rails.application.routes.draw do
30
+ get '/index' => 'array_params#index'
31
+ get '/new' => 'array_params#new'
32
+ get '/edit' => 'array_params#edit'
33
+ end
34
+ end
35
+
36
+ it { expect{ get :edit }.to raise_error(ActionBouncer::Unauthorized) }
37
+ it { expect{ get :index }.not_to raise_error }
38
+ it { expect{ get :new }.not_to raise_error }
39
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ class MultipleAllowancesController < ActionController::Base
4
+ helper_method :current_user
5
+
6
+ include ActionBouncer
7
+
8
+ allow :current_user, to: [:index, :new], if: [:leader?, :admin?]
9
+ allow :current_user, to: :edit, if: :admin?
10
+
11
+ def index
12
+ render nothing: true, status: :success
13
+ end
14
+
15
+ def new
16
+ render nothing: true, status: :success
17
+ end
18
+
19
+ def edit
20
+ render nothing: true, status: :success
21
+ end
22
+ end
23
+
24
+ describe MultipleAllowancesController do
25
+ before do
26
+ Rails.application.routes.draw do
27
+ get '/index' => 'multiple_allowances#index'
28
+ get '/new' => 'multiple_allowances#new'
29
+ get '/edit' => 'multiple_allowances#edit'
30
+ end
31
+ end
32
+
33
+ context 'when authorized' do
34
+ context 'as leader' do
35
+ before do
36
+ allow(subject).to receive(:current_user) { OpenStruct.new(leader?: true) }
37
+ end
38
+
39
+ it { expect{ get :index }.not_to raise_error }
40
+ it { expect{ get :new }.not_to raise_error }
41
+ end
42
+
43
+ context 'as admin' do
44
+ before do
45
+ allow(subject).to receive(:current_user) { OpenStruct.new(admin?: true) }
46
+ end
47
+
48
+ it { expect{ get :index }.not_to raise_error }
49
+ it { expect{ get :new }.not_to raise_error }
50
+ it { expect{ get :edit }.not_to raise_error }
51
+ end
52
+ end
53
+
54
+ context 'when not authorized' do
55
+ context 'when leader' do
56
+ before do
57
+ allow(subject).to receive(:current_user) { OpenStruct.new(leader?: true) }
58
+ end
59
+
60
+ it { expect{ get :edit }.to raise_error{ ActionBouncer::Unauthorized } }
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ class NoSetupController < ActionController::Base
4
+ helper_method :current_user
5
+
6
+ include ActionBouncer
7
+
8
+ def index
9
+ render nothing: true, status: :success
10
+ end
11
+ end
12
+
13
+ describe NoSetupController do
14
+ before do
15
+ Rails.application.routes.draw do
16
+ get '/index' => 'no_setup#index'
17
+ end
18
+ end
19
+
20
+ it { expect{ get :index }.not_to raise_error }
21
+ end
22
+
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ class SymbolParamsController < ActionController::Base
4
+ helper_method :current_user
5
+
6
+ def current_user
7
+ OpenStruct.new(admin?: true)
8
+ end
9
+
10
+ include ActionBouncer
11
+
12
+ allow :current_user, to: :index, if: :admin?
13
+
14
+ def index
15
+ render nothing: true, status: :success
16
+ end
17
+
18
+ def new
19
+ render nothing: true, status: :success
20
+ end
21
+ end
22
+
23
+ describe SymbolParamsController do
24
+ before do
25
+ Rails.application.routes.draw do
26
+ get '/index' => 'symbol_params#index'
27
+ get '/new' => 'symbol_params#new'
28
+ end
29
+ end
30
+
31
+ it { expect{ get :new }.to raise_error(ActionBouncer::Unauthorized) }
32
+ it { expect{ get :index }.not_to raise_error }
33
+ end
34
+