Commit 2a0b7a7a authored by Franco Fichtner's avatar Franco Fichtner

mvc: merge pluggable authentication remains et al

parent c91450bb
...@@ -371,6 +371,7 @@ ...@@ -371,6 +371,7 @@
/usr/local/opnsense/mvc/app/library/OPNsense/Auth/Local.php /usr/local/opnsense/mvc/app/library/OPNsense/Auth/Local.php
/usr/local/opnsense/mvc/app/library/OPNsense/Auth/LocalTOTP.php /usr/local/opnsense/mvc/app/library/OPNsense/Auth/LocalTOTP.php
/usr/local/opnsense/mvc/app/library/OPNsense/Auth/Radius.php /usr/local/opnsense/mvc/app/library/OPNsense/Auth/Radius.php
/usr/local/opnsense/mvc/app/library/OPNsense/Auth/TOTP.php
/usr/local/opnsense/mvc/app/library/OPNsense/Auth/Voucher.php /usr/local/opnsense/mvc/app/library/OPNsense/Auth/Voucher.php
/usr/local/opnsense/mvc/app/library/OPNsense/Base/Filters/QueryFilter.php /usr/local/opnsense/mvc/app/library/OPNsense/Base/Filters/QueryFilter.php
/usr/local/opnsense/mvc/app/library/OPNsense/Base/UIModelGrid.php /usr/local/opnsense/mvc/app/library/OPNsense/Base/UIModelGrid.php
......
...@@ -42,6 +42,15 @@ class API implements IAuthConnector ...@@ -42,6 +42,15 @@ class API implements IAuthConnector
*/ */
private $lastAuthProperties = array(); private $lastAuthProperties = array();
/**
* type name in configuration
* @return string
*/
public static function getType()
{
return 'api';
}
/** /**
* set connector properties * set connector properties
* @param array $config connection properties * @param array $config connection properties
......
...@@ -57,6 +57,33 @@ class AuthenticationFactory ...@@ -57,6 +57,33 @@ class AuthenticationFactory
return $result; return $result;
} }
/**
* list installed auth connectors
* @return array
*/
private function listConnectors()
{
$connectors = array();
foreach (glob(__DIR__."/*.php") as $filename) {
$pathParts = explode('/', $filename);
$vendor = $pathParts[count($pathParts)-3];
$module = $pathParts[count($pathParts)-2];
$classname = explode('.php', $pathParts[count($pathParts)-1])[0];
$reflClass = new \ReflectionClass("{$vendor}\\{$module}\\{$classname}");
if ($reflClass->implementsInterface('OPNsense\\Auth\\IAuthConnector')) {
if ($reflClass->hasMethod('getType')) {
$connectorType = $reflClass->getMethod('getType')->invoke(null);
$connector = array();
$connector['class'] = "{$vendor}\\{$module}\\{$classname}";
$connector['classHandle'] = $reflClass;
$connector['type'] = $connectorType;
$connectors[$connectorType] = $connector;
}
}
}
return $connectors;
}
/** /**
* request list of configured servers, the factory needs to be aware of it's options and settings to * request list of configured servers, the factory needs to be aware of it's options and settings to
* be able to instantiate useful connectors. * be able to instantiate useful connectors.
...@@ -90,32 +117,16 @@ class AuthenticationFactory ...@@ -90,32 +117,16 @@ class AuthenticationFactory
$localUserMap = array(); $localUserMap = array();
$servers = $this->listServers(); $servers = $this->listServers();
$servers['Local API'] = array("name" => "Local API Database", "type" => "api"); $servers['Local API'] = array("name" => "Local API Database", "type" => "api");
// create a new auth connector // create a new auth connector
if (isset($servers[$authserver]['type'])) { if (isset($servers[$authserver]['type'])) {
switch ($servers[$authserver]['type']) { $connectors = $this->listConnectors();
case 'local': if (!empty($connectors[$servers[$authserver]['type']])) {
$authObject = new Local(); $authObject = $connectors[$servers[$authserver]['type']]['classHandle']->newInstance();
break; }
case 'ldap': if ($servers[$authserver]['type'] == 'ldap') {
$authObject = new LDAP();
$localUserMap = $this->fetchUserDNs(); $localUserMap = $this->fetchUserDNs();
break;
case 'radius':
$authObject = new Radius();
break;
case 'voucher':
$authObject = new Voucher();
break;
case 'api':
$authObject = new API();
break;
case 'totp':
$authObject = new LocalTOTP();
break;
default:
$authObject = null;
} }
if ($authObject != null) { if ($authObject != null) {
$props = $servers[$authserver]; $props = $servers[$authserver];
// when a local user exist and has a different (distinguished) name on the authenticator we already // when a local user exist and has a different (distinguished) name on the authenticator we already
...@@ -128,4 +139,27 @@ class AuthenticationFactory ...@@ -128,4 +139,27 @@ class AuthenticationFactory
return null; return null;
} }
/**
* list configuration options for pluggable auth modules
* @return array
*/
public function listConfigOptions()
{
$result = array();
foreach ($this->listConnectors() as $connector) {
if ($connector['classHandle']->hasMethod('getDescription')) {
$obj = $connector['classHandle']->newInstance();
$authItem = $connector;
$authItem['description'] = $obj->getDescription();
if ($connector['classHandle']->hasMethod('getConfigurationOptions')) {
$authItem['additionalFields'] = $obj->getConfigurationOptions();
} else {
$authItem['additionalFields'] = array();
}
$result[$obj->getType()] = $authItem;
}
}
return $result;
}
} }
...@@ -141,6 +141,24 @@ class LDAP implements IAuthConnector ...@@ -141,6 +141,24 @@ class LDAP implements IAuthConnector
return $result; return $result;
} }
/**
* type name in configuration
* @return string
*/
public static function getType()
{
return 'ldap';
}
/**
* user friendly description of this authenticator
* @return string
*/
public function getDescription()
{
return gettext("LDAP");
}
/** /**
* construct a new LDAP connector * construct a new LDAP connector
* @param null|string $baseSearchDN setup base searchDN or list of DN's separated by ; * @param null|string $baseSearchDN setup base searchDN or list of DN's separated by ;
......
...@@ -37,6 +37,15 @@ use OPNsense\Core\Config; ...@@ -37,6 +37,15 @@ use OPNsense\Core\Config;
*/ */
class Local implements IAuthConnector class Local implements IAuthConnector
{ {
/**
* type name in configuration
* @return string
*/
public static function getType()
{
return 'local';
}
/** /**
* set connector properties * set connector properties
* @param array $config connection properties * @param array $config connection properties
......
...@@ -30,146 +30,48 @@ ...@@ -30,146 +30,48 @@
namespace OPNsense\Auth; namespace OPNsense\Auth;
require_once 'base32/Base32.php';
/** /**
* RFC 6238 TOTP: Time-Based One-Time Password Authenticator * RFC 6238 TOTP: Time-Based One-Time Password Authenticator
* @package OPNsense\Auth * @package OPNsense\Auth
*/ */
class LocalTOTP extends Local class LocalTOTP extends Local
{ {
/** use TOTP;
* @var int time window in seconds (google auth uses 30, some hardware tokens use 60)
*/
private $timeWindow = 30;
/**
* @var int key length (6,8)
*/
private $otpLength = 6;
/** /**
* @var int number of seconds the clocks (local, remote) may differ * type name in configuration
*/ * @return string
private $graceperiod = 10;
/**
* set connector properties
* @param array $config connection properties
*/ */
public function setProperties($config) public static function getType()
{ {
parent::setProperties($config); return 'totp';
if (!empty($config['timeWindow'])) {
$this->timeWindow = $config['timeWindow'];
}
if (!empty($config['otpLength'])) {
$this->otpLength = $config['otpLength'];
}
if (!empty($config['graceperiod'])) {
$this->graceperiod = $config['graceperiod'];
}
} }
/** /**
* use graceperiod and timeWindow to calculate which moments in time we should check * user friendly description of this authenticator
* @return array timestamps * @return string
*/ */
private function timesToCheck() public function getDescription()
{ {
$result = array(); return gettext("Local + Timebased One Time Password");
if ($this->graceperiod > $this->timeWindow) {
$step = $this->timeWindow;
$start = -1 * floor($this->graceperiod / $this->timeWindow) * $this->timeWindow;
} else {
$step = $this->graceperiod;
$start = -1 * $this->graceperiod;
}
$now = time();
for ($count = $start; $count <= $this->graceperiod; $count += $step) {
$result[] = $now + $count;
if ($this->graceperiod == 0) {
// special case, we expect the clocks to match 100%, so step and target are both 0
break;
}
}
return $result;
} }
/** /**
* @param int $moment timestemp * set connector properties
* @param string $secret secret to use * @param array $config connection properties
* @return calculated token code
*/
private function calculateToken($moment, $secret)
{
// calculate binary 8 character time for provided window
$binary_time = pack("N", (int)($moment/$this->timeWindow));
$binary_time = str_pad($binary_time, 8, chr(0), STR_PAD_LEFT);
// Generate the hash using the SHA1 algorithm
$hash = hash_hmac('sha1', $binary_time, $secret, true);
$offset = ord($hash[19]) & 0xf;
$otp = (
((ord($hash[$offset+0]) & 0x7f) << 24 ) |
((ord($hash[$offset+1]) & 0xff) << 16 ) |
((ord($hash[$offset+2]) & 0xff) << 8 ) |
(ord($hash[$offset+3]) & 0xff)
) % pow(10, $this->otpLength);
$otp = str_pad($otp, $this->otpLength, "0", STR_PAD_LEFT);
return $otp;
}
/**
* return current token code
* @param $base32seed secret to use
* @return string token code
*/
public function testToken($base32seed)
{
$otp_seed = \Base32\Base32::decode($base32seed);
return $this->calculateToken(time(), $otp_seed);
}
/**
* authenticate TOTP RFC 6238
* @param string $secret secret seed to use
* @param string $code provided code
* @return bool is valid
*/ */
private function authTOTP($secret, $code) public function setProperties($config)
{ {
foreach ($this->timesToCheck() as $moment) { parent::setProperties($config);
if ($code == $this->calculateToken($moment, $secret)) { $this->setTOTPProperties($config);
return true;
}
}
return false;
} }
/** /**
* authenticate user against otp key stored in local database * retrieve configuration options
* @param string $username username to authenticate * @return array
* @param string $password user password
* @return bool authentication status
*/ */
public function authenticate($username, $password) public function getConfigurationOptions()
{ {
$userObject = $this->getUser($username); return $this->getTOTPConfigurationOptions();
if ($userObject != null && !empty($userObject->otp_seed)) {
if (strlen($password) > $this->otpLength) {
// split otp token code and userpassword
$code = substr($password, 0, $this->otpLength);
$userPassword = substr($password, $this->otpLength);
$otp_seed = \Base32\Base32::decode($userObject->otp_seed);
if ($this->authTOTP($otp_seed, $code)) {
// token valid, do local auth
return parent::authenticate($userObject, $userPassword);
}
}
}
return false;
} }
} }
...@@ -81,6 +81,24 @@ class Radius implements IAuthConnector ...@@ -81,6 +81,24 @@ class Radius implements IAuthConnector
*/ */
private $lastAuthProperties = array(); private $lastAuthProperties = array();
/**
* type name in configuration
* @return string
*/
public static function getType()
{
return 'radius';
}
/**
* user friendly description of this authenticator
* @return string
*/
public function getDescription()
{
return gettext("Radius");
}
/** /**
* set connector properties * set connector properties
* @param array $config connection properties * @param array $config connection properties
......
<?php
/**
* Copyright (C) 2016 Deciso B.V.
*
* All rights reserved.
*
* 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 ``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
* AUTHOR 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.
*
*/
namespace OPNsense\Auth;
require_once 'base32/Base32.php';
/**
* RFC 6238 TOTP: Time-Based One-Time Password Authenticator
* @package OPNsense\Auth
*/
trait TOTP
{
/**
* @var int time window in seconds (google auth uses 30, some hardware tokens use 60)
*/
private $timeWindow = 30;
/**
* @var int key length (6,8)
*/
private $otpLength = 6;
/**
* @var int number of seconds the clocks (local, remote) may differ
*/
private $graceperiod = 10;
/**
* @var string method accepting username and returning a simplexml user object
*/
private $getUserMethod = 'getUser';
/**
* use graceperiod and timeWindow to calculate which moments in time we should check
* @return array timestamps
*/
private function timesToCheck()
{
$result = array();
if ($this->graceperiod > $this->timeWindow) {
$step = $this->timeWindow;
$start = -1 * floor($this->graceperiod / $this->timeWindow) * $this->timeWindow;
} else {
$step = $this->graceperiod;
$start = -1 * $this->graceperiod;
}
$now = time();
for ($count = $start; $count <= $this->graceperiod; $count += $step) {
$result[] = $now + $count;
if ($this->graceperiod == 0) {
// special case, we expect the clocks to match 100%, so step and target are both 0
break;
}
}
return $result;
}
/**
* @param int $moment timestemp
* @param string $secret secret to use
* @return calculated token code
*/
private function calculateToken($moment, $secret)
{
// calculate binary 8 character time for provided window
$binary_time = pack("N", (int)($moment/$this->timeWindow));
$binary_time = str_pad($binary_time, 8, chr(0), STR_PAD_LEFT);
// Generate the hash using the SHA1 algorithm
$hash = hash_hmac('sha1', $binary_time, $secret, true);
$offset = ord($hash[19]) & 0xf;
$otp = (
((ord($hash[$offset+0]) & 0x7f) << 24 ) |
((ord($hash[$offset+1]) & 0xff) << 16 ) |
((ord($hash[$offset+2]) & 0xff) << 8 ) |
(ord($hash[$offset+3]) & 0xff)
) % pow(10, $this->otpLength);
$otp = str_pad($otp, $this->otpLength, "0", STR_PAD_LEFT);
return $otp;
}
/**
* return current token code
* @param $base32seed secret to use
* @return string token code
*/
public function testToken($base32seed)
{
$otp_seed = \Base32\Base32::decode($base32seed);
return $this->calculateToken(time(), $otp_seed);
}
/**
* authenticate TOTP RFC 6238
* @param string $secret secret seed to use
* @param string $code provided code
* @return bool is valid
*/
private function authTOTP($secret, $code)
{
foreach ($this->timesToCheck() as $moment) {
if ($code == $this->calculateToken($moment, $secret)) {
return true;
}
}
return false;
}
/**
* authenticate user against otp key stored in local database
* @param string $username username to authenticate
* @param string $password user password
* @return bool authentication status
*/
public function authenticate($username, $password)
{
$getUserMethod = $this->getUserMethod;
$userObject = $this->$getUserMethod($username);
if ($userObject != null && !empty($userObject->otp_seed)) {
if (strlen($password) > $this->otpLength) {
// split otp token code and userpassword
$code = substr($password, 0, $this->otpLength);
$userPassword = substr($password, $this->otpLength);
$otp_seed = \Base32\Base32::decode($userObject->otp_seed);
if ($this->authTOTP($otp_seed, $code)) {
// token valid, do parents auth
return parent::authenticate($userObject, $userPassword);
}
}
}
return false;
}
/**
* set TOTP specific connector properties
* @param array $config connection properties
*/
public function setTOTPProperties($config)
{
if (!empty($config['timeWindow'])) {
$this->timeWindow = $config['timeWindow'];
}
if (!empty($config['otpLength'])) {
$this->otpLength = $config['otpLength'];
}
if (!empty($config['graceperiod'])) {
$this->graceperiod = $config['graceperiod'];
}
}
/**
* retrieve TOTP specific configuration options
* @return array
*/
private function getTOTPConfigurationOptions()
{
$fields = array();
$fields["otpLength"] = array();
$fields["otpLength"]["name"] = gettext("Token length");
$fields["otpLength"]["type"] = "dropdown";
$fields["otpLength"]["default"] = 6;
$fields["otpLength"]["options"] = array();
$fields["otpLength"]["options"]["6"] = "6";
$fields["otpLength"]["options"]["8"] = "8";
$fields["otpLength"]["help"] = gettext("Token length to use");
$fields["otpLength"]["validate"] = function ($value) {
if (!in_array($value, array(6,8))) {
return array(gettext("Only token lengths of 6 or 8 characters are supported"));
} else {
return array();
}
};
$fields["timeWindow"] = array();
$fields["timeWindow"]["name"] = gettext("Time window");
$fields["timeWindow"]["type"] = "text";
$fields["timeWindow"]["default"] = null;
$fields["timeWindow"]["help"] = gettext("The time period in which the token will be valid,".
" default is 30 seconds (google authenticator)");
$fields["timeWindow"]["validate"] = function ($value) {
if (!empty($value) && filter_var($value, FILTER_SANITIZE_NUMBER_INT) != $value) {
return array(gettext("Please enter a valid time window in seconds"));
} else {
return array();
}
};
$fields["graceperiod"] = array();
$fields["graceperiod"]["name"] = gettext("Grace period");
$fields["graceperiod"]["type"] = "text";
$fields["graceperiod"]["default"] = null;
$fields["graceperiod"]["help"] = gettext("Time in seconds in which this server and the token may differ,".
" default is 10 seconds. Set higher for a less secure easier match.");
$fields["graceperiod"]["validate"] = function ($value) {
if (!empty($value) && filter_var($value, FILTER_SANITIZE_NUMBER_INT) != $value) {
return array(gettext("Please enter a valid grace period in seconds"));
} else {
return array();
}
};
return $fields;
}
}
...@@ -68,6 +68,24 @@ class Voucher implements IAuthConnector ...@@ -68,6 +68,24 @@ class Voucher implements IAuthConnector
*/ */
private $lastAuthProperties = array(); private $lastAuthProperties = array();
/**
* type name in configuration
* @return string
*/
public static function getType()
{
return 'voucher';
}
/**
* user friendly description of this authenticator
* @return string
*/
public function getDescription()
{
return gettext("Voucher");
}
/** /**
* open database * open database
*/ */
...@@ -391,4 +409,46 @@ class Voucher implements IAuthConnector ...@@ -391,4 +409,46 @@ class Voucher implements IAuthConnector
} }
return false; return false;
} }
/**
* retrieve configuration options
* @return array
*/
public function getConfigurationOptions()
{
$fields = array();
$fields["simplePasswords"] = array();
$fields["simplePasswords"]["name"] = gettext("Use simple passwords (less secure)");
$fields["simplePasswords"]["type"] = "checkbox";
$fields["simplePasswords"]["help"] = gettext("Use simple (less secure) passwords, which are easier to read");
$fields["simplePasswords"]["validate"] = function ($value) {
return array();
};
$fields["usernameLength"] = array();
$fields["usernameLength"]["name"] = gettext("Username length");
$fields["usernameLength"]["type"] = "text";
$fields["usernameLength"]["default"] = null;
$fields["usernameLength"]["help"] = gettext("Specify alternative username length for generating vouchers");
$fields["usernameLength"]["validate"] = function ($value) {
if (!empty($value) && filter_var($value, FILTER_SANITIZE_NUMBER_INT) != $value) {
return array(gettext("Username length must be a number or empty for default."));
} else {
return array();
}
};
$fields["passwordLength"] = array();
$fields["passwordLength"]["name"] = gettext("Password length");
$fields["passwordLength"]["type"] = "text";
$fields["passwordLength"]["default"] = null;
$fields["passwordLength"]["help"] = gettext("Specify alternative password length for generating vouchers");
$fields["passwordLength"]["validate"] = function ($value) {
if (!empty($value) && filter_var($value, FILTER_SANITIZE_NUMBER_INT) != $value) {
return array(gettext("Password length must be a number or empty for default."));
} else {
return array();
}
};
return $fields;
}
} }
...@@ -27,7 +27,8 @@ try { ...@@ -27,7 +27,8 @@ try {
} catch (\Exception $e) { } catch (\Exception $e) {
$response = array(); $response = array();
$response['errorMessage'] = $e->getMessage(); $response['errorMessage'] = $e->getMessage();
header('HTTP', true, 500);
header("Content-Type: application/json;charset=utf-8"); header("Content-Type: application/json;charset=utf-8");
echo htmlspecialchars(json_encode($response), ENT_NOQUOTES); echo json_encode($response, JSON_UNESCAPED_SLASHES);
error_log($e); error_log($e);
} }
...@@ -81,18 +81,7 @@ function saveFormToEndpoint(url,formid,callback_ok, disable_dialog) { ...@@ -81,18 +81,7 @@ function saveFormToEndpoint(url,formid,callback_ok, disable_dialog) {
// execute callback function // execute callback function
callback_ok(); callback_ok();
} }
} else {
// error handling, show internal errors
// Normally the form should only return validation issues, if other things go wrong throw an error.
BootstrapDialog.show({
type: BootstrapDialog.TYPE_ERROR,
title: 'save',
message: 'Unable to save data, an internal error occurred.<br> ' +
'Response from server was: <br> <small>'+JSON.stringify(data)+'</small>'
});
} }
}); });
} }
......
...@@ -30,14 +30,8 @@ ...@@ -30,14 +30,8 @@
require_once("guiconfig.inc"); require_once("guiconfig.inc");
require_once("auth.inc"); require_once("auth.inc");
$authFactory = new \OPNsense\Auth\AuthenticationFactory();
$auth_server_types = array( $authCNFOptions = $authFactory->listConfigOptions();
'ldap' => gettext("LDAP"),
'radius' => gettext("Radius"),
'voucher' => gettext("Voucher"),
'totp' => gettext("Local + Timebased One Time Password")
);
if (!isset($config['system']['authserver'])) { if (!isset($config['system']['authserver'])) {
$config['system']['authserver'] = array(); $config['system']['authserver'] = array();
...@@ -69,6 +63,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { ...@@ -69,6 +63,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$pconfig['radius_auth_port'] = "1812"; $pconfig['radius_auth_port'] = "1812";
$pconfig['radius_acct_port'] = "1813"; $pconfig['radius_acct_port'] = "1813";
$pconfig['type'] = 'ldap'; $pconfig['type'] = 'ldap';
// gather auth plugin defaults
// the hotplug properties should be different per type, if not the default won't function correctly
foreach ($authCNFOptions as $authType) {
foreach ($authType['additionalFields'] as $fieldname => $field) {
if (!empty($field['default']) && empty($pconfig[$fieldname])) {
$pconfig[$fieldname] = $field['default'];
}
}
}
} elseif ($act == "edit" && isset($id)) { } elseif ($act == "edit" && isset($id)) {
$pconfig['type'] = $a_server[$id]['type']; $pconfig['type'] = $a_server[$id]['type'];
$pconfig['name'] = $a_server[$id]['name']; $pconfig['name'] = $a_server[$id]['name'];
...@@ -107,13 +110,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { ...@@ -107,13 +110,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
if (empty($pconfig['radius_auth_port'])) { if (empty($pconfig['radius_auth_port'])) {
$pconfig['radius_auth_port'] = 1812; $pconfig['radius_auth_port'] = 1812;
} }
} elseif ($pconfig['type'] == 'voucher') { } elseif (!empty($authCNFOptions[$pconfig['type']])) {
$pconfig['simplePasswords'] = $a_server[$id]['simplePasswords']; foreach ($authCNFOptions[$pconfig['type']]['additionalFields'] as $fieldname => $field) {
$pconfig['usernameLength'] = $a_server[$id]['usernameLength']; $pconfig[$fieldname] = $a_server[$id][$fieldname];
$pconfig['passwordLength'] = $a_server[$id]['passwordLength']; }
} elseif ($pconfig['type'] == 'totp') {
$pconfig['graceperiod'] = $a_server[$id]['graceperiod'];
$pconfig['timeWindow'] = $a_server[$id]['timeWindow'];
} }
} }
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
...@@ -166,12 +166,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { ...@@ -166,12 +166,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$reqdfields[] = "radius_secret"; $reqdfields[] = "radius_secret";
$reqdfieldsn[] = gettext("Shared Secret"); $reqdfieldsn[] = gettext("Shared Secret");
} }
} elseif ($pconfig['type'] == "voucher") { } elseif (!empty($authCNFOptions[$pconfig['type']])) {
if (!empty($pconfig['usernameLength']) && !is_numeric($pconfig['usernameLength'])) { foreach ($authCNFOptions[$pconfig['type']]['additionalFields'] as $fieldname => $field) {
$input_errors[] = gettext("username length must be a number or empty for default."); if (!empty($field['validate'])) {
foreach ($field['validate']($pconfig[$fieldname]) as $input_error) {
$input_errors[] = $input_error;
}
} }
if (!empty($pconfig['passwordLength']) && !is_numeric($pconfig['passwordLength'])) {
$input_errors[] = gettext("password length must be a number or empty for default.");
} }
} }
...@@ -251,13 +252,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { ...@@ -251,13 +252,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$server['radius_auth_port'] = $pconfig['radius_auth_port']; $server['radius_auth_port'] = $pconfig['radius_auth_port'];
unset($server['radius_acct_port']); unset($server['radius_acct_port']);
} }
} elseif ($server['type'] == "voucher") { } elseif (!empty($authCNFOptions[$server['type']])) {
$server['simplePasswords'] = !empty($pconfig['simplePasswords']); foreach ($authCNFOptions[$server['type']]['additionalFields'] as $fieldname => $field) {
$server['usernameLength'] = $pconfig['usernameLength']; $server[$fieldname] = $pconfig[$fieldname];
$server['passwordLength'] = $pconfig['passwordLength']; }
} elseif ($server['type'] == 'totp') {
$server['timeWindow'] = filter_var($pconfig['timeWindow'], FILTER_SANITIZE_NUMBER_INT);
$server['graceperiod'] = filter_var($pconfig['graceperiod'], FILTER_SANITIZE_NUMBER_INT);
} }
if (isset($id) && isset($config['system']['authserver'][$id])) { if (isset($id) && isset($config['system']['authserver'][$id])) {
...@@ -317,19 +315,11 @@ if (!isset($_GET['act']) || $_GET['act'] != 'new') ...@@ -317,19 +315,11 @@ if (!isset($_GET['act']) || $_GET['act'] != 'new')
<script type="text/javascript"> <script type="text/javascript">
$( document ).ready(function() { $( document ).ready(function() {
$("#type").change(function(){ $("#type").change(function(){
$(".auth_radius").addClass('hidden'); $(".auth_options").addClass('hidden');
$(".auth_ldap").addClass('hidden'); $(".auth_options :input").prop( "disabled", true );
$(".auth_voucher").addClass('hidden'); $(".auth_"+$(this).val()).removeClass('hidden');
$(".auth_totp").addClass('hidden'); $(".auth_"+$(this).val()+" :input").prop( "disabled", false );
if ($("#type").val() == 'ldap') { $('.selectpicker').selectpicker('refresh');
$(".auth_ldap").removeClass('hidden');
} else if ($("#type").val() == 'radius') {
$(".auth_radius").removeClass('hidden');
} else if ($("#type").val() == 'voucher') {
$(".auth_voucher").removeClass('hidden');
} else if ($("#type").val() == 'totp') {
$(".auth_totp").removeClass('hidden');
}
}); });
$("#ldap_urltype").change(function(){ $("#ldap_urltype").change(function(){
...@@ -465,10 +455,9 @@ endif; ?> ...@@ -465,10 +455,9 @@ endif; ?>
?> ?>
<select name='type' id='type' class="selectpicker" data-style="btn-default"> <select name='type' id='type' class="selectpicker" data-style="btn-default">
<?php <?php
foreach ($auth_server_types as $typename => $typedesc) : foreach ($authCNFOptions as $typename => $authType) :?>
?>
<option value="<?=$typename;?>" <?=$pconfig['type'] == $typename ? "selected=\"selected\"" : "";?> > <option value="<?=$typename;?>" <?=$pconfig['type'] == $typename ? "selected=\"selected\"" : "";?> >
<?=$typedesc;?> <?=$authType['description'];?>
</option> </option>
<?php <?php
endforeach; ?> endforeach; ?>
...@@ -476,14 +465,14 @@ endif; ?> ...@@ -476,14 +465,14 @@ endif; ?>
<?php <?php
else : else :
?> ?>
<strong><?=$auth_server_types[$pconfig['type']];?></strong> <strong><?=$authCNFOptions[$pconfig['type']]['description'];?></strong>
<input name='type' type='hidden' id='type' value="<?=$pconfig['type'];?>"/> <input name='type' type='hidden' id='type' value="<?=$pconfig['type'];?>"/>
<?php <?php
endif; ?> endif; ?>
</td> </td>
</tr> </tr>
<!-- LDAP --> <!-- LDAP -->
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><a id="help_for_ldap_host" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Hostname or IP address");?></td> <td><a id="help_for_ldap_host" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Hostname or IP address");?></td>
<td> <td>
<input name="ldap_host" type="text" id="ldap_host" size="20" value="<?=$pconfig['ldap_host'];?>"/> <input name="ldap_host" type="text" id="ldap_host" size="20" value="<?=$pconfig['ldap_host'];?>"/>
...@@ -492,13 +481,13 @@ endif; ?> ...@@ -492,13 +481,13 @@ endif; ?>
</div> </div>
</td> </td>
</tr> </tr>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Port value");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Port value");?></td>
<td> <td>
<input name="ldap_port" type="text" id="ldap_port" size="5" value="<?=$pconfig['ldap_port'];?>"/> <input name="ldap_port" type="text" id="ldap_port" size="5" value="<?=$pconfig['ldap_port'];?>"/>
</td> </td>
</tr> </tr>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Transport");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Transport");?></td>
<td> <td>
<select name='ldap_urltype' id='ldap_urltype' class="formselect selectpicker" data-style="btn-default"> <select name='ldap_urltype' id='ldap_urltype' class="formselect selectpicker" data-style="btn-default">
...@@ -511,7 +500,7 @@ endif; ?> ...@@ -511,7 +500,7 @@ endif; ?>
</select> </select>
</td> </td>
</tr> </tr>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><a id="help_for_ldap_caref" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Peer Certificate Authority"); ?></td> <td><a id="help_for_ldap_caref" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Peer Certificate Authority"); ?></td>
<td> <td>
<?php <?php
...@@ -535,7 +524,7 @@ endif; ?> ...@@ -535,7 +524,7 @@ endif; ?>
endif; ?> endif; ?>
</td> </td>
</tr> </tr>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Protocol version");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Protocol version");?></td>
<td> <td>
<select name='ldap_protver' id='ldap_protver' class="formselect selectpicker" data-style="btn-default"> <select name='ldap_protver' id='ldap_protver' class="formselect selectpicker" data-style="btn-default">
...@@ -544,7 +533,7 @@ endif; ?> ...@@ -544,7 +533,7 @@ endif; ?>
</select> </select>
</td> </td>
</tr> </tr>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><a id="help_for_ldap_binddn" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Bind credentials");?></td> <td><a id="help_for_ldap_binddn" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Bind credentials");?></td>
<td> <td>
<?=gettext("User DN:");?><br/> <?=gettext("User DN:");?><br/>
...@@ -556,7 +545,7 @@ endif; ?> ...@@ -556,7 +545,7 @@ endif; ?>
</div> </div>
</td> </td>
</tr> </tr>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Search scope");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Search scope");?></td>
<td> <td>
<div> <div>
...@@ -576,7 +565,7 @@ endif; ?> ...@@ -576,7 +565,7 @@ endif; ?>
</div> </div>
</td> </td>
</tr> </tr>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><a id="help_for_ldapauthcontainers" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Authentication containers");?></td> <td><a id="help_for_ldapauthcontainers" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Authentication containers");?></td>
<td> <td>
<ul class="list-inline"> <ul class="list-inline">
...@@ -591,7 +580,7 @@ endif; ?> ...@@ -591,7 +580,7 @@ endif; ?>
</div> </div>
</td> </td>
</tr> </tr>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><a id="help_for_ldap_extended_query" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Extended Query");?></td> <td><a id="help_for_ldap_extended_query" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Extended Query");?></td>
<td> <td>
<input name="ldap_extended_query" type="text" id="ldap_extended_query" size="40" value="<?=$pconfig['ldap_extended_query'];?>"/> <input name="ldap_extended_query" type="text" id="ldap_extended_query" size="40" value="<?=$pconfig['ldap_extended_query'];?>"/>
...@@ -602,7 +591,7 @@ endif; ?> ...@@ -602,7 +591,7 @@ endif; ?>
</tr> </tr>
<?php if (!isset($id)) : <?php if (!isset($id)) :
?> ?>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Initial Template");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Initial Template");?></td>
<td> <td>
<select name='ldap_tmpltype' id='ldap_tmpltype' class="formselect selectpicker" data-style="btn-default"> <select name='ldap_tmpltype' id='ldap_tmpltype' class="formselect selectpicker" data-style="btn-default">
...@@ -614,26 +603,26 @@ endif; ?> ...@@ -614,26 +603,26 @@ endif; ?>
</tr> </tr>
<?php <?php
endif; ?> endif; ?>
<tr class="auth_ldap hidden"> <tr class="auth_ldap auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("User naming attribute");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("User naming attribute");?></td>
<td> <td>
<input name="ldap_attr_user" type="text" id="ldap_attr_user" size="20" value="<?=$pconfig['ldap_attr_user'];?>"/> <input name="ldap_attr_user" type="text" id="ldap_attr_user" size="20" value="<?=$pconfig['ldap_attr_user'];?>"/>
</td> </td>
</tr> </tr>
<!-- RADIUS --> <!-- RADIUS -->
<tr class="auth_radius hidden"> <tr class="auth_radius auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Hostname or IP address");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Hostname or IP address");?></td>
<td> <td>
<input name="radius_host" type="text" id="radius_host" size="20" value="<?=$pconfig['radius_host'];?>"/> <input name="radius_host" type="text" id="radius_host" size="20" value="<?=$pconfig['radius_host'];?>"/>
</td> </td>
</tr> </tr>
<tr class="auth_radius hidden"> <tr class="auth_radius auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Shared Secret");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Shared Secret");?></td>
<td> <td>
<input name="radius_secret" type="password" class="formfld pwd" id="radius_secret" size="20" value="<?=$pconfig['radius_secret'];?>"/> <input name="radius_secret" type="password" class="formfld pwd" id="radius_secret" size="20" value="<?=$pconfig['radius_secret'];?>"/>
</td> </td>
</tr> </tr>
<tr class="auth_radius hidden"> <tr class="auth_radius auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Services offered");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Services offered");?></td>
<td> <td>
<select name='radius_srvcs' id='radius_srvcs' class="formselect selectpicker" data-style="btn-default"> <select name='radius_srvcs' id='radius_srvcs' class="formselect selectpicker" data-style="btn-default">
...@@ -646,19 +635,19 @@ endif; ?> ...@@ -646,19 +635,19 @@ endif; ?>
</select> </select>
</td> </td>
</tr> </tr>
<tr id="radius_auth" class="auth_radius hidden"> <tr id="radius_auth" class="auth_radius auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Authentication port value");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Authentication port value");?></td>
<td> <td>
<input name="radius_auth_port" type="text" id="radius_auth_port" size="5" value="<?=$pconfig['radius_auth_port'];?>"/> <input name="radius_auth_port" type="text" id="radius_auth_port" size="5" value="<?=$pconfig['radius_auth_port'];?>"/>
</td> </td>
</tr> </tr>
<tr id="radius_acct" class="auth_radius hidden"> <tr id="radius_acct" class="auth_radius auth_options hidden">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Accounting port value");?></td> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Accounting port value");?></td>
<td> <td>
<input name="radius_acct_port" type="text" id="radius_acct_port" size="5" value="<?=$pconfig['radius_acct_port'];?>"/> <input name="radius_acct_port" type="text" id="radius_acct_port" size="5" value="<?=$pconfig['radius_acct_port'];?>"/>
</td> </td>
</tr> </tr>
<tr class="auth_radius hidden"> <tr class="auth_radius auth_options hidden">
<td><a id="help_for_radius_timeout" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Authentication Timeout");?></td> <td><a id="help_for_radius_timeout" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Authentication Timeout");?></td>
<td> <td>
<input name="radius_timeout" type="text" id="radius_timeout" size="20" value="<?=$pconfig['radius_timeout'];?>"/> <input name="radius_timeout" type="text" id="radius_timeout" size="20" value="<?=$pconfig['radius_timeout'];?>"/>
...@@ -669,65 +658,56 @@ endif; ?> ...@@ -669,65 +658,56 @@ endif; ?>
</div> </div>
</td> </td>
</tr> </tr>
<!-- Vouchers --> <!-- pluggable options -->
<tr class="auth_voucher hidden"> <?php
<td><a id="help_for_voucher_simplepasswd" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Use simple passwords (less secure)");?></td> foreach ($authCNFOptions as $typename => $authtype):
<td> if (!empty($authtype['additionalFields'])):
<input name="simplePasswords" type="checkbox" value="yes" <?=!empty($pconfig['simplePasswords']) ? "checked=\"checked\"" : ""; ?>/> foreach ($authtype['additionalFields'] as $fieldname => $field):?>
<div class="hidden" for="help_for_voucher_simplepasswd">
<br /><?= gettext("Use simple (less secure) passwords, which are easier to read") ?> <tr class="auth_options auth_<?=$typename;?> hidden">
</div>
</td>
</tr>
<tr class="auth_voucher hidden">
<td><a id="help_for_voucher_usernameLength" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Username length");?></td>
<td>
<input name="usernameLength" type="text" value="<?=$pconfig['usernameLength'];?>"/>
<div class="hidden" for="help_for_voucher_usernameLength">
<?= gettext("Specify alternative username length for generating vouchers") ?>
</div>
</td>
</tr>
<tr class="auth_voucher hidden">
<td><a id="help_for_voucher_passwordLength" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Password length");?></td>
<td> <td>
<input name="passwordLength" type="text" value="<?=$pconfig['passwordLength'];?>"/> <?php
<div class="hidden" for="help_for_voucher_passwordLength"> if (!empty($field['help'])):?>
<?= gettext("Specify alternative password length for generating vouchers") ?> <a id="help_for_field_<?=$typename;?>_<?=$fieldname;?>" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a>
</div> <?php
else:?>
<i class="fa fa-info-circle text-muted"></i>
<?php
endif;?>
<?=$field['name']; ?>
</td> </td>
</tr>
<!-- TOTP -->
<tr class="auth_totp hidden">
<td><a id="help_for_totp_otpLength" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Token length");?></td>
<td> <td>
<select name="otpLength" class="selectpicker" data-style="btn-default"> <?php
<option value="6" <?=empty($pconfig['otpLength']) || $pconfig['otpLength'] == "6" ? "selected=\"selected\"" : "";?> >6</option> if ($field['type'] == 'text'):?>
<option value="8" <?=!empty($pconfig['otpLength']) && $pconfig['otpLength'] == "8" ? "selected=\"selected\"" : "";?> >8</option> <input name="<?=$fieldname;?>" type="text" value="<?=$pconfig[$fieldname];?>"/>
<?php
elseif ($field['type'] == 'dropdown'):?>
<select name="<?=$fieldname;?>" class="selectpicker" data-style="btn-default">
<?php
foreach ($field['options'] as $option => $optiontext):?>
<option value="<?=$option;?>" <?=(empty($pconfig[$fieldname]) && $field['default'] == $option) || $pconfig[$fieldname] == $option ? "selected=\"selected\"" : "";?> >
<?=$optiontext;?>
</option>
<?php
endforeach;?>
</select> </select>
<div class="hidden" for="help_for_totp_otpLength"> <?php
<?= gettext("Token length to use") ?> elseif ($field['type'] == 'checkbox'):?>
</div> <input name="<?=$fieldname;?>" type="checkbox" value="1" <?=!empty($pconfig[$fieldname]) ? "checked=\"checked\"" : ""; ?>/>
</td> <?php
</tr> endif;?>
<tr class="auth_totp hidden"> <div class="hidden" for="help_for_field_<?=$typename;?>_<?=$fieldname;?>">
<td><a id="help_for_totp_timeWindow" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Time window");?></td> <?=$field['help'];?>
<td>
<input name="timeWindow" type="text" value="<?=$pconfig['timeWindow'];?>"/>
<div class="hidden" for="help_for_totp_timeWindow">
<?= gettext("The time period in which the token will be valid, default is 30 seconds (google authenticator)") ?>
</div>
</td>
</tr>
<tr class="auth_totp hidden">
<td><a id="help_for_totp_graceperiod" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Grace period");?></td>
<td>
<input name="graceperiod" type="text" value="<?=$pconfig['graceperiod'];?>"/>
<div class="hidden" for="help_for_totp_graceperiod">
<?= gettext("Time in seconds in which this server and the token may differ, default is 10 seconds. Set higher for a less secure easier match.") ?>
</div> </div>
</td> </td>
</tr> </tr>
<?php
endforeach;
endif;
endforeach;?>
<!-- /pluggable options -->
<tr> <tr>
<td>&nbsp;</td> <td>&nbsp;</td>
<td> <td>
...@@ -763,7 +743,7 @@ $i = 0; ...@@ -763,7 +743,7 @@ $i = 0;
?> ?>
<tr> <tr>
<td><?=$server['name']?></td> <td><?=$server['name']?></td>
<td><?=!empty($auth_server_types[$server['type']]) ? $auth_server_types[$server['type']] : "";;?></td> <td><?=!empty($authCNFOptions[$server['type']]) ? $authCNFOptions[$server['type']]['description'] : "";;?></td>
<td><?=$server['host'];?></td> <td><?=$server['host'];?></td>
<td> <td>
<?php if ($i < (count($a_server) - 1)) : <?php if ($i < (count($a_server) - 1)) :
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment