VPN: OpenVPN - Support "password first" for static-challenges, closes https://github.com/opnsense/core/pull/8058

This commit is contained in:
Ad Schellevis 2025-02-12 21:12:14 +01:00
parent e248e4517f
commit cc16ba7b33
2 changed files with 28 additions and 12 deletions

View File

@ -134,6 +134,14 @@ trait TOTP
return false;
}
/**
* @return bool token after password
*/
public function isPasswordFirst()
{
return $this->passwordFirst;
}
/**
* authenticate user against otp key stored in local database
* @param string $username username to authenticate

View File

@ -80,18 +80,7 @@ function do_auth($common_name, $serverid, $method, $auth_file)
if (empty($username) || empty($password)) {
return "username or password missing ({$method} - {$auth_file})";
}
if (strpos($password, 'SCRV1:') === 0) {
// static-challenge https://github.com/OpenVPN/openvpn/blob/v2.4.7/doc/management-notes.txt#L1146
// validate and concat password into our default pin+password
$tmp = explode(':', $password);
if (count($tmp) == 3) {
$pass = base64_decode($tmp[1]);
$pin = base64_decode($tmp[2]);
if ($pass !== false && $pin !== false) {
$password = $pin . $pass;
}
}
}
$a_server = $serverid !== null ? (new OPNsense\OpenVPN\OpenVPN())->getInstanceById($serverid, 'server') : null;
if ($a_server == null) {
return "OpenVPN '$serverid' was not found. Denying authentication for user {$username}";
@ -121,6 +110,25 @@ function do_auth($common_name, $serverid, $method, $auth_file)
foreach (explode(',', $a_server['authmode']) as $authName) {
$authenticator = $authFactory->get($authName);
if ($authenticator) {
if (strpos($password, 'SCRV1:') === 0) {
// static-challenge https://github.com/OpenVPN/openvpn/blob/v2.4.7/doc/management-notes.txt#L1146
// validate and concat password into our default pin+password
$tmp = explode(':', $password);
if (count($tmp) == 3) {
$pass = base64_decode($tmp[1]);
$pin = base64_decode($tmp[2]);
if ($pass !== false && $pin !== false) {
if (isset(class_uses($authenticator)[OPNsense\Auth\TOTP::class]) &&
$authenticator->isPasswordFirst()
) {
$password = $pass . $pin;
} else {
$password = $pin . $pass;
}
}
}
}
if ($authenticator->authenticate($username, $password)) {
// fetch or create client specific override
$common_name = empty($a_server['cso_login_matching']) ? $common_name : $username;