{"record":{"id":"9c866d2bdb89168f","repo":"passbolt/passbolt_api","slug":"only-admin-can-create-or-update-organization-settings","errorCode":null,"errorMessage":"Only admin can create or update organization settings.","messagePattern":"Only admin can create or update organization settings\\.","errorType":"http","errorClass":"Cake\\Http\\Exception\\UnauthorizedException","httpStatus":401,"severity":"error","filePath":"src/Model/Table/OrganizationSettingsTable.php","lineNumber":169,"sourceCode":"            return null;\n        }\n    }\n\n    /**\n     * Create (or update) an organization setting\n     *\n     * @param string $property The property name\n     * @param array|string $value The property value\n     * @param \\App\\Utility\\UserAccessControl $control user access control object\n     * @return \\App\\Model\\Entity\\OrganizationSetting\n     * @throws \\Cake\\Http\\Exception\\UnauthorizedException When user role is not admin.\n     * @throws \\App\\Error\\Exception\\CustomValidationException When there are validation errors.\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException|\\Exception When unable to save the entity.\n     */\n    public function createOrUpdateSetting(string $property, string|array $value, UserAccessControl $control): OrganizationSetting // phpcs:ignore\n    {\n        if (!$control->isAdmin()) {\n            throw new UnauthorizedException(__('Only admin can create or update organization settings.'));\n        }\n\n        $settingId = $this->_getSettingPropertyId($property);\n        $settingFinder = ['property_id' => $settingId];\n        $settingValues = ['value' => $value, 'property' => $property];\n        $settingItem = $this->find()\n            ->where($settingFinder)\n            ->first();\n        if ($settingItem) {\n            $settingValues['modified_by'] = $control->getId();\n            /** @var \\App\\Model\\Entity\\OrganizationSetting $settingItem */\n            $settingItem = $this->patchEntity($settingItem, $settingValues);\n        } else {\n            $settingValues['created_by'] = $settingValues['modified_by'] = $control->getId();\n            $settingItem = $this->newEntity(array_merge($settingFinder, $settingValues));\n        }\n        if ($settingItem->getErrors()) {\n            throw new CustomValidationException(__('This is not a valid setting.'), $settingItem->getErrors(), $this);","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Model/Table/OrganizationSettingsTable.php#L151-L187","documentation":"OrganizationSettingsTable::createOrUpdateSetting() throws UnauthorizedException when the UserAccessControl object does not represent an administrator. Only admins may create or update organization settings (e.g. SMTP, MFA policy). The check happens before any database work, so the request is rejected with 403/401 before any write.","triggerScenarios":"POST/PUT to organization settings endpoints with a logged-in user whose role is not admin — e.g. a 'user' role account calling PUT /org-settings.json, or a service calling createOrUpdateSetting() with a UserAccessControl built from a non-admin user or a missing/invalid role.","commonSituations":"Running CLI/automation tasks without impersonating an admin; provisioning scripts using a normal user's credentials; forgetting to pass role context so $control->isAdmin() is false; testing with a non-admin account.","solutions":["Log in with, or impersonate, an administrator account (role id/name 'admin') when calling the settings API.","For CLI tasks, ensure the UserAccessControl is built with admin privileges (e.g. root/admin user context).","Fix the role assignment if the user should be an admin (update users.role_id to the admin role).","If RBAC plugin customizes role permissions, ensure it still allows admins to write OrgSettings."],"exampleFix":"// before\n$control = new UserAccessControl($user);\n$this->OrganizationSettings->createOrUpdateSetting('smtp', $value, $control);\n// after\nif ($control->isAdmin()) {\n    $this->OrganizationSettings->createOrUpdateSetting('smtp', $value, $control);\n}","handlingStrategy":"validation","validationCode":"if (!$control->isAdmin()) { throw new UnauthorizedException('Admin role required to modify organization settings.'); }","typeGuard":"function isAdminContext(App\\Utility\\UserAccessControl $c): bool { return $c->isAdmin(); }","tryCatchPattern":"try { $this->OrganizationSettings->createOrUpdateSetting($property, $value, $control); } catch (\\Cake\\Http\\Exception\\UnauthorizedException $e) { // return 403 to the client }","preventionTips":["Check UserAccessControl::isAdmin() before calling settings APIs.","Use admin/root context for CLI and automation tasks.","Keep role fixtures correct in tests.","Gate settings UI/routes on admin role."],"tags":["authorization","permissions","organization-settings"],"backgroundTag":"permission-denied","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}