acl9 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 105b1a050bdefc20d0671c4035500f9abd99f8f588b69ed3ceb3357f61ea01e1
4
- data.tar.gz: 2e5f73791a47de3e9fe4148c81868d6befcda7075163813eb86877c7e21084a5
3
+ metadata.gz: 7ee10c2f6e3894b825f17a575524a0343dcdf16217a3049b665e04da980bce1c
4
+ data.tar.gz: cd72c5c1e1983b28e8799c9792e5fa843f89415e104588feaf2dbeb72fd1f651
5
5
  SHA512:
6
- metadata.gz: 9caadac85342a7885a46581b4a60fc7c83d51b23c50f85e0e2121fa2d15fd4ab0383984f5f7b48076f18dd49409ad40e5292f9d8a2615aced3088f0f004c28b0
7
- data.tar.gz: edec0e425c0dfaf67f934b9a79ae37e3fad11baeedb605c04ccf0533bc59d1e3c4851f41f2d909cec855310fe69f811f0ff9aec78755ee3fb8a52c61e47a698d
6
+ metadata.gz: dca2492214e239e447b4de8f1874be52c617ca361fdcbc79ac5f4c58782ff92449e29db54f9618356680c96e55023412a6206e1f9b3ec9d7f20074d7cb89d76d
7
+ data.tar.gz: 0a8963681d65a13fd39e3d4e46d75be288fda1a3ce1a8bb05c1e6264da2e1601c0abb698dbbfd9abe10e965bd6c0491acab62131852f508ad3c2b1d852f3cdc8
@@ -8,8 +8,10 @@ rvm:
8
8
  gemfile:
9
9
  - gemfiles/rails_5.0.gemfile
10
10
  - gemfiles/rails_5.1.gemfile
11
+ - gemfiles/rails_5.2.gemfile
11
12
 
12
13
  matrix:
13
14
  fast_finish: true
14
15
  allow_failures:
15
16
  - rvm: ruby-head
17
+ - gemfile: gemfiles/rails_5.2.gemfile
data/Appraisals CHANGED
@@ -5,3 +5,7 @@ end
5
5
  appraise "rails-5.1" do
6
6
  gem 'rails', '~> 5.1.0'
7
7
  end
8
+
9
+ appraise "rails-5.2" do
10
+ gem 'rails', '~> 5.2.0.rc1'
11
+ end
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- acl9 (2.1.2)
5
- rails (>= 4.0)
4
+ acl9 (3.1.0)
5
+ rails (~> 5.0)
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # acl9
2
2
 
3
- [![Travis-CI](https://travis-ci.org/be9/acl9.svg?branch=master)](https://travis-ci.org/be9/acl9) [![Code Climate](https://codeclimate.com/github/be9/acl9/badges/gpa.svg)](https://codeclimate.com/github/be9/acl9) [![Test Coverage](https://codeclimate.com/github/be9/acl9/badges/coverage.svg)](https://codeclimate.com/github/be9/acl9)
3
+ [![Travis-CI](https://travis-ci.org/be9/acl9.svg?branch=master)](https://travis-ci.org/be9/acl9)
4
4
 
5
5
  Acl9 is a role-based authorization system that provides a concise DSL for
6
6
  securing your Rails application.
@@ -16,11 +16,19 @@ Acl9 is [Semantically Versioned](http://semver.org/), so just add this to your
16
16
  `Gemfile`:
17
17
 
18
18
  ```ruby
19
- gem 'acl9', '~> 2.0'
19
+ gem 'acl9', '~> 3.0'
20
20
  ```
21
21
 
22
22
  You will need Ruby 2.x
23
23
 
24
+ ### Rails 4 - stick with 2.x
25
+
26
+ ```ruby
27
+ gem 'acl9', '~> 2.0'
28
+ ```
29
+
30
+ ### Rails < 4 - upgrade Rails!
31
+
24
32
  We dropped support for Rails < 4 in the 1.x releases, so if you're still using
25
33
  Rails 2.x or 3.x then you'll want this:
26
34
 
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_RETRY: "1"
@@ -3,6 +3,7 @@
3
3
  source "http://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
+ gem "byebug"
6
7
  gem "rails", "~> 5.0.0"
7
8
 
8
9
  gemspec path: "../"
@@ -3,6 +3,7 @@
3
3
  source "http://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
+ gem "byebug"
6
7
  gem "rails", "~> 5.1.0"
7
8
 
8
9
  gemspec path: "../"
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "byebug"
7
+ gem "rails", "~> 5.2.0.rc1"
8
+
9
+ gemspec path: "../"
@@ -35,6 +35,42 @@ module Acl9
35
35
  def self.configure
36
36
  yield config
37
37
  end
38
+
39
+ class ArgumentError < ArgumentError; end
40
+ class RuntimeError < RuntimeError; end
41
+ class NilObjectError < RuntimeError; end
42
+
43
+ ##
44
+ # This exception is raised whenever ACL block finds that the current user
45
+ # is not authorized for the controller action he wants to execute.
46
+ # @example How to catch this exception in ApplicationController
47
+ # class ApplicationController < ActionController::Base
48
+ # rescue_from 'Acl9::AccessDenied', :with => :access_denied
49
+ #
50
+ # # ...other stuff...
51
+ # private
52
+ #
53
+ # def access_denied
54
+ # if current_user
55
+ # # It's presumed you have a template with words of pity and regret
56
+ # # for unhappy user who is not authorized to do what he wanted
57
+ # render :template => 'home/access_denied'
58
+ # else
59
+ # # In this case user has not even logged in. Might be OK after login.
60
+ # flash[:notice] = 'Access denied. Try to log in first.'
61
+ # redirect_to login_path
62
+ # end
63
+ # end
64
+ # end
65
+ #
66
+ class AccessDenied < RuntimeError; end
67
+
68
+ ##
69
+ # This exception is raised when acl9 has generated invalid code for the
70
+ # filtering method or block. Should never happen, and it's a bug when it
71
+ # happens.
72
+ class FilterSyntaxError < ArgumentError; end
73
+
38
74
  end
39
75
 
40
76
  ActiveRecord::Base.send(:include, Acl9::ModelExtensions)
@@ -12,6 +12,7 @@ module Acl9
12
12
  @allows = []
13
13
  @denys = []
14
14
  @original_args = args
15
+ @action_clause = nil
15
16
  end
16
17
 
17
18
  def acl_block!(&acl_block)
@@ -108,7 +109,7 @@ module Acl9
108
109
 
109
110
  _set_action_clause( _retrieve_only(options), options.delete(:except))
110
111
 
111
- object = _role_object(options)
112
+ object_s = _role_object_s(options)
112
113
 
113
114
  role_checks = args.map do |who|
114
115
  case who
@@ -116,7 +117,7 @@ module Acl9
116
117
  when logged_in then "!#{_subject_ref}.nil?"
117
118
  when all then "true"
118
119
  else
119
- "!#{_subject_ref}.nil? && #{_subject_ref}.has_role?('#{who}', #{object})"
120
+ "!#{_subject_ref}.nil? && #{_subject_ref}.has_role?('#{who}'#{object_s})"
120
121
  end
121
122
  end
122
123
 
@@ -179,13 +180,13 @@ module Acl9
179
180
  end
180
181
  end
181
182
 
182
- def _role_object(options)
183
+ def _role_object_s(options)
183
184
  object = _by_preposition options
184
185
 
185
186
  case object
186
- when Class then object.to_s
187
- when Symbol then _object_ref object
188
- when nil then "nil"
187
+ when Class then ", #{object}"
188
+ when Symbol then ", #{_object_ref object}"
189
+ when nil then ""
189
190
  else
190
191
  raise ArgumentError, "object specified by preposition can only be a Class or a Symbol"
191
192
  end
@@ -1,37 +1,6 @@
1
1
  require_relative "dsl_base"
2
2
 
3
3
  module Acl9
4
- ##
5
- # This exception is raised whenever ACL block finds that the current user
6
- # is not authorized for the controller action he wants to execute.
7
- # @example How to catch this exception in ApplicationController
8
- # class ApplicationController < ActionController::Base
9
- # rescue_from 'Acl9::AccessDenied', :with => :access_denied
10
- #
11
- # # ...other stuff...
12
- # private
13
- #
14
- # def access_denied
15
- # if current_user
16
- # # It's presumed you have a template with words of pity and regret
17
- # # for unhappy user who is not authorized to do what he wanted
18
- # render :template => 'home/access_denied'
19
- # else
20
- # # In this case user has not even logged in. Might be OK after login.
21
- # flash[:notice] = 'Access denied. Try to log in first.'
22
- # redirect_to login_path
23
- # end
24
- # end
25
- # end
26
- #
27
- class AccessDenied < StandardError; end
28
-
29
- ##
30
- # This exception is raised when acl9 has generated invalid code for the
31
- # filtering method or block. Should never happen, and it's a bug when it
32
- # happens.
33
- class FilterSyntaxError < StandardError; end
34
-
35
4
  module Dsl
36
5
  module Generators
37
6
  class BaseGenerator < Acl9::Dsl::Base
@@ -171,7 +140,7 @@ module Acl9
171
140
  raise ArgumentError, "call #{@method_name} with 0, 1 or 2 arguments"
172
141
  end
173
142
 
174
- action_name = args.empty? ? self.action_name : args.first.to_s
143
+ self.action_name = args.first.to_s if args.present?
175
144
 
176
145
  return #{allowance_expression}
177
146
  end
@@ -5,6 +5,12 @@ module Acl9
5
5
  module ForSubject
6
6
  include Prepositions
7
7
 
8
+ DEFAULT = Class.new do
9
+ def default?
10
+ true
11
+ end
12
+ end.new.freeze
13
+
8
14
  ##
9
15
  # Role check.
10
16
  #
@@ -38,16 +44,17 @@ module Acl9
38
44
  # @param [Object] object Object to query a role on
39
45
  #
40
46
  # @see Acl9::ModelExtensions::Object#accepts_role?
41
- def has_role?(role_name, object = nil)
47
+ def has_role?(role_name, object = default)
48
+ check! object
42
49
  role_name = normalize role_name
43
50
  object = _by_preposition object
44
51
 
45
- !! if object.nil? && !::Acl9.config[:protect_global_roles]
46
- self._role_objects.find_by_name(role_name.to_s) ||
47
- self._role_objects.member?(get_role(role_name, nil))
52
+ !! if object == default && !::Acl9.config[:protect_global_roles]
53
+ _role_objects.find_by_name(role_name.to_s) ||
54
+ _role_objects.member?(get_role(role_name, object))
48
55
  else
49
56
  role = get_role(role_name, object)
50
- role && self._role_objects.exists?(role.id)
57
+ role && _role_objects.exists?(role.id)
51
58
  end
52
59
  end
53
60
 
@@ -57,7 +64,8 @@ module Acl9
57
64
  # @param [Symbol,String] role_name Role name
58
65
  # @param [Object] object Object to add a role for
59
66
  # @see Acl9::ModelExtensions::Object#accepts_role!
60
- def has_role!(role_name, object = nil)
67
+ def has_role!(role_name, object = default)
68
+ check! object
61
69
  role_name = normalize role_name
62
70
  object = _by_preposition object
63
71
 
@@ -65,15 +73,15 @@ module Acl9
65
73
 
66
74
  if role.nil?
67
75
  role_attrs = case object
68
- when Class then { :authorizable_type => object.to_s }
69
- when nil then {}
70
- else { :authorizable => object }
71
- end.merge( { :name => role_name.to_s })
76
+ when Class then { :authorizable_type => object.to_s }
77
+ when default then {}
78
+ else { :authorizable => object }
79
+ end.merge({ :name => role_name.to_s })
72
80
 
73
- role = self._auth_role_class.create(role_attrs)
81
+ role = _auth_role_class.create(role_attrs)
74
82
  end
75
83
 
76
- self._role_objects << role if role && !self._role_objects.exists?(role.id)
84
+ _role_objects << role if role && !_role_objects.exists?(role.id)
77
85
  end
78
86
 
79
87
  ##
@@ -82,7 +90,8 @@ module Acl9
82
90
  # @param [Symbol,String] role_name Role name
83
91
  # @param [Object] object Object to remove a role on
84
92
  # @see Acl9::ModelExtensions::Object#accepts_no_role!
85
- def has_no_role!(role_name, object = nil)
93
+ def has_no_role!(role_name, object = default)
94
+ check! object
86
95
  role_name = normalize role_name
87
96
  object = _by_preposition object
88
97
  delete_role(get_role(role_name, object))
@@ -95,7 +104,8 @@ module Acl9
95
104
  # @return [Boolean] Returns true if +self+ has any roles on +object+.
96
105
  # @see Acl9::ModelExtensions::Object#accepts_roles_by?
97
106
  def has_roles_for?(object)
98
- !!self._role_objects.detect(&role_selecting_lambda(object))
107
+ check! object
108
+ !!_role_objects.detect(&role_selecting_lambda(object))
99
109
  end
100
110
 
101
111
  alias :has_role_for? :has_roles_for?
@@ -112,14 +122,16 @@ module Acl9
112
122
  #
113
123
  # user.roles_for(product).map(&:name).sort #=> role names in alphabetical order
114
124
  def roles_for(object)
115
- self._role_objects.select(&role_selecting_lambda(object))
125
+ check! object
126
+ _role_objects.select(&role_selecting_lambda(object))
116
127
  end
117
128
 
118
129
  ##
119
130
  # Unassign any roles on +object+ from +self+.
120
131
  #
121
- # @param [Object,nil] object Object to unassign roles for. +nil+ means unassign global roles.
122
- def has_no_roles_for!(object = nil)
132
+ # @param [Object,default] object Object to unassign roles for. Empty args means unassign global roles.
133
+ def has_no_roles_for!(object = default)
134
+ check! object
123
135
  roles_for(object).each { |role| delete_role(role) }
124
136
  end
125
137
 
@@ -128,11 +140,11 @@ module Acl9
128
140
  def has_no_roles!
129
141
  # for some reason simple
130
142
  #
131
- # self.roles.each { |role| delete_role(role) }
143
+ # roles.each { |role| delete_role(role) }
132
144
  #
133
145
  # doesn't work. seems like a bug in ActiveRecord
134
- self._role_objects.map(&:id).each do |role_id|
135
- delete_role self._auth_role_class.find(role_id)
146
+ _role_objects.map(&:id).each do |role_id|
147
+ delete_role _auth_role_class.find(role_id)
136
148
  end
137
149
  end
138
150
 
@@ -142,7 +154,7 @@ module Acl9
142
154
  case object
143
155
  when Class
144
156
  lambda { |role| role.authorizable_type == object.to_s }
145
- when nil
157
+ when default
146
158
  lambda { |role| role.authorizable.nil? }
147
159
  else
148
160
  lambda do |role|
@@ -152,13 +164,14 @@ module Acl9
152
164
  end
153
165
  end
154
166
 
155
- def get_role(role_name, object)
167
+ def get_role(role_name, object = default)
168
+ check! object
156
169
  role_name = normalize role_name
157
170
 
158
171
  cond = case object
159
172
  when Class
160
173
  [ 'name = ? and authorizable_type = ? and authorizable_id IS NULL', role_name, object.to_s ]
161
- when nil
174
+ when default
162
175
  [ 'name = ? and authorizable_type IS NULL and authorizable_id IS NULL', role_name ]
163
176
  else
164
177
  [
@@ -167,17 +180,17 @@ module Acl9
167
180
  ]
168
181
  end
169
182
 
170
- if self._auth_role_class.respond_to?(:where)
171
- self._auth_role_class.where(cond).first
183
+ if _auth_role_class.respond_to?(:where)
184
+ _auth_role_class.where(cond).first
172
185
  else
173
- self._auth_role_class.find(:first, :conditions => cond)
186
+ _auth_role_class.find(:first, :conditions => cond)
174
187
  end
175
188
  end
176
189
 
177
190
  def delete_role(role)
178
191
  if role
179
- if ret = self._role_objects.delete(role)
180
- if role.send(self._auth_subject_class_name.demodulize.tableize).empty?
192
+ if ret = _role_objects.delete(role)
193
+ if role.send(_auth_subject_class_name.demodulize.tableize).empty?
181
194
  ret &&= role.destroy unless role.respond_to?(:system?) && role.system?
182
195
  end
183
196
  end
@@ -189,7 +202,11 @@ module Acl9
189
202
  Acl9.config[:normalize_role_names] ? role_name.to_s.underscore.singularize : role_name.to_s
190
203
  end
191
204
 
192
- protected
205
+ private
206
+
207
+ def check! object
208
+ raise NilObjectError if object.nil?
209
+ end
193
210
 
194
211
  def _by_preposition object
195
212
  object.is_a?(Hash) ? super : object
@@ -204,7 +221,11 @@ module Acl9
204
221
  end
205
222
 
206
223
  def _role_objects
207
- send(self._auth_role_assoc)
224
+ send(_auth_role_assoc)
225
+ end
226
+
227
+ def default
228
+ DEFAULT
208
229
  end
209
230
  end
210
231
  end
@@ -1,3 +1,3 @@
1
1
  module Acl9
2
- VERSION = "3.0.0"
2
+ VERSION = "3.1.0"
3
3
  end
@@ -121,7 +121,7 @@ module ControllerExtensions
121
121
 
122
122
  assert set_all_actions
123
123
  permit_some owner, @all_actions, :foo => foo
124
- permit_some hacker, %w(show index destroy)
124
+ permit_some hacker, %w(show index destroy), foo: foo
125
125
  permit_some another_owner, %w(show index destroy), :foo => foo
126
126
  end
127
127
 
@@ -107,29 +107,30 @@ module ControllerExtensions
107
107
 
108
108
  test "should also respect :to and :except" do
109
109
  assert foo = Foo.create
110
+ assert too = Foo.create
110
111
 
111
- assert ( foo = User.create ).has_role! :foo
112
+ assert ( goo = User.create ).has_role! :goo
112
113
  assert ( joo = User.create ).has_role! :joo, foo
113
114
  assert ( qoo = User.create ).has_role! :qoo, Bar
114
115
 
115
116
  @tester.acl_block! do
116
- allow :foo, :boo, :to => [:index, :show]
117
+ allow :goo, :boo, :to => [:index, :show]
117
118
  allow :zoo, :joo, :by => :foo, :to => [:edit, :update]
118
119
  allow :qoo, :woo, :of => Bar
119
120
  deny :qoo, :woo, :of => Bar, :except => [:delete, :destroy]
120
121
  end
121
122
 
122
- assert_permitted foo, 'index'
123
- assert_permitted foo, 'show'
124
- assert_forbidden foo, 'edit'
123
+ assert_permitted goo, 'index'
124
+ assert_permitted goo, 'show'
125
+ assert_forbidden goo, 'edit', foo: too
125
126
  assert_permitted joo, 'edit', :foo => foo
126
127
  assert_permitted joo, 'update', :foo => foo
127
128
  assert_forbidden joo, 'show', :foo => foo
128
- assert_forbidden joo, 'show'
129
- assert_permitted qoo, 'delete'
130
- assert_permitted qoo, 'destroy'
131
- assert_forbidden qoo, 'edit'
132
- assert_forbidden qoo, 'show'
129
+ assert_forbidden joo, 'show', foo: foo
130
+ assert_permitted qoo, 'delete', foo: too
131
+ assert_permitted qoo, 'destroy', foo: too
132
+ assert_forbidden qoo, 'edit', foo: too
133
+ assert_forbidden qoo, 'show', foo: too
133
134
  end
134
135
  end
135
136
  end
@@ -13,10 +13,13 @@ class ACLHelperMethodTest < ActionController::TestCase
13
13
  end
14
14
 
15
15
  test "another user denied" do
16
+ assert @another = User.create
17
+ assert @another.has_role! :owner, Foo.first_or_create
18
+
16
19
  assert @user.has_role! :owner
17
20
 
18
21
  assert get :allow, params: { user_id: @user.id }
19
- assert_select 'div', 'OK'
22
+ assert_select 'div', 'AccessDenied'
20
23
  end
21
24
 
22
25
  test "anon denied" do
@@ -6,7 +6,10 @@ module ACLQueryMixin
6
6
  setup do
7
7
  assert ( @editor = User.create ).has_role! :editor
8
8
  assert ( @viewer = User.create ).has_role! :viewer
9
- assert ( @owneroffoo = User.create ).has_role! :owner, Foo.first_or_create
9
+ assert ( @foo = Foo.first_or_create )
10
+ assert ( @owneroffoo = User.create ).has_role! :owner, @foo
11
+
12
+ @controller.before_action
10
13
  end
11
14
 
12
15
  %i[edit update destroy].each do |meth|
@@ -8,6 +8,8 @@ class ACLQueryMethodNamed < ApplicationController
8
8
  end
9
9
 
10
10
  def acl?(*args)
11
+ @foo = Foo.first
12
+
11
13
  allow_ay(*args)
12
14
  end
13
15
  end
@@ -1,7 +1,13 @@
1
1
  class ApplicationController < ActionController::Base
2
+ before_action :before_action
3
+
2
4
  attr_accessor :current_user
3
5
 
4
6
  def current_user
5
7
  @current_user ||= User.find params[:user_id] if params[:user_id]
6
8
  end
9
+
10
+ def before_action
11
+ @foo = Foo.first
12
+ end
7
13
  end
@@ -13,6 +13,14 @@ class RolesTest < ActiveSupport::TestCase
13
13
  Acl9.config[:protect_global_roles] = true
14
14
  end
15
15
 
16
+ test "should not set global role with nil object" do
17
+
18
+ assert_raise Acl9::NilObjectError do
19
+ assert @user.has_role! :admin, nil
20
+ end
21
+ refute @user.has_role? :admin
22
+ end
23
+
16
24
  test "should not have any roles by default" do
17
25
  %w(user manager admin owner).each do |role|
18
26
  refute @user.has_role? role
@@ -8,11 +8,16 @@ require "rails/test_help"
8
8
  Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]
9
9
 
10
10
  ActiveRecord::Migration.verbose = false
11
+
11
12
  ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
12
13
 
13
14
  $VERBOSE = nil
14
15
 
15
16
  class ActionController::TestCase
17
+ setup do
18
+ assert Foo.create
19
+ end
20
+
16
21
  class << self
17
22
  def test_allowed method, action, params={}
18
23
  test "allowed #{method} #{action}" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acl9
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - oleg dashevskii
@@ -92,8 +92,10 @@ files:
92
92
  - bin/yard
93
93
  - bin/yardoc
94
94
  - bin/yri
95
+ - gemfiles/.bundle/config
95
96
  - gemfiles/rails_5.0.gemfile
96
97
  - gemfiles/rails_5.1.gemfile
98
+ - gemfiles/rails_5.2.gemfile
97
99
  - lib/acl9.rb
98
100
  - lib/acl9/controller_extensions.rb
99
101
  - lib/acl9/controller_extensions/dsl_base.rb