commit
5682245739
|
@ -25,4 +25,4 @@ There are two modules. Usually, you only need the files inside "lam".
|
|||
LAM is published under the GNU General Public License.
|
||||
The complete list of licenses can be found in the copyright file.
|
||||
|
||||
Copyright (C) 2003 - 2018 Roland Gruber <post@rolandgruber.de>
|
||||
Copyright (C) 2003 - 2019 Roland Gruber <post@rolandgruber.de>
|
|
@ -1,4 +1,4 @@
|
|||
This software is copyright (c) 2003 - 2018 by Roland Gruber
|
||||
This software is copyright (c) 2003 - 2019 by Roland Gruber
|
||||
|
||||
If you purchased a copy of LDAP Account Manager Pro then the following
|
||||
files are licensed under the conditions which you accepted at purchase
|
||||
|
@ -199,6 +199,29 @@ B:
|
|||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
C:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Programs and licenses with other licenses and/or authors than the
|
||||
main license and authors:
|
||||
|
@ -206,6 +229,7 @@ main license and authors:
|
|||
lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah
|
||||
lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
|
||||
lib/3rdParty/phpseclib B Jim Wigginton
|
||||
lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB
|
||||
templates/lib/*jquery*.js B 2018 jQuery Foundation and other contributors
|
||||
style/120_jquery-ui*.css B 2016 jQuery Foundation and other contributors
|
||||
templates/lib/*jquery-dropmenu-*.js B 2010 Fred Heusschen
|
||||
|
@ -221,4 +245,3 @@ style/610_magnific-popup.css B 2016 Dmitry Semenov
|
|||
style/responsive/105_normalize.css B Nicolas Gallagher and Jonathan Neal
|
||||
style/responsive/110_grid.css B
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
March 2019
|
||||
- Added YubiKey as 2-factor authentication provider
|
||||
|
||||
28.12.2018 6.6
|
||||
- New import/export in tools menu
|
||||
- YubiKey support
|
||||
|
|
|
@ -15,7 +15,7 @@ LAM - Readme
|
|||
|
||||
https://www.ldap-account-manager.org/
|
||||
|
||||
Copyright (C) 2003 - 2018 Roland Gruber <post@rolandgruber.de>
|
||||
Copyright (C) 2003 - 2019 Roland Gruber <post@rolandgruber.de>
|
||||
|
||||
Installation and documentation:
|
||||
Please see the LAM manual in docs/manual/index.html.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
This software is copyright (c) 2003 - 2018 by Roland Gruber
|
||||
This software is copyright (c) 2003 - 2019 by Roland Gruber
|
||||
|
||||
If you purchased a copy of LDAP Account Manager Pro then the following
|
||||
files are licensed under the conditions which you accepted at purchase
|
||||
|
@ -198,6 +198,29 @@ B:
|
|||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
C:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Programs and licenses with other licenses and/or authors than the
|
||||
main license and authors:
|
||||
|
@ -205,6 +228,7 @@ main license and authors:
|
|||
lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah
|
||||
lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
|
||||
lib/3rdParty/phpseclib B Jim Wigginton
|
||||
lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB
|
||||
templates/lib/*jquery*.js B 2018 jQuery Foundation and other contributors
|
||||
style/120_jquery-ui*.css B 2016 jQuery Foundation and other contributors
|
||||
templates/lib/*jquery-dropmenu-*.js B 2010 Fred Heusschen
|
||||
|
|
|
@ -596,11 +596,53 @@
|
|||
<para><ulink
|
||||
url="https://www.privacyidea.org/">privacyIdea</ulink></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><ulink url="https://www.yubico.com/">YubiKey</ulink></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>By default LAM will enforce to use a token and reject users that
|
||||
did not setup one. You can set this check to optional. But if a user
|
||||
has setup a token then this will always be required.</para>
|
||||
<para>Configuration options:</para>
|
||||
|
||||
<para>privacyIDEA:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Base URL: please enter the URL of your privacyIDEA
|
||||
instance</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>YubiKey:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>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.
|
||||
http://www.example.com:8000/wsapi/2.0/verify). The URL needs to
|
||||
end with "/wsapi/2.0/verify".</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Client id: this is only required for YubiKey cloud. You can
|
||||
register here: https://upgrade.yubico.com/getapikey/</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Secret key: this is only required for YubiKey cloud. You can
|
||||
register here: https://upgrade.yubico.com/getapikey/</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Optional: By default LAM will enforce to use a token and reject
|
||||
users that did not setup one. You can set this check to optional. But
|
||||
if a user has setup a token then this will always be required.</para>
|
||||
|
||||
<para>Disable certificate check: This should be used on development
|
||||
instances only. It skips the certificate check when connecting to
|
||||
verification server.</para>
|
||||
|
||||
<screenshot>
|
||||
<mediaobject>
|
||||
|
|
|
@ -279,11 +279,51 @@
|
|||
<para><ulink
|
||||
url="https://www.privacyidea.org/">privacyIdea</ulink></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><ulink url="https://www.yubico.com/">YubiKey</ulink></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>By default LAM will enforce to use a token and reject users that
|
||||
did not setup one. You can set this check to optional. But if a user
|
||||
has setup a token then this will always be required.</para>
|
||||
<para>privacyIDEA:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Base URL: please enter the URL of your privacyIDEA
|
||||
instance</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>YubiKey:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>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.
|
||||
http://www.example.com:8000/wsapi/2.0/verify). The URL needs to
|
||||
end with "/wsapi/2.0/verify".</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Client id: this is only required for YubiKey cloud. You can
|
||||
register here: https://upgrade.yubico.com/getapikey/</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Secret key: this is only required for YubiKey cloud. You can
|
||||
register here: https://upgrade.yubico.com/getapikey/</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Optional: By default LAM will enforce to use a token and reject
|
||||
users that did not setup one. You can set this check to optional. But
|
||||
if a user has setup a token then this will always be required.</para>
|
||||
|
||||
<para>Disable certificate check: This should be used on development
|
||||
instances only. It skips the certificate check when connecting to
|
||||
verification server.</para>
|
||||
|
||||
<screenshot>
|
||||
<mediaobject>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<para><ulink
|
||||
url="https://www.ldap-account-manager.org/">https://www.ldap-account-manager.org/</ulink></para>
|
||||
|
||||
<para>Copyright (C) 2003 - 2018 Roland Gruber
|
||||
<para>Copyright (C) 2003 - 2019 Roland Gruber
|
||||
<post@rolandgruber.de></para>
|
||||
|
||||
<para><emphasis role="bold">Key features:</emphasis></para>
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -5,7 +5,7 @@ use \LAMConfig;
|
|||
|
||||
/*
|
||||
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
|
||||
Copyright (C) 2017 - 2018 Roland Gruber
|
||||
Copyright (C) 2017 - 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
|
||||
|
@ -53,6 +53,8 @@ interface TwoFactorProvider {
|
|||
*/
|
||||
public function verify2ndFactor($user, $password, $serial, $twoFactorInput);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,6 +225,76 @@ 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($this->config->twoFactorAuthenticationSerialAttributeName);
|
||||
if (isset($_SESSION['selfService_clientDN'])) {
|
||||
$loginDn = lamDecrypt($_SESSION['selfService_clientDN'], 'SelfService');
|
||||
}
|
||||
else {
|
||||
$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 +304,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 +334,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 +347,22 @@ 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;
|
||||
$tfConfig->twoFactorAuthenticationClientId = $profile->twoFactorAuthenticationClientId;
|
||||
$tfConfig->twoFactorAuthenticationSecretKey = $profile->twoFactorAuthenticationSecretKey;
|
||||
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
|
||||
$moduleSettings = $profile->moduleSettings;
|
||||
if (!empty($moduleSettings['yubiKeyUser_attributeName'][0])) {
|
||||
$tfConfig->twoFactorAuthenticationSerialAttributeName = $moduleSettings['yubiKeyUser_attributeName'][0];
|
||||
}
|
||||
else {
|
||||
$tfConfig->twoFactorAuthenticationSerialAttributeName = 'yubiKeyId';
|
||||
}
|
||||
}
|
||||
return $tfConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -284,11 +372,22 @@ 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();
|
||||
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
|
||||
$moduleSettings = $conf->get_moduleSettings();
|
||||
if (!empty($moduleSettings['yubiKeyUser_attributeName'][0])) {
|
||||
$tfConfig->twoFactorAuthenticationSerialAttributeName = $moduleSettings['yubiKeyUser_attributeName'][0];
|
||||
}
|
||||
else {
|
||||
$tfConfig->twoFactorAuthenticationSerialAttributeName = 'yubiKeyId';
|
||||
}
|
||||
}
|
||||
return $tfConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -299,7 +398,35 @@ 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;
|
||||
|
||||
/**
|
||||
* @var LDAP attribute name that stores the token serials
|
||||
*/
|
||||
public $twoFactorAuthenticationSerialAttributeName = null;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
<?php
|
||||
/**
|
||||
* Class for verifying Yubico One-Time-Passcodes
|
||||
*
|
||||
* @category Auth
|
||||
* @package Auth_Yubico
|
||||
* @author Simon Josefsson <simon@yubico.com>, Olov Danielson <olov@yubico.com>
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws LAMException if verification failed
|
||||
*/
|
||||
public function verify($token, $use_timestamp = null) {
|
||||
$timeout = 10;
|
||||
/* 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;
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
||||
$query = $this->url . "?" . $parameters;
|
||||
|
||||
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);
|
||||
curl_setopt($handle, CURLOPT_TIMEOUT, $timeout);
|
||||
|
||||
/* Execute and read request. */
|
||||
$this->response = null;
|
||||
$str = curl_exec($handle);
|
||||
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
|
||||
curl_close($handle);
|
||||
logNewMessage(LOG_DEBUG, 'Server answer: ' . $str);
|
||||
if (is_string($str) && ($httpCode == 200) && 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)) {
|
||||
if ($status == 'BAD_OTP') {
|
||||
throw new LAMException(_('Error'), 'OTP not accepted. Maybe key is not registered.');
|
||||
}
|
||||
throw new LAMException(_('Error'), 'Invalid answer ' . $str);
|
||||
}
|
||||
elseif ($this->clientKey != "") {
|
||||
/* Case 2. Verify signature first */
|
||||
$rows = explode("\r\n", trim($str));
|
||||
$response = array();
|
||||
foreach ($rows as $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) {
|
||||
$this->checkStatus($status);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw new LAMException(_('Error'), 'Invalid signature, expected ' . $checksignature);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Case 3. We check the status directly */
|
||||
$this->checkStatus($status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new LAMException(_('Error'), 'Call to verification service failed with ' . $httpCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the status is ok.
|
||||
*
|
||||
* @param string $status status
|
||||
* @throws LAMException invalid status
|
||||
*/
|
||||
private function checkStatus($status) {
|
||||
if ($status == 'REPLAYED_OTP') {
|
||||
throw new LAMException(_('Error'), 'OTP replay detected.');
|
||||
}
|
||||
elseif ($status == 'BAD_OTP') {
|
||||
throw new LAMException(_('Error'), 'OTP not accepted. Maybe key is not registered.');
|
||||
}
|
||||
elseif ($status == 'OK') {
|
||||
return;
|
||||
}
|
||||
throw new LAMException(_('Error'), 'Invalid status: ' . $status);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -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;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
$Id$
|
||||
|
||||
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
|
||||
|
@ -57,7 +57,7 @@ class Ldap{
|
|||
*
|
||||
* @param object $config an object of class Config
|
||||
*/
|
||||
function __construct($config) {
|
||||
public function __construct($config) {
|
||||
if (is_object($config)) {
|
||||
$this->conf = $config;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ class Ldap{
|
|||
* @param boolean $allowAnonymous specifies if anonymous binds are allowed
|
||||
* @return mixed if connect succeeds the 0 is returned, else false or error number
|
||||
*/
|
||||
function connect($user, $passwd, $allowAnonymous=false) {
|
||||
public function connect($user, $passwd, $allowAnonymous=false) {
|
||||
// close any prior connection
|
||||
@$this->close();
|
||||
// do not allow anonymous bind
|
||||
|
@ -105,7 +105,7 @@ class Ldap{
|
|||
}
|
||||
|
||||
/** Closes connection to server */
|
||||
function close() {
|
||||
public function close() {
|
||||
if ($this->server != null) {
|
||||
@ldap_close($this->server);
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ class Ldap{
|
|||
*
|
||||
* @return object connection handle
|
||||
*/
|
||||
function server() {
|
||||
public function server() {
|
||||
if (!$this->is_connected) {
|
||||
$data = $this->decrypt_login();
|
||||
$this->connect($data[0], $data[1]);
|
||||
|
@ -126,14 +126,14 @@ class Ldap{
|
|||
}
|
||||
|
||||
/** Closes connection to LDAP server before serialization */
|
||||
function __sleep() {
|
||||
public function __sleep() {
|
||||
$this->close();
|
||||
// define which attributes to save
|
||||
return array("conf", "username", "password");
|
||||
}
|
||||
|
||||
/** Reconnects to LDAP server when deserialized */
|
||||
function __wakeup() {
|
||||
public function __wakeup() {
|
||||
$this->is_connected = false;
|
||||
// delete PDF files and images which are older than 15 min
|
||||
$tmpDir = dirname(__FILE__) . '/../tmp/';
|
||||
|
@ -173,7 +173,7 @@ class Ldap{
|
|||
* @param string $username LDAP user name
|
||||
* @param string $password LDAP password
|
||||
*/
|
||||
function encrypt_login($username, $password) {
|
||||
public function encrypt_login($username, $password) {
|
||||
// encrypt username and password
|
||||
$this->username = base64_encode(lamEncrypt($username));
|
||||
$this->password = base64_encode(lamEncrypt($password));
|
||||
|
@ -184,7 +184,7 @@ class Ldap{
|
|||
*
|
||||
* @return array array(user name, password)
|
||||
*/
|
||||
function decrypt_login() {
|
||||
public function decrypt_login() {
|
||||
// decrypt username and password
|
||||
$username = lamDecrypt(base64_decode($this->username));
|
||||
$password = lamDecrypt(base64_decode($this->password));
|
||||
|
@ -192,8 +192,26 @@ class Ldap{
|
|||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP user name.
|
||||
*
|
||||
* @return string user name
|
||||
*/
|
||||
public function getUserName() {
|
||||
return lamDecrypt(base64_decode($this->username));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP password.
|
||||
*
|
||||
* @return string password
|
||||
*/
|
||||
public function getPassword() {
|
||||
return lamDecrypt(base64_decode($this->password));
|
||||
}
|
||||
|
||||
/** Closes connection to LDAP server and deletes encrypted username/password */
|
||||
function destroy() {
|
||||
public function destroy() {
|
||||
$this->close();
|
||||
$this->username="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
$this->password="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
|
|
|
@ -5,7 +5,7 @@ use \LAM\PDF\PDFTableRow;
|
|||
/*
|
||||
|
||||
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
|
||||
Copyright (C) 2018 Roland Gruber
|
||||
Copyright (C) 2018 - 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
|
||||
|
@ -308,7 +308,7 @@ class yubiKeyUser extends baseModule {
|
|||
for ($i = 0; $i < sizeof($keys); $i++) {
|
||||
$group = new htmlGroup();
|
||||
$keyInput = new htmlInputField('yubiKeyId_' . $i, $keys[$i]);
|
||||
$keyInput->setFieldMaxLength(16384);
|
||||
$keyInput->setFieldMaxLength(12);
|
||||
$group->addElement($keyInput);
|
||||
$delLink = new htmlLink('', '#', '../../graphics/del.png');
|
||||
$delLink->setTitle(_('Delete'));
|
||||
|
|
|
@ -284,7 +284,7 @@ function installPDFTemplates() {
|
|||
$entry = $templateDir->read();
|
||||
while ($entry){
|
||||
$path = $basePath . '/logos/' . $entry;
|
||||
if ((strpos($entry, '.') !== 1) && !is_file($path)) {
|
||||
if ((strpos($entry, '.') !== 0) && !is_file($path)) {
|
||||
$template = $templatePath . '/' . $entry;
|
||||
logNewMessage(LOG_DEBUG, 'Copy template ' . $template . ' to ' . $path);
|
||||
@copy($template, $path);
|
||||
|
|
|
@ -3,7 +3,7 @@ use \LAM\LIB\TWO_FACTOR\TwoFactorProviderService;
|
|||
/*
|
||||
|
||||
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
|
||||
Copyright (C) 2006 - 2018 Roland Gruber
|
||||
Copyright (C) 2006 - 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
|
||||
|
@ -300,6 +300,38 @@ function isSelfService() {
|
|||
return session_name() == 'SELFSERVICE';
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the LDAP connection and returns the handle. No bind is done.
|
||||
*
|
||||
* @param selfServiceProfile $profile profile
|
||||
* @return handle LDAP handle or null if connection failed
|
||||
*/
|
||||
function openSelfServiceLdapConnection($profile) {
|
||||
$server = connectToLDAP($profile->serverURL, $profile->useTLS);
|
||||
if ($server != null) {
|
||||
// follow referrals
|
||||
ldap_set_option($server, LDAP_OPT_REFERRALS, $profile->followReferrals);
|
||||
}
|
||||
return $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the LDAP connections with given user and password.
|
||||
*
|
||||
* @param handle $handle LDAP handle
|
||||
* @param selfServiceProfile profile
|
||||
* @param string $userDn bind DN
|
||||
* @param string $password bind password
|
||||
* @return boolean binding successful
|
||||
*/
|
||||
function bindLdapUser($handle, $profile, $userDn, $password) {
|
||||
if ($profile->useForAllOperations) {
|
||||
$userDn = $profile->LDAPUser;
|
||||
$password = deobfuscateText($profile->LDAPPassword);
|
||||
}
|
||||
return @ldap_bind($handle, $userDn, $password);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Includes all settings of a self service profile.
|
||||
|
@ -391,6 +423,8 @@ class selfServiceProfile {
|
|||
public $twoFactorAuthenticationLabel = null;
|
||||
public $twoFactorAuthenticationOptional = false;
|
||||
public $twoFactorAuthenticationCaption = '';
|
||||
public $twoFactorAuthenticationClientId = '';
|
||||
public $twoFactorAuthenticationSecretKey = '';
|
||||
|
||||
/** provider for captcha (-/google) */
|
||||
public $captchaProvider = '-';
|
||||
|
@ -445,6 +479,8 @@ class selfServiceProfile {
|
|||
$this->twoFactorAuthenticationLabel = null;
|
||||
$this->twoFactorAuthenticationOptional = false;
|
||||
$this->twoFactorAuthenticationCaption = '';
|
||||
$this->twoFactorAuthenticationClientId = '';
|
||||
$this->twoFactorAuthenticationSecretKey = '';
|
||||
$this->captchaProvider = '-';
|
||||
$this->reCaptchaSiteKey = '';
|
||||
$this->reCaptchaSecretKey = '';
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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()
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue