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.
@@ -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, ContextMethods # defined in lib/zuul/active_record.rb
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, ContextMethods # defined in lib/zuul/active_record.rb
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, ContextMethods # defined in lib/zuul/active_record.rb
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, ContextMethods # defined in lib/zuul/active_record.rb
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) && permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
55
+ return false unless verify_target_context(target, context, force_context) && verify_target_context(self, context, false)
57
56
 
58
- return permission_role_class.create(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
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 = permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
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 unless (context.id.nil? && !force_context) || permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
98
- unless force_context
99
- return true unless context.class_name.nil? || permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
100
- return !permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
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 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})
111
+ return role_permissions_for(context)
115
112
  else
116
- return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("#{permission_roles_table_name}.#{role_foreign_key} = ? AND (#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_roles_table_name}.context_type IS NULL) AND (#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_roles_table_name}.context_id IS NULL)", id, context.class_name, context.id)
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, ContextMethods # defined in lib/zuul/active_record.rb
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) && role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
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 = role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
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 unless (context.id.nil? && !force_context) || role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
69
- return false if force_context
70
- return true unless context.class_name.nil? || role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
71
- return !role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
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
- return true unless context.id.nil? || 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("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
93
- return true unless context.class_name.nil? || role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => nil).where("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
94
- return !role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, :context_type => nil, :context_id => nil).where("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
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 role_class.joins(role_subject_plural_key).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND #{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?", id, context.class_name, context.id)
117
+ return subject_roles_for(context)
117
118
  else
118
- return role_class.joins(role_subject_plural_key).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND ((#{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{role_subjects_table_name}.context_type IS NULL) AND (#{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{role_subjects_table_name}.context_id IS NULL))", id, context.class_name, context.id)
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) && permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
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 = permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
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 unless (context.id.nil? && !force_context) || permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
197
- unless force_context
198
- return true unless context.class_name.nil? || permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
199
- return true unless permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
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 permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id LEFT JOIN #{permission_subjects_table_name} ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("(#{permission_subjects_table_name}.#{subject_foreign_key} = ? AND #{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?) OR (#{permission_roles_table_name}.#{role_foreign_key} IN (?) AND #{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?)", id, context.class_name, context.id, roles_for(context).map(&:id), context.class_name, context.id)
287
+ return role_and_subject_permissions_for(context, roles)
222
288
  else
223
- return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id LEFT JOIN #{permission_subjects_table_name} ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("(#{permission_subjects_table_name}.#{subject_foreign_key} = ? AND (#{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_subjects_table_name}.context_type IS NULL) AND (#{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_subjects_table_name}.context_id IS NULL)) OR (#{permission_roles_table_name}.#{role_foreign_key} IN (?) AND (#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_roles_table_name}.context_type IS NULL) AND (#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_roles_table_name}.context_id IS NULL))", id, context.class_name, context.id, roles_for(context).map(&:id), context.class_name, context.id)
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).count > 0
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