fix(security): enforce ownership on 4 IDOR read/bind endpoints (M2-M5)
- M2 GET /insurance/{id}: was unguarded; now owner-or-admin (403 otherwise) —
stops reading another doctor's negotiated price by id enumeration.
- M3 GET /clinic-pro/doctor-address/{id}: add the same owner/admin check the
sibling PATCH/DELETE already had.
- M4 POST/PATCH /service-item: staff_uuid must belong to the caller's tenant
(entity_type/entity_id) → 422; stops binding another tenant's staff.
- M5 appointment-settings list endpoints (date-override/holidays/
available-locations): add the per-doctor ownership check the sibling
single-record endpoints already enforce.
Regressions (6 negative cases fail without the fixes):
DoctorInsuranceOwnershipTest, DoctorAddressOwnershipTest,
ServiceItemStaffOwnershipTest, AppointmentSettingsListOwnershipTest.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -156,9 +156,10 @@ class ClinicServiceController extends BaseController
|
||||
|
||||
if (!empty($data['staff_uuid'])) {
|
||||
$staff = $this->staffRepo->findByUuid($data['staff_uuid']);
|
||||
if ($staff !== null) {
|
||||
$item->setStaff($staff);
|
||||
if ($staff === null || $staff->getEntityType() !== $entityType || $staff->getEntityId() !== $entityId) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'پرسنل انتخابشده متعلق به شما نیست', 422, 'staff_uuid');
|
||||
}
|
||||
$item->setStaff($staff);
|
||||
}
|
||||
|
||||
if (isset($data['insurance_covered'])) {
|
||||
@@ -193,7 +194,13 @@ class ClinicServiceController extends BaseController
|
||||
if (isset($data['price_rials'])) { $item->setPriceRials((int) $data['price_rials']); $priceChanged = true; }
|
||||
if (isset($data['active'])) { $item->setActive((bool) $data['active']); }
|
||||
if (array_key_exists('staff_uuid', $data)) {
|
||||
$staff = $data['staff_uuid'] ? $this->staffRepo->findByUuid($data['staff_uuid']) : null;
|
||||
$staff = null;
|
||||
if ($data['staff_uuid']) {
|
||||
$staff = $this->staffRepo->findByUuid($data['staff_uuid']);
|
||||
if ($staff === null || $staff->getEntityType() !== $entityType || $staff->getEntityId() !== $entityId) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'پرسنل انتخابشده متعلق به شما نیست', 422, 'staff_uuid');
|
||||
}
|
||||
}
|
||||
$item->setStaff($staff);
|
||||
}
|
||||
if (isset($data['insurance_covered'])) {
|
||||
|
||||
Reference in New Issue
Block a user