{"record":{"id":"d6a9e91e16d24d3a","repo":"passbolt/passbolt_api","slug":"an-administrator-user-cannot-be-suspended-via-scim","errorCode":null,"errorMessage":"An administrator user cannot be suspended via SCIM.","messagePattern":"An administrator user cannot be suspended via SCIM\\.","errorType":"http","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"plugins/PassboltEe/Scim/src/Utility/Resource/UserScimResource.php","lineNumber":711,"sourceCode":"    protected function assertAdminSuspendAllowed(array $userPatchData): void\n    {\n        // Only check when user is being disabled (disabled field is being set to a non-null value)\n        if (empty($userPatchData['disabled'])) {\n            return;\n        }\n\n        // If already disabled, no change — skip guard\n        if ($this->userEntity->disabled) {\n            return;\n        }\n\n        // Check if the config allows suspending administrators\n        if (Configure::read('passbolt.plugins.scim.security.allowSuspendAdministrators')) {\n            return;\n        }\n\n        if ($this->isUserAdmin()) {\n            throw new ForbiddenException(__('An administrator user cannot be suspended via SCIM.'));\n        }\n    }\n\n    /**\n     * Assert that the user being deleted is not an administrator.\n     *\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException If trying to delete an admin and the config flag is not set.\n     */\n    protected function assertAdminDeleteAllowed(): void\n    {\n        $allowed = Configure::read('passbolt.plugins.scim.security.allowDeleteAdministrators');\n        // Fallback on allowSuspendAdministrators configuration\n        if (!is_bool($allowed)) {\n            $allowed = Configure::read('passbolt.plugins.scim.security.allowSuspendAdministrators');\n        }\n\n        if ($allowed) {","sourceCodeStart":693,"sourceCodeEnd":729,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Scim/src/Utility/Resource/UserScimResource.php#L693-L729","documentation":"UserScimResource::assertAdminSuspendAllowed() forbids deactivating (suspending) a user holding the administrator role via SCIM, unless the config flag `passbolt.plugins.scim.security.allowSuspendAdministrators` is enabled. This protects the last-resort admin accounts from being disabled by an IdP synchronization. Throws 403 ForbiddenException.","triggerScenarios":"PATCH /scim/v2/Users/<id-of-admin> with {\"op\":\"replace\",\"path\":\"active\",\"value\":false} (or add/remove with active false) when the target user is an admin and the allowSuspendAdministrators config is false/unset.","commonSituations":"An IdP deactivates a leaving employee who also happened to be a passbolt admin; a bulk SCIM sync disables all users not present in the IdP, including admins; operators are unaware the opt-in config flag exists.","solutions":["Remove the admin role from the user first (passbolt UI/CLI) so they are a normal user, then suspend via SCIM.","If suspension of admins via SCIM is intended, set passbolt.plugins.scim.security.allowSuspendAdministrators to true in config.","Exclude administrator accounts from the IdP's SCIM sync scope.","Verify with `passbolt users` which users are admins before running bulk deactivations."],"exampleFix":"// before (config/passbolt.php)\n//'scim' => ['security' => ['allowSuspendAdministrators' => false]]\n// after (only if policy allows admins to be suspended by the IdP)\n'scim' => ['security' => ['allowSuspendAdministrators' => true]]","handlingStrategy":"try-catch","validationCode":"// before deactivating via SCIM\nconst user = await scim.getUser(id);\nconst roles = user.roles || (await passbolt.getUserRoles(id));\nif (roles.includes('admin')) throw new Error('target is an admin; SCIM suspend forbidden');","typeGuard":null,"tryCatchPattern":"try { await scim.patchUser(adminId, [{op:'replace',path:'active',value:false}]); } catch (e) { if (e.status === 403 && /administrator/.test(e.message)) { /* demote admin first or skip */ } else throw e; }","preventionTips":["Exclude admin accounts from IdP deactivation syncs","Check the user's role before sending active=false","Only enable allowSuspendAdministrators if policy explicitly permits it"],"tags":["scim","forbidden","admin","suspend"],"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"}