ae_declarative_authorization 0.7.1 → 0.8.0
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.
- checksums.yaml +5 -5
- data/Appraisals +31 -21
- data/CHANGELOG +189 -189
- data/Gemfile +7 -7
- data/Gemfile.lock +68 -60
- data/LICENSE.txt +20 -20
- data/README.md +620 -620
- data/README.rdoc +597 -597
- data/Rakefile +35 -33
- data/authorization_rules.dist.rb +20 -20
- data/declarative_authorization.gemspec +24 -24
- data/gemfiles/rails4252.gemfile +10 -10
- data/gemfiles/rails4252.gemfile.lock +126 -0
- data/gemfiles/rails4271.gemfile +10 -10
- data/gemfiles/rails4271.gemfile.lock +126 -0
- data/gemfiles/rails507.gemfile +11 -11
- data/gemfiles/rails507.gemfile.lock +136 -0
- data/gemfiles/rails516.gemfile +11 -0
- data/gemfiles/rails516.gemfile.lock +136 -0
- data/gemfiles/rails521.gemfile +11 -0
- data/gemfiles/rails521.gemfile.lock +144 -0
- data/init.rb +5 -5
- data/lib/declarative_authorization.rb +18 -18
- data/lib/declarative_authorization/authorization.rb +821 -821
- data/lib/declarative_authorization/helper.rb +78 -78
- data/lib/declarative_authorization/in_controller.rb +713 -713
- data/lib/declarative_authorization/in_model.rb +156 -156
- data/lib/declarative_authorization/maintenance.rb +215 -215
- data/lib/declarative_authorization/obligation_scope.rb +348 -345
- data/lib/declarative_authorization/railsengine.rb +5 -5
- data/lib/declarative_authorization/reader.rb +549 -549
- data/lib/declarative_authorization/test/helpers.rb +261 -261
- data/lib/declarative_authorization/version.rb +3 -3
- data/lib/generators/authorization/install/install_generator.rb +77 -77
- data/lib/generators/authorization/rules/rules_generator.rb +13 -13
- data/lib/generators/authorization/rules/templates/authorization_rules.rb +27 -27
- data/lib/tasks/authorization_tasks.rake +89 -89
- data/log/test.log +15246 -0
- data/pkg/ae_declarative_authorization-0.7.1.gem +0 -0
- data/pkg/ae_declarative_authorization-0.8.0.gem +0 -0
- data/test/authorization_test.rb +1121 -1121
- data/test/controller_filter_resource_access_test.rb +573 -573
- data/test/controller_test.rb +478 -478
- data/test/database.yml +3 -3
- data/test/dsl_reader_test.rb +178 -178
- data/test/functional/filter_access_to_with_id_in_scope_test.rb +88 -88
- data/test/functional/no_filter_access_to_test.rb +79 -79
- data/test/functional/params_block_arity_test.rb +39 -39
- data/test/helper_test.rb +248 -248
- data/test/maintenance_test.rb +46 -46
- data/test/model_test.rb +1840 -1840
- data/test/profiles/access_checking +20 -0
- data/test/schema.sql +60 -60
- data/test/test_helper.rb +174 -174
- data/test/test_support/minitest_compatibility.rb +26 -26
- metadata +17 -5
@@ -1,156 +1,156 @@
|
|
1
|
-
# Authorization::AuthorizationInModel
|
2
|
-
require File.dirname(__FILE__) + '/authorization.rb'
|
3
|
-
require File.dirname(__FILE__) + '/obligation_scope.rb'
|
4
|
-
|
5
|
-
module Authorization
|
6
|
-
|
7
|
-
module AuthorizationInModel
|
8
|
-
|
9
|
-
# If the user meets the given privilege, permitted_to? returns true
|
10
|
-
# and yields to the optional block.
|
11
|
-
def permitted_to?(privilege, options = {})
|
12
|
-
options = {
|
13
|
-
:user => Authorization.current_user,
|
14
|
-
:object => self
|
15
|
-
}.merge(options)
|
16
|
-
Authorization::Engine.instance.permit?(privilege, { :user => options[:user], :object => options[:object]}) do
|
17
|
-
yield if block_given?
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Works similar to the permitted_to? method, but doesn't accept a block
|
22
|
-
# and throws the authorization exceptions, just like Engine#permit!
|
23
|
-
def permitted_to!(privilege, options = {})
|
24
|
-
options = {
|
25
|
-
:user => Authorization.current_user,
|
26
|
-
:object => self
|
27
|
-
}.merge(options)
|
28
|
-
Authorization::Engine.instance.permit!(privilege, { :user => options[:user], :object => options[:object] }) do
|
29
|
-
yield if block_given?
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.included(base) # :nodoc:
|
34
|
-
base.module_eval do
|
35
|
-
# Builds and returns a scope with joins and conditions satisfying all obligations.
|
36
|
-
def self.obligation_scope_for( privileges, options = {})
|
37
|
-
options = {
|
38
|
-
:user => Authorization.current_user,
|
39
|
-
:context => nil,
|
40
|
-
:model => self,
|
41
|
-
:engine => nil,
|
42
|
-
}.merge(options)
|
43
|
-
engine = options[:engine] || Authorization::Engine.instance
|
44
|
-
|
45
|
-
obligation_scope = ObligationScope.new( options[:model], {} )
|
46
|
-
engine.obligations( privileges, :user => options[:user], :context => options[:context] ).each do |obligation|
|
47
|
-
obligation_scope.parse!( obligation )
|
48
|
-
end
|
49
|
-
|
50
|
-
obligation_scope.scope
|
51
|
-
end
|
52
|
-
|
53
|
-
# Named scope for limiting query results according to the authorization
|
54
|
-
# of the current user. If no privilege is given, :+read+ is assumed.
|
55
|
-
#
|
56
|
-
# User.with_permissions_to
|
57
|
-
# User.with_permissions_to(:update)
|
58
|
-
# User.with_permissions_to(:update, :context => :users)
|
59
|
-
#
|
60
|
-
# As in the case of other named scopes, this one may be chained:
|
61
|
-
# User.with_permission_to.find(:all, :conditions...)
|
62
|
-
#
|
63
|
-
# Options
|
64
|
-
# [:+context+]
|
65
|
-
# Context for the privilege to be evaluated in; defaults to the
|
66
|
-
# model's table name.
|
67
|
-
# [:+user+]
|
68
|
-
# User to be used for gathering obligations; defaults to the
|
69
|
-
# current user.
|
70
|
-
#
|
71
|
-
def self.with_permissions_to(*args)
|
72
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
73
|
-
privilege = (args[0] || :read).to_sym
|
74
|
-
privileges = [privilege]
|
75
|
-
parent_scope = where(nil)
|
76
|
-
context =
|
77
|
-
if options[:context]
|
78
|
-
options[:context]
|
79
|
-
elsif parent_scope.klass.respond_to?(:decl_auth_context)
|
80
|
-
parent_scope.klass.decl_auth_context
|
81
|
-
else
|
82
|
-
parent_scope.klass.name.tableize.to_sym
|
83
|
-
end
|
84
|
-
|
85
|
-
user = options[:user] || Authorization.current_user
|
86
|
-
|
87
|
-
engine = options[:engine] || Authorization::Engine.instance
|
88
|
-
engine.permit!(privileges,
|
89
|
-
:user => user,
|
90
|
-
:skip_attribute_test => true,
|
91
|
-
:context => context)
|
92
|
-
|
93
|
-
obligation_scope_for(privileges,
|
94
|
-
:user => user,
|
95
|
-
:context => context,
|
96
|
-
:engine => engine,
|
97
|
-
:model => parent_scope.klass)
|
98
|
-
end
|
99
|
-
|
100
|
-
# Activates model security for the current model. Then, CRUD operations
|
101
|
-
# are checked against the authorization of the current user. The
|
102
|
-
# privileges are :+create+, :+read+, :+update+ and :+delete+ in the
|
103
|
-
# context of the model. By default, :+read+ is not checked because of
|
104
|
-
# performance impacts, especially with large result sets.
|
105
|
-
#
|
106
|
-
# class User < ActiveRecord::Base
|
107
|
-
# using_access_control
|
108
|
-
# end
|
109
|
-
#
|
110
|
-
# If an operation is not permitted, a Authorization::AuthorizationError
|
111
|
-
# is raised.
|
112
|
-
#
|
113
|
-
# To activate model security on all models, call using_access_control
|
114
|
-
# on ActiveRecord::Base
|
115
|
-
# ActiveRecord::Base.using_access_control
|
116
|
-
#
|
117
|
-
# Available options
|
118
|
-
# [:+context+] Specify context different from the models table name.
|
119
|
-
# [:+include_read+] Also check for :+read+ privilege after find.
|
120
|
-
#
|
121
|
-
def self.using_access_control(options = {})
|
122
|
-
options = {
|
123
|
-
:context => nil,
|
124
|
-
:include_read => false
|
125
|
-
}.merge(options)
|
126
|
-
|
127
|
-
class_eval do
|
128
|
-
[:create, :update, [:destroy, :delete]].each do |action, privilege|
|
129
|
-
send(:"before_#{action}") do |object|
|
130
|
-
Authorization::Engine.instance.permit!(privilege || action,
|
131
|
-
:object => object, :context => options[:context])
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
if options[:include_read]
|
136
|
-
# after_find is only called if after_find is implemented
|
137
|
-
after_find do |object|
|
138
|
-
Authorization::Engine.instance.permit!(:read, :object => object,
|
139
|
-
:context => options[:context])
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def self.using_access_control?
|
144
|
-
true
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
# Returns true if the model is using model security.
|
150
|
-
def self.using_access_control?
|
151
|
-
false
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
1
|
+
# Authorization::AuthorizationInModel
|
2
|
+
require File.dirname(__FILE__) + '/authorization.rb'
|
3
|
+
require File.dirname(__FILE__) + '/obligation_scope.rb'
|
4
|
+
|
5
|
+
module Authorization
|
6
|
+
|
7
|
+
module AuthorizationInModel
|
8
|
+
|
9
|
+
# If the user meets the given privilege, permitted_to? returns true
|
10
|
+
# and yields to the optional block.
|
11
|
+
def permitted_to?(privilege, options = {})
|
12
|
+
options = {
|
13
|
+
:user => Authorization.current_user,
|
14
|
+
:object => self
|
15
|
+
}.merge(options)
|
16
|
+
Authorization::Engine.instance.permit?(privilege, { :user => options[:user], :object => options[:object]}) do
|
17
|
+
yield if block_given?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Works similar to the permitted_to? method, but doesn't accept a block
|
22
|
+
# and throws the authorization exceptions, just like Engine#permit!
|
23
|
+
def permitted_to!(privilege, options = {})
|
24
|
+
options = {
|
25
|
+
:user => Authorization.current_user,
|
26
|
+
:object => self
|
27
|
+
}.merge(options)
|
28
|
+
Authorization::Engine.instance.permit!(privilege, { :user => options[:user], :object => options[:object] }) do
|
29
|
+
yield if block_given?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.included(base) # :nodoc:
|
34
|
+
base.module_eval do
|
35
|
+
# Builds and returns a scope with joins and conditions satisfying all obligations.
|
36
|
+
def self.obligation_scope_for( privileges, options = {})
|
37
|
+
options = {
|
38
|
+
:user => Authorization.current_user,
|
39
|
+
:context => nil,
|
40
|
+
:model => self,
|
41
|
+
:engine => nil,
|
42
|
+
}.merge(options)
|
43
|
+
engine = options[:engine] || Authorization::Engine.instance
|
44
|
+
|
45
|
+
obligation_scope = ObligationScope.new( options[:model], {} )
|
46
|
+
engine.obligations( privileges, :user => options[:user], :context => options[:context] ).each do |obligation|
|
47
|
+
obligation_scope.parse!( obligation )
|
48
|
+
end
|
49
|
+
|
50
|
+
obligation_scope.scope
|
51
|
+
end
|
52
|
+
|
53
|
+
# Named scope for limiting query results according to the authorization
|
54
|
+
# of the current user. If no privilege is given, :+read+ is assumed.
|
55
|
+
#
|
56
|
+
# User.with_permissions_to
|
57
|
+
# User.with_permissions_to(:update)
|
58
|
+
# User.with_permissions_to(:update, :context => :users)
|
59
|
+
#
|
60
|
+
# As in the case of other named scopes, this one may be chained:
|
61
|
+
# User.with_permission_to.find(:all, :conditions...)
|
62
|
+
#
|
63
|
+
# Options
|
64
|
+
# [:+context+]
|
65
|
+
# Context for the privilege to be evaluated in; defaults to the
|
66
|
+
# model's table name.
|
67
|
+
# [:+user+]
|
68
|
+
# User to be used for gathering obligations; defaults to the
|
69
|
+
# current user.
|
70
|
+
#
|
71
|
+
def self.with_permissions_to(*args)
|
72
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
73
|
+
privilege = (args[0] || :read).to_sym
|
74
|
+
privileges = [privilege]
|
75
|
+
parent_scope = where(nil)
|
76
|
+
context =
|
77
|
+
if options[:context]
|
78
|
+
options[:context]
|
79
|
+
elsif parent_scope.klass.respond_to?(:decl_auth_context)
|
80
|
+
parent_scope.klass.decl_auth_context
|
81
|
+
else
|
82
|
+
parent_scope.klass.name.tableize.to_sym
|
83
|
+
end
|
84
|
+
|
85
|
+
user = options[:user] || Authorization.current_user
|
86
|
+
|
87
|
+
engine = options[:engine] || Authorization::Engine.instance
|
88
|
+
engine.permit!(privileges,
|
89
|
+
:user => user,
|
90
|
+
:skip_attribute_test => true,
|
91
|
+
:context => context)
|
92
|
+
|
93
|
+
obligation_scope_for(privileges,
|
94
|
+
:user => user,
|
95
|
+
:context => context,
|
96
|
+
:engine => engine,
|
97
|
+
:model => parent_scope.klass)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Activates model security for the current model. Then, CRUD operations
|
101
|
+
# are checked against the authorization of the current user. The
|
102
|
+
# privileges are :+create+, :+read+, :+update+ and :+delete+ in the
|
103
|
+
# context of the model. By default, :+read+ is not checked because of
|
104
|
+
# performance impacts, especially with large result sets.
|
105
|
+
#
|
106
|
+
# class User < ActiveRecord::Base
|
107
|
+
# using_access_control
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# If an operation is not permitted, a Authorization::AuthorizationError
|
111
|
+
# is raised.
|
112
|
+
#
|
113
|
+
# To activate model security on all models, call using_access_control
|
114
|
+
# on ActiveRecord::Base
|
115
|
+
# ActiveRecord::Base.using_access_control
|
116
|
+
#
|
117
|
+
# Available options
|
118
|
+
# [:+context+] Specify context different from the models table name.
|
119
|
+
# [:+include_read+] Also check for :+read+ privilege after find.
|
120
|
+
#
|
121
|
+
def self.using_access_control(options = {})
|
122
|
+
options = {
|
123
|
+
:context => nil,
|
124
|
+
:include_read => false
|
125
|
+
}.merge(options)
|
126
|
+
|
127
|
+
class_eval do
|
128
|
+
[:create, :update, [:destroy, :delete]].each do |action, privilege|
|
129
|
+
send(:"before_#{action}") do |object|
|
130
|
+
Authorization::Engine.instance.permit!(privilege || action,
|
131
|
+
:object => object, :context => options[:context])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
if options[:include_read]
|
136
|
+
# after_find is only called if after_find is implemented
|
137
|
+
after_find do |object|
|
138
|
+
Authorization::Engine.instance.permit!(:read, :object => object,
|
139
|
+
:context => options[:context])
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.using_access_control?
|
144
|
+
true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns true if the model is using model security.
|
150
|
+
def self.using_access_control?
|
151
|
+
false
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -1,215 +1,215 @@
|
|
1
|
-
# Authorization::Maintenance
|
2
|
-
require File.dirname(__FILE__) + '/authorization.rb'
|
3
|
-
|
4
|
-
module Authorization
|
5
|
-
# Provides a few maintenance methods for modifying data without enforcing
|
6
|
-
# authorization.
|
7
|
-
module Maintenance
|
8
|
-
# Disables access control for the given block. Appropriate for
|
9
|
-
# maintenance operation at the Rails console or in test case setup.
|
10
|
-
#
|
11
|
-
# For use in the Rails console:
|
12
|
-
# require "vendor/plugins/declarative_authorization/lib/maintenance"
|
13
|
-
# include Authorization::Maintenance
|
14
|
-
#
|
15
|
-
# without_access_control do
|
16
|
-
# SomeModel.find(:first).save
|
17
|
-
# end
|
18
|
-
def without_access_control
|
19
|
-
Authorization::Maintenance.without_access_control() do
|
20
|
-
yield if block_given?
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# A class method variant of without_access_control. Thus, one can call
|
25
|
-
# Authorization::Maintenance::without_access_control do
|
26
|
-
# ...
|
27
|
-
# end
|
28
|
-
def self.without_access_control
|
29
|
-
previous_state = Authorization.ignore_access_control
|
30
|
-
begin
|
31
|
-
Authorization.ignore_access_control(true)
|
32
|
-
yield
|
33
|
-
ensure
|
34
|
-
Authorization.ignore_access_control(previous_state)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Sets the current user for the declarative authorization plugin to the
|
39
|
-
# given one for the execution of the supplied block. Suitable for tests
|
40
|
-
# on certain users.
|
41
|
-
def with_user(user)
|
42
|
-
Authorization::Maintenance.with_user(user) do
|
43
|
-
yield if block_given?
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.with_user(user)
|
48
|
-
prev_user = Authorization.current_user
|
49
|
-
Authorization.current_user = user
|
50
|
-
yield
|
51
|
-
ensure
|
52
|
-
Authorization.current_user = prev_user
|
53
|
-
end
|
54
|
-
|
55
|
-
# Module for grouping usage-related helper methods
|
56
|
-
module Usage
|
57
|
-
# Delivers a hash of {ControllerClass => usage_info_hash},
|
58
|
-
# where usage_info_hash has the form of
|
59
|
-
def self.usages_by_controller
|
60
|
-
# load each application controller
|
61
|
-
begin
|
62
|
-
Dir.glob(File.join(::Rails.root, 'app', 'controllers', '**', '*_controller\.rb')) do |entry|
|
63
|
-
require entry
|
64
|
-
end
|
65
|
-
rescue Errno::ENOENT
|
66
|
-
end
|
67
|
-
controllers = ObjectSpace.each_object(Class).select do |obj|
|
68
|
-
obj.ancestors.include?(ActionController::Base) &&
|
69
|
-
obj != ActionController::Base &&
|
70
|
-
(!obj.name || obj.name.demodulize != 'ApplicationController')
|
71
|
-
end
|
72
|
-
|
73
|
-
controllers.inject({}) do |memo, controller|
|
74
|
-
catchall_permissions = []
|
75
|
-
permission_by_action = {}
|
76
|
-
controller.all_filter_access_permissions.each do |controller_permissions|
|
77
|
-
catchall_permissions << controller_permissions if controller_permissions.actions.include?(:all)
|
78
|
-
controller_permissions.actions.reject {|action| action == :all}.each do |action|
|
79
|
-
permission_by_action[action] = controller_permissions
|
80
|
-
end
|
81
|
-
end
|
82
|
-
actions = controller.public_instance_methods(false) - controller.private_methods
|
83
|
-
memo[controller] = actions.inject({}) do |actions_memo, action|
|
84
|
-
action_sym = action.to_sym
|
85
|
-
actions_memo[action_sym] =
|
86
|
-
if permission_by_action[action_sym]
|
87
|
-
{
|
88
|
-
:privilege => permission_by_action[action_sym].privilege,
|
89
|
-
:context => permission_by_action[action_sym].context,
|
90
|
-
:controller_permissions => [permission_by_action[action_sym]]
|
91
|
-
}
|
92
|
-
elsif !catchall_permissions.empty?
|
93
|
-
{
|
94
|
-
:privilege => catchall_permissions[0].privilege,
|
95
|
-
:context => catchall_permissions[0].context,
|
96
|
-
:controller_permissions => catchall_permissions
|
97
|
-
}
|
98
|
-
else
|
99
|
-
{}
|
100
|
-
end
|
101
|
-
actions_memo
|
102
|
-
end
|
103
|
-
memo
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# TestHelper provides assert methods and controller request methods which
|
110
|
-
# take authorization into account and set the current user to a specific
|
111
|
-
# one.
|
112
|
-
#
|
113
|
-
# Defines get_with, post_with, get_by_xhr_with etc. for methods
|
114
|
-
# get, post, put, delete each with the signature
|
115
|
-
# get_with(user, action, params = {}, session = {}, flash = {})
|
116
|
-
#
|
117
|
-
# Use it by including it in your TestHelper:
|
118
|
-
# require File.expand_path(File.dirname(__FILE__) +
|
119
|
-
# "/../vendor/plugins/declarative_authorization/lib/maintenance")
|
120
|
-
# class Test::Unit::TestCase
|
121
|
-
# include Authorization::TestHelper
|
122
|
-
# ...
|
123
|
-
#
|
124
|
-
# def admin
|
125
|
-
# # create admin user
|
126
|
-
# end
|
127
|
-
# end
|
128
|
-
#
|
129
|
-
# class SomeControllerTest < ActionController::TestCase
|
130
|
-
# def test_should_get_index
|
131
|
-
# ...
|
132
|
-
# get_with admin, :index, :param_1 => "param value"
|
133
|
-
# ...
|
134
|
-
# end
|
135
|
-
# end
|
136
|
-
#
|
137
|
-
# Note: get_with etc. do two things to set the user for the request:
|
138
|
-
# Authorization.current_user is set and session[:user], session[:user_id]
|
139
|
-
# are set appropriately. If you determine the current user in a different
|
140
|
-
# way, these methods might not work for you.
|
141
|
-
module TestHelper
|
142
|
-
include Authorization::Maintenance
|
143
|
-
|
144
|
-
# Analogue to the Ruby's assert_raise method, only executing the block
|
145
|
-
# in the context of the given user.
|
146
|
-
def assert_raise_with_user(user, *args)
|
147
|
-
assert_raise(*args) do
|
148
|
-
with_user(user) do
|
149
|
-
yield if block_given?
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# Test helper to test authorization rules.
|
155
|
-
# with_user a_normal_user do
|
156
|
-
# should_not_be_allowed_to :update, :conferences
|
157
|
-
# should_not_be_allowed_to :read, an_unpublished_conference
|
158
|
-
# should_be_allowed_to :read, a_published_conference
|
159
|
-
# end
|
160
|
-
#
|
161
|
-
# If the objects class name does not match the controller name, you can set the object and context manually
|
162
|
-
# should_be_allowed_to :create, :object => car, :context => :vehicles
|
163
|
-
#
|
164
|
-
# If you use specify the object and context manually, you can also specify the user manually, skipping the with_user block:
|
165
|
-
# should_be_allowed_to :create, :object => car, :context => :vehicles, :user => a_normal_user
|
166
|
-
def should_be_allowed_to(privilege, *args)
|
167
|
-
options = {}
|
168
|
-
if(args.first.class == Hash)
|
169
|
-
options = args.extract_options!
|
170
|
-
else
|
171
|
-
options[args[0].is_a?(Symbol) ? :context : :object] = args[0]
|
172
|
-
end
|
173
|
-
assert_nothing_raised do
|
174
|
-
Authorization::Engine.instance.permit!(privilege, options)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
# See should_be_allowed_to
|
179
|
-
def should_not_be_allowed_to(privilege, *args)
|
180
|
-
options = {}
|
181
|
-
if(args.first.class == Hash)
|
182
|
-
options = args.extract_options!
|
183
|
-
else
|
184
|
-
options[args[0].is_a?(Symbol) ? :context : :object] = args[0]
|
185
|
-
end
|
186
|
-
assert !Authorization::Engine.instance.permit?(privilege, options)
|
187
|
-
end
|
188
|
-
|
189
|
-
def request_with(user, method, xhr, action, params = {},
|
190
|
-
session = {}, flash = {})
|
191
|
-
session = session.merge({:user => user, :user_id => user && user.id})
|
192
|
-
with_user(user) do
|
193
|
-
if xhr
|
194
|
-
xhr method, action, params, session, flash
|
195
|
-
else
|
196
|
-
send method, action, params, session, flash
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def self.included(base)
|
202
|
-
[:get, :post, :put, :delete].each do |method|
|
203
|
-
base.class_eval <<-EOV, __FILE__, __LINE__
|
204
|
-
def #{method}_with(user, *args)
|
205
|
-
request_with(user, #{method.inspect}, false, *args)
|
206
|
-
end
|
207
|
-
|
208
|
-
def #{method}_by_xhr_with(user, *args)
|
209
|
-
request_with(user, #{method.inspect}, true, *args)
|
210
|
-
end
|
211
|
-
EOV
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
1
|
+
# Authorization::Maintenance
|
2
|
+
require File.dirname(__FILE__) + '/authorization.rb'
|
3
|
+
|
4
|
+
module Authorization
|
5
|
+
# Provides a few maintenance methods for modifying data without enforcing
|
6
|
+
# authorization.
|
7
|
+
module Maintenance
|
8
|
+
# Disables access control for the given block. Appropriate for
|
9
|
+
# maintenance operation at the Rails console or in test case setup.
|
10
|
+
#
|
11
|
+
# For use in the Rails console:
|
12
|
+
# require "vendor/plugins/declarative_authorization/lib/maintenance"
|
13
|
+
# include Authorization::Maintenance
|
14
|
+
#
|
15
|
+
# without_access_control do
|
16
|
+
# SomeModel.find(:first).save
|
17
|
+
# end
|
18
|
+
def without_access_control
|
19
|
+
Authorization::Maintenance.without_access_control() do
|
20
|
+
yield if block_given?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# A class method variant of without_access_control. Thus, one can call
|
25
|
+
# Authorization::Maintenance::without_access_control do
|
26
|
+
# ...
|
27
|
+
# end
|
28
|
+
def self.without_access_control
|
29
|
+
previous_state = Authorization.ignore_access_control
|
30
|
+
begin
|
31
|
+
Authorization.ignore_access_control(true)
|
32
|
+
yield
|
33
|
+
ensure
|
34
|
+
Authorization.ignore_access_control(previous_state)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Sets the current user for the declarative authorization plugin to the
|
39
|
+
# given one for the execution of the supplied block. Suitable for tests
|
40
|
+
# on certain users.
|
41
|
+
def with_user(user)
|
42
|
+
Authorization::Maintenance.with_user(user) do
|
43
|
+
yield if block_given?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.with_user(user)
|
48
|
+
prev_user = Authorization.current_user
|
49
|
+
Authorization.current_user = user
|
50
|
+
yield
|
51
|
+
ensure
|
52
|
+
Authorization.current_user = prev_user
|
53
|
+
end
|
54
|
+
|
55
|
+
# Module for grouping usage-related helper methods
|
56
|
+
module Usage
|
57
|
+
# Delivers a hash of {ControllerClass => usage_info_hash},
|
58
|
+
# where usage_info_hash has the form of
|
59
|
+
def self.usages_by_controller
|
60
|
+
# load each application controller
|
61
|
+
begin
|
62
|
+
Dir.glob(File.join(::Rails.root, 'app', 'controllers', '**', '*_controller\.rb')) do |entry|
|
63
|
+
require entry
|
64
|
+
end
|
65
|
+
rescue Errno::ENOENT
|
66
|
+
end
|
67
|
+
controllers = ObjectSpace.each_object(Class).select do |obj|
|
68
|
+
obj.ancestors.include?(ActionController::Base) &&
|
69
|
+
obj != ActionController::Base &&
|
70
|
+
(!obj.name || obj.name.demodulize != 'ApplicationController')
|
71
|
+
end
|
72
|
+
|
73
|
+
controllers.inject({}) do |memo, controller|
|
74
|
+
catchall_permissions = []
|
75
|
+
permission_by_action = {}
|
76
|
+
controller.all_filter_access_permissions.each do |controller_permissions|
|
77
|
+
catchall_permissions << controller_permissions if controller_permissions.actions.include?(:all)
|
78
|
+
controller_permissions.actions.reject {|action| action == :all}.each do |action|
|
79
|
+
permission_by_action[action] = controller_permissions
|
80
|
+
end
|
81
|
+
end
|
82
|
+
actions = controller.public_instance_methods(false) - controller.private_methods
|
83
|
+
memo[controller] = actions.inject({}) do |actions_memo, action|
|
84
|
+
action_sym = action.to_sym
|
85
|
+
actions_memo[action_sym] =
|
86
|
+
if permission_by_action[action_sym]
|
87
|
+
{
|
88
|
+
:privilege => permission_by_action[action_sym].privilege,
|
89
|
+
:context => permission_by_action[action_sym].context,
|
90
|
+
:controller_permissions => [permission_by_action[action_sym]]
|
91
|
+
}
|
92
|
+
elsif !catchall_permissions.empty?
|
93
|
+
{
|
94
|
+
:privilege => catchall_permissions[0].privilege,
|
95
|
+
:context => catchall_permissions[0].context,
|
96
|
+
:controller_permissions => catchall_permissions
|
97
|
+
}
|
98
|
+
else
|
99
|
+
{}
|
100
|
+
end
|
101
|
+
actions_memo
|
102
|
+
end
|
103
|
+
memo
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# TestHelper provides assert methods and controller request methods which
|
110
|
+
# take authorization into account and set the current user to a specific
|
111
|
+
# one.
|
112
|
+
#
|
113
|
+
# Defines get_with, post_with, get_by_xhr_with etc. for methods
|
114
|
+
# get, post, put, delete each with the signature
|
115
|
+
# get_with(user, action, params = {}, session = {}, flash = {})
|
116
|
+
#
|
117
|
+
# Use it by including it in your TestHelper:
|
118
|
+
# require File.expand_path(File.dirname(__FILE__) +
|
119
|
+
# "/../vendor/plugins/declarative_authorization/lib/maintenance")
|
120
|
+
# class Test::Unit::TestCase
|
121
|
+
# include Authorization::TestHelper
|
122
|
+
# ...
|
123
|
+
#
|
124
|
+
# def admin
|
125
|
+
# # create admin user
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# class SomeControllerTest < ActionController::TestCase
|
130
|
+
# def test_should_get_index
|
131
|
+
# ...
|
132
|
+
# get_with admin, :index, :param_1 => "param value"
|
133
|
+
# ...
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# Note: get_with etc. do two things to set the user for the request:
|
138
|
+
# Authorization.current_user is set and session[:user], session[:user_id]
|
139
|
+
# are set appropriately. If you determine the current user in a different
|
140
|
+
# way, these methods might not work for you.
|
141
|
+
module TestHelper
|
142
|
+
include Authorization::Maintenance
|
143
|
+
|
144
|
+
# Analogue to the Ruby's assert_raise method, only executing the block
|
145
|
+
# in the context of the given user.
|
146
|
+
def assert_raise_with_user(user, *args)
|
147
|
+
assert_raise(*args) do
|
148
|
+
with_user(user) do
|
149
|
+
yield if block_given?
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Test helper to test authorization rules.
|
155
|
+
# with_user a_normal_user do
|
156
|
+
# should_not_be_allowed_to :update, :conferences
|
157
|
+
# should_not_be_allowed_to :read, an_unpublished_conference
|
158
|
+
# should_be_allowed_to :read, a_published_conference
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# If the objects class name does not match the controller name, you can set the object and context manually
|
162
|
+
# should_be_allowed_to :create, :object => car, :context => :vehicles
|
163
|
+
#
|
164
|
+
# If you use specify the object and context manually, you can also specify the user manually, skipping the with_user block:
|
165
|
+
# should_be_allowed_to :create, :object => car, :context => :vehicles, :user => a_normal_user
|
166
|
+
def should_be_allowed_to(privilege, *args)
|
167
|
+
options = {}
|
168
|
+
if(args.first.class == Hash)
|
169
|
+
options = args.extract_options!
|
170
|
+
else
|
171
|
+
options[args[0].is_a?(Symbol) ? :context : :object] = args[0]
|
172
|
+
end
|
173
|
+
assert_nothing_raised do
|
174
|
+
Authorization::Engine.instance.permit!(privilege, options)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# See should_be_allowed_to
|
179
|
+
def should_not_be_allowed_to(privilege, *args)
|
180
|
+
options = {}
|
181
|
+
if(args.first.class == Hash)
|
182
|
+
options = args.extract_options!
|
183
|
+
else
|
184
|
+
options[args[0].is_a?(Symbol) ? :context : :object] = args[0]
|
185
|
+
end
|
186
|
+
assert !Authorization::Engine.instance.permit?(privilege, options)
|
187
|
+
end
|
188
|
+
|
189
|
+
def request_with(user, method, xhr, action, params = {},
|
190
|
+
session = {}, flash = {})
|
191
|
+
session = session.merge({:user => user, :user_id => user && user.id})
|
192
|
+
with_user(user) do
|
193
|
+
if xhr
|
194
|
+
xhr method, action, params, session, flash
|
195
|
+
else
|
196
|
+
send method, action, params, session, flash
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.included(base)
|
202
|
+
[:get, :post, :put, :delete].each do |method|
|
203
|
+
base.class_eval <<-EOV, __FILE__, __LINE__
|
204
|
+
def #{method}_with(user, *args)
|
205
|
+
request_with(user, #{method.inspect}, false, *args)
|
206
|
+
end
|
207
|
+
|
208
|
+
def #{method}_by_xhr_with(user, *args)
|
209
|
+
request_with(user, #{method.inspect}, true, *args)
|
210
|
+
end
|
211
|
+
EOV
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|