diff --git a/lam/HISTORY b/lam/HISTORY index bd9b08dd..b770a043 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,5 +1,6 @@ September 2019 6.9 - Group account types can show member+owner count in list view + - 2-factor authentication: user name attribute for privacyIDEA can be specified - LAM Pro: -> New self service settings for login and main page footer diff --git a/lam/docs/manual-sources/chapter-configuration.xml b/lam/docs/manual-sources/chapter-configuration.xml index 974cb3fb..5a7c9c25 100644 --- a/lam/docs/manual-sources/chapter-configuration.xml +++ b/lam/docs/manual-sources/chapter-configuration.xml @@ -636,6 +636,11 @@ Base URL: please enter the URL of your privacyIDEA instance + + + User name attribute: please enter the LDAP attribute name + that contains the user ID (e.g. "uid") + YubiKey: diff --git a/lam/docs/manual-sources/chapter-selfService.xml b/lam/docs/manual-sources/chapter-selfService.xml index 240ba73d..cab1f47a 100644 --- a/lam/docs/manual-sources/chapter-selfService.xml +++ b/lam/docs/manual-sources/chapter-selfService.xml @@ -334,6 +334,11 @@ Base URL: please enter the URL of your privacyIDEA instance + + + User name attribute: please enter the LDAP attribute name + that contains the user ID (e.g. "uid") + YubiKey: diff --git a/lam/docs/manual-sources/images/conf7.png b/lam/docs/manual-sources/images/conf7.png index 718b0773..3b5d7891 100644 Binary files a/lam/docs/manual-sources/images/conf7.png and b/lam/docs/manual-sources/images/conf7.png differ diff --git a/lam/help/help.inc b/lam/help/help.inc index 8f828079..797f0bd7 100644 --- a/lam/help/help.inc +++ b/lam/help/help.inc @@ -323,6 +323,8 @@ $helpArray = array ( "Text" => _('This text is displayed as footer on the self service login page.')), "527" => array ("Headline" => _('Main page footer'), "Text" => _('This text is displayed as footer on the self service main page.')), + "528" => array ("Headline" => _('User name attribute'), + "Text" => _('The attribute (e.g. "uid") that contains the user name for the 2-factor service.')), "550" => array ("Headline" => _("From address"), "Text" => _("This email address will be set as sender address of all password mails. If empty the system default (php.ini) will be used.")), "551" => array ("Headline" => _("Subject"), diff --git a/lam/lib/2factor.inc b/lam/lib/2factor.inc index 0cbaee92..417e6831 100644 --- a/lam/lib/2factor.inc +++ b/lam/lib/2factor.inc @@ -53,8 +53,6 @@ interface TwoFactorProvider { */ public function verify2ndFactor($user, $password, $serial, $twoFactorInput); - - } /** @@ -79,8 +77,27 @@ class PrivacyIDEAProvider implements TwoFactorProvider { */ public function getSerials($user, $password) { logNewMessage(LOG_DEBUG, 'PrivacyIDEAProvider: Getting serials for ' . $user); - $token = $this->authenticate($user, $password); - return $this->getSerialsForUser($user, $token); + $loginAttribute = $this->getLoginAttributeValue($user); + $token = $this->authenticate($loginAttribute, $password); + return $this->getSerialsForUser($loginAttribute, $token); + } + + /** + * Returns the value of the user attribute in LDAP. + * + * @param string $userDn user DN + * @return string user name + */ + private function getLoginAttributeValue($userDn) { + $attrName = $this->config->twoFactorAuthenticationSerialAttributeName; + $userData = ldapGetDN($userDn, array($attrName)); + if (empty($userData[$attrName])) { + return null; + } + if (is_array($userData[$attrName])) { + return $userData[$attrName][0]; + } + return $userData[$attrName]; } /** @@ -89,7 +106,8 @@ class PrivacyIDEAProvider implements TwoFactorProvider { */ public function verify2ndFactor($user, $password, $serial, $twoFactorInput) { logNewMessage(LOG_DEBUG, 'PrivacyIDEAProvider: Checking 2nd factor for ' . $user); - $token = $this->authenticate($user, $password); + $loginAttribute = $this->getLoginAttributeValue($user); + $token = $this->authenticate($loginAttribute, $password); return $this->verify($token, $serial, $twoFactorInput); } @@ -360,6 +378,13 @@ class TwoFactorProviderService { $tfConfig->twoFactorAuthenticationSerialAttributeName = 'yubiKeyId'; } } + if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA) { + $attrName = $profile->twoFactorAuthenticationAttribute; + if (empty($attrName)) { + $attrName = 'uid'; + } + $tfConfig->twoFactorAuthenticationSerialAttributeName = strtolower($attrName); + } return $tfConfig; } @@ -385,6 +410,9 @@ class TwoFactorProviderService { $tfConfig->twoFactorAuthenticationSerialAttributeName = 'yubiKeyId'; } } + if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA) { + $tfConfig->twoFactorAuthenticationSerialAttributeName = strtolower($conf->getTwoFactorAuthenticationAttribute()); + } return $tfConfig; } diff --git a/lam/lib/account.inc b/lam/lib/account.inc index d822ae75..9e36d88a 100644 --- a/lam/lib/account.inc +++ b/lam/lib/account.inc @@ -881,7 +881,7 @@ function searchLDAPPaged($server, $dn, $filter, $attributes, $attrsOnly, $limit) */ function ldapGetDN($dn, $attributes = array('dn'), $handle = null) { if ($handle == null) { - $handle = $_SESSION['ldap']->server(); + $handle = getLDAPServerHandle(); } $return = null; $sr = @ldap_read($handle, escapeDN($dn), 'objectClass=*', $attributes, 0, 0, 0, LDAP_DEREF_NEVER); diff --git a/lam/lib/config.inc b/lam/lib/config.inc index 5c7b4db6..540a7d69 100644 --- a/lam/lib/config.inc +++ b/lam/lib/config.inc @@ -598,6 +598,7 @@ class LAMConfig { private $twoFactorAuthenticationLabel = null; private $twoFactorAuthenticationOptional = false; private $twoFactorAuthenticationCaption = ''; + private $twoFactorAuthenticationAttribute = ''; /** List of all settings in config file */ private $settings = array("ServerURL", "useTLS", "followReferrals", 'pagedResults', "Passwd", "Admins", "treesuffix", @@ -610,7 +611,8 @@ class LAMConfig { 'pwdResetAllowScreenPassword', 'pwdResetForcePasswordChange', 'pwdResetDefaultPasswordOutput', 'scriptUserName', 'scriptSSHKey', 'scriptSSHKeyPassword', 'twoFactorAuthentication', 'twoFactorAuthenticationURL', 'twoFactorAuthenticationInsecure', 'twoFactorAuthenticationLabel', 'twoFactorAuthenticationOptional', - 'twoFactorAuthenticationCaption', 'twoFactorAuthenticationClientId', 'twoFactorAuthenticationSecretKey', 'referentialIntegrityOverlay' + 'twoFactorAuthenticationCaption', 'twoFactorAuthenticationClientId', 'twoFactorAuthenticationSecretKey', + 'twoFactorAuthenticationAttribute', 'referentialIntegrityOverlay' ); @@ -868,14 +870,33 @@ class LAMConfig { if (!in_array("pwdResetAllowScreenPassword", $saved)) array_push($file_array, "\n" . "pwdResetAllowScreenPassword: " . $this->pwdResetAllowScreenPassword . "\n"); if (!in_array("pwdResetForcePasswordChange", $saved)) array_push($file_array, "\n" . "pwdResetForcePasswordChange: " . $this->pwdResetForcePasswordChange . "\n"); if (!in_array("pwdResetDefaultPasswordOutput", $saved)) array_push($file_array, "\n" . "pwdResetDefaultPasswordOutput: " . $this->pwdResetDefaultPasswordOutput . "\n"); - if (!in_array("twoFactorAuthentication", $saved)) array_push($file_array, "\n" . "twoFactorAuthentication: " . $this->twoFactorAuthentication . "\n"); - if (!in_array("twoFactorAuthenticationURL", $saved)) array_push($file_array, "\n" . "twoFactorAuthenticationURL: " . $this->twoFactorAuthenticationURL . "\n"); - if (!in_array("twoFactorAuthenticationClientId", $saved)) array_push($file_array, "\n" . "twoFactorAuthenticationClientId: " . $this->twoFactorAuthenticationClientId . "\n"); - if (!in_array("twoFactorAuthenticationSecretKey", $saved)) array_push($file_array, "\n" . "twoFactorAuthenticationSecretKey: " . $this->twoFactorAuthenticationSecretKey . "\n"); - if (!in_array("twoFactorAuthenticationInsecure", $saved)) array_push($file_array, "\n" . "twoFactorAuthenticationInsecure: " . $this->twoFactorAuthenticationInsecure . "\n"); - if (!in_array("twoFactorAuthenticationLabel", $saved)) array_push($file_array, "\n" . "twoFactorAuthenticationLabel: " . $this->twoFactorAuthenticationLabel . "\n"); - if (!in_array("twoFactorAuthenticationOptional", $saved)) array_push($file_array, "\n" . "twoFactorAuthenticationOptional: " . $this->twoFactorAuthenticationOptional . "\n"); - if (!in_array("twoFactorAuthenticationCaption", $saved)) array_push($file_array, "\n" . "twoFactorAuthenticationCaption: " . $this->twoFactorAuthenticationCaption . "\n"); + if (!in_array("twoFactorAuthentication", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthentication: " . $this->twoFactorAuthentication . "\n"); + } + if (!in_array("twoFactorAuthenticationURL", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthenticationURL: " . $this->twoFactorAuthenticationURL . "\n"); + } + if (!in_array("twoFactorAuthenticationClientId", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthenticationClientId: " . $this->twoFactorAuthenticationClientId . "\n"); + } + if (!in_array("twoFactorAuthenticationSecretKey", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthenticationSecretKey: " . $this->twoFactorAuthenticationSecretKey . "\n"); + } + if (!in_array("twoFactorAuthenticationInsecure", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthenticationInsecure: " . $this->twoFactorAuthenticationInsecure . "\n"); + } + if (!in_array("twoFactorAuthenticationLabel", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthenticationLabel: " . $this->twoFactorAuthenticationLabel . "\n"); + } + if (!in_array("twoFactorAuthenticationOptional", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthenticationOptional: " . $this->twoFactorAuthenticationOptional . "\n"); + } + if (!in_array("twoFactorAuthenticationCaption", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthenticationCaption: " . $this->twoFactorAuthenticationCaption . "\n"); + } + if (!in_array("twoFactorAuthenticationAttribute", $saved)) { + array_push($file_array, "\n" . "twoFactorAuthenticationAttribute: " . $this->twoFactorAuthenticationAttribute . "\n"); + } // check if all module settings were added $m_settings = array_keys($this->moduleSettings); for ($i = 0; $i < sizeof($m_settings); $i++) { @@ -2280,6 +2301,27 @@ class LAMConfig { $this->twoFactorAuthenticationCaption = $twoFactorAuthenticationCaption; } + /** + * Returns the user attribute. + * + * @return string user attribute + */ + public function getTwoFactorAuthenticationAttribute() { + if (empty($this->twoFactorAuthenticationAttribute)) { + return 'uid'; + } + return $this->twoFactorAuthenticationAttribute; + } + + /** + * Sets the user attribute. + * + * @param string $twoFactorAuthenticationAttribute user attribute + */ + public function setTwoFactorAuthenticationAttribute($twoFactorAuthenticationAttribute) { + $this->twoFactorAuthenticationAttribute = $twoFactorAuthenticationAttribute; + } + } diff --git a/lam/lib/selfService.inc b/lam/lib/selfService.inc index 5e35c503..bbf379aa 100644 --- a/lam/lib/selfService.inc +++ b/lam/lib/selfService.inc @@ -451,6 +451,7 @@ class selfServiceProfile { public $twoFactorAuthenticationCaption = ''; public $twoFactorAuthenticationClientId = ''; public $twoFactorAuthenticationSecretKey = ''; + public $twoFactorAuthenticationAttribute = 'uid'; /** provider for captcha (-/google) */ public $captchaProvider = '-'; @@ -510,6 +511,7 @@ class selfServiceProfile { $this->twoFactorAuthenticationCaption = ''; $this->twoFactorAuthenticationClientId = ''; $this->twoFactorAuthenticationSecretKey = ''; + $this->twoFactorAuthenticationAttribute = 'uid'; $this->captchaProvider = '-'; $this->reCaptchaSiteKey = ''; $this->reCaptchaSecretKey = ''; diff --git a/lam/templates/config/confmain.php b/lam/templates/config/confmain.php index c79e62be..ed87aa79 100644 --- a/lam/templates/config/confmain.php +++ b/lam/templates/config/confmain.php @@ -466,16 +466,19 @@ if (extension_loaded('curl')) { $twoFactorSelect->setHasDescriptiveElements(true); $twoFactorSelect->setTableRowsToHide(array( TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', - 'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'), - TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorClientId', 'twoFactorSecretKey') + 'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'), + TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorClientId', 'twoFactorSecretKey'), + TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorAttribute'), )); $twoFactorSelect->setTableRowsToShow(array( TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', - 'twoFactorOptional', 'twoFactorCaption'), + 'twoFactorOptional', 'twoFactorCaption', 'twoFactorAttribute'), TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'), )); $row->add($twoFactorSelect, 12); + $twoFactorAttribute = new htmlResponsiveInputField(_("User name attribute"), 'twoFactorAttribute', $conf->getTwoFactorAuthenticationAttribute(), '528'); + $row->add($twoFactorAttribute, 12); $twoFactorUrl = new htmlResponsiveInputField(_("Base URL"), 'twoFactorURL', $conf->getTwoFactorAuthenticationURL(), '515'); $twoFactorUrl->setRequired(true); $row->add($twoFactorUrl, 12); diff --git a/lam/templates/login.php b/lam/templates/login.php index 2188a989..31968804 100644 --- a/lam/templates/login.php +++ b/lam/templates/login.php @@ -572,12 +572,6 @@ if(isset($_POST['checklogin'])) { } else { $_SESSION['2factorRequired'] = true; - if (($_SESSION['config']->getLoginMethod() == LAMConfig::LOGIN_SEARCH) && ($_SESSION['config']->getHttpAuthentication() == 'true')) { - $_SESSION['user2factor'] = $_SERVER['PHP_AUTH_USER']; - } - else { - $_SESSION['user2factor'] = $_POST['username']; - } metaRefresh("./login2Factor.php"); } die(); diff --git a/lam/templates/login2Factor.php b/lam/templates/login2Factor.php index 9f4b4383..7088338b 100644 --- a/lam/templates/login2Factor.php +++ b/lam/templates/login2Factor.php @@ -46,10 +46,7 @@ setlanguage(); $config = $_SESSION['config']; $password = $_SESSION['ldap']->getPassword(); -$user = $_SESSION['user2factor']; -if (get_preg($user, 'dn')) { - $user = extractRDNValue($user); -} +$user = $_SESSION['ldap']->getUserName(); // get serials try { @@ -69,7 +66,6 @@ $twoFactorLabel = empty($twoFactorLabelConfig) ? _('PIN+Token') : $twoFactorLabe if (sizeof($serials) == 0) { if ($config->getTwoFactorAuthenticationOptional()) { unset($_SESSION['2factorRequired']); - unset($_SESSION['user2factor']); metaRefresh("main.php"); die(); } @@ -104,7 +100,6 @@ if (isset($_POST['submit'])) { } if ($twoFactorValid) { unset($_SESSION['2factorRequired']); - unset($_SESSION['user2factor']); metaRefresh("main.php"); die(); } diff --git a/lam/tests/lib/LAMConfigTest.php b/lam/tests/lib/LAMConfigTest.php index 9a661b2e..58e94bf5 100644 --- a/lam/tests/lib/LAMConfigTest.php +++ b/lam/tests/lib/LAMConfigTest.php @@ -3,7 +3,7 @@ $Id$ This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2016 - 2017 Roland Gruber + Copyright (C) 2016 - 2019 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -587,6 +587,17 @@ class LAMConfigTest extends PHPUnit_Framework_TestCase { $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationCaption()); } + /** + * Tests LAMConfig->getTwoFactorAuthenticationAttribute() and LAMConfig->setTwoFactorAuthenticationAttribute() + */ + public function testTwoFactorAuthenticationAttribute() { + $val = 'user'; + $this->lAMConfig->setTwoFactorAuthenticationAttribute($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationAttribute()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationAttribute()); + } + /** * Tests LAMConfig->getLamProMailFrom() and LAMConfig->setLamProMailFrom() */