zero_authorization 1.0.0 → 1.4.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 +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:
|