diff --git a/lam/help/help.inc b/lam/help/help.inc index 516f2a75..d176dba1 100644 --- a/lam/help/help.inc +++ b/lam/help/help.inc @@ -311,6 +311,10 @@ $helpArray = array ( "Text" => _('Protect the self service login with a captcha.')), "523" => array ("Headline" => _('Base color'), "Text" => _('Background color for self service pages.')), + "524" => array ("Headline" => _('Client id'), + "Text" => _('Please enter your client id for the verification API.')), + "525" => array ("Headline" => _('Secret key'), + "Text" => _('Please enter your secret key for the verification API.')), "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 f4907667..7bccb039 100644 --- a/lam/lib/2factor.inc +++ b/lam/lib/2factor.inc @@ -53,6 +53,8 @@ interface TwoFactorProvider { */ public function verify2ndFactor($user, $password, $serial, $twoFactorInput); + + } /** @@ -223,6 +225,71 @@ class PrivacyIDEAProvider implements TwoFactorProvider { } +/** + * Authentication via YubiKeys. + * + * @author Roland Gruber + */ +class YubicoProvider implements TwoFactorProvider { + + private $config; + + /** + * Constructor. + * + * @param TwoFactorConfiguration $config configuration + */ + public function __construct(&$config) { + $this->config = $config; + } + + /** + * {@inheritDoc} + * @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::getSerials() + */ + public function getSerials($user, $password) { + $keyAttributeName = strtolower('yubiKeyId'); + $loginDn = $_SESSION['ldap']->getUserName(); + $handle = getLDAPServerHandle(); + $ldapData = ldapGetDN($loginDn, array($keyAttributeName), $handle); + if (empty($ldapData[$keyAttributeName])) { + return array(); + } + return array(implode(', ', $ldapData[$keyAttributeName])); + } + + /** + * {@inheritDoc} + * @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::verify2ndFactor() + */ + public function verify2ndFactor($user, $password, $serial, $twoFactorInput) { + include_once(__DIR__ . "/3rdParty/yubico/Yubico.php"); + $serialData = $this->getSerials($user, $password); + if (empty($serialData)) { + return false; + } + $serials = explode(', ', $serialData[0]); + $serialMatched = false; + foreach ($serials as $serial) { + if (strpos($twoFactorInput, $serial) === 0) { + $serialMatched = true; + break; + } + } + if (!$serialMatched) { + throw new \Exception(_('YubiKey id does not match allowed list of key ids.')); + } + $url = $this->config->twoFactorAuthenticationURL; + $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; + } + +} + /** * Returns the correct 2 factor provider. */ @@ -232,6 +299,8 @@ class TwoFactorProviderService { const TWO_FACTOR_NONE = 'none'; /** 2factor authentication via privacyIDEA */ const TWO_FACTOR_PRIVACYIDEA = 'privacyidea'; + /** 2factor authentication via YubiKey */ + const TWO_FACTOR_YUBICO = 'yubico'; private $config; @@ -260,6 +329,9 @@ class TwoFactorProviderService { if ($this->config->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA) { return new PrivacyIDEAProvider($this->config); } + elseif ($this->config->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) { + return new YubicoProvider($this->config); + } throw new \Exception('Invalid provider: ' . $this->config->twoFactorAuthentication); } @@ -270,11 +342,11 @@ class TwoFactorProviderService { * @return TwoFactorConfiguration configuration */ private function getConfigSelfService(&$profile) { - $config = new TwoFactorConfiguration(); - $config->twoFactorAuthentication = $profile->twoFactorAuthentication; - $config->twoFactorAuthenticationInsecure = $profile->twoFactorAuthenticationInsecure; - $config->twoFactorAuthenticationURL = $profile->twoFactorAuthenticationURL; - return $config; + $tfConfig = new TwoFactorConfiguration(); + $tfConfig->twoFactorAuthentication = $profile->twoFactorAuthentication; + $tfConfig->twoFactorAuthenticationInsecure = $profile->twoFactorAuthenticationInsecure; + $tfConfig->twoFactorAuthenticationURL = $profile->twoFactorAuthenticationURL; + return $tfConfig; } /** @@ -284,11 +356,13 @@ class TwoFactorProviderService { * @return TwoFactorConfiguration configuration */ private function getConfigAdmin($conf) { - $config = new TwoFactorConfiguration(); - $config->twoFactorAuthentication = $conf->getTwoFactorAuthentication(); - $config->twoFactorAuthenticationInsecure = $conf->getTwoFactorAuthenticationInsecure(); - $config->twoFactorAuthenticationURL = $conf->getTwoFactorAuthenticationURL(); - return $config; + $tfConfig = new TwoFactorConfiguration(); + $tfConfig->twoFactorAuthentication = $conf->getTwoFactorAuthentication(); + $tfConfig->twoFactorAuthenticationInsecure = $conf->getTwoFactorAuthenticationInsecure(); + $tfConfig->twoFactorAuthenticationURL = $conf->getTwoFactorAuthenticationURL(); + $tfConfig->twoFactorAuthenticationClientId = $conf->getTwoFactorAuthenticationClientId(); + $tfConfig->twoFactorAuthenticationSecretKey = $conf->getTwoFactorAuthenticationSecretKey(); + return $tfConfig; } } @@ -299,7 +373,30 @@ class TwoFactorProviderService { * @author Roland Gruber */ class TwoFactorConfiguration { + + /** + * @var string provider id + */ public $twoFactorAuthentication = null; + + /** + * @var service URL + */ public $twoFactorAuthenticationURL = null; + + /** + * @var disable certificate check + */ public $twoFactorAuthenticationInsecure = false; + + /** + * @var client ID for API access + */ + public $twoFactorAuthenticationClientId = null; + + /** + * @var secret key for API access + */ + public $twoFactorAuthenticationSecretKey = null; + } diff --git a/lam/lib/3rdParty/yubico/Yubico.php b/lam/lib/3rdParty/yubico/Yubico.php new file mode 100644 index 00000000..148d6f5f --- /dev/null +++ b/lam/lib/3rdParty/yubico/Yubico.php @@ -0,0 +1,351 @@ +, Olov Danielson + * @author Roland Gruber + * @copyright 2007-2015 Yubico AB + * @copyright 2018 Roland Gruber + * @license https://opensource.org/licenses/bsd-license.php New BSD License + * @version 2.0 + * @link https://www.yubico.com/ + * + * Adapted for LAM. + */ + +/** + * Class for verifying Yubico One-Time-Passcodes + */ +class Auth_Yubico { + + /** + * Yubico client ID + * + * @var string + */ + private $clientId; + + /** + * Yubico client key + * + * @var string + */ + private $clientKey; + + /** + * URL part of validation server + * + * @var string + */ + private $url; + + /** + * Last query to server + * + * @var string + */ + private $lastquery; + + /** + * Response from server + * + * @var string + */ + private $response; + + /** + * Flag whether to verify HTTPS server certificates or not. + * + * @var boolean + */ + private $httpsVerify; + + /** + * Constructor + * + * Sets up the object + * + * @param string $id The client identity + * @param string $key The client MAC key + * @param string $url URL + * @param boolean $httpsverify Flag whether to use verify HTTPS + * server certificates + */ + public function __construct($id, $key, $url, $httpsverify) { + $this->clientId = $id; + $this->clientKey = base64_decode($key); + $this->httpsVerify = $httpsverify; + $this->url = $url; + } + + /** + * Parse input string into password, yubikey prefix, + * ciphertext, and OTP. + * + * @param string Input string to parse + * @param string Optional delimiter re-class, default is '[:]' + * @return array Keyed array with fields + */ + private function parsePasswordOTP($str, $delim = '[:]') { + if (!preg_match("/^((.*)" . $delim . ")?(([cbdefghijklnrtuv]{0,12})([cbdefghijklnrtuv]{32}))$/i", $str, $matches)) { + /* Dvorak? */ + if (!preg_match("/^((.*)" . $delim . ")?(([jxe\\.uidchtnbpygk]{0,12})([jxe\\.uidchtnbpygk]{32}))$/i", $str, $matches)) { + return false; + } + else { + $ret['otp'] = strtr($matches[3], "jxe.uidchtnbpygk", "cbdefghijklnrtuv"); + } + } + else { + $ret['otp'] = $matches[3]; + } + $ret['password'] = $matches[2]; + $ret['prefix'] = $matches[4]; + $ret['ciphertext'] = $matches[5]; + return $ret; + } + + /** + * Parse parameters from last response + * + * example: getParameters("timestamp", "sessioncounter", "sessionuse"); + * + * @param array @parameters Array with strings representing + * parameters to parse + * @return array parameter array from last response + */ + private function getParameters($parameters) { + if ($parameters == null) { + $parameters = array( + 'timestamp', + 'sessioncounter', + 'sessionuse' + ); + } + $param_array = array(); + foreach ($parameters as $param) { + if (!preg_match("/" . $param . "=([0-9]+)/", $this->response, $out)) { + throw new LAMException(_('Error'), 'Could not parse parameter ' . $param . ' from response'); + } + $param_array[$param] = $out[1]; + } + return $param_array; + } + + /** + * Verify Yubico OTP against multiple URLs + * Protocol specification 2.0 is used to construct validation requests + * + * @param string $token Yubico OTP + * @param int $use_timestamp 1=>send request with ×tamp=1 to + * get timestamp and session information + * in the response + * @param string $sl Sync level in percentage between 0 + * and 100 or "fast" or "secure". + * @param int $timeout Max number of seconds to wait + * for responses + */ + public function verify($token, $use_timestamp = null, $sl = null, $timeout = null) { + /* Construct parameters string */ + $ret = $this->parsePasswordOTP($token); + if (!$ret) { + throw new LAMException(_('Error'), 'Could not parse Yubikey OTP'); + } + $params = array( + 'id' => $this->clientId, + 'otp' => $ret['otp'], + 'nonce' => md5(uniqid(getRandomNumber())) + ); + /* Take care of protocol version 2 parameters */ + if ($use_timestamp) { + $params['timestamp'] = 1; + } + if ($sl) { + $params['sl'] = $sl; + } + if ($timeout) { + $params['timeout'] = $timeout; + } + ksort($params); + $parameters = ''; + foreach ($params as $p => $v) { + $parameters .= "&" . $p . "=" . $v; + } + $parameters = ltrim($parameters, "&"); + + /* Generate signature. */ + if ($this->clientKey != "") { + $signature = base64_encode(hash_hmac('sha1', $parameters, $this->clientKey, true)); + $signature = preg_replace('/\+/', '%2B', $signature); + $parameters .= '&h=' . $signature; + } + + /* Generate and prepare request. */ + $mh = curl_multi_init(); + $ch = array(); + $query = $this->url . "?" . $parameters; + + $this->lastquery = $query; + logNewMessage(LOG_DEBUG, 'Yubico url: ' . $query); + + $handle = curl_init($query); + curl_setopt($handle, CURLOPT_USERAGENT, "LAM Auth Yubico"); + curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1); + if (!$this->httpsVerify) { + curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 0); + } + curl_setopt($handle, CURLOPT_FAILONERROR, true); + /* + * If timeout is set, we better apply it here as well + * in case the validation server fails to follow it. + */ + if ($timeout) { + curl_setopt($handle, CURLOPT_TIMEOUT, $timeout); + } + // TODO single curl call + curl_multi_add_handle($mh, $handle); + + $ch[(int) $handle] = $handle; + + /* Execute and read request. */ + $this->response = null; + $replay = False; + $valid = False; + do { + /* Let curl do its work. */ + while (($mrc = curl_multi_exec($mh, $active)) == CURLM_CALL_MULTI_PERFORM); + + while ($info = curl_multi_info_read($mh)) { + if ($info['result'] == CURLE_OK) { + + /* We have a complete response from one server. */ + + $str = curl_multi_getcontent($info['handle']); + logNewMessage(LOG_DEBUG, 'Yubico answer: ' . $str); + $cinfo = curl_getinfo($info['handle']); + + if (preg_match("/status=([a-zA-Z0-9_]+)/", $str, $out)) { + $status = $out[1]; + + /* + * There are 3 cases. + * + * 1. OTP or Nonce values doesn't match - ignore + * response. + * + * 2. We have a HMAC key. If signature is invalid - + * ignore response. Return if status=OK/REPLAYED_OTP/BAD_OTP. + * + * 3. Return if status=OK or status=REPLAYED_OTP. + */ + if (!preg_match("/otp=" . $params['otp'] . "/", $str) || !preg_match("/nonce=" . $params['nonce'] . "/", $str)) { + /* Case 1. Ignore response. */ + } + elseif ($this->clientKey != "") { + /* Case 2. Verify signature first */ + $rows = explode("\r\n", trim($str)); + $response = array(); + foreach ($rows as $key => $val) { + /* + * = is also used in BASE64 encoding so we only replace the first = by # which is not + * used in BASE64 + */ + $val = preg_replace('/=/', '#', $val, 1); + $row = explode("#", $val); + $response[$row[0]] = $row[1]; + } + + $parameters = array( + 'nonce', + 'otp', + 'sessioncounter', + 'sessionuse', + 'sl', + 'status', + 't', + 'timeout', + 'timestamp' + ); + sort($parameters); + $check = Null; + foreach ($parameters as $param) { + if (array_key_exists($param, $response)) { + if ($check) $check = $check . '&'; + $check = $check . $param . '=' . $response[$param]; + } + } + + $checksignature = base64_encode(hash_hmac('sha1', utf8_encode($check), $this->clientKey, true)); + + if ($response['h'] == $checksignature) { + if ($status == 'REPLAYED_OTP') { + $this->response = $str; + $replay = True; + } + if ($status == 'OK') { + $this->response = $str; + $valid = True; + } + // TODO status BAD_OTP + } + else { + // TODO throw invalid signature exception + } + } + else { + /* Case 3. We check the status directly */ + if ($status == 'REPLAYED_OTP') { + $this->response = $str; + $replay = True; + } + if ($status == 'OK') { + $this->response = $str; + $valid = True; + } + // TODO status BAD_OTP + } + } + if ($valid || $replay) { + /* We have status=OK or status=REPLAYED_OTP, return. */ + foreach ($ch as $h) { + curl_multi_remove_handle($mh, $h); + curl_close($h); + } + curl_multi_close($mh); + if ($replay) { + throw new LAMException(_('Error'), 'OTP replay detected.'); + } + if ($valid) { + return; + } + } + + curl_multi_remove_handle($mh, $info['handle']); + curl_close($info['handle']); + unset($ch[(int) $info['handle']]); + } + curl_multi_select($mh); + } + } + while ($active); + + /* + * Typically this is only reached + * when the timeout is reached and there is no + * OK/REPLAYED_REQUEST answer (think firewall). + */ + + foreach ($ch as $h) { + curl_multi_remove_handle($mh, $h); + curl_close($h); + } + curl_multi_close($mh); + + throw new LAMException(_('Error'), 'Invalid answer: ' . print_r($this->response, true)); + } + +} +?> diff --git a/lam/lib/config.inc b/lam/lib/config.inc index c254241c..0232cf2e 100644 --- a/lam/lib/config.inc +++ b/lam/lib/config.inc @@ -591,6 +591,8 @@ class LAMConfig { private $twoFactorAuthentication = TwoFactorProviderService::TWO_FACTOR_NONE; private $twoFactorAuthenticationURL = 'https://localhost'; + private $twoFactorAuthenticationClientId = null; + private $twoFactorAuthenticationSecretKey = null; private $twoFactorAuthenticationInsecure = false; private $twoFactorAuthenticationLabel = null; private $twoFactorAuthenticationOptional = false; @@ -607,7 +609,7 @@ class LAMConfig { 'pwdResetAllowScreenPassword', 'pwdResetForcePasswordChange', 'pwdResetDefaultPasswordOutput', 'scriptUserName', 'scriptSSHKey', 'scriptSSHKeyPassword', 'twoFactorAuthentication', 'twoFactorAuthenticationURL', 'twoFactorAuthenticationInsecure', 'twoFactorAuthenticationLabel', 'twoFactorAuthenticationOptional', - 'twoFactorAuthenticationCaption', 'referentialIntegrityOverlay' + 'twoFactorAuthenticationCaption', 'twoFactorAuthenticationClientId', 'twoFactorAuthenticationSecretKey', 'referentialIntegrityOverlay' ); @@ -867,6 +869,8 @@ class LAMConfig { 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"); @@ -2151,7 +2155,7 @@ class LAMConfig { /** * Returns the authentication URL. * - * @return string $twoFactorAuthenticationURL authentication URL + * @return string authentication URL */ public function getTwoFactorAuthenticationURL() { return $this->twoFactorAuthenticationURL; @@ -2166,10 +2170,46 @@ class LAMConfig { $this->twoFactorAuthenticationURL = $twoFactorAuthenticationURL; } + /** + * Sets the client id. + * + * @param string $clientId client id + */ + public function setTwoFactorAuthenticationClientId($clientId) { + $this->twoFactorAuthenticationClientId = $clientId; + } + + /** + * Returns the client id. + * + * @return string client id + */ + public function getTwoFactorAuthenticationClientId() { + return $this->twoFactorAuthenticationClientId; + } + + /** + * Sets the secret key. + * + * @param string $secretKey secret key + */ + public function setTwoFactorAuthenticationSecretKey($secretKey) { + $this->twoFactorAuthenticationSecretKey = $secretKey; + } + + /** + * Returns the secret key. + * + * @return string secret key + */ + public function getTwoFactorAuthenticationSecretKey() { + return $this->twoFactorAuthenticationSecretKey; + } + /** * Returns if SSL certificate verification is turned off. * - * @return bool $twoFactorAuthenticationInsecure SSL certificate verification is turned off + * @return bool SSL certificate verification is turned off */ public function getTwoFactorAuthenticationInsecure() { return $this->twoFactorAuthenticationInsecure; @@ -2187,7 +2227,7 @@ class LAMConfig { /** * Returns the authentication label. * - * @return string $twoFactorAuthenticationLabel authentication label + * @return string authentication label */ public function getTwoFactorAuthenticationLabel() { return $this->twoFactorAuthenticationLabel; @@ -2205,7 +2245,7 @@ class LAMConfig { /** * Returns if 2nd factor is optional. * - * @return bool $twoFactorAuthenticationOptional 2nd factor is optional + * @return bool 2nd factor is optional */ public function getTwoFactorAuthenticationOptional() { return $this->twoFactorAuthenticationOptional; @@ -2223,7 +2263,7 @@ class LAMConfig { /** * Returns the caption HTML. * - * @return string $twoFactorAuthenticationCaption caption HTML + * @return string caption HTML */ public function getTwoFactorAuthenticationCaption() { return $this->twoFactorAuthenticationCaption; diff --git a/lam/templates/config/confmain.php b/lam/templates/config/confmain.php index 3e0e7c8d..c79e62be 100644 --- a/lam/templates/config/confmain.php +++ b/lam/templates/config/confmain.php @@ -22,7 +22,7 @@ use \htmlGroup; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2003 - 2017 Roland Gruber + Copyright (C) 2003 - 2018 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 @@ -460,19 +460,29 @@ if (extension_loaded('curl')) { $twoFactorOptions = array( _('None') => TwoFactorProviderService::TWO_FACTOR_NONE, 'privacyIDEA' => TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA, + 'YubiKey' => TwoFactorProviderService::TWO_FACTOR_YUBICO, ); $twoFactorSelect = new htmlResponsiveSelect('twoFactor', $twoFactorOptions, array($conf->getTwoFactorAuthentication()), _('Provider'), '514'); $twoFactorSelect->setHasDescriptiveElements(true); $twoFactorSelect->setTableRowsToHide(array( - TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorOptional', 'twoFactorCaption') + TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', + 'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'), + TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorClientId', 'twoFactorSecretKey') )); $twoFactorSelect->setTableRowsToShow(array( - TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorOptional', 'twoFactorCaption') + TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', + 'twoFactorOptional', 'twoFactorCaption'), + TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', + 'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'), )); $row->add($twoFactorSelect, 12); $twoFactorUrl = new htmlResponsiveInputField(_("Base URL"), 'twoFactorURL', $conf->getTwoFactorAuthenticationURL(), '515'); $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'); + $row->add($twoFactorSecretKey, 12); $twoFactorLabel = new htmlResponsiveInputField(_("Label"), 'twoFactorLabel', $conf->getTwoFactorAuthenticationLabel(), '517'); $row->add($twoFactorLabel, 12); $row->add(new htmlResponsiveInputCheckbox('twoFactorOptional', $conf->getTwoFactorAuthenticationOptional(), _('Optional'), '519'), 12); @@ -677,6 +687,8 @@ function checkInput() { if (extension_loaded('curl')) { $conf->setTwoFactorAuthentication($_POST['twoFactor']); $conf->setTwoFactorAuthenticationURL($_POST['twoFactorURL']); + $conf->setTwoFactorAuthenticationClientId($_POST['twoFactorClientId']); + $conf->setTwoFactorAuthenticationSecretKey($_POST['twoFactorSecretKey']); $conf->setTwoFactorAuthenticationInsecure(isset($_POST['twoFactorInsecure']) && ($_POST['twoFactorInsecure'] == 'on')); $conf->setTwoFactorAuthenticationLabel($_POST['twoFactorLabel']); $conf->setTwoFactorAuthenticationOptional(isset($_POST['twoFactorOptional']) && ($_POST['twoFactorOptional'] == 'on')); diff --git a/lam/tests/lib/LAMConfigTest.php b/lam/tests/lib/LAMConfigTest.php index d792214d..9a661b2e 100644 --- a/lam/tests/lib/LAMConfigTest.php +++ b/lam/tests/lib/LAMConfigTest.php @@ -499,6 +499,94 @@ class LAMConfigTest extends PHPUnit_Framework_TestCase { $this->assertEquals($val, $this->lAMConfig->getHttpAuthentication()); } + /** + * Tests LAMConfig->getTwoFactorAuthentication() and LAMConfig->setTwoFactorAuthentication() + */ + public function testTwoFactorAuthentication() { + $val = '2fid'; + $this->lAMConfig->setTwoFactorAuthentication($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthentication()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthentication()); + } + + /** + * Tests LAMConfig->getTwoFactorAuthenticationURL() and LAMConfig->setTwoFactorAuthenticationURL() + */ + public function testTwoFactorAuthenticationURL() { + $val = 'http://example.com'; + $this->lAMConfig->setTwoFactorAuthenticationURL($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationURL()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationURL()); + } + + /** + * Tests LAMConfig->getTwoFactorAuthenticationClientId() and LAMConfig->setTwoFactorAuthenticationClientId() + */ + public function testTwoFactorAuthenticationClientId() { + $val = '1234'; + $this->lAMConfig->setTwoFactorAuthenticationClientId($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationClientId()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationClientId()); + } + + /** + * Tests LAMConfig->getTwoFactorAuthenticationSecretKey() and LAMConfig->setTwoFactorAuthenticationSecretKey() + */ + public function testTwoFactorAuthenticationSecretKey() { + $val = '3333key'; + $this->lAMConfig->setTwoFactorAuthenticationSecretKey($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationSecretKey()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationSecretKey()); + } + + /** + * Tests LAMConfig->getTwoFactorAuthenticationInsecure() and LAMConfig->setTwoFactorAuthenticationInsecure() + */ + public function testTwoFactorAuthenticationInsecure() { + $val = true; + $this->lAMConfig->setTwoFactorAuthenticationInsecure($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationInsecure()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationInsecure()); + } + + /** + * Tests LAMConfig->getTwoFactorAuthenticationLabel() and LAMConfig->setTwoFactorAuthenticationLabel() + */ + public function testTwoFactorAuthenticationLabel() { + $val = '2falabel'; + $this->lAMConfig->setTwoFactorAuthenticationLabel($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationLabel()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationLabel()); + } + + /** + * Tests LAMConfig->getTwoFactorAuthenticationOptional() and LAMConfig->setTwoFactorAuthenticationOptional() + */ + public function testTwoFactorAuthenticationOptional() { + $val = true; + $this->lAMConfig->setTwoFactorAuthenticationOptional($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationOptional()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationOptional()); + } + + /** + * Tests LAMConfig->getTwoFactorAuthenticationCaption() and LAMConfig->setTwoFactorAuthenticationCaption() + */ + public function testTwoFactorAuthenticationCaption() { + $val = '2facaption'; + $this->lAMConfig->setTwoFactorAuthenticationCaption($val); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationCaption()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationCaption()); + } + /** * Tests LAMConfig->getLamProMailFrom() and LAMConfig->setLamProMailFrom() */