@@ -186,23 +186,143 @@ def permit!(privilege, options = {})
186186 attr_validator = AttributeValidator . new ( self , user , options [ :object ] , privilege , options [ :context ] )
187187 rules = matching_auth_rules ( roles , privileges , options [ :context ] )
188188
189- # Test each rule in turn to see whether any one of them is satisfied.
189+ # _____ _ ____ ____
190+ # / ___| (_) | _ \| _ \
191+ # \ `--. _ __ _ ___ ___| | | | |_) |
192+ # `--. \ '_ \| |/ __/ _ \ | | | _ <
193+ # /\__/ / |_) | | (_| __/ |_| | |_) |
194+ # \____/| .__/|_|\___\___|____/|____/
195+ # | |
196+ # |_|
197+ use_spicedb_auth = false
198+
190199 rules . each do |rule |
191- return true if rule . validate? ( attr_validator , options [ :skip_attribute_test ] )
200+ unless rule . role . to_s . start_with? ( "leases__" , "lease_renewals__" )
201+ # Existing behavior for non-lease-related rules
202+ return true if rule . validate? ( attr_validator , options [ :skip_attribute_test ] )
203+ next
204+ end
205+
206+ use_spicedb_auth = true
207+
208+ auth_service_class = Rails . application . config . try ( :spicedb_authorization_service )
209+ @auth_service = auth_service_class . new
210+
211+ vhost_id = Core ::Company . guid if defined? ( Core ::Company )
212+ raise StandardError , "Vhost ID not found" if vhost_id . nil?
213+
214+ puts "\n ==== Processing new rule ===="
215+ puts "Rule: #{ rule . inspect } "
216+ puts "Role: #{ rule . role } "
217+
218+ permission_to_check = rule . role . to_s . gsub ( "__" , "_" ) + "_permission"
219+ puts "Permission to check: #{ permission_to_check } "
220+
221+ if rule . attributes . empty?
222+ puts "Rule has no attributes, checking spicedb directly"
223+
224+ authorized = @auth_service . check_permission (
225+ resource : { type : "vhost" , id : vhost_id } ,
226+ permission : permission_to_check
227+ )
228+ puts "Authorized? #{ authorized } "
229+
230+ return true if authorized
231+ else
232+ puts "Rule has #{ rule . attributes . count } attributes, examining them:"
233+
234+ rule . attributes . each_with_index do |attribute , index |
235+ puts "\n -- Attribute ##{ index + 1 } : #{ attribute . inspect } "
236+
237+ if attribute . instance_variable_defined? ( '@conditions_hash' )
238+ conditions = attribute . instance_variable_get ( '@conditions_hash' )
239+ puts " Conditions hash: #{ conditions . inspect } "
240+ else
241+ puts " !! No conditions_hash instance variable found, skipping"
242+ next
243+ end
244+
245+ next unless conditions . is_a? ( Hash )
246+
247+ puts " Checking conditions against current values:"
248+ condition_matched = false
249+
250+ if conditions . key? ( :granular_permissions )
251+ rule_requires = conditions [ :granular_permissions ] [ 1 ]
252+ actual_value = options [ :object ] &.granular_permissions if options [ :object ] . respond_to? ( :granular_permissions )
253+
254+ puts " Granular permissions - Rule requires: #{ rule_requires } , Actual: #{ actual_value } "
255+ if rule_requires == actual_value
256+ condition_matched = true
257+ puts " ✓ Granular permissions condition matched!"
258+ else
259+ puts " ✗ Granular permissions condition did not match"
260+ end
261+ else
262+ puts " (No granular_permissions condition to check)"
263+ end
264+
265+ if conditions . key? ( :is_renewal )
266+ rule_requires = conditions [ :is_renewal ] [ 1 ]
267+ # Check if the lease document is a renewal
268+ response = @auth_service . lookup_subjects (
269+ resource_type : "lease_document" ,
270+ resource_id : options [ :object ] &.lease_uuid ,
271+ permission : "renewal" ,
272+ subject_type : "lease_document" ,
273+ )
274+ actual_value = response [ :subject_ids ] . any?
275+
276+ puts " Is renewal - Rule requires: #{ rule_requires } , Actual: #{ actual_value } "
277+ if rule_requires == actual_value
278+ condition_matched = true
279+ puts " ✓ Is_renewal condition matched!"
280+ else
281+ puts " ✗ Is_renewal condition did not match"
282+ end
283+ else
284+ puts " (No is_renewal condition to check)"
285+ end
286+
287+ if condition_matched
288+ puts " At least one matching condition found, checking spicedb"
289+
290+ authorized = @auth_service . check_permission (
291+ resource : { type : "vhost" , id : vhost_id } ,
292+ permission : permission_to_check
293+ )
294+ puts " Authorized? #{ authorized } "
295+
296+ return true if authorized
297+ else
298+ puts " No matching conditions, skipping spicedb check for this attribute"
299+ end
300+ end
301+ end
192302 end
193303
304+ source_prefix = use_spicedb_auth ? "SpiceDB authorization failed. " : ""
305+
194306 if options [ :bang ]
195307 if rules . empty?
196308 raise NotAuthorized , "No matching rules found for #{ privilege } for User with id #{ user . try ( :id ) } " +
197309 "(roles #{ roles . inspect } , privileges #{ privileges . inspect } , " +
198310 "context #{ options [ :context ] . inspect } )."
199311 else
200- raise AttributeAuthorizationError , "#{ privilege } not allowed for User with id #{ user . try ( :id ) } on #{ ( options [ :object ] || options [ :context ] ) . inspect } ."
312+ raise AttributeAuthorizationError , "#{ source_prefix } #{ privilege } not allowed for User with id #{ user . try ( :id ) } " +
313+ "on #{ ( options [ :object ] || options [ :context ] ) . inspect } ."
201314 end
202315 else
203316 false
204317 end
205- end
318+ end
319+ # _____ _ _ _____
320+ # | ___| | \ | | | _ |
321+ # | |__ | \| | | | | |
322+ # | __| | . ` | | | | |
323+ # | |___ | |\ | \ \_/ /
324+ # \____/ \_| \_/ \___/
325+
206326
207327 # Calls permit! but doesn't raise authorization errors. If no exception is
208328 # raised, permit? returns true and yields to the optional block.
0 commit comments