From 128dc774fbdeea83e3c23b5f1c957929663147d3 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sat, 16 Nov 2019 08:28:24 +0100 Subject: [PATCH 1/3] 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')); From 61025edd680da9685729527da8e5e064699f551d Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sun, 17 Nov 2019 17:44:30 +0100 Subject: [PATCH 2/3] YubiKey multiple servers --- lam/lib/2factor.inc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lam/lib/2factor.inc b/lam/lib/2factor.inc index dd4e2154..074c99e6 100644 --- a/lam/lib/2factor.inc +++ b/lam/lib/2factor.inc @@ -534,7 +534,12 @@ class TwoFactorProviderService { $tfConfig->isSelfService = true; $tfConfig->twoFactorAuthentication = $profile->twoFactorAuthentication; $tfConfig->twoFactorAuthenticationInsecure = $profile->twoFactorAuthenticationInsecure; - $tfConfig->twoFactorAuthenticationURL = $profile->twoFactorAuthenticationURL; + if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) { + $tfConfig->twoFactorAuthenticationURL = explode("\r\n", $profile->twoFactorAuthenticationURL); + } + else { + $tfConfig->twoFactorAuthenticationURL = $profile->twoFactorAuthenticationURL; + } $tfConfig->twoFactorAuthenticationClientId = $profile->twoFactorAuthenticationClientId; $tfConfig->twoFactorAuthenticationSecretKey = $profile->twoFactorAuthenticationSecretKey; if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) { From 3719e5510506fcfdabfe54a8d63de896c21881fb Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sun, 17 Nov 2019 17:50:30 +0100 Subject: [PATCH 3/3] docs update --- .../manual-sources/chapter-configuration.xml | 21 ++++++++++++------- .../manual-sources/chapter-selfService.xml | 21 ++++++++++++------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/lam/docs/manual-sources/chapter-configuration.xml b/lam/docs/manual-sources/chapter-configuration.xml index d0ccf6ce..8b69b1e4 100644 --- a/lam/docs/manual-sources/chapter-configuration.xml +++ b/lam/docs/manual-sources/chapter-configuration.xml @@ -659,7 +659,7 @@ Configuration options: - privacyIDEA: + privacyIDEA @@ -686,16 +686,21 @@ - YubiKey: + YubiKey - Base URL: please enter the URL of your YubiKey verfication - server. For YubiKey cloud this is - "https://api.yubico.com/wsapi/2.0/verify". If you run a custom - verification API such as yubiserver then enter its URL (e.g. + Base URLs: please enter the URL(s) of your YubiKey + verification server(s). If you run a custom verification API such + as yubiserver then enter its URL (e.g. http://www.example.com:8000/wsapi/2.0/verify). The URL needs to - end with "/wsapi/2.0/verify". + end with "/wsapi/2.0/verify". For YubiKey cloud these are + "https://api.yubico.com/wsapi/2.0/verify", + "https://api2.yubico.com/wsapi/2.0/verify", + "https://api3.yubico.com/wsapi/2.0/verify", + "https://api4.yubico.com/wsapi/2.0/verify" and + "https://api5.yubico.com/wsapi/2.0/verify". Enter one URL per + line. @@ -722,7 +727,7 @@ - Duo: + Duo This requires to register a new "Web SDK" application in your Duo admin panel. diff --git a/lam/docs/manual-sources/chapter-selfService.xml b/lam/docs/manual-sources/chapter-selfService.xml index bc5e1126..eebead07 100644 --- a/lam/docs/manual-sources/chapter-selfService.xml +++ b/lam/docs/manual-sources/chapter-selfService.xml @@ -331,7 +331,7 @@ - privacyIDEA: + privacyIDEA @@ -358,16 +358,21 @@ - YubiKey: + YubiKey - Base URL: please enter the URL of your YubiKey verfication - server. For YubiKey cloud this is - "https://api.yubico.com/wsapi/2.0/verify". If you run a custom - verification API such as yubiserver then enter its URL (e.g. + Base URLs: please enter the URL(s) of your YubiKey + verification server(s). If you run a custom verification API such + as yubiserver then enter its URL (e.g. http://www.example.com:8000/wsapi/2.0/verify). The URL needs to - end with "/wsapi/2.0/verify". + end with "/wsapi/2.0/verify". For YubiKey cloud these are + "https://api.yubico.com/wsapi/2.0/verify", + "https://api2.yubico.com/wsapi/2.0/verify", + "https://api3.yubico.com/wsapi/2.0/verify", + "https://api4.yubico.com/wsapi/2.0/verify" and + "https://api5.yubico.com/wsapi/2.0/verify". Enter one URL per + line. @@ -394,7 +399,7 @@ - Duo: + Duo This requires to register a new "Web SDK" application in your Duo admin panel.