From 4543c73b4f89bf522f4d5a136533f0ece4d1e6f2 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 9 Oct 2019 11:43:22 +0200 Subject: [PATCH] add possibility to enable/disable api access on a per user base Signed-off-by: Michael Kaufmann --- install/froxlor.sql | 4 +- install/lib/class.FroxlorInstall.php | 1 + .../updates/froxlor/0.10/update_0.10.inc.php | 10 ++++ lib/Froxlor/Api/Commands/Admins.php | 15 +++++- lib/Froxlor/Api/Commands/Customers.php | 54 +++++-------------- lib/Froxlor/Api/FroxlorRPC.php | 11 +++- lib/Froxlor/Froxlor.php | 2 +- .../admin/admin/formfield.admin_add.php | 15 ++++++ .../admin/admin/formfield.admin_edit.php | 15 ++++++ .../admin/customer/formfield.customer_add.php | 19 ++++++- .../customer/formfield.customer_edit.php | 15 ++++++ lng/english.lng.php | 2 + lng/german.lng.php | 2 + 13 files changed, 115 insertions(+), 50 deletions(-) diff --git a/install/froxlor.sql b/install/froxlor.sql index b150ab48..da14ee16 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -132,6 +132,7 @@ CREATE TABLE `panel_admins` ( `custom_notes_show` tinyint(1) NOT NULL default '0', `type_2fa` tinyint(1) NOT NULL default '0', `data_2fa` varchar(500) NOT NULL default '', + `api_allowed` tinyint(1) NOT NULL default '1', PRIMARY KEY (`adminid`), UNIQUE KEY `loginname` (`loginname`) ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci; @@ -199,6 +200,7 @@ CREATE TABLE `panel_customers` ( `allowed_phpconfigs` varchar(500) NOT NULL default '', `type_2fa` tinyint(1) NOT NULL default '0', `data_2fa` varchar(500) NOT NULL default '', + `api_allowed` tinyint(1) NOT NULL default '1', `logviewenabled` tinyint(1) NOT NULL default '0', PRIMARY KEY (`customerid`), UNIQUE KEY `loginname` (`loginname`) @@ -684,7 +686,7 @@ opcache.interned_strings_buffer'), ('panel', 'customer_hide_options', ''), ('panel', 'is_configured', '0'), ('panel', 'version', '0.10.0'), - ('panel', 'db_version', '201910030'); + ('panel', 'db_version', '201910090'); DROP TABLE IF EXISTS `panel_tasks`; diff --git a/install/lib/class.FroxlorInstall.php b/install/lib/class.FroxlorInstall.php index 1ae347a0..ddc3166a 100644 --- a/install/lib/class.FroxlorInstall.php +++ b/install/lib/class.FroxlorInstall.php @@ -407,6 +407,7 @@ class FroxlorInstall `name` = 'Froxlor-Administrator', `email` = :email, `def_language` = :deflang, + `api_allowed` = 1, `customers` = -1, `customers_see_all` = 1, `caneditphpsettings` = 1, diff --git a/install/updates/froxlor/0.10/update_0.10.inc.php b/install/updates/froxlor/0.10/update_0.10.inc.php index a3a1827f..43bc0f99 100644 --- a/install/updates/froxlor/0.10/update_0.10.inc.php +++ b/install/updates/froxlor/0.10/update_0.10.inc.php @@ -339,3 +339,13 @@ if (\Froxlor\Froxlor::isDatabaseVersion('201909150')) { \Froxlor\Froxlor::updateToDbVersion('201910030'); } + +if (\Froxlor\Froxlor::isDatabaseVersion('201910030')) { + + showUpdateStep("Adding field api_allowed to admins and customers"); + Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` ADD `api_allowed` tinyint(1) NOT NULL default '1';"); + Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `api_allowed` tinyint(1) NOT NULL default '1';"); + lastStepStatus(0); + + \Froxlor\Froxlor::updateToDbVersion('201910090'); +} diff --git a/lib/Froxlor/Api/Commands/Admins.php b/lib/Froxlor/Api/Commands/Admins.php index a29ac9ad..72b7bb48 100644 --- a/lib/Froxlor/Api/Commands/Admins.php +++ b/lib/Froxlor/Api/Commands/Admins.php @@ -97,6 +97,8 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * optional, default auto-generated * @param string $def_language * optional, default is system-default language + * @param bool $api_allowed + * optional, default is true if system setting api.enabled is true, else false * @param string $custom_notes * optional, default empty * @param bool $custom_notes_show @@ -171,6 +173,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt // parameters $def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage')); + $api_allowed = $this->getBoolParam('api_allowed', true, Settings::Get('api.enabled')); $custom_notes = $this->getParam('custom_notes', true, ''); $custom_notes_show = $this->getBoolParam('custom_notes_show', true, 0); $password = $this->getParam('admin_password', true, ''); @@ -271,6 +274,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt 'name' => $name, 'email' => $email, 'lang' => $def_language, + 'api_allowed' => $api_allowed, 'change_serversettings' => $change_serversettings, 'customers' => $customers, 'customers_see_all' => $customers_see_all, @@ -299,6 +303,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt `name` = :name, `email` = :email, `def_language` = :lang, + `api_allowed` = :api_allowed, `change_serversettings` = :change_serversettings, `customers` = :customers, `customers_see_all` = :customers_see_all, @@ -350,6 +355,8 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * optional, default auto-generated * @param string $def_language * optional, default is system-default language + * @param bool $api_allowed + * optional, default is true if system setting api.enabled is true, else false * @param string $custom_notes * optional, default empty * @param string $theme @@ -444,6 +451,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt // you cannot edit some of the details of yourself if ($result['adminid'] == $this->getUserDetail('adminid')) { + $api_allowed = $result['api_allowed']; $deactivated = $result['deactivated']; $customers = $result['customers']; $domains = $result['domains']; @@ -462,6 +470,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt $traffic = $result['traffic']; $ipaddress = ($result['ip'] != - 1 ? json_decode($result['ip'], true) : - 1); } else { + $api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']); $deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']); $dec_places = Settings::Get('panel.decimal_places'); @@ -578,6 +587,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt 'name' => $name, 'email' => $email, 'lang' => $def_language, + 'api_allowed' => $api_allowed, 'change_serversettings' => $change_serversettings, 'customers' => $customers, 'customers_see_all' => $customers_see_all, @@ -607,6 +617,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt `name` = :name, `email` = :email, `def_language` = :lang, + `api_allowed` = :api_allowed, `change_serversettings` = :change_serversettings, `customers` = :customers, `customers_see_all` = :customers_see_all, @@ -793,7 +804,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * @param string $extra * optional, default empty * @param int $increase_by - * optional, default 1 + * optional, default 1 */ public static function increaseUsage($adminid = 0, $resource = null, $extra = '', $increase_by = 1) { @@ -808,7 +819,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * @param string $extra * optional, default empty * @param int $decrease_by - * optional, default 1 + * optional, default 1 */ public static function decreaseUsage($adminid = 0, $resource = null, $extra = '', $decrease_by = 1) { diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index 1fb82107..8d500f9b 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -136,6 +136,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource * optional * @param string $def_language, * optional, default is system-default language + * @param bool $api_allowed + * optional, default is true if system setting api.enabled is true, else false * @param int $gender * optional, 0 = no-gender, 1 = male, 2 = female * @param string $custom_notes @@ -229,6 +231,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $fax = $this->getParam('fax', true, ''); $customernumber = $this->getParam('customernumber', true, ''); $def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage')); + $api_allowed = $this->getBoolParam('api_allowed', true, Settings::Get('api.enabled')); $gender = (int) $this->getParam('gender', true, 0); $custom_notes = $this->getParam('custom_notes', true, ''); $custom_notes_show = $this->getBoolParam('custom_notes_show', true, 0); @@ -388,26 +391,6 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource \Froxlor\UI\Response::standard_error('documentrootexists', $documentroot, true); } - if ($createstdsubdomain != '1') { - $createstdsubdomain = '0'; - } - - if ($phpenabled != '0') { - $phpenabled = '1'; - } - - if ($perlenabled != '0') { - $perlenabled = '1'; - } - - if ($dnsenabled != '0') { - $dnsenabled = '1'; - } - - if ($logviewenabled != '0') { - $logviewenabled = '1'; - } - if ($password == '') { $password = \Froxlor\System\Crypt::generatePassword(); } @@ -430,6 +413,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource 'email' => $email, 'customerno' => $customernumber, 'lang' => $def_language, + 'api_allowed' => $api_allowed, 'docroot' => $documentroot, 'guid' => $guid, 'diskspace' => $diskspace, @@ -470,6 +454,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource `email` = :email, `customernumber` = :customerno, `def_language` = :lang, + `api_allowed` = :api_allowed, `documentroot` = :docroot, `guid` = :guid, `diskspace` = :diskspace, @@ -755,6 +740,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource * optional * @param string $def_language, * optional, default is system-default language + * @param bool $api_allowed + * optional, default is true if system setting api.enabled is true, else false * @param int $gender * optional, 0 = no-gender, 1 = male, 2 = female * @param string $custom_notes @@ -857,6 +844,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $fax = $this->getParam('fax', true, $result['fax']); $customernumber = $this->getParam('customernumber', true, $result['customernumber']); $def_language = $this->getParam('def_language', true, $result['def_language']); + $api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']); $gender = (int) $this->getParam('gender', true, $result['gender']); $custom_notes = $this->getParam('custom_notes', true, $result['custom_notes']); $custom_notes_show = $this->getBoolParam('custom_notes_show', true, $result['custom_notes_show']); @@ -999,30 +987,10 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource \Froxlor\System\Cronjob::inserttask('1'); } - if ($deactivated != '1') { - $deactivated = '0'; - } - - if ($phpenabled != '0') { - $phpenabled = '1'; - } - - if ($perlenabled != '0') { - $perlenabled = '1'; - } - - if ($dnsenabled != '0') { - $dnsenabled = '1'; - } - if ($phpenabled != $result['phpenabled'] || $perlenabled != $result['perlenabled']) { \Froxlor\System\Cronjob::inserttask('1'); } - if ($logviewenabled != '0') { - $logviewenabled = '1'; - } - // activate/deactivate customer services if ($deactivated != $result['deactivated']) { @@ -1166,7 +1134,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource 'dnsenabled' => $dnsenabled, 'logviewenabled' => $logviewenabled, 'custom_notes' => $custom_notes, - 'custom_notes_show' => $custom_notes_show + 'custom_notes_show' => $custom_notes_show, + 'api_allowed' => $api_allowed ); $upd_data = $upd_data + $admin_upd_data; } @@ -1207,7 +1176,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource `dnsenabled` = :dnsenabled, `logviewenabled` = :logviewenabled, `custom_notes` = :custom_notes, - `custom_notes_show` = :custom_notes_show"; + `custom_notes_show` = :custom_notes_show, + `api_allowed` = :api_allowed"; $upd_query .= $admin_upd_query; } $upd_query .= " WHERE `customerid` = :customerid"; diff --git a/lib/Froxlor/Api/FroxlorRPC.php b/lib/Froxlor/Api/FroxlorRPC.php index d96e2c7c..f4dce617 100644 --- a/lib/Froxlor/Api/FroxlorRPC.php +++ b/lib/Froxlor/Api/FroxlorRPC.php @@ -55,13 +55,20 @@ class FroxlorRPC */ private static function validateAuth($key, $secret) { - $sel_stmt = \Froxlor\Database\Database::prepare("SELECT * FROM `api_keys` WHERE `apikey` = :ak AND `secret` = :as"); + $sel_stmt = \Froxlor\Database\Database::prepare(" + SELECT ak.*, a.api_allowed as admin_api_allowed, c.api_allowed as cust_api_allowed + FROM `api_keys` ak + LEFT JOIN `panel_admins` a ON a.adminid = ak.adminid + LEFT JOIN `panel_customers` c ON c.customerid = ak.customerid + WHERE `apikey` = :ak AND `secret` = :as + "); $result = \Froxlor\Database\Database::pexecute_first($sel_stmt, array( 'ak' => $key, 'as' => $secret ), true, true); if ($result) { - if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == - 1 || $result['valid_until'] >= time())) { + if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == - 1 || $result['valid_until'] >= time()) && (($result['customerid'] == 0 && $result['admin_api_allowed'] == 1) || ($result['customerid'] > 0 && $result['cust_api_allowed'] == 1))) { + // get user to check whether api call is allowed if (! empty($result['allowed_from'])) { // @todo allow specification and validating of whole subnets later $ip_list = explode(",", $result['allowed_from']); diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 6abe1274..a9382f05 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -10,7 +10,7 @@ final class Froxlor const VERSION = '0.10.0'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '201910030'; + const DBVERSION = '201910090'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; diff --git a/lib/formfields/admin/admin/formfield.admin_add.php b/lib/formfields/admin/admin/formfield.admin_add.php index d2ac4b67..24b41211 100644 --- a/lib/formfields/admin/admin/formfield.admin_add.php +++ b/lib/formfields/admin/admin/formfield.admin_add.php @@ -44,6 +44,21 @@ return array( 'label' => $lng['login']['language'], 'type' => 'select', 'select_var' => $language_options + ), + 'api_allowed' => array( + 'label' => $lng['usersettings']['api_allowed']['title'], + 'desc' => $lng['usersettings']['api_allowed']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + '1' + ), + 'visible' => (\Froxlor\Settings::Get('api.enabled') == '1' ? true : false) ) ) ), diff --git a/lib/formfields/admin/admin/formfield.admin_edit.php b/lib/formfields/admin/admin/formfield.admin_edit.php index b0b7f5a4..4827d4ae 100644 --- a/lib/formfields/admin/admin/formfield.admin_edit.php +++ b/lib/formfields/admin/admin/formfield.admin_edit.php @@ -59,6 +59,21 @@ return array( 'type' => 'select', 'select_var' => $language_options, 'visible' => ($result['adminid'] == $userinfo['userid'] ? false : true) + ), + 'api_allowed' => array( + 'label' => $lng['usersettings']['api_allowed']['title'], + 'desc' => $lng['usersettings']['api_allowed']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['api_allowed'] + ), + 'visible' => (\Froxlor\Settings::Get('api.enabled') == '1' ? true : false) ) ) ), diff --git a/lib/formfields/admin/customer/formfield.customer_add.php b/lib/formfields/admin/customer/formfield.customer_add.php index 2afb1b2b..ede3cc94 100644 --- a/lib/formfields/admin/customer/formfield.customer_add.php +++ b/lib/formfields/admin/customer/formfield.customer_add.php @@ -81,6 +81,21 @@ return array( 'label' => $lng['login']['language'], 'type' => 'select', 'select_var' => $language_options + ), + 'api_allowed' => array( + 'label' => $lng['usersettings']['api_allowed']['title'], + 'desc' => $lng['usersettings']['api_allowed']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + '1' + ), + 'visible' => (\Froxlor\Settings::Get('api.enabled') == '1' ? true : false) ) ) ), @@ -294,9 +309,9 @@ return array( 'values' => $phpconfigs, 'value' => ((int) \Froxlor\Settings::Get('system.mod_fcgid') == 1 ? array( \Froxlor\Settings::Get('system.mod_fcgid_defaultini') - ) : (int) \Froxlor\Settings::Get('phpfpm.enabled') == 1 ? array( + ) : ((int) \Froxlor\Settings::Get('phpfpm.enabled') == 1 ? array( \Froxlor\Settings::Get('phpfpm.defaultini') - ) : array()), + ) : array())), 'is_array' => 1 ), 'perlenabled' => array( diff --git a/lib/formfields/admin/customer/formfield.customer_edit.php b/lib/formfields/admin/customer/formfield.customer_edit.php index 9f5879da..47980f3c 100644 --- a/lib/formfields/admin/customer/formfield.customer_edit.php +++ b/lib/formfields/admin/customer/formfield.customer_edit.php @@ -74,6 +74,21 @@ return array( 'label' => $lng['login']['language'], 'type' => 'select', 'select_var' => $language_options + ), + 'api_allowed' => array( + 'label' => $lng['usersettings']['api_allowed']['title'], + 'desc' => $lng['usersettings']['api_allowed']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['api_allowed'] + ), + 'visible' => (\Froxlor\Settings::Get('api.enabled') == '1' ? true : false) ) ) ), diff --git a/lng/english.lng.php b/lng/english.lng.php index 66c1debb..86980a64 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -2069,3 +2069,5 @@ $lng['serversettings']['froxloraliases']['description'] = "Comma separated list $lng['serversettings']['ssl']['tlsv13_cipher_list']['title'] = 'Configure explicit TLSv1.3 ciphers if used'; $lng['serversettings']['ssl']['tlsv13_cipher_list']['description'] = 'This is a list of ciphers that you want (or don\'t want) to use when talking TLSv1.3. For a list of ciphers and how to include/exclude them, see the docs for TLSv1.3.

Default value is empty'; +$lng['usersettings']['api_allowed']['title'] = 'Allow API access'; +$lng['usersettings']['api_allowed']['description'] = 'When enabled in the settings, this user can create API keys and access the froxlor API'; diff --git a/lng/german.lng.php b/lng/german.lng.php index 0e012d30..a4988273 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -1716,3 +1716,5 @@ $lng['serversettings']['froxloraliases']['description'] = "Komma getrennte Liste $lng['serversettings']['ssl']['tlsv13_cipher_list']['title'] = 'Explizite TLSv1.3 Ciphers, wenn genutzt'; $lng['serversettings']['ssl']['tlsv13_cipher_list']['description'] = 'Dies ist eine Liste von Ciphers, die genutzt werden sollen (oder auch nicht genutzt werden sollen), wenn eine TLSv1.3 Verbindung hergestellt werden soll. Eine Liste aller Ciphers und wie diese hinzugefügt/ausgeschlossen werden ist der Dokumentation für TLSv1.3 zu entnehmen.

Standard-Wert ist leer'; +$lng['usersettings']['api_allowed']['title'] = 'Erlaube API Zugriff'; +$lng['usersettings']['api_allowed']['description'] = 'Wenn in den Einstellungen aktiviert, kann der Benutzer API Schlüssel erstellen und auf die froxlor API Zugreifen';