@@ -186,23 +186,145 @@ def permit!(privilege, options = {})
186
186
attr_validator = AttributeValidator . new ( self , user , options [ :object ] , privilege , options [ :context ] )
187
187
rules = matching_auth_rules ( roles , privileges , options [ :context ] )
188
188
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
+
190
199
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
+ should_consider = options [ :object ] &.respond_to? ( :granular_permissions ) && options [ :object ] &.granular_permissions != nil
253
+ actual_value = should_consider ? options [ :object ] &.granular_permissions : nil
254
+
255
+ puts " Granular permissions - Rule requires: #{ rule_requires } , Actual: #{ actual_value } "
256
+ if rule_requires == actual_value
257
+ condition_matched = true
258
+ puts " ✓ Granular permissions condition matched!"
259
+ else
260
+ puts " ✗ Granular permissions condition did not match"
261
+ end
262
+ else
263
+ puts " (No granular_permissions condition to check)"
264
+ end
265
+
266
+ if conditions . key? ( :is_renewal )
267
+ rule_requires = conditions [ :is_renewal ] [ 1 ]
268
+ should_consider = options [ :object ] &.respond_to? ( :is_renewal ) && options [ :object ] &.is_renewal != nil
269
+ # Check if the lease document is a renewal
270
+ response = @auth_service . lookup_subjects (
271
+ resource_type : "lease_document" ,
272
+ resource_id : options [ :object ] &.lease_uuid ,
273
+ permission : "renewal" ,
274
+ subject_type : "lease_document" ,
275
+ )
276
+ actual_value = response [ :subject_ids ] . any?
277
+
278
+ puts " Is renewal - Rule requires: #{ rule_requires } , Actual: #{ actual_value } "
279
+ if rule_requires == actual_value
280
+ condition_matched = true
281
+ puts " ✓ Is_renewal condition matched!"
282
+ else
283
+ puts " ✗ Is_renewal condition did not match"
284
+ end
285
+ else
286
+ puts " (No is_renewal condition to check)"
287
+ end
288
+
289
+ if condition_matched
290
+ puts " At least one matching condition found, checking spicedb"
291
+
292
+ authorized = @auth_service . check_permission (
293
+ resource : { type : "vhost" , id : vhost_id } ,
294
+ permission : permission_to_check
295
+ )
296
+ puts " Authorized? #{ authorized } "
297
+
298
+ return true if authorized
299
+ else
300
+ puts " No matching conditions, skipping spicedb check for this attribute"
301
+ end
302
+ end
303
+ end
192
304
end
193
305
306
+ source_prefix = use_spicedb_auth ? "SpiceDB authorization failed. " : ""
307
+
194
308
if options [ :bang ]
195
309
if rules . empty?
196
310
raise NotAuthorized , "No matching rules found for #{ privilege } for User with id #{ user . try ( :id ) } " +
197
311
"(roles #{ roles . inspect } , privileges #{ privileges . inspect } , " +
198
312
"context #{ options [ :context ] . inspect } )."
199
313
else
200
- raise AttributeAuthorizationError , "#{ privilege } not allowed for User with id #{ user . try ( :id ) } on #{ ( options [ :object ] || options [ :context ] ) . inspect } ."
314
+ raise AttributeAuthorizationError , "#{ source_prefix } #{ privilege } not allowed for User with id #{ user . try ( :id ) } " +
315
+ "on #{ ( options [ :object ] || options [ :context ] ) . inspect } ."
201
316
end
202
317
else
203
318
false
204
319
end
205
- end
320
+ end
321
+ # _____ _ _ _____
322
+ # | ___| | \ | | | _ |
323
+ # | |__ | \| | | | | |
324
+ # | __| | . ` | | | | |
325
+ # | |___ | |\ | \ \_/ /
326
+ # \____/ \_| \_/ \___/
327
+
206
328
207
329
# Calls permit! but doesn't raise authorization errors. If no exception is
208
330
# raised, permit? returns true and yields to the optional block.
0 commit comments