zero_authorization 1.0.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +33 -24
- data/lib/zero_authorization/engine.rb +49 -65
- data/lib/zero_authorization/exceptions.rb +32 -3
- data/lib/zero_authorization/role.rb +101 -2
- data/lib/zero_authorization/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1890303102d3d41dea0c99df76d07cc731bfc1c
|
4
|
+
data.tar.gz: 337d2c4103dc0a5c099c642394296b9b86ae5c70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6adf012cb827cb91b5da8e96d52e375d2c8b14b1ebaf7ec8ba77c39ca1dd66d14c0b6fd45f596b9df0ef4cb61a668b0ace078b22f0e6799e6519c5575f49af86
|
7
|
+
data.tar.gz: a1463d0d766c3597b6e7724a37926c048c069eea052bd680a35927582ffc66939f8436c39df2d65fbf30ecd53a0952ef33e1e20d7f592873cfda9dcfa3d605c5
|
data/README.md
CHANGED
@@ -22,40 +22,37 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
:role_role_name_one:
|
24
24
|
:can_do:
|
25
|
-
:
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
:account:
|
26
|
+
- create
|
27
|
+
- save
|
28
|
+
- update
|
29
29
|
:User:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
:
|
30
|
+
- :create
|
31
|
+
- :save
|
32
|
+
- :update
|
33
|
+
:model_crud_history: :nothing
|
34
34
|
:Permission: :anything
|
35
35
|
:cant_do:
|
36
36
|
:Project:
|
37
37
|
- :destroy
|
38
|
+
:model_crud_history: :anything
|
38
39
|
:role_role_name_two:
|
39
40
|
:can_do:
|
40
41
|
:Project:
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
:if:
|
50
|
-
:authorize?
|
42
|
+
- create
|
43
|
+
- save: is_authorized?
|
44
|
+
- :update: is_authorized?
|
45
|
+
- :destroy: is_authorized?
|
46
|
+
:user:
|
47
|
+
create: :create_authorized?
|
48
|
+
save: :update_authorized?
|
49
|
+
update: :update_authorized?
|
51
50
|
:role_role_name_three:
|
52
51
|
:can_do:
|
53
|
-
:
|
54
|
-
- :
|
55
|
-
|
56
|
-
- :
|
57
|
-
- :destroy
|
58
|
-
:cant_do: :anything
|
52
|
+
- :Project
|
53
|
+
- :Organization
|
54
|
+
:cant_do:
|
55
|
+
- :User
|
59
56
|
|
60
57
|
2. Restrict models for activity and let rule-set(s) via zero-authorization take control of activity
|
61
58
|
|
@@ -75,6 +72,18 @@ Or install it yourself as:
|
|
75
72
|
|
76
73
|
4. (Re-)boot application.
|
77
74
|
|
75
|
+
## Rules for rule-sets execution (Precedence: from top to bottom)
|
76
|
+
|
77
|
+
1. Rule 00: If no rule-sets are available for 'can do' and 'cant do' then is authorized true '(with warning message)'.
|
78
|
+
2. Rule 01: If role can't do 'anything' or can do 'nothing' then is authorized false.
|
79
|
+
3. Rule 02: If role can't do 'nothing' or can do 'anything' then is authorized true.
|
80
|
+
4. Rule 03: If role can't do 'specified' method and given 'evaluate' method returns true then is authorized false.
|
81
|
+
5. Rule 04: If role can't do 'specified' method and given 'evaluate' method returns false then is authorized true.
|
82
|
+
6. Rule 05: If role can do 'specified' method and given 'evaluate' method returns true then is authorized true.
|
83
|
+
7. Rule 06: If role can do 'specified' method and given 'evaluate' method returns false then is authorized false.
|
84
|
+
8. Rule 07: If role can't do 'specified' method then is authorized false.
|
85
|
+
9. Rule 08: If role can do 'specified' method then is authorized true.
|
86
|
+
|
78
87
|
## Contributing
|
79
88
|
|
80
89
|
1. Fork it
|
@@ -26,13 +26,12 @@ module ZeroAuthorization
|
|
26
26
|
# Authorization for authorization mode :strict
|
27
27
|
def authorize_strictly(action)
|
28
28
|
role = ZeroAuthorization::Role.role
|
29
|
-
raise '
|
29
|
+
raise ZeroAuthorization::Exceptions::RoleNotAvailable, 'Executing authorize_strictly but role not available' if role.nil?
|
30
30
|
|
31
31
|
if zero_authorized_core(role, action)
|
32
32
|
return true
|
33
33
|
else
|
34
|
-
|
35
|
-
raise 'NotAuthorized'
|
34
|
+
raise ZeroAuthorization::Exceptions::NotAuthorized.new(role), "Not authorized to execute #{action} on #{self.class.name}."
|
36
35
|
end
|
37
36
|
|
38
37
|
false
|
@@ -41,7 +40,7 @@ module ZeroAuthorization
|
|
41
40
|
# Authorization for authorization mode :warning
|
42
41
|
def authorize_with_warning(action)
|
43
42
|
role = ZeroAuthorization::Role.role
|
44
|
-
raise '
|
43
|
+
raise ZeroAuthorization::Exceptions::RoleNotAvailable, 'Executing authorize_with_warning but role not available' if role.nil?
|
45
44
|
|
46
45
|
if zero_authorized_core(role, action)
|
47
46
|
return true
|
@@ -68,48 +67,41 @@ module ZeroAuthorization
|
|
68
67
|
elsif self.class.authorization_mode == :superficial
|
69
68
|
return authorize_superficially(action)
|
70
69
|
else
|
71
|
-
raise
|
70
|
+
raise ZeroAuthorization::Exceptions::InvalidAuthorizationMode
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
75
74
|
# Core of authorization after reading/parsing rule set for current role
|
75
|
+
# Rules for rule-sets execution (Precedence: from top to bottom)
|
76
|
+
# Rule 00: If no rule-sets are available for 'can do' and 'cant do' then is authorized true '(with warning message)'.
|
77
|
+
# Rule 01: If role can't do 'anything' or can do 'nothing' then is authorized false.
|
78
|
+
# Rule 02: If role can't do 'nothing' or can do 'anything' then is authorized true.
|
79
|
+
# Rule 03: If role can't do 'specified' method and given 'evaluate' method returns true then is authorized false.
|
80
|
+
# Rule 04: If role can't do 'specified' method and given 'evaluate' method returns false then is authorized true.
|
81
|
+
# Rule 05: If role can do 'specified' method and given 'evaluate' method returns true then is authorized true.
|
82
|
+
# Rule 06: If role can do 'specified' method and given 'evaluate' method returns false then is authorized false.
|
83
|
+
# Rule 07: If role can't do 'specified' method then is authorized false.
|
84
|
+
# Rule 08: If role can do 'specified' method then is authorized true.
|
76
85
|
def zero_authorized_core(role, action)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
logger.debug "----------- self.class.name.to_sym: #{self.class.name.to_sym}"
|
88
|
-
symbolized_actions = role.rule_set[:can_do][self.class.name.to_sym].collect { |x| x if x.is_a?(Symbol) }.compact
|
89
|
-
_auth_flag = if symbolized_actions.include?(action)
|
90
|
-
true
|
91
|
-
else
|
92
|
-
conditional_check =nil
|
93
|
-
(role.rule_set[:can_do][self.class.name.to_sym]- symbolized_actions).each do |action_rule_hash|
|
94
|
-
conditional_check = action_rule_hash[action] if action_rule_hash.keys.include? action
|
95
|
-
end
|
96
|
-
conditional_check ||= {}
|
97
|
-
conditional_check= conditional_check[:if]
|
98
|
-
return self.send(conditional_check) unless conditional_check.nil?
|
99
|
-
false
|
100
|
-
end
|
101
|
-
#_auth_flag = true if (role.rule_set[:can_do][self.class.name.to_sym] || []).include?(action)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
unless role.rule_set[:cant_do].nil?
|
106
|
-
if role.rule_set[:cant_do] == :anything
|
107
|
-
_auth_flag = false
|
108
|
-
elsif role.rule_set[:cant_do].is_a?(Hash)
|
109
|
-
_auth_flag = false if (role.rule_set[:cant_do][self.class.name.to_sym] || []).include?(action)
|
110
|
-
end
|
86
|
+
can_rights = role.can_do_rights(self.class.name)
|
87
|
+
can_rights_names = can_rights.keys
|
88
|
+
cant_rights = role.cant_do_rights(self.class.name)
|
89
|
+
cant_rights_names = cant_rights.keys
|
90
|
+
|
91
|
+
if can_rights.empty? and cant_rights.empty? #Rule 00
|
92
|
+
_temp_i = "#{self.class.name} is exempted from ZeroAuthorization. To enable back, try adding rule-set(s) in role_n_privileges.yml"
|
93
|
+
puts _temp_i
|
94
|
+
Rails.logger.info _temp_i
|
95
|
+
return true
|
111
96
|
end
|
112
|
-
|
97
|
+
return false if cant_rights_names.include?(:anything) or can_rights_names.include?(:nothing) #Rule 01
|
98
|
+
return true if cant_rights_names.include?(:nothing) or can_rights_names.include?(:anything) #Rule 02
|
99
|
+
return (self.send(cant_rights[action.to_sym]) ? false : true) unless cant_rights[action.to_sym].nil? # Rule 03 and Rule 04
|
100
|
+
return (self.send(can_rights[action.to_sym]) ? true : false) unless can_rights[action.to_sym].nil? # Rule 05 and Rule 06
|
101
|
+
return false if cant_rights_names.include?(action.to_sym) # Rule 07
|
102
|
+
return true if can_rights_names.include?(action.to_sym) # Rule 08
|
103
|
+
|
104
|
+
raise ZeroAuthorization::Exceptions::ExecutingUnreachableCode
|
113
105
|
end
|
114
106
|
|
115
107
|
def is_zero_authorized_4_save
|
@@ -132,25 +124,12 @@ module ZeroAuthorization
|
|
132
124
|
module ClassMethods
|
133
125
|
attr_accessor :authorization_mode
|
134
126
|
|
127
|
+
def declared_methods_to_restrict
|
128
|
+
Role.methods_marked_for(self.name).keys
|
129
|
+
end
|
130
|
+
|
135
131
|
def list_of_methods_to_guard
|
136
|
-
|
137
|
-
Role.roles_n_privileges_hash.each do |role_key, permission_value|
|
138
|
-
unless permission_value[:can_do].nil?
|
139
|
-
_model_methods_set = _model_methods_set.merge(permission_value[:can_do]) { |key, oval, nval| ([oval] << [nval]).flatten.compact.uniq } if permission_value[:can_do].is_a?(Hash)
|
140
|
-
end
|
141
|
-
unless permission_value[:cant_do].nil?
|
142
|
-
_model_methods_set = _model_methods_set.merge(permission_value[:cant_do]) { |key, oval, nval| ([oval] << [nval]).flatten.compact.uniq } if permission_value[:cant_do].is_a?(Hash)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
if _model_methods_set[self.name.to_sym] == :anything
|
146
|
-
_model_methods_set.delete(self.name.to_sym)
|
147
|
-
end
|
148
|
-
(_model_methods_set[self.name.to_sym] || []).clone.delete_if do |x|
|
149
|
-
if x.is_a? Hash
|
150
|
-
x= x.keys.first
|
151
|
-
end
|
152
|
-
[:create, :save, :update, :destroy, :anything].include?(x)
|
153
|
-
end
|
132
|
+
declared_methods_to_restrict - [:create, :save, :update, :destroy, :anything, :nothing]
|
154
133
|
end
|
155
134
|
|
156
135
|
private
|
@@ -161,13 +140,18 @@ module ZeroAuthorization
|
|
161
140
|
# applying restriction on methods
|
162
141
|
def initialize_methods_restriction
|
163
142
|
list_of_methods_to_guard.each do |method_name|
|
164
|
-
if
|
165
|
-
method_name
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
143
|
+
if self.instance_methods.include?(method_name)
|
144
|
+
send(:alias_method, "za_#{method_name}", method_name)
|
145
|
+
define_method "#{method_name}" do |*args|
|
146
|
+
_temp_i = "Restricted method call to #{self.class.name}#{method_name}.."
|
147
|
+
puts _temp_i
|
148
|
+
Rails.logger.debug(_temp_i)
|
149
|
+
send("za_#{method_name}", *args) if zero_authorized_checker(method_name)
|
150
|
+
end
|
151
|
+
else
|
152
|
+
_temp_i = "[WARNING] ZeroAuthorization: Method '#{method_name}' unavailable in #{self.name} for restriction application."
|
153
|
+
puts _temp_i
|
154
|
+
Rails.logger.debug(_temp_i)
|
171
155
|
end
|
172
156
|
end
|
173
157
|
end
|
@@ -1,6 +1,35 @@
|
|
1
|
-
module
|
1
|
+
module ZeroAuthorization
|
2
|
+
module Exceptions
|
3
|
+
class ExecutingUnreachableCode < StandardError
|
4
|
+
def initialize(msg = 'It may be a bug. Please report to ZeroAuthorization\'s authors!')
|
5
|
+
super(msg)
|
6
|
+
end
|
7
|
+
end
|
2
8
|
|
3
|
-
|
4
|
-
|
9
|
+
class RoleNotAvailable < StandardError
|
10
|
+
end
|
5
11
|
|
12
|
+
class NotAuthorized < StandardError
|
13
|
+
attr_reader :role
|
14
|
+
|
15
|
+
def initialize(role)
|
16
|
+
@role = role
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class InvalidAuthorizationMode < StandardError
|
21
|
+
def initialize(msg = 'Invalid authorization mode in use it should be from :strict, :warning or :superficial')
|
22
|
+
super(msg)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class InvalidRolesNPrivilegesHash < StandardError
|
27
|
+
attr_reader :hash_in_use
|
28
|
+
|
29
|
+
def initialize(hash_in_use)
|
30
|
+
@hash_in_use = hash_in_use
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
6
35
|
end
|
@@ -22,15 +22,114 @@ module ZeroAuthorization
|
|
22
22
|
roles_n_privileges_hash.keys.collect { |key| key.to_s.gsub(/^role_/, '') }.include?(@@role) ? new(@@role) : nil
|
23
23
|
end
|
24
24
|
|
25
|
+
def can_do_rights(for_classname)
|
26
|
+
self.class.methods_marked_for(for_classname, :can_do, rule_set)
|
27
|
+
end
|
28
|
+
|
29
|
+
def cant_do_rights(for_classname)
|
30
|
+
self.class.methods_marked_for(for_classname, :cant_do, rule_set)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.methods_marked_for(for_classname, specific_can_or_cant = nil, source_class_rule_sets = nil)
|
34
|
+
method_collection = {}
|
35
|
+
if source_class_rule_sets.nil?
|
36
|
+
validate_roles_n_privileges_hash.each do |role, class_rule_sets|
|
37
|
+
method_collection.merge!(extract_rule_hash(class_rule_sets, for_classname, specific_can_or_cant))
|
38
|
+
end
|
39
|
+
else
|
40
|
+
method_collection.merge!(extract_rule_hash(source_class_rule_sets, for_classname, specific_can_or_cant))
|
41
|
+
end
|
42
|
+
method_collection
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.extract_rule_hash(class_rule_sets, for_classname, specific_can_or_cant)
|
46
|
+
method_collection = {}
|
47
|
+
basic_rule = class_rule_sets[for_classname.to_sym]
|
48
|
+
basic_rule.each do |can_or_cant, rule_hash|
|
49
|
+
(method_collection.merge!(rule_hash)) if (specific_can_or_cant.nil? ? true : (can_or_cant == specific_can_or_cant)) and rule_hash.is_a?(Hash)
|
50
|
+
end if basic_rule.is_a?(Hash)
|
51
|
+
method_collection
|
52
|
+
end
|
53
|
+
|
25
54
|
# Cache read of config/roles_n_privileges.yml for role_privileges_hash
|
26
55
|
def self.roles_n_privileges_hash
|
27
|
-
@roles_n_privileges_hash ||=
|
56
|
+
@roles_n_privileges_hash ||= validate_roles_n_privileges_hash
|
28
57
|
@roles_n_privileges_hash
|
29
58
|
end
|
30
59
|
|
31
60
|
# Hard read of config/roles_n_privileges.yml for role_privileges_hash
|
32
61
|
def self.roles_n_privileges_hash_reload
|
33
|
-
@roles_n_privileges_hash =
|
62
|
+
@roles_n_privileges_hash = validate_roles_n_privileges_hash
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.validate_roles_n_privileges_hash
|
66
|
+
_result_hash = {}
|
67
|
+
YAML::load_file(File.join(Rails.root, 'config', 'roles_n_privileges.yml')).each do |role_name, role_permissions|
|
68
|
+
_result_hash[role_name.to_sym] ||= {}
|
69
|
+
_rh_with_role = _result_hash[role_name.to_sym]
|
70
|
+
|
71
|
+
role_permissions.symbolize_keys!
|
72
|
+
[:can_do, :cant_do].each do |_can|
|
73
|
+
|
74
|
+
if role_permissions[_can].is_a?(Array)
|
75
|
+
|
76
|
+
role_permissions[_can].each do |class_name|
|
77
|
+
if [Symbol, String].include?(class_name.class)
|
78
|
+
_class_name = class_name.to_s.classify.to_sym
|
79
|
+
((_rh_with_role[_class_name] ||= {})[_can] ||={}).merge!({:anything => nil})
|
80
|
+
else
|
81
|
+
raise ZeroAuthorization::Exceptions::InvalidRolesNPrivilegesHash.new(class_name), 'It should only be a Symbol or String'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
elsif role_permissions[_can].is_a?(Hash)
|
86
|
+
|
87
|
+
role_permissions[_can].each do |class_name, permission_set|
|
88
|
+
_class_name = class_name.to_s.classify.to_sym
|
89
|
+
|
90
|
+
if [Symbol, String].include?(class_name.class)
|
91
|
+
if [Symbol, String].include?(permission_set.class)
|
92
|
+
if [:anything, :nothing].include?(permission_set.to_sym)
|
93
|
+
((_rh_with_role[_class_name] ||= {})[_can] ||={}).merge!({permission_set.to_sym => nil})
|
94
|
+
else
|
95
|
+
raise ZeroAuthorization::Exceptions::InvalidRolesNPrivilegesHash.new(permission_set.to_sym), 'It should only have :anything or :nothing'
|
96
|
+
end
|
97
|
+
elsif permission_set.is_a?(Array)
|
98
|
+
permission_set.each do |i_permission_set|
|
99
|
+
if [Symbol, String].include?(i_permission_set.class)
|
100
|
+
((_rh_with_role[_class_name] ||= {})[_can] ||={}).merge!({i_permission_set.to_sym => nil})
|
101
|
+
elsif i_permission_set.is_a?(Hash)
|
102
|
+
i_permission_set.each do |_key, _value|
|
103
|
+
if [Symbol, String].include?(_key.class) and [Symbol, String].include?(_value.class)
|
104
|
+
((_rh_with_role[_class_name] ||= {})[_can] ||={}).merge!({_key.to_sym => _value.to_sym})
|
105
|
+
else
|
106
|
+
raise ZeroAuthorization::Exceptions::InvalidRolesNPrivilegesHash.new({_key => _value}), 'Hash should only have key and value of type Symbol or String'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
else
|
110
|
+
raise ZeroAuthorization::Exceptions::InvalidRolesNPrivilegesHash.new(i_permission_set), 'It should only be a Symbol, String or Hash'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
elsif permission_set.is_a?(Hash)
|
114
|
+
permission_set.each do |i_permission_key, i_permission_value|
|
115
|
+
if [Symbol, String].include?(i_permission_key.class) and [Symbol, String].include?(i_permission_value.class)
|
116
|
+
((_rh_with_role[_class_name] ||= {})[_can] ||={}).merge!({i_permission_key.to_sym => i_permission_value.to_sym})
|
117
|
+
else
|
118
|
+
raise ZeroAuthorization::Exceptions::InvalidRolesNPrivilegesHash.new({i_permission_key => i_permission_value}), 'Hash should only have key and value of type Symbol or String'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
else
|
122
|
+
raise ZeroAuthorization::Exceptions::InvalidRolesNPrivilegesHash.new(permission_set), 'It should only be a Symbol, String, Hash or Array'
|
123
|
+
end
|
124
|
+
else
|
125
|
+
raise ZeroAuthorization::Exceptions::InvalidRolesNPrivilegesHash.new(class_name), 'It should only be a Symbol or String'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
_result_hash
|
34
133
|
end
|
35
134
|
|
36
135
|
# Do any activity with any specific temporary role and then revert back to normal situation.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zero_authorization
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rajeev Kannav Sharma
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-12-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -95,9 +95,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
95
|
version: '0'
|
96
96
|
requirements: []
|
97
97
|
rubyforge_project:
|
98
|
-
rubygems_version: 2.
|
98
|
+
rubygems_version: 2.4.5
|
99
99
|
signing_key:
|
100
100
|
specification_version: 4
|
101
101
|
summary: 'How to setup: Specify what any specific role of current root entity(logged_user)
|
102
102
|
can do/can''t do in roles_n_privileges.yml and (re-)boot application.'
|
103
103
|
test_files: []
|
104
|
+
has_rdoc:
|