{"record":{"id":"5b05cac6f2756463","repo":"passbolt/passbolt_api","slug":"could-not-validate-duo-configuration","errorCode":null,"errorMessage":"Could not validate Duo configuration","messagePattern":"Could not validate Duo configuration","errorType":"validation","errorClass":"CustomValidationException","httpStatus":null,"severity":"error","filePath":"plugins/PassboltCe/MultiFactorAuthentication/src/Service/MfaOrgSettings/MfaOrgSettingsDuoService.php","lineNumber":141,"sourceCode":"            $errors[MfaSettings::PROVIDER_DUO][MfaOrgSettings::DUO_CLIENT_ID]['notEmpty'] = $msg;\n        }\n\n        if ($performHealthcheck && empty($errors[MfaSettings::PROVIDER_DUO])) {\n            try {\n                $duoClient = $client ?? (new MfaDuoGetSdkClientService())->getOrFail(\n                    $this,\n                    AuthenticationToken::TYPE_MFA_SETUP\n                );\n                $duoClient->healthCheck();\n            } catch (DuoException | InternalErrorException $e) {\n                $msg = __('Cannot verify Duo settings.') . ' ' . $e->getMessage();\n                $errors[MfaSettings::PROVIDER_DUO][MfaOrgSettings::DUO_HEALTH_CHECK] = $msg;\n            }\n        }\n\n        if (count($errors) !== 0) {\n            $msg = __('Could not validate Duo configuration');\n            throw new CustomValidationException($msg, $errors);\n        }\n    }\n\n    /**\n     * Get Duo provider setting.\n     *\n     * @param string $settingKey organization settings key\n     * @param string $errorMessage error message if organization settings key is not found\n     * @return string\n     * @throws \\Cake\\Datasource\\Exception\\RecordNotFoundException if setting is missing\n     */\n    private function getSetting(string $settingKey, string $errorMessage): string\n    {\n        if (!isset($this->settings[MfaSettings::PROVIDER_DUO][$settingKey])) {\n            throw new RecordNotFoundException($errorMessage);\n        }\n\n        return $this->settings[MfaSettings::PROVIDER_DUO][$settingKey];","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/MultiFactorAuthentication/src/Service/MfaOrgSettings/MfaOrgSettingsDuoService.php#L123-L159","documentation":"Thrown by MfaOrgSettingsDuoService::validateDuoSettings() when any Duo setting fails validation (missing/empty fields or failed Duo health check). It raises a CustomValidationException carrying per-field errors under the 'duo' provider key.","triggerScenarios":"POST/PUT /mfa/policies/duo.json with missing client id, client secret, api hostname, empty values, or when the Duo health check API call fails.","commonSituations":"Typo in the Duo integration key/secret; pasting values with whitespace or quotes; wrong api hostname format (missing sso-*.sso.duosecurity.com pattern); Duo application deleted or disabled on the Duo side.","solutions":["Read $errors in the CustomValidationException response for the exact failing field.","Ensure client id (integration key), client secret, and api hostname are all non-empty and correctly formatted.","Verify credentials against the Duo Admin Panel application protecting passbolt.","Confirm the server can reach Duo's API for the health check (network/firewall).","Trim whitespace/quotes from pasted secrets."],"exampleFix":"// before: incomplete payload\n{\"duo\": {\"clientId\": \"DI...\"}}\n// after: complete settings\n{\"duo\": {\"clientId\": \"DI...\", \"clientSecret\": \"...\", \"apiHostname\": \"sso-abc.sso.duosecurity.com\"}}","handlingStrategy":"validation","validationCode":"$duo = $payload['duo'] ?? [];\n$required = ['clientId', 'clientSecret', 'apiHostname'];\nforeach ($required as $field) {\n    if (empty(trim($duo[$field] ?? ''))) {\n        throw new CustomValidationException(\"Missing duo field: $field\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    $service->validateDuoSettings($data);\n} catch (CustomValidationException $e) {\n    return $this->response->withStatus(400)->withErrors($e->getErrors());\n}","preventionTips":["Trim pasted credentials of whitespace/quotes before saving.","Validate hostname format against sso-*.sso.duosecurity.com.","Test Duo credentials with the health check after any change."],"tags":["mfa","duo","validation","configuration"],"backgroundTag":"schema-validation-failed","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"}