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.
This commit is contained in:
DevSoftTech Server 2026-07-28 03:47:06 +05:30
parent b26920c6f4
commit a5219bca2d
5 changed files with 101 additions and 16 deletions

View File

@ -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,

View File

@ -23,6 +23,7 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
private string $hfrId;
private string $bridgeHospitalId;
private int $timeoutSec;
private bool $sslVerify = true;
/** @var array<int, string> */
private array $tokenCandidates = [];
/** @var array<string, string> */
@ -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 = [

View File

@ -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'] ?? ''),
];
}

View File

@ -51,6 +51,27 @@
</div>
</div>
<!-- SSL Verification -->
<div class="mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="abdm_ssl_verify"
<?= (! isset($ssl_verify) || $ssl_verify) ? 'checked' : '' ?>>
<label class="form-check-label fw-semibold" for="abdm_ssl_verify">Verify SSL Certificate</label>
</div>
<div class="form-text">
Keep this <strong>ON</strong> (default). Only turn it <strong>OFF</strong> 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.
</div>
<div class="alert alert-warning py-1 px-2 mt-1 d-none" id="abdm_ssl_verify_warning" style="font-size:12px">
<i class="bi bi-exclamation-triangle me-1"></i>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.
</div>
</div>
<!-- API Key -->
<div class="mb-3">
<label class="form-label fw-semibold">API Key (Bearer Token)</label>
@ -90,6 +111,13 @@
<?= esc($gateway_url ?? 'https://abdm-bridge.e-atria.in/api') ?>
</a>
</span>
<span><strong>SSL Verify:</strong>
<?php if (! isset($ssl_verify) || $ssl_verify) : ?>
<span class="badge bg-success">ON</span>
<?php else : ?>
<span class="badge bg-warning text-dark">OFF</span>
<?php endif; ?>
</span>
</div>
</div>
@ -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');

5
check_ssl_setting.php Normal file
View File

@ -0,0 +1,5 @@
<?php
$db = new mysqli('localhost', 'root', '', 'hms_data_ci4');
$res = $db->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();