@@ -214,6 +214,7 @@ def permit!(privilege, options = {})
214214 puts "\n ==== Processing new rule ===="
215215 puts "Rule: #{ rule . inspect } "
216216 puts "Role: #{ rule . role } "
217+ puts "Join Operator: #{ rule . join_operator } " if rule . respond_to? ( :join_operator )
217218
218219 permission_to_check = rule . role . to_s . gsub ( "__" , "_" ) + "_permission"
219220 puts "Permission to check: #{ permission_to_check } "
@@ -226,10 +227,13 @@ def permit!(privilege, options = {})
226227 permission : permission_to_check
227228 )
228229 puts "Authorized? #{ authorized } "
229-
230+
230231 return true if authorized
231232 else
232233 puts "Rule has #{ rule . attributes . count } attributes, examining them:"
234+
235+ all_attributes_matched = true
236+ any_attribute_matched = false
233237
234238 rule . attributes . each_with_index do |attribute , index |
235239 puts "\n -- Attribute ##{ index + 1 } : #{ attribute . inspect } "
@@ -245,24 +249,22 @@ def permit!(privilege, options = {})
245249 next unless conditions . is_a? ( Hash )
246250
247251 puts " Checking conditions against current values:"
248- condition_matched = false
252+ current_attribute_matched = true
249253
250254 if conditions . key? ( :granular_permissions )
251255 rule_requires = conditions [ :granular_permissions ] [ 1 ]
252256 actual_value = options [ :object ] &.granular_permissions if options [ :object ] . respond_to? ( :granular_permissions )
253257
254258 puts " Granular permissions - Rule requires: #{ rule_requires } , Actual: #{ actual_value } "
255259 if rule_requires == actual_value
256- condition_matched = true
257260 puts " ✓ Granular permissions condition matched!"
258261 else
259262 puts " ✗ Granular permissions condition did not match"
263+ current_attribute_matched = false
260264 end
261- else
262- puts " (No granular_permissions condition to check)"
263265 end
264266
265- if conditions . key? ( :is_renewal )
267+ if conditions . key? ( :is_renewal ) && current_attribute_matched
266268 rule_requires = conditions [ :is_renewal ] [ 1 ]
267269 # If options[:object] has is_renewal, we'll use that value instead of obtaining it from SpiceDB.
268270 # This allows for Blue Moon leases and others to be checked without having to make a SpiceDB call for the value of is_renewal.
@@ -276,36 +278,73 @@ def permit!(privilege, options = {})
276278 resource_type : "lease_document" ,
277279 resource_id : options [ :object ] &.lease_document_uuid . to_s ,
278280 permission : "renewal" ,
279- subject_type : "lease_document" ,
281+ subject_type : "lease_document"
280282 )
281- actual_value = response [ :subject_ids ] . any?
283+ actual_value = response . any?
282284 end
283285
284286 puts " Is renewal - Rule requires: #{ rule_requires } , Actual: #{ actual_value } "
285287 if rule_requires == actual_value
286- condition_matched = true
287288 puts " ✓ Is_renewal condition matched!"
288289 else
289290 puts " ✗ Is_renewal condition did not match"
291+ current_attribute_matched = false
290292 end
293+ end
294+
295+ if conditions . key? ( :id ) && current_attribute_matched
296+ condition_type = conditions [ :id ] [ 0 ]
297+ condition_proc = conditions [ :id ] [ 1 ]
298+
299+ if condition_type == :id_in_scope && condition_proc . is_a? ( Proc )
300+ puts " Checking Occupancy ID in scope condition"
301+ user_has_access_to_occupancy = attribute . validate? ( attr_validator )
302+ puts " User has access to occupancy? #{ user_has_access_to_occupancy } "
303+ if user_has_access_to_occupancy
304+ puts " ✓ This attribute matched conditions"
305+ else
306+ puts " ✗ This attribute did not match conditions"
307+ current_attribute_matched = false
308+ end
309+ end
310+ end
311+
312+ if current_attribute_matched
313+ any_attribute_matched = true
314+ puts " ✓ All conditions matched for this attribute"
291315 else
292- puts " (No is_renewal condition to check)"
316+ all_attributes_matched = false
317+ puts " ✗ Not all conditions matched for this attribute"
293318 end
294-
295- if condition_matched
296- # For now, we will assume each rule's conditions are OR'd together. This is not the case
297- # for all rules, but it's the most common case and a good starting point.
298- puts " At least one matching condition found, checking spicedb"
299-
319+ end
320+
321+ puts " Finished checking attributes, checking if rule is authorized"
322+
323+ if rule . respond_to? ( :join_operator ) && rule . join_operator == :and
324+ puts " Rule uses AND operator, checking if all attributes matched: #{ all_attributes_matched } "
325+ if all_attributes_matched
326+ puts " All attributes matched, checking SpiceDB permission"
327+ authorized = @auth_service . check_permission (
328+ resource : { type : "vhost" , id : vhost_id } ,
329+ permission : permission_to_check
330+ )
331+ puts " Authorized? #{ authorized } "
332+ return true if authorized
333+ else
334+ puts " Not all attributes matched, authorization denied for this rule"
335+ end
336+ else
337+ puts " Rule uses OR operator (default), checking if any attribute matched: #{ any_attribute_matched } "
338+ if any_attribute_matched
339+ puts " At least one attribute matched, checking SpiceDB permission"
300340 authorized = @auth_service . check_permission (
301341 resource : { type : "vhost" , id : vhost_id } ,
302342 permission : permission_to_check
303343 )
304344 puts " Authorized? #{ authorized } "
305-
306345 return true if authorized
307346 else
308- puts " No matching conditions, skipping spicedb check for this attribute "
347+ puts " No attributes matched, authorization denied for this rule "
309348 end
310349 end
311350 end
0 commit comments