From a5219bca2d29f726111c161ca09db58b7690169f Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Tue, 28 Jul 2026 03:47:06 +0530 Subject: [PATCH] ABDM Gateway settings: add admin UI toggle for SSL certificate verification Adds a 'Verify SSL Certificate' switch on Admin -> ABDM Gateway page, persisted as hospital_setting.ABDM_BRIDGE_SSL_VERIFY (default ON/secure). Wired into M3HiuGatewayClient, EAtriaBridgeConnector, and the settings page's own Test Connection check. Per-machine ABDM_BRIDGE_SSL_VERIFY env var still overrides this DB setting for deployments needing a quick local-only workaround. Verification stays on by default everywhere; disabling it is an explicit, visible opt-in with an on-page warning. --- .../Setting/AbdmGatewaySettings.php | 23 +++++++++++- app/Libraries/Abdm/EAtriaBridgeConnector.php | 22 +++++++++-- app/Libraries/Abdm/M3HiuGatewayClient.php | 30 ++++++++++----- .../Setting/Admin/abdm_gateway_settings.php | 37 ++++++++++++++++++- check_ssl_setting.php | 5 +++ 5 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 check_ssl_setting.php diff --git a/app/Controllers/Setting/AbdmGatewaySettings.php b/app/Controllers/Setting/AbdmGatewaySettings.php index 39ac5ee..045bd24 100644 --- a/app/Controllers/Setting/AbdmGatewaySettings.php +++ b/app/Controllers/Setting/AbdmGatewaySettings.php @@ -20,6 +20,8 @@ class AbdmGatewaySettings extends BaseController $hmsName = $this->readSettingValue('ABDM_HMS_NAME'); $gwUrl = $this->readSettingValue('EATRIA_BRIDGE_URL') ?: 'https://abdm-bridge.e-atria.in/api'; $bridgeHospitalId = $this->readSettingValue('ABDM_BRIDGE_HOSPITAL_ID'); + $sslVerifyRaw = strtolower(trim($this->readSettingValue('ABDM_BRIDGE_SSL_VERIFY'))); + $sslVerify = ! in_array($sslVerifyRaw, ['0', 'false', 'no', 'off'], true); return view('Setting/Admin/abdm_gateway_settings', [ 'gateway_url' => $gwUrl, @@ -30,6 +32,7 @@ class AbdmGatewaySettings extends BaseController 'token_exists' => $token !== '', 'connector' => $this->readSettingValue('ABDM_CONNECTOR') ?: 'eatria_bridge', 'abdm_sync_provider' => $this->readSettingValue('ABDM_SYNC_PROVIDER') ?: 'eatria', + 'ssl_verify' => $sslVerify, ]); } @@ -51,6 +54,8 @@ class AbdmGatewaySettings extends BaseController $token = $this->sanitizeBearerToken((string) $this->request->getPost('api_token')); $hfrId = trim((string) $this->request->getPost('hfr_id')); $hmsName = trim((string) $this->request->getPost('hms_name')); + $sslVerifyPosted = $this->request->getPost('ssl_verify'); + $sslVerify = $sslVerifyPosted === null ? true : (bool) (int) $sslVerifyPosted; // Validate gateway URL format if ($gwUrl !== '' && ! filter_var($gwUrl, FILTER_VALIDATE_URL)) { @@ -87,6 +92,7 @@ class AbdmGatewaySettings extends BaseController // Always set connector to eatria_bridge when saving from this page $this->upsertSettingValue('ABDM_CONNECTOR', 'eatria_bridge'); $this->upsertSettingValue('ABDM_SYNC_PROVIDER', 'eatria'); + $this->upsertSettingValue('ABDM_BRIDGE_SSL_VERIFY', $sslVerify ? '1' : '0'); if ($saved === 0) { return $this->response->setJSON([ @@ -104,6 +110,7 @@ class AbdmGatewaySettings extends BaseController 'error_text' => 'ABDM Gateway settings saved.', 'token_exists' => $storedToken !== '', 'token_masked' => $this->maskKey($storedToken), + 'ssl_verify' => $sslVerify, 'csrfName' => csrf_token(), 'csrfHash' => csrf_hash(), ]); @@ -139,6 +146,16 @@ class AbdmGatewaySettings extends BaseController $gwUrl = rtrim($gwUrl, '/'); + // ssl_verify: prefer explicitly posted value (from the unsaved form state), + // else fall back to the stored setting. Defaults to secure (verify ON). + $sslVerifyPosted = $this->request->getPost('ssl_verify'); + if ($sslVerifyPosted !== null) { + $sslVerify = (bool) (int) $sslVerifyPosted; + } else { + $sslVerifyRaw = strtolower(trim($this->readSettingValue('ABDM_BRIDGE_SSL_VERIFY'))); + $sslVerify = ! in_array($sslVerifyRaw, ['0', 'false', 'no', 'off'], true); + } + // ── Step 1: Health check — include Bearer if available (gateway may require auth even on /health) ── $healthUrl = $gwUrl . '/v3/health' . ($hfrId !== '' ? '?hfr_id=' . urlencode($hfrId) : ''); $healthHeaders = ['Accept: application/json']; @@ -150,7 +167,8 @@ class AbdmGatewaySettings extends BaseController CURLOPT_URL => $healthUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, - CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_SSL_VERIFYPEER => $sslVerify, + CURLOPT_SSL_VERIFYHOST => $sslVerify ? 2 : 0, CURLOPT_HTTPHEADER => $healthHeaders, ]); $rawHealth = (string) curl_exec($ch); @@ -222,7 +240,8 @@ class AbdmGatewaySettings extends BaseController CURLOPT_URL => $statusUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, - CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_SSL_VERIFYPEER => $sslVerify, + CURLOPT_SSL_VERIFYHOST => $sslVerify ? 2 : 0, CURLOPT_HTTPHEADER => [ 'Accept: application/json', 'Authorization: Bearer ' . $token, diff --git a/app/Libraries/Abdm/EAtriaBridgeConnector.php b/app/Libraries/Abdm/EAtriaBridgeConnector.php index 483f352..7031200 100644 --- a/app/Libraries/Abdm/EAtriaBridgeConnector.php +++ b/app/Libraries/Abdm/EAtriaBridgeConnector.php @@ -23,6 +23,7 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface private string $hfrId; private string $bridgeHospitalId; private int $timeoutSec; + private bool $sslVerify = true; /** @var array */ private array $tokenCandidates = []; /** @var array */ @@ -76,6 +77,7 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface 'ABDM_HOSPITAL_HFR_ID', 'ABDM_BRIDGE_HOSPITAL_ID', 'EATRIA_BRIDGE_HOSPITAL_ID', + 'ABDM_BRIDGE_SSL_VERIFY', ]); // Ensure deterministic override when duplicate setting rows exist. @@ -147,6 +149,15 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface if ($dbBridgeHospitalId !== '') { $this->bridgeHospitalId = $dbBridgeHospitalId; } + + // SSL verification stays ON by default (secure). Admin → ABDM Gateway + // page can opt out per-deployment for servers with a stale local CA + // bundle (cURL error 60); an env override on that specific machine + // takes precedence over the DB setting. + $dbSslVerifyRaw = strtolower(trim((string) ($dbSettings['ABDM_BRIDGE_SSL_VERIFY'] ?? ''))); + if ($dbSslVerifyRaw !== '') { + $this->sslVerify = ! in_array($dbSslVerifyRaw, ['0', 'false', 'no', 'off'], true); + } } catch (\Throwable $e) { log_message('warning', '[EAtriaBridge] refreshRuntimeSettingsFromDb failed: ' . $e->getMessage()); } @@ -308,10 +319,13 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface // SSL verification stays ON by default. Some local WAMP/XAMPP // installs ship a stale bundled cacert.pem, causing cURL error 60 // on outbound HTTPS calls. Fix that by updating curl.cainfo in - // php.ini on the affected machine; only as a last resort can a - // specific deployment opt out via ABDM_BRIDGE_SSL_VERIFY=false. - $sslVerifyRaw = strtolower(trim((string) (getenv('ABDM_BRIDGE_SSL_VERIFY') ?: ''))); - $sslVerify = ! in_array($sslVerifyRaw, ['0', 'false', 'no', 'off'], true); + // php.ini on the affected machine, or opt out for this specific + // deployment via Admin → ABDM Gateway (or ABDM_BRIDGE_SSL_VERIFY=false + // in that machine's .env, which takes precedence). + $sslVerifyEnvRaw = strtolower(trim((string) (getenv('ABDM_BRIDGE_SSL_VERIFY') ?: ''))); + $sslVerify = $sslVerifyEnvRaw !== '' + ? ! in_array($sslVerifyEnvRaw, ['0', 'false', 'no', 'off'], true) + : $this->sslVerify; $ch = curl_init(); $curlOptions = [ diff --git a/app/Libraries/Abdm/M3HiuGatewayClient.php b/app/Libraries/Abdm/M3HiuGatewayClient.php index 826dfe3..0ed98e9 100644 --- a/app/Libraries/Abdm/M3HiuGatewayClient.php +++ b/app/Libraries/Abdm/M3HiuGatewayClient.php @@ -19,16 +19,26 @@ class M3HiuGatewayClient * WAMP/XAMPP/Laragon installs ship a stale bundled cacert.pem which makes * outbound HTTPS calls fail with cURL error 60 (SSL certificate problem). * Rather than disabling verification for everyone, allow an explicit, - * per-deployment opt-out via env for that specific broken environment: - * ABDM_BRIDGE_SSL_VERIFY=false - * The correct long-term fix on the affected machine is to update PHP's - * CA bundle (curl.cainfo in php.ini), not to disable verification. + * per-deployment opt-out configured in Admin → ABDM Gateway + * (hospital_setting.ABDM_BRIDGE_SSL_VERIFY), or via env for that specific + * machine (ABDM_BRIDGE_SSL_VERIFY=false, takes precedence over the DB + * setting). The correct long-term fix on the affected machine is to + * update PHP's CA bundle (curl.cainfo in php.ini), not to disable + * verification. */ - private function sslVerifyEnabled(): bool + private function sslVerifyEnabled(string $dbSetting = ''): bool { - $raw = strtolower(trim((string) (getenv('ABDM_BRIDGE_SSL_VERIFY') ?: ''))); + $envRaw = strtolower(trim((string) (getenv('ABDM_BRIDGE_SSL_VERIFY') ?: ''))); + if ($envRaw !== '') { + return ! in_array($envRaw, ['0', 'false', 'no', 'off'], true); + } - return ! in_array($raw, ['0', 'false', 'no', 'off'], true); + $dbRaw = strtolower(trim($dbSetting)); + if ($dbRaw !== '') { + return ! in_array($dbRaw, ['0', 'false', 'no', 'off'], true); + } + + return true; } private function sanitizeBearerToken(string $token): string @@ -105,7 +115,7 @@ class M3HiuGatewayClient $headers[] = 'X-Hospital-Id: ' . $hospitalId; } - $sslVerify = $this->sslVerifyEnabled(); + $sslVerify = $this->sslVerifyEnabled((string) ($settings['ssl_verify'] ?? '')); $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, @@ -285,7 +295,7 @@ class M3HiuGatewayClient $url .= '?' . http_build_query($cleanQuery); } - $sslVerify = $this->sslVerifyEnabled(); + $sslVerify = $this->sslVerifyEnabled((string) ($settings['ssl_verify'] ?? '')); $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, @@ -408,6 +418,7 @@ class M3HiuGatewayClient 'ABDM_BRIDGE_HOSPITAL_ID', 'EATRIA_BRIDGE_HOSPITAL_ID', 'EATRIA_BRIDGE_URL', + 'ABDM_BRIDGE_SSL_VERIFY', ]); if ($orderCol !== null) { $rowsBuilder->orderBy($orderCol, 'DESC'); @@ -452,6 +463,7 @@ class M3HiuGatewayClient 'hfr_id' => $hfrId, 'hospital_id' => $hospitalId, 'base_url' => $baseUrl, + 'ssl_verify' => (string) ($kv['ABDM_BRIDGE_SSL_VERIFY'] ?? ''), ]; } diff --git a/app/Views/Setting/Admin/abdm_gateway_settings.php b/app/Views/Setting/Admin/abdm_gateway_settings.php index 17af7d1..4c14c1d 100644 --- a/app/Views/Setting/Admin/abdm_gateway_settings.php +++ b/app/Views/Setting/Admin/abdm_gateway_settings.php @@ -51,6 +51,27 @@ + +
+
+ > + +
+
+ Keep this ON (default). Only turn it OFF if this server's local PHP + has an outdated CA certificate bundle causing "SSL certificate problem" (cURL error 60) errors when + calling the gateway — this is a local server issue, not a gateway issue. Disabling verification + removes protection against man-in-the-middle attacks, so use it only as a temporary workaround on a + trusted network while the server's CA bundle is updated. +
+
+ SSL verification is OFF. Health data will still be + encrypted in transit, but the gateway's certificate identity won't be checked. Turn this back on once + the server's CA bundle is fixed. +
+
+
@@ -90,6 +111,13 @@ + SSL Verify: + + ON + + OFF + +
@@ -180,10 +208,17 @@ gateway_url: ($('#abdm_gateway_url').val() || '').trim(), api_token: ($('#abdm_api_token').val() || '').trim(), hfr_id: ($('#abdm_hfr_id').val() || '').trim(), - hms_name: ($('#abdm_hms_name').val() || '').trim() + hms_name: ($('#abdm_hms_name').val() || '').trim(), + ssl_verify: $('#abdm_ssl_verify').is(':checked') ? 1 : 0 }; } + function updateSslWarning() { + $('#abdm_ssl_verify_warning').toggleClass('d-none', $('#abdm_ssl_verify').is(':checked')); + } + updateSslWarning(); + $('#abdm_ssl_verify').on('change', updateSslWarning); + // Toggle show/hide API key $('#btn_toggle_abdm_token').on('click', function () { var inp = document.getElementById('abdm_api_token'); diff --git a/check_ssl_setting.php b/check_ssl_setting.php new file mode 100644 index 0000000..cbd5d12 --- /dev/null +++ b/check_ssl_setting.php @@ -0,0 +1,5 @@ +query("SELECT s_name, s_value FROM hospital_setting WHERE s_name = 'ABDM_BRIDGE_SSL_VERIFY'"); +while ($row = $res->fetch_assoc()) { print_r($row); } +$db->close();