zuul 0.2.7 → 0.2.8
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/lib/zuul/action_controller.rb +8 -4
- data/lib/zuul/action_controller/dsl.rb +6 -378
- data/lib/zuul/action_controller/dsl/actionable.rb +19 -0
- data/lib/zuul/action_controller/dsl/actions.rb +8 -0
- data/lib/zuul/action_controller/dsl/base.rb +254 -0
- data/lib/zuul/action_controller/dsl/permissions.rb +45 -0
- data/lib/zuul/action_controller/dsl/roles.rb +77 -0
- data/lib/zuul/active_record.rb +34 -35
- data/lib/zuul/active_record/context_accessors.rb +23 -0
- data/lib/zuul/active_record/permission.rb +2 -3
- data/lib/zuul/active_record/permission_role.rb +2 -3
- data/lib/zuul/active_record/permission_subject.rb +2 -3
- data/lib/zuul/active_record/role.rb +60 -15
- data/lib/zuul/active_record/role_subject.rb +2 -3
- data/lib/zuul/active_record/scope.rb +41 -1
- data/lib/zuul/active_record/subject.rb +213 -39
- data/lib/zuul/context.rb +15 -1
- data/lib/zuul/version.rb +1 -1
- data/spec/support/models.rb +11 -20
- data/spec/zuul/active_record/permission_role_spec.rb +1 -1
- data/spec/zuul/active_record/permission_subject_spec.rb +1 -1
- data/spec/zuul/active_record/role_spec.rb +10 -7
- data/spec/zuul/active_record/role_subject_spec.rb +1 -1
- data/spec/zuul/active_record/subject_spec.rb +14 -8
- data/spec/zuul/active_record_spec.rb +4 -4
- data/spec/zuul/context_spec.rb +350 -3
- metadata +66 -60
@@ -0,0 +1,23 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
# These are included in roles & permissions objects and assigned roles & permissions objects
|
4
|
+
# to provide easy access to the context for that object.
|
5
|
+
module ContextAccessors
|
6
|
+
def self.included(base)
|
7
|
+
base.send :attr_accessible, :context if ::Zuul.should_whitelist?
|
8
|
+
end
|
9
|
+
|
10
|
+
# Return a Zuul::Context object representing the context for the role
|
11
|
+
def context
|
12
|
+
Zuul::Context.new context_type, context_id
|
13
|
+
end
|
14
|
+
|
15
|
+
# Parse a context into an Zuul::Context and set the type and id
|
16
|
+
def context=(context)
|
17
|
+
context = Zuul::Context.parse(context)
|
18
|
+
self.context_type = context.klass
|
19
|
+
self.context_id = context.id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -3,14 +3,13 @@ module Zuul
|
|
3
3
|
module Permission
|
4
4
|
def self.included(base)
|
5
5
|
base.send :extend, ClassMethods
|
6
|
-
base.send :include,
|
6
|
+
base.send :include, ContextAccessors
|
7
7
|
base.send :include, InstanceMethods
|
8
8
|
end
|
9
9
|
|
10
10
|
module ClassMethods
|
11
11
|
def self.extended(base)
|
12
|
-
base.send :attr_accessible, :context, :context_id, :context_type, :slug if ::Zuul
|
13
|
-
.should_whitelist?
|
12
|
+
base.send :attr_accessible, :context, :context_id, :context_type, :slug if ::Zuul.should_whitelist?
|
14
13
|
add_validations base
|
15
14
|
add_associations base
|
16
15
|
end
|
@@ -3,13 +3,12 @@ module Zuul
|
|
3
3
|
module PermissionRole
|
4
4
|
def self.included(base)
|
5
5
|
base.send :extend, ClassMethods
|
6
|
-
base.send :include,
|
6
|
+
base.send :include, ContextAccessors
|
7
7
|
end
|
8
8
|
|
9
9
|
module ClassMethods
|
10
10
|
def self.extended(base)
|
11
|
-
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym if ::Zuul
|
12
|
-
.should_whitelist?
|
11
|
+
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym if ::Zuul.should_whitelist?
|
13
12
|
add_validations base
|
14
13
|
add_associations base
|
15
14
|
end
|
@@ -3,13 +3,12 @@ module Zuul
|
|
3
3
|
module PermissionSubject
|
4
4
|
def self.included(base)
|
5
5
|
base.send :extend, ClassMethods
|
6
|
-
base.send :include,
|
6
|
+
base.send :include, ContextAccessors
|
7
7
|
end
|
8
8
|
|
9
9
|
module ClassMethods
|
10
10
|
def self.extended(base)
|
11
|
-
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul
|
12
|
-
.should_whitelist?
|
11
|
+
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul.should_whitelist?
|
13
12
|
add_validations base
|
14
13
|
add_associations base
|
15
14
|
end
|
@@ -3,15 +3,14 @@ module Zuul
|
|
3
3
|
module Role
|
4
4
|
def self.included(base)
|
5
5
|
base.send :extend, ClassMethods
|
6
|
-
base.send :include,
|
6
|
+
base.send :include, ContextAccessors
|
7
7
|
base.send :include, InstanceMethods
|
8
8
|
base.send :include, PermissionMethods if base.auth_scope.config.with_permissions
|
9
9
|
end
|
10
10
|
|
11
11
|
module ClassMethods
|
12
12
|
def self.extended(base)
|
13
|
-
base.send :attr_accessible, :context_id, :context_type, :level, :slug if ::Zuul
|
14
|
-
.should_whitelist?
|
13
|
+
base.send :attr_accessible, :context_id, :context_type, :level, :slug if ::Zuul.should_whitelist?
|
15
14
|
add_validations base
|
16
15
|
add_associations base
|
17
16
|
end
|
@@ -53,9 +52,9 @@ module Zuul
|
|
53
52
|
auth_scope do
|
54
53
|
context = Zuul::Context.parse(context)
|
55
54
|
target = target_permission(permission, context, force_context)
|
56
|
-
return false unless verify_target_context(target, context, force_context) && verify_target_context(self, context, false)
|
55
|
+
return false unless verify_target_context(target, context, force_context) && verify_target_context(self, context, false)
|
57
56
|
|
58
|
-
return permission_role_class.
|
57
|
+
return permission_role_class.find_or_create_by(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
@@ -70,7 +69,7 @@ module Zuul
|
|
70
69
|
target = target_permission(permission, context, force_context)
|
71
70
|
return false if target.nil?
|
72
71
|
|
73
|
-
assigned_permission =
|
72
|
+
assigned_permission = permission_role_for(target, context)
|
74
73
|
return false if assigned_permission.nil?
|
75
74
|
return assigned_permission.destroy
|
76
75
|
end
|
@@ -85,20 +84,18 @@ module Zuul
|
|
85
84
|
#
|
86
85
|
# The assigned context behaves the same way, in that if the permission is not found
|
87
86
|
# to belong to the role with the specified context, we look up the context chain.
|
88
|
-
#
|
89
|
-
# TODO add options to force context, not go up the chain
|
90
87
|
def has_permission?(permission, context=nil, force_context=nil)
|
91
88
|
auth_scope do
|
92
89
|
force_context ||= config.force_context
|
93
90
|
context = Zuul::Context.parse(context)
|
94
91
|
target = target_permission(permission, context, force_context)
|
95
92
|
return false if target.nil?
|
93
|
+
return permission_role_for?(target, context) if force_context
|
96
94
|
|
97
|
-
return true
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
95
|
+
return true if permission_role_for?(target, context)
|
96
|
+
return true if context.instance? && permission_role_for?(target, Zuul::Context.new(context.klass))
|
97
|
+
return true if !context.global? && permission_role_for?(target, Zuul::Context.new)
|
98
|
+
return false
|
102
99
|
end
|
103
100
|
end
|
104
101
|
alias_method :permission?, :has_permission?
|
@@ -111,9 +108,9 @@ module Zuul
|
|
111
108
|
force_context ||= config.force_context
|
112
109
|
context = Zuul::Context.parse(context)
|
113
110
|
if force_context
|
114
|
-
return
|
111
|
+
return role_permissions_for(context)
|
115
112
|
else
|
116
|
-
return
|
113
|
+
return role_permissions_within(context)
|
117
114
|
end
|
118
115
|
end
|
119
116
|
end
|
@@ -122,6 +119,54 @@ module Zuul
|
|
122
119
|
def permissions_for?(context=nil, force_context=nil)
|
123
120
|
permissions_for(context, force_context).count > 0
|
124
121
|
end
|
122
|
+
|
123
|
+
# Looks up a single permission_role based on the passed target and context
|
124
|
+
def permission_role_for(target, context)
|
125
|
+
auth_scope do
|
126
|
+
return permission_role_class.find_by(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def permission_role_for?(target, context)
|
131
|
+
!permission_role_for(target, context).nil?
|
132
|
+
end
|
133
|
+
|
134
|
+
# Looks up all permissions for this role for the passed context
|
135
|
+
def role_permissions_for(context)
|
136
|
+
auth_scope do
|
137
|
+
return permission_class.joins(permission_role_plural_key).where(permission_role_plural_key => {role_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id})
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def role_permissions_for?(context)
|
142
|
+
!role_permissions_for(context).empty?
|
143
|
+
end
|
144
|
+
|
145
|
+
# Looks up all permissions for this role within the passed context (within the context chain)
|
146
|
+
def role_permissions_within(context)
|
147
|
+
auth_scope do
|
148
|
+
return permission_class.joins("
|
149
|
+
LEFT JOIN #{permission_roles_table_name}
|
150
|
+
ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id"
|
151
|
+
).where("
|
152
|
+
#{permission_roles_table_name}.#{role_foreign_key} = ?
|
153
|
+
AND (
|
154
|
+
#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
|
155
|
+
OR #{permission_roles_table_name}.context_type IS NULL
|
156
|
+
)
|
157
|
+
AND (
|
158
|
+
#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?
|
159
|
+
OR #{permission_roles_table_name}.context_id IS NULL
|
160
|
+
)",
|
161
|
+
id,
|
162
|
+
context.class_name,
|
163
|
+
context.id)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def role_permissions_within?(context)
|
168
|
+
!role_permissions_within(context).empty?
|
169
|
+
end
|
125
170
|
end
|
126
171
|
end
|
127
172
|
end
|
@@ -3,13 +3,12 @@ module Zuul
|
|
3
3
|
module RoleSubject
|
4
4
|
def self.included(base)
|
5
5
|
base.send :extend, ClassMethods
|
6
|
-
base.send :include,
|
6
|
+
base.send :include, ContextAccessors
|
7
7
|
end
|
8
8
|
|
9
9
|
module ClassMethods
|
10
10
|
def self.extended(base)
|
11
|
-
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul
|
12
|
-
.should_whitelist?
|
11
|
+
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul.should_whitelist?
|
13
12
|
add_validations base
|
14
13
|
add_associations base
|
15
14
|
end
|
@@ -9,10 +9,49 @@ module Zuul
|
|
9
9
|
@config = config
|
10
10
|
@name = @config.scope
|
11
11
|
define_reflection_methods
|
12
|
-
super()
|
13
12
|
end
|
14
13
|
|
15
14
|
# Define dynamic reflection methods that reference the config to be used for subjects, roles, permissions and their associations.
|
15
|
+
#
|
16
|
+
# With a standard configuration, this defines the following methods:
|
17
|
+
#
|
18
|
+
# def subject_class : Subject
|
19
|
+
# def role_class : Role
|
20
|
+
# def permission_class : Permission
|
21
|
+
# def role_subject_class : RoleSubject
|
22
|
+
# def permission_role_class : PermissionRole
|
23
|
+
#
|
24
|
+
# def subject_class_name : 'Subject'
|
25
|
+
# def role_class_name : 'Role'
|
26
|
+
# def permission_class_name : 'Permission'
|
27
|
+
# def role_subject_class_name : 'RoleSubject'
|
28
|
+
# def permission_role_class_name : 'PermissionRole'
|
29
|
+
#
|
30
|
+
# def subject_table_name : 'subjects'
|
31
|
+
# def role_table_name : 'roles'
|
32
|
+
# def permission_table_name : 'permissions'
|
33
|
+
# def role_subject_table_name : 'role_subjects'
|
34
|
+
# def permission_role_table_name : 'permission_roles'
|
35
|
+
#
|
36
|
+
# def subject_singular_key : 'subject'
|
37
|
+
# def role_singular_key : 'role'
|
38
|
+
# def permission_singular_key : 'permission'
|
39
|
+
# def role_subject_singular_key : 'role_subject'
|
40
|
+
# def permission_role_singular_key : 'permission_role'
|
41
|
+
#
|
42
|
+
# def subject_plural_key : 'subjects'
|
43
|
+
# def role_plural_key : 'roles'
|
44
|
+
# def permission_plural_key : 'permissions'
|
45
|
+
# def role_subject_plural_key : 'role_subjects'
|
46
|
+
# def permission_role_plural_key : 'permission_roles'
|
47
|
+
#
|
48
|
+
# def subject_foreign_key : 'subject_id'
|
49
|
+
# def role_foreign_key : 'role_id'
|
50
|
+
# def permission_foreign_key : 'permission_id'
|
51
|
+
#
|
52
|
+
# All methods are also aliased to pluralized versions, so you can use `subject_class` or `subjects_class`, and
|
53
|
+
# when custom class names are used the methods are prefixed with those classes and aliased, so `user_class_name`
|
54
|
+
# is aliased to `subject_class_name`
|
16
55
|
def define_reflection_methods
|
17
56
|
|
18
57
|
# *_class_name, *_class, *_table_name methods for all classes
|
@@ -54,6 +93,7 @@ module Zuul
|
|
54
93
|
end
|
55
94
|
alias_method "#{class_type_name.pluralize}_plural_key", "#{class_type_name}_plural_key"
|
56
95
|
|
96
|
+
# These define aliases for custom class names, like user_class and user_table_name aliased to subject_class and subject_table_name
|
57
97
|
unless class_type.to_s.underscore == "#{class_name.to_s.underscore}_class"
|
58
98
|
%w(_class_name _class _table_name _singular_key _plural_key).each do |suffix|
|
59
99
|
alias_method "#{class_name.to_s.underscore.singularize}#{suffix}", "#{class_type_name}#{suffix}"
|
@@ -28,9 +28,8 @@ module Zuul
|
|
28
28
|
auth_scope do
|
29
29
|
context = Zuul::Context.parse(context)
|
30
30
|
target = target_role(role, context, force_context)
|
31
|
-
return false unless verify_target_context(target, context, force_context)
|
32
|
-
|
33
|
-
return role_subject_class.create(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
31
|
+
return false unless verify_target_context(target, context, force_context)
|
32
|
+
return role_subject_class.find_or_create_by(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
@@ -43,8 +42,8 @@ module Zuul
|
|
43
42
|
context = Zuul::Context.parse(context)
|
44
43
|
target = target_role(role, context, force_context)
|
45
44
|
return false if target.nil?
|
46
|
-
|
47
|
-
assigned_role =
|
45
|
+
|
46
|
+
assigned_role = role_subject_for(target, context)
|
48
47
|
return false if assigned_role.nil?
|
49
48
|
return assigned_role.destroy
|
50
49
|
end
|
@@ -64,11 +63,12 @@ module Zuul
|
|
64
63
|
context = Zuul::Context.parse(context)
|
65
64
|
target = target_role(role, context, force_context)
|
66
65
|
return false if target.nil?
|
66
|
+
return role_subject_for?(target, context) if force_context
|
67
67
|
|
68
|
-
return true
|
69
|
-
return
|
70
|
-
return true
|
71
|
-
return
|
68
|
+
return true if role_subject_for?(target, context)
|
69
|
+
return true if context.instance? && role_subject_for?(target, Zuul::Context.new(context.klass))
|
70
|
+
return true if !context.global? && role_subject_for?(target, Zuul::Context.new)
|
71
|
+
return false
|
72
72
|
end
|
73
73
|
end
|
74
74
|
alias_method :role?, :has_role?
|
@@ -86,12 +86,13 @@ module Zuul
|
|
86
86
|
context = Zuul::Context.parse(context)
|
87
87
|
target = target_role(role, context, force_context)
|
88
88
|
return false if target.nil?
|
89
|
-
|
90
89
|
return true if has_role?(target, context, force_context)
|
91
|
-
|
92
|
-
|
93
|
-
return true
|
94
|
-
return
|
90
|
+
return role_subject_or_higher_for?(target, context) if force_context
|
91
|
+
|
92
|
+
return true if role_subject_or_higher_for?(target, context)
|
93
|
+
return true if context.instance? && role_subject_or_higher_for?(target, Zuul::Context.new(context.klass))
|
94
|
+
return true if !context.global? && role_subject_or_higher_for?(target, Zuul::Context.new)
|
95
|
+
return false
|
95
96
|
end
|
96
97
|
end
|
97
98
|
alias_method :role_or_higher?, :has_role_or_higher?
|
@@ -113,19 +114,89 @@ module Zuul
|
|
113
114
|
force_context ||= config.force_context
|
114
115
|
context = Zuul::Context.parse(context)
|
115
116
|
if force_context
|
116
|
-
return
|
117
|
+
return subject_roles_for(context)
|
117
118
|
else
|
118
|
-
return
|
119
|
+
return subject_roles_within(context)
|
119
120
|
end
|
120
121
|
end
|
121
122
|
end
|
122
|
-
|
123
|
+
|
123
124
|
# Check whether the subject possesses any roles within the specified context.
|
124
125
|
#
|
125
126
|
# This includes any roles found by looking up the context chain.
|
126
127
|
def roles_for?(context=nil, force_context=nil)
|
127
128
|
roles_for(context, force_context).count > 0
|
128
129
|
end
|
130
|
+
|
131
|
+
# Looks up a single role subject based on the passed target and context
|
132
|
+
def role_subject_for(target, context)
|
133
|
+
auth_scope do
|
134
|
+
return role_subject_class.joins(role_table_name.singularize.to_sym).find_by(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def role_subject_for?(target, context)
|
139
|
+
!role_subject_for(target, context).nil?
|
140
|
+
end
|
141
|
+
|
142
|
+
# Looks up a single role subject with a level greather than or equal to the target level based on the passed target and context
|
143
|
+
def role_subject_or_higher_for(target, context)
|
144
|
+
auth_scope do
|
145
|
+
return role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id).where("
|
146
|
+
#{roles_table_name}.level >= ?
|
147
|
+
AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ?
|
148
|
+
AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?",
|
149
|
+
target.level,
|
150
|
+
target.context_type,
|
151
|
+
target.context_id).limit(1).first
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def role_subject_or_higher_for?(target, context)
|
156
|
+
!role_subject_or_higher_for(target, context).nil?
|
157
|
+
end
|
158
|
+
|
159
|
+
# Looks up all roles for the subject for the passed context
|
160
|
+
def subject_roles_for(context)
|
161
|
+
auth_scope do
|
162
|
+
return role_class.joins(role_subject_plural_key).where("
|
163
|
+
#{role_subjects_table_name}.#{subject_foreign_key} = ?
|
164
|
+
AND #{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
|
165
|
+
AND #{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?",
|
166
|
+
id,
|
167
|
+
context.class_name,
|
168
|
+
context.id)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def subject_roles_for?(context)
|
173
|
+
!subject_roles_for(context).empty?
|
174
|
+
end
|
175
|
+
|
176
|
+
# Looks up all roles for the subject within the passed context (within the context chain)
|
177
|
+
def subject_roles_within(context)
|
178
|
+
auth_scope do
|
179
|
+
return role_class.joins(role_subject_plural_key).where("
|
180
|
+
#{role_subjects_table_name}.#{subject_foreign_key} = ?
|
181
|
+
AND (
|
182
|
+
(
|
183
|
+
#{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
|
184
|
+
OR #{role_subjects_table_name}.context_type IS NULL
|
185
|
+
)
|
186
|
+
AND (
|
187
|
+
#{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?
|
188
|
+
OR #{role_subjects_table_name}.context_id IS NULL
|
189
|
+
)
|
190
|
+
)",
|
191
|
+
id,
|
192
|
+
context.class_name,
|
193
|
+
context.id)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def subject_roles_within?(context)
|
198
|
+
!subject_roles_within(context).empty?
|
199
|
+
end
|
129
200
|
end
|
130
201
|
end
|
131
202
|
|
@@ -146,30 +217,29 @@ module Zuul
|
|
146
217
|
# Assigns a permission to a subject within the provided context.
|
147
218
|
#
|
148
219
|
# If a Permission object is provided it's used directly, otherwise if a
|
149
|
-
# permission slug is provided, the permission is looked up in the context
|
220
|
+
# permission slug is provided, the permission is looked up in the context
|
150
221
|
# chain by target_permission.
|
151
222
|
def assign_permission(permission, context=nil, force_context=nil)
|
152
223
|
auth_scope do
|
153
224
|
context = Zuul::Context.parse(context)
|
154
225
|
target = target_permission(permission, context, force_context)
|
155
|
-
return false unless verify_target_context(target, context, force_context)
|
156
|
-
|
157
|
-
return permission_subject_class.create(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
226
|
+
return false unless verify_target_context(target, context, force_context)
|
227
|
+
return permission_subject_class.find_or_create_by(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
158
228
|
end
|
159
229
|
end
|
160
230
|
|
161
231
|
# Removes a permission from a subject within the provided context.
|
162
232
|
#
|
163
233
|
# If a Permission object is provided it's used directly, otherwise if a
|
164
|
-
# permission slug is provided, the permission is looked up in the context
|
234
|
+
# permission slug is provided, the permission is looked up in the context
|
165
235
|
# chain by target_permission.
|
166
236
|
def unassign_permission(permission, context=nil, force_context=nil)
|
167
237
|
auth_scope do
|
168
238
|
context = Zuul::Context.parse(context)
|
169
239
|
target = target_permission(permission, context, force_context)
|
170
240
|
return false if target.nil?
|
171
|
-
|
172
|
-
assigned_permission =
|
241
|
+
|
242
|
+
assigned_permission = permission_subject_for(target, context)
|
173
243
|
return false if assigned_permission.nil?
|
174
244
|
return assigned_permission.destroy
|
175
245
|
end
|
@@ -179,7 +249,7 @@ module Zuul
|
|
179
249
|
# Checks whether a subject has a permission within the provided context.
|
180
250
|
#
|
181
251
|
# If a Permission object is provided it's used directly, otherwise if a
|
182
|
-
# permission slug is provided, the permission is looked up in the context
|
252
|
+
# permission slug is provided, the permission is looked up in the context
|
183
253
|
# chain by target_permission.
|
184
254
|
#
|
185
255
|
# The assigned context behaves the same way, in that if the permission is not found
|
@@ -192,17 +262,12 @@ module Zuul
|
|
192
262
|
context = Zuul::Context.parse(context)
|
193
263
|
target = target_permission(permission, context, force_context)
|
194
264
|
return false if target.nil?
|
265
|
+
return permission_role_or_subject_for?(target, context) if force_context
|
195
266
|
|
196
|
-
return true
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
end
|
201
|
-
|
202
|
-
return true unless (context.id.nil? && !force_context) || permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
|
203
|
-
return false if force_context
|
204
|
-
return true unless context.class_name.nil? || permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
|
205
|
-
return !permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
|
267
|
+
return true if permission_role_or_subject_for?(target, context)
|
268
|
+
return true if context.instance? && permission_role_or_subject_for?(target, Zuul::Context.new(context.klass))
|
269
|
+
return true if !context.global? && permission_role_or_subject_for?(target, Zuul::Context.new)
|
270
|
+
return false
|
206
271
|
end
|
207
272
|
end
|
208
273
|
alias_method :permission?, :has_permission?
|
@@ -217,21 +282,130 @@ module Zuul
|
|
217
282
|
auth_scope do
|
218
283
|
force_context ||= config.force_context
|
219
284
|
context = Zuul::Context.parse(context)
|
285
|
+
roles = roles_for(context)
|
220
286
|
if force_context
|
221
|
-
return
|
287
|
+
return role_and_subject_permissions_for(context, roles)
|
222
288
|
else
|
223
|
-
return
|
289
|
+
return role_and_subject_permissions_within(context, roles)
|
224
290
|
end
|
225
291
|
end
|
226
292
|
end
|
227
|
-
|
293
|
+
|
228
294
|
# Check whether the subject possesses any permissions within the specified context.
|
229
295
|
#
|
230
296
|
# This includes permissions assigned directly to the subject or any roles possessed by
|
231
297
|
# the subject, as well as all permissions found by looking up the context chain.
|
232
298
|
def permissions_for?(context=nil, force_context=nil)
|
233
|
-
permissions_for(context, force_context).
|
299
|
+
!permissions_for(context, force_context).empty?
|
300
|
+
end
|
301
|
+
|
302
|
+
# Looks up a permission subject based on the passed target and context
|
303
|
+
def permission_subject_for(target, context)
|
304
|
+
auth_scope do
|
305
|
+
return permission_subject_class.find_by(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def permission_subject_for?(target, context)
|
310
|
+
!permission_subject_for(target, context).nil?
|
311
|
+
end
|
312
|
+
|
313
|
+
# Looks up a permission role based on the passed target and context
|
314
|
+
def permission_role_for(target, context, proles=nil)
|
315
|
+
auth_scope do
|
316
|
+
proles ||= roles_for(context)
|
317
|
+
return permission_role_class.find_by(role_foreign_key.to_sym => proles.map(&:id), permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def permission_role_for?(target, context, proles=nil)
|
322
|
+
!permission_role_for(target, context, proles).nil?
|
323
|
+
end
|
324
|
+
|
325
|
+
# Looks up a permission subject or role based on the passed target and context
|
326
|
+
def permission_role_or_subject_for(target, context, proles=nil)
|
327
|
+
permission_subject_for(target, context) || permission_role_for(target, context, proles)
|
234
328
|
end
|
329
|
+
|
330
|
+
def permission_role_or_subject_for?(target, context, proles=nil)
|
331
|
+
!permission_role_or_subject_for(target, context, proles).nil?
|
332
|
+
end
|
333
|
+
|
334
|
+
def role_and_subject_permissions_for(context, proles=nil)
|
335
|
+
auth_scope do
|
336
|
+
return permission_class.joins("
|
337
|
+
LEFT JOIN #{permission_roles_table_name}
|
338
|
+
ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id
|
339
|
+
LEFT JOIN #{permission_subjects_table_name}
|
340
|
+
ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id"
|
341
|
+
).where("
|
342
|
+
(
|
343
|
+
#{permission_subjects_table_name}.#{subject_foreign_key} = ?
|
344
|
+
AND #{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
|
345
|
+
AND #{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?
|
346
|
+
)
|
347
|
+
OR
|
348
|
+
(
|
349
|
+
#{permission_roles_table_name}.#{role_foreign_key} IN (?)
|
350
|
+
AND #{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
|
351
|
+
AND #{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?
|
352
|
+
)",
|
353
|
+
id,
|
354
|
+
context.class_name,
|
355
|
+
context.id,
|
356
|
+
(proles || roles_for(context)).map(&:id),
|
357
|
+
context.class_name,
|
358
|
+
context.id)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
def role_and_subject_permissions_for?(context, proles=nil)
|
363
|
+
!role_and_subject_permissions_for(context, proles).empty?
|
364
|
+
end
|
365
|
+
|
366
|
+
def role_and_subject_permissions_within(context, proles=nil)
|
367
|
+
auth_scope do
|
368
|
+
return permission_class.joins("
|
369
|
+
LEFT JOIN #{permission_roles_table_name}
|
370
|
+
ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id
|
371
|
+
LEFT JOIN #{permission_subjects_table_name}
|
372
|
+
ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id"
|
373
|
+
).where("
|
374
|
+
(
|
375
|
+
#{permission_subjects_table_name}.#{subject_foreign_key} = ?
|
376
|
+
AND (
|
377
|
+
#{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
|
378
|
+
OR #{permission_subjects_table_name}.context_type IS NULL
|
379
|
+
)
|
380
|
+
AND (
|
381
|
+
#{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?
|
382
|
+
OR #{permission_subjects_table_name}.context_id IS NULL
|
383
|
+
)
|
384
|
+
)
|
385
|
+
OR (
|
386
|
+
#{permission_roles_table_name}.#{role_foreign_key} IN (?)
|
387
|
+
AND (
|
388
|
+
#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
|
389
|
+
OR #{permission_roles_table_name}.context_type IS NULL
|
390
|
+
)
|
391
|
+
AND (
|
392
|
+
#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?
|
393
|
+
OR #{permission_roles_table_name}.context_id IS NULL
|
394
|
+
)
|
395
|
+
)",
|
396
|
+
id,
|
397
|
+
context.class_name,
|
398
|
+
context.id,
|
399
|
+
(proles || roles_for(context)).map(&:id),
|
400
|
+
context.class_name,
|
401
|
+
context.id)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def role_and_subject_permissions_within?(context, proles=nil)
|
406
|
+
!role_and_subject_permissions_within(context, proles).empty?
|
407
|
+
end
|
408
|
+
|
235
409
|
end
|
236
410
|
end
|
237
411
|
end
|