action_bouncer 0.0.2 → 0.0.3

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.
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
+