@@ -448,4 +448,83 @@ private function countQueuedRequestForWebhook(Webhook $webhook): int
448448 'webhooks_id ' => $ webhook ->getID (),
449449 ]);
450450 }
451+
452+ /**
453+ * Ensure the get_webhook_body action enforces READ permission on the requested item.
454+ * A user who cannot READ an item must not be able to retrieve its webhook body.
455+ */
456+ public function testGetWebhookBodyReadPermissionCheck (): void
457+ {
458+ $ this ->login ();
459+
460+ $ computer = $ this ->createItem (\Computer::class, [
461+ 'name ' => 'Test computer ' ,
462+ 'entities_id ' => $ _SESSION ['glpiactive_entity ' ],
463+ ]);
464+ $ computers_id = $ computer ->getID ();
465+
466+ $ webhook = $ this ->createItem (Webhook::class, [
467+ 'name ' => 'Test webhook ' ,
468+ 'entities_id ' => $ _SESSION ['glpiactive_entity ' ],
469+ 'url ' => 'http://localhost ' ,
470+ 'itemtype ' => \Computer::class,
471+ 'event ' => 'new ' ,
472+ 'is_active ' => 1 ,
473+ 'use_default_payload ' => 1 ,
474+ ]);
475+
476+ // Sanity check: with READ right the item is accessible
477+ $ obj = new \Computer ();
478+ $ this ->assertTrue ($ obj ->can ($ computers_id , READ ));
479+
480+ // Remove READ right on Computer for the current profile
481+ $ saved_rights = $ _SESSION ['glpiactiveprofile ' ];
482+ $ _SESSION ['glpiactiveprofile ' ]['computer ' ] = ALLSTANDARDRIGHT & ~READ ;
483+
484+ // The can() check must now fail, which is the guard used by the ajax action
485+ $ obj2 = new \Computer ();
486+ $ this ->assertFalse ($ obj2 ->can ($ computers_id , READ ));
487+
488+ // Restore rights
489+ $ _SESSION ['glpiactiveprofile ' ] = $ saved_rights ;
490+ }
491+
492+ /**
493+ * Ensure the get_webhook_body action rejects requests whose itemtype does not
494+ * match the webhook's configured itemtype.
495+ */
496+ public function testGetWebhookBodyItemtypeMismatch (): void
497+ {
498+ $ this ->login ();
499+
500+ // Create a webhook configured for Computer
501+ $ webhook = $ this ->createItem (Webhook::class, [
502+ 'name ' => 'Test webhook ' ,
503+ 'entities_id ' => $ _SESSION ['glpiactive_entity ' ],
504+ 'url ' => 'http://localhost ' ,
505+ 'itemtype ' => \Computer::class,
506+ 'event ' => 'new ' ,
507+ 'is_active ' => 1 ,
508+ 'use_default_payload ' => 1 ,
509+ ]);
510+
511+ // The webhook's configured itemtype is Computer
512+ $ this ->assertEquals (\Computer::class, $ webhook ->fields ['itemtype ' ]);
513+
514+ // A request asking for Monitor (a different itemtype) must be rejected:
515+ // the mismatch condition used in the ajax action is:
516+ // $webhook->getID() && $itemtype !== $webhook->fields['itemtype']
517+ $ requested_itemtype = \Monitor::class;
518+ $ this ->assertNotEquals ($ requested_itemtype , $ webhook ->fields ['itemtype ' ]);
519+ $ this ->assertGreaterThan (0 , $ webhook ->getID ());
520+
521+ // Directly testing the mismatch guard logic
522+ $ mismatch_detected = $ webhook ->getID () && $ requested_itemtype !== $ webhook ->fields ['itemtype ' ];
523+ $ this ->assertTrue ($ mismatch_detected , 'Itemtype mismatch should have been detected ' );
524+
525+ // A request with the correct itemtype must not be rejected
526+ $ matching_itemtype = \Computer::class;
527+ $ no_mismatch = $ webhook ->getID () && $ matching_itemtype !== $ webhook ->fields ['itemtype ' ];
528+ $ this ->assertFalse ($ no_mismatch , 'Correct itemtype should not trigger the mismatch guard ' );
529+ }
451530}
0 commit comments