From 128dc774fbdeea83e3c23b5f1c957929663147d3 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sat, 16 Nov 2019 08:28:24 +0100 Subject: [PATCH] YubiKey multi server setup --- lam/HISTORY | 1 + lam/help/help.inc | 2 ++ lam/lib/2factor.inc | 28 +++++++++++++++++++++------- lam/lib/config.inc | 4 ++-- lam/templates/config/confmain.php | 20 ++++++++++++++------ 5 files changed, 40 insertions(+), 15 deletions(-) diff --git a/lam/HISTORY b/lam/HISTORY index ad6f591c..f7b14b47 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,6 +1,7 @@ December 2019 7.0 - Lamdaemon can be configured with directory prefix for homedirs - Account list filters match on substrings instead of whole value + - YubiKey: support to configure multiple verification servers - Fixed bugs: -> Missing CSS for Duo -> Editing of DNs with comma on Windows (210) diff --git a/lam/help/help.inc b/lam/help/help.inc index fd9b1f85..89f8b3ad 100644 --- a/lam/help/help.inc +++ b/lam/help/help.inc @@ -301,6 +301,8 @@ $helpArray = array ( "Text" => _('You can enable 2-factor authentication here (e.g. via mobile device).')), "515" => array ("Headline" => _('Base URL'), "Text" => _('URL of external 2-factor authentication service.')), + "515a" => array ("Headline" => _('Base URLs'), + "Text" => _('URLs of external 2-factor authentication service. Enter one per line.')), "516" => array ("Headline" => _('Disable certificate check'), "Text" => _('This will disable the check of the SSL certificates for the 2-factor authentication service. Not recommended for production usage.')), "517" => array ("Headline" => _('Label'), diff --git a/lam/lib/2factor.inc b/lam/lib/2factor.inc index 55267b31..dd4e2154 100644 --- a/lam/lib/2factor.inc +++ b/lam/lib/2factor.inc @@ -3,8 +3,8 @@ namespace LAM\LIB\TWO_FACTOR; use \selfServiceProfile; use \LAMConfig; use \htmlScript; -use \htmlInputField; use \htmlIframe; +use \LAMException; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) @@ -356,13 +356,22 @@ class YubicoProvider extends BaseProvider { if (!$serialMatched) { throw new \Exception(_('YubiKey id does not match allowed list of key ids.')); } - $url = $this->config->twoFactorAuthenticationURL; + $urls = $this->config->twoFactorAuthenticationURL; + shuffle($urls); $httpsverify = !$this->config->twoFactorAuthenticationInsecure; $clientId = $this->config->twoFactorAuthenticationClientId; $secretKey = $this->config->twoFactorAuthenticationSecretKey; - $auth = new \Auth_Yubico($clientId, $secretKey, $url, $httpsverify); - $auth->verify($twoFactorInput); - return true; + foreach ($urls as $url) { + try { + $auth = new \Auth_Yubico($clientId, $secretKey, $url, $httpsverify); + $auth->verify($twoFactorInput); + return true; + } + catch (LAMException $e) { + logNewMessage(LOG_DEBUG, 'Unable to verify 2FA: ' . $e->getMessage()); + } + } + return false; } } @@ -559,7 +568,12 @@ class TwoFactorProviderService { $tfConfig->isSelfService = false; $tfConfig->twoFactorAuthentication = $conf->getTwoFactorAuthentication(); $tfConfig->twoFactorAuthenticationInsecure = $conf->getTwoFactorAuthenticationInsecure(); - $tfConfig->twoFactorAuthenticationURL = $conf->getTwoFactorAuthenticationURL(); + if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) { + $tfConfig->twoFactorAuthenticationURL = explode("\r\n", $conf->getTwoFactorAuthenticationURL()); + } + else { + $tfConfig->twoFactorAuthenticationURL = $conf->getTwoFactorAuthenticationURL(); + } $tfConfig->twoFactorAuthenticationClientId = $conf->getTwoFactorAuthenticationClientId(); $tfConfig->twoFactorAuthenticationSecretKey = $conf->getTwoFactorAuthenticationSecretKey(); if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) { @@ -598,7 +612,7 @@ class TwoFactorConfiguration { public $twoFactorAuthentication = null; /** - * @var service URL + * @var string|array service URL(s) */ public $twoFactorAuthenticationURL = null; diff --git a/lam/lib/config.inc b/lam/lib/config.inc index 89cdf07f..076b006a 100644 --- a/lam/lib/config.inc +++ b/lam/lib/config.inc @@ -2368,7 +2368,7 @@ class LAMConfig { * @return string authentication URL */ public function getTwoFactorAuthenticationURL() { - return $this->twoFactorAuthenticationURL; + return implode("\r\n", explode(LAMConfig::LINE_SEPARATOR, $this->twoFactorAuthenticationURL)); } /** @@ -2377,7 +2377,7 @@ class LAMConfig { * @param string $twoFactorAuthenticationURL authentication URL */ public function setTwoFactorAuthenticationURL($twoFactorAuthenticationURL) { - $this->twoFactorAuthenticationURL = $twoFactorAuthenticationURL; + $this->twoFactorAuthenticationURL = implode(LAMConfig::LINE_SEPARATOR, explode("\r\n", $twoFactorAuthenticationURL)); } /** diff --git a/lam/templates/config/confmain.php b/lam/templates/config/confmain.php index 76dc4480..6a506aeb 100644 --- a/lam/templates/config/confmain.php +++ b/lam/templates/config/confmain.php @@ -470,16 +470,16 @@ if (extension_loaded('curl')) { $twoFactorSelect = new htmlResponsiveSelect('twoFactor', $twoFactorOptions, array($conf->getTwoFactorAuthentication()), _('Provider'), '514'); $twoFactorSelect->setHasDescriptiveElements(true); $twoFactorSelect->setTableRowsToHide(array( - TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', + TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'), - TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorClientId', 'twoFactorSecretKey'), - TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorAttribute'), - TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorOptional', 'twoFactorInsecure'), + TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURLs', 'twoFactorClientId', 'twoFactorSecretKey'), + TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorAttribute'), + TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURLs', 'twoFactorOptional', 'twoFactorInsecure'), )); $twoFactorSelect->setTableRowsToShow(array( TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorOptional', 'twoFactorCaption', 'twoFactorAttribute'), - TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', + TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'), TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURL', 'twoFactorLabel', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'), @@ -490,6 +490,9 @@ if (extension_loaded('curl')) { $twoFactorUrl = new htmlResponsiveInputField(_("Base URL"), 'twoFactorURL', $conf->getTwoFactorAuthenticationURL(), '515'); $twoFactorUrl->setRequired(true); $row->add($twoFactorUrl, 12); + $twoFactorUrl = new htmlResponsiveInputTextarea('twoFactorURLs', $conf->getTwoFactorAuthenticationURL(), '80', '4', _("Base URLs"), '515a'); + $twoFactorUrl->setRequired(true); + $row->add($twoFactorUrl, 12); $twoFactorClientId = new htmlResponsiveInputField(_("Client id"), 'twoFactorClientId', $conf->getTwoFactorAuthenticationClientId(), '524'); $row->add($twoFactorClientId, 12); $twoFactorSecretKey = new htmlResponsiveInputField(_("Secret key"), 'twoFactorSecretKey', $conf->getTwoFactorAuthenticationSecretKey(), '525'); @@ -725,7 +728,12 @@ function checkInput() { // 2-factor if (extension_loaded('curl')) { $conf->setTwoFactorAuthentication($_POST['twoFactor']); - $conf->setTwoFactorAuthenticationURL($_POST['twoFactorURL']); + if ($_POST['twoFactor'] === TwoFactorProviderService::TWO_FACTOR_YUBICO) { + $conf->setTwoFactorAuthenticationURL($_POST['twoFactorURLs']); + } + else { + $conf->setTwoFactorAuthenticationURL($_POST['twoFactorURL']); + } $conf->setTwoFactorAuthenticationClientId($_POST['twoFactorClientId']); $conf->setTwoFactorAuthenticationSecretKey($_POST['twoFactorSecretKey']); $conf->setTwoFactorAuthenticationInsecure(isset($_POST['twoFactorInsecure']) && ($_POST['twoFactorInsecure'] == 'on'));